]> git.lizzy.rs Git - rust.git/blob - src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs
Add comment about the lack of `ExpnData` serialization for proc-macro crates
[rust.git] / src / librustc_infer / 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
89                         .into_iter()
90                         .filter(|t| t.span.desugaring_kind().is_none())
91                         .next()
92                         .is_some()
93                 {
94                     // If the failure is due to a `'static` requirement coming from a `dyn` or
95                     // `impl` Trait that *isn't* caused by `async fn` desugaring, handle this case
96                     // better in `static_impl_trait`.
97                     debug!("try_report_named_anon_conflict: impl Trait + 'static");
98                     return None;
99                 }
100             }
101         }
102
103         let (error_var, span_label_var) = match param.pat.simple_ident() {
104             Some(simple_ident) => (
105                 format!("the type of `{}`", simple_ident),
106                 format!("the type of `{}`", simple_ident),
107             ),
108             None => ("parameter type".to_owned(), "type".to_owned()),
109         };
110
111         let mut diag = struct_span_err!(
112             self.tcx().sess,
113             span,
114             E0621,
115             "explicit lifetime required in {}",
116             error_var
117         );
118
119         diag.span_label(span, format!("lifetime `{}` required", named));
120         diag.span_suggestion(
121             new_ty_span,
122             &format!("add explicit lifetime `{}` to {}", named, span_label_var),
123             new_ty.to_string(),
124             Applicability::Unspecified,
125         );
126
127         Some(diag)
128     }
129 }