1 //! Error Reporting for Anonymous Region Lifetime Errors
2 //! where both the regions are anonymous.
4 use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
5 use crate::infer::error_reporting::nice_region_error::util::AnonymousParamInfo;
6 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
7 use crate::infer::lexical_region_resolve::RegionResolutionError;
8 use crate::infer::SubregionOrigin;
10 use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorReported};
12 use rustc_hir::{GenericParamKind, Ty};
13 use rustc_middle::ty::Region;
15 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
16 /// Print the error message for lifetime errors when both the concerned regions are anonymous.
18 /// Consider a case where we have
21 /// fn foo(x: &mut Vec<&u8>, y: &u8) {
29 /// fn foo(x: &mut Vec<&u8>, y: &u8) {
30 /// --- --- these references are declared with different lifetimes...
32 /// ^ ...but data from `y` flows into `x` here
35 /// It has been extended for the case of structs too.
37 /// Consider the example
40 /// struct Ref<'a> { x: &'a u32 }
44 /// fn foo(mut x: Vec<Ref>, y: Ref) {
45 /// --- --- these structs are declared with different lifetimes...
47 /// ^ ...but data from `y` flows into `x` here
51 /// It will later be extended to trait objects.
52 pub(super) fn try_report_anon_anon_conflict(&self) -> Option<ErrorReported> {
53 let (span, sub, sup) = self.regions()?;
55 if let Some(RegionResolutionError::ConcreteFailure(
56 SubregionOrigin::ReferenceOutlivesReferent(..),
60 // This error doesn't make much sense in this case.
64 // Determine whether the sub and sup consist of both anonymous (elided) regions.
65 let anon_reg_sup = self.tcx().is_suitable_region(sup)?;
67 let anon_reg_sub = self.tcx().is_suitable_region(sub)?;
68 let scope_def_id_sup = anon_reg_sup.def_id;
69 let bregion_sup = anon_reg_sup.boundregion;
70 let scope_def_id_sub = anon_reg_sub.def_id;
71 let bregion_sub = anon_reg_sub.boundregion;
73 let ty_sup = find_anon_type(self.tcx(), sup, &bregion_sup)?;
75 let ty_sub = find_anon_type(self.tcx(), sub, &bregion_sub)?;
78 "try_report_anon_anon_conflict: found_param1={:?} sup={:?} br1={:?}",
79 ty_sub, sup, bregion_sup
82 "try_report_anon_anon_conflict: found_param2={:?} sub={:?} br2={:?}",
83 ty_sup, sub, bregion_sub
86 let (ty_sup, ty_fndecl_sup) = ty_sup;
87 let (ty_sub, ty_fndecl_sub) = ty_sub;
89 let AnonymousParamInfo { param: anon_param_sup, .. } =
90 self.find_param_with_region(sup, sup)?;
91 let AnonymousParamInfo { param: anon_param_sub, .. } =
92 self.find_param_with_region(sub, sub)?;
95 self.is_return_type_anon(scope_def_id_sup, bregion_sup, ty_fndecl_sup);
97 self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub);
99 let span_label_var1 = match anon_param_sup.pat.simple_ident() {
100 Some(simple_ident) => format!(" from `{}`", simple_ident),
101 None => String::new(),
104 let span_label_var2 = match anon_param_sub.pat.simple_ident() {
105 Some(simple_ident) => format!(" into `{}`", simple_ident),
106 None => String::new(),
110 "try_report_anon_anon_conflict: sub_is_ret_type={:?} sup_is_ret_type={:?}",
111 sub_is_ret_type, sup_is_ret_type
114 let mut err = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch");
116 match (sup_is_ret_type, sub_is_ret_type) {
117 (ret_capture @ Some(ret_span), _) | (_, ret_capture @ Some(ret_span)) => {
119 if sup_is_ret_type == ret_capture { ty_sub.span } else { ty_sup.span };
123 "this parameter and the return type are declared with different lifetimes...",
125 err.span_label(ret_span, "");
126 err.span_label(span, format!("...but data{} is returned here", span_label_var1));
130 if ty_sup.hir_id == ty_sub.hir_id {
131 err.span_label(ty_sup.span, "this type is declared with multiple lifetimes...");
132 err.span_label(ty_sub.span, "");
133 err.span_label(span, "...but data with one lifetime flows into the other here");
137 "these two types are declared with different lifetimes...",
139 err.span_label(ty_sub.span, "");
142 format!("...but data{} flows{} here", span_label_var1, span_label_var2),
148 self.suggest_adding_lifetime_params(sub, ty_sup, ty_sub, &mut err);
154 fn suggest_adding_lifetime_params(
159 err: &mut Diagnostic,
162 hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
163 hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
166 if lifetime_sub.name.is_elided() && lifetime_sup.name.is_elided() {
167 if let Some(anon_reg) = self.tcx().is_suitable_region(sub) {
168 let hir_id = self.tcx().hir().local_def_id_to_hir_id(anon_reg.def_id);
169 if let hir::Node::Item(&hir::Item {
170 kind: hir::ItemKind::Fn(_, ref generics, ..),
172 }) = self.tcx().hir().get(hir_id)
174 let (suggestion_param_name, introduce_new) = generics
177 .find(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
178 .and_then(|p| self.tcx().sess.source_map().span_to_snippet(p.span).ok())
179 .map(|name| (name, false))
180 .unwrap_or_else(|| ("'a".to_string(), true));
182 let mut suggestions = vec![
183 if let hir::LifetimeName::Underscore = lifetime_sub.name {
184 (lifetime_sub.span, suggestion_param_name.clone())
187 lifetime_sub.span.shrink_to_hi(),
188 suggestion_param_name.clone() + " ",
191 if let hir::LifetimeName::Underscore = lifetime_sup.name {
192 (lifetime_sup.span, suggestion_param_name.clone())
195 lifetime_sup.span.shrink_to_hi(),
196 suggestion_param_name.clone() + " ",
202 let new_param_suggestion = match &generics.params {
203 [] => (generics.span, format!("<{}>", suggestion_param_name)),
205 first.span.shrink_to_lo(),
206 format!("{}, ", suggestion_param_name),
210 suggestions.push(new_param_suggestion);
213 err.multipart_suggestion(
214 "consider introducing a named lifetime parameter",
216 Applicability::MaybeIncorrect,
219 "each elided lifetime in input position becomes a distinct lifetime",