]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
[fuchsia] Propagate the userspace UTC clock
[rust.git] / compiler / rustc_infer / src / 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 rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
5 use rustc_hir::intravisit::Visitor;
6 use rustc_hir::FnRetTy;
7 use rustc_middle::ty;
8
9 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
10     /// When given a `ConcreteFailure` for a function with parameters containing a named region and
11     /// an anonymous region, emit an descriptive diagnostic error.
12     pub(super) fn try_report_named_anon_conflict(&self) -> Option<DiagnosticBuilder<'a>> {
13         let (span, sub, sup) = self.regions()?;
14
15         debug!(
16             "try_report_named_anon_conflict(sub={:?}, sup={:?}, error={:?})",
17             sub, sup, self.error,
18         );
19
20         // Determine whether the sub and sup consist of one named region ('a)
21         // and one anonymous (elided) region. If so, find the parameter arg
22         // where the anonymous region appears (there must always be one; we
23         // only introduced anonymous regions in parameters) as well as a
24         // version new_ty of its type where the anonymous region is replaced
25         // with the named one.
26         let (named, anon, anon_param_info, region_info) = if sub.has_name()
27             && self.tcx().is_suitable_region(sup).is_some()
28             && self.find_param_with_region(sup, sub).is_some()
29         {
30             (
31                 sub,
32                 sup,
33                 self.find_param_with_region(sup, sub).unwrap(),
34                 self.tcx().is_suitable_region(sup).unwrap(),
35             )
36         } else if sup.has_name()
37             && self.tcx().is_suitable_region(sub).is_some()
38             && self.find_param_with_region(sub, sup).is_some()
39         {
40             (
41                 sup,
42                 sub,
43                 self.find_param_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!("try_report_named_anon_conflict: anon_param_info = {:?}", anon_param_info);
52         debug!("try_report_named_anon_conflict: region_info = {:?}", region_info);
53
54         let (param, new_ty, new_ty_span, br, is_first, scope_def_id, is_impl_item) = (
55             anon_param_info.param,
56             anon_param_info.param_ty,
57             anon_param_info.param_ty_span,
58             anon_param_info.bound_region,
59             anon_param_info.is_first,
60             region_info.def_id,
61             region_info.is_impl_item,
62         );
63         match br {
64             ty::BrAnon(_) => {}
65             _ => {
66                 /* not an anonymous region */
67                 debug!("try_report_named_anon_conflict: not an anonymous region");
68                 return None;
69             }
70         }
71
72         if is_impl_item {
73             debug!("try_report_named_anon_conflict: impl item, bail out");
74             return None;
75         }
76
77         if let Some((_, fndecl)) = self.find_anon_type(anon, &br) {
78             if self.is_self_anon(is_first, scope_def_id) {
79                 return None;
80             }
81
82             if let FnRetTy::Return(ty) = &fndecl.output {
83                 let mut v = ty::TraitObjectVisitor(vec![], self.tcx().hir());
84                 v.visit_ty(ty);
85
86                 debug!("try_report_named_anon_conflict: ret ty {:?}", ty);
87                 if sub == &ty::ReStatic
88                     && v.0.into_iter().find(|t| t.span.desugaring_kind().is_none()).is_some()
89                 {
90                     // If the failure is due to a `'static` requirement coming from a `dyn` or
91                     // `impl` Trait that *isn't* caused by `async fn` desugaring, handle this case
92                     // better in `static_impl_trait`.
93                     debug!("try_report_named_anon_conflict: impl Trait + 'static");
94                     return None;
95                 }
96             }
97         }
98
99         let (error_var, span_label_var) = match param.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 }