]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
Rollup merge of #101193 - thomcc:win-stdio-nozero, r=ChrisDenton
[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::find_anon_type::find_anon_type;
4 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
5 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
6 use rustc_middle::ty;
7 use rustc_span::symbol::kw;
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(
13         &self,
14     ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
15         let (span, sub, sup) = self.regions()?;
16
17         debug!(
18             "try_report_named_anon_conflict(sub={:?}, sup={:?}, error={:?})",
19             sub, sup, self.error,
20         );
21
22         // Determine whether the sub and sup consist of one named region ('a)
23         // and one anonymous (elided) region. If so, find the parameter arg
24         // where the anonymous region appears (there must always be one; we
25         // only introduced anonymous regions in parameters) as well as a
26         // version new_ty of its type where the anonymous region is replaced
27         // with the named one.
28         let (named, anon, anon_param_info, region_info) = if sub.has_name()
29             && self.tcx().is_suitable_region(sup).is_some()
30             && self.find_param_with_region(sup, sub).is_some()
31         {
32             (
33                 sub,
34                 sup,
35                 self.find_param_with_region(sup, sub).unwrap(),
36                 self.tcx().is_suitable_region(sup).unwrap(),
37             )
38         } else if sup.has_name()
39             && self.tcx().is_suitable_region(sub).is_some()
40             && self.find_param_with_region(sub, sup).is_some()
41         {
42             (
43                 sup,
44                 sub,
45                 self.find_param_with_region(sub, sup).unwrap(),
46                 self.tcx().is_suitable_region(sub).unwrap(),
47             )
48         } else {
49             return None; // inapplicable
50         };
51
52         // Suggesting to add a `'static` lifetime to a parameter is nearly always incorrect,
53         // and can steer users down the wrong path.
54         if named.is_static() {
55             return None;
56         }
57
58         debug!("try_report_named_anon_conflict: named = {:?}", named);
59         debug!("try_report_named_anon_conflict: anon_param_info = {:?}", anon_param_info);
60         debug!("try_report_named_anon_conflict: region_info = {:?}", region_info);
61
62         let param = anon_param_info.param;
63         let new_ty = anon_param_info.param_ty;
64         let new_ty_span = anon_param_info.param_ty_span;
65         let br = anon_param_info.bound_region;
66         let is_first = anon_param_info.is_first;
67         let scope_def_id = region_info.def_id;
68         let is_impl_item = region_info.is_impl_item;
69
70         match br {
71             ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) => {}
72             _ => {
73                 /* not an anonymous region */
74                 debug!("try_report_named_anon_conflict: not an anonymous region");
75                 return None;
76             }
77         }
78
79         if is_impl_item {
80             debug!("try_report_named_anon_conflict: impl item, bail out");
81             return None;
82         }
83
84         if find_anon_type(self.tcx(), anon, &br).is_some()
85             && self.is_self_anon(is_first, scope_def_id)
86         {
87             return None;
88         }
89
90         let (error_var, span_label_var) = match param.pat.simple_ident() {
91             Some(simple_ident) => (
92                 format!("the type of `{}`", simple_ident),
93                 format!("the type of `{}`", simple_ident),
94             ),
95             None => ("parameter type".to_owned(), "type".to_owned()),
96         };
97
98         let mut diag = struct_span_err!(
99             self.tcx().sess,
100             span,
101             E0621,
102             "explicit lifetime required in {}",
103             error_var
104         );
105
106         diag.span_label(span, format!("lifetime `{}` required", named));
107         diag.span_suggestion(
108             new_ty_span,
109             &format!("add explicit lifetime `{}` to {}", named, span_label_var),
110             new_ty,
111             Applicability::Unspecified,
112         );
113
114         Some(diag)
115     }
116 }