]> git.lizzy.rs Git - rust.git/blob - src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs
rustc: async fn drop order lowering in HIR
[rust.git] / src / librustc / infer / error_reporting / nice_region_error / named_anon_conflict.rs
1 //! Error Reporting for Anonymous Region Lifetime Errors
2 //! where one region is named and the other is anonymous.
3 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
4 use crate::hir::{FunctionRetTy, TyKind};
5 use crate::ty;
6 use errors::{Applicability, DiagnosticBuilder};
7
8 impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
9     /// When given a `ConcreteFailure` for a function with arguments containing a named region and
10     /// an anonymous region, emit an descriptive diagnostic error.
11     pub(super) fn try_report_named_anon_conflict(&self) -> Option<DiagnosticBuilder<'a>> {
12         let (span, sub, sup) = self.get_regions();
13
14         debug!(
15             "try_report_named_anon_conflict(sub={:?}, sup={:?}, error={:?})",
16             sub,
17             sup,
18             self.error,
19         );
20
21         // Determine whether the sub and sup consist of one named region ('a)
22         // and one anonymous (elided) region. If so, find the parameter arg
23         // where the anonymous region appears (there must always be one; we
24         // only introduced anonymous regions in parameters) as well as a
25         // version new_ty of its type where the anonymous region is replaced
26         // with the named one.//scope_def_id
27         let (named, anon, anon_arg_info, region_info) = if self.is_named_region(sub)
28             && self.tcx().is_suitable_region(sup).is_some()
29             && self.find_arg_with_region(sup, sub).is_some()
30         {
31             (
32                 sub,
33                 sup,
34                 self.find_arg_with_region(sup, sub).unwrap(),
35                 self.tcx().is_suitable_region(sup).unwrap(),
36             )
37         } else if self.is_named_region(sup) && self.tcx().is_suitable_region(sub).is_some()
38             && self.find_arg_with_region(sub, sup).is_some()
39         {
40             (
41                 sup,
42                 sub,
43                 self.find_arg_with_region(sub, sup).unwrap(),
44                 self.tcx().is_suitable_region(sub).unwrap(),
45             )
46         } else {
47             return None; // inapplicable
48         };
49
50         debug!("try_report_named_anon_conflict: named = {:?}", named);
51         debug!(
52             "try_report_named_anon_conflict: anon_arg_info = {:?}",
53             anon_arg_info
54         );
55         debug!(
56             "try_report_named_anon_conflict: region_info = {:?}",
57             region_info
58         );
59
60         let (arg, new_ty, new_ty_span, br, is_first, scope_def_id, is_impl_item) = (
61             anon_arg_info.arg,
62             anon_arg_info.arg_ty,
63             anon_arg_info.arg_ty_span,
64             anon_arg_info.bound_region,
65             anon_arg_info.is_first,
66             region_info.def_id,
67             region_info.is_impl_item,
68         );
69         match br {
70             ty::BrAnon(_) => {}
71             _ => {
72                 /* not an anonymous region */
73                 debug!("try_report_named_anon_conflict: not an anonymous region");
74                 return None;
75             }
76         }
77
78         if is_impl_item {
79             debug!("try_report_named_anon_conflict: impl item, bail out");
80             return None;
81         }
82
83         if let Some((_, fndecl)) = self.find_anon_type(anon, &br) {
84             if self.is_return_type_anon(scope_def_id, br, fndecl).is_some()
85                 || self.is_self_anon(is_first, scope_def_id)
86             {
87                 return None;
88             }
89             if let FunctionRetTy::Return(ty) = &fndecl.output {
90                 if let (TyKind::Def(_, _), ty::ReStatic) = (&ty.node, sub) {
91                     // This is an impl Trait return that evaluates de need of 'static.
92                     // We handle this case better in `static_impl_trait`.
93                     return None;
94                 }
95             }
96         }
97
98         let arg_pat = self.tcx().hir().original_pat_of_argument(arg);
99         let (error_var, span_label_var) = match arg_pat.simple_ident() {
100             Some(simple_ident) => (
101                 format!("the type of `{}`", simple_ident),
102                 format!("the type of `{}`", simple_ident),
103             ),
104             None => ("parameter type".to_owned(), "type".to_owned()),
105         };
106
107         let mut diag = struct_span_err!(
108             self.tcx().sess,
109             span,
110             E0621,
111             "explicit lifetime required in {}",
112             error_var
113         );
114
115         diag.span_label(span, format!("lifetime `{}` required", named));
116         diag.span_suggestion(
117             new_ty_span,
118             &format!("add explicit lifetime `{}` to {}", named, span_label_var),
119             new_ty.to_string(),
120             Applicability::Unspecified,
121         );
122
123         Some(diag)
124     }
125
126     // This method returns whether the given Region is Named
127     pub(super) fn is_named_region(&self, region: ty::Region<'tcx>) -> bool {
128         match *region {
129             ty::ReStatic => true,
130             ty::ReFree(ref free_region) => match free_region.bound_region {
131                 ty::BrNamed(..) => true,
132                 _ => false,
133             },
134             ty::ReEarlyBound(ebr) => ebr.has_name(),
135             _ => false,
136         }
137     }
138 }