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