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
;
9 use crate::infer
::TyCtxt
;
11 use rustc_errors
::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed}
;
13 use rustc_hir
::{GenericParamKind, Ty}
;
14 use rustc_middle
::ty
::Region
;
15 use rustc_span
::symbol
::kw
;
17 impl<'a
, 'tcx
> NiceRegionError
<'a
, 'tcx
> {
18 /// Print the error message for lifetime errors when both the concerned regions are anonymous.
20 /// Consider a case where we have
22 /// ```compile_fail,E0623
23 /// fn foo(x: &mut Vec<&u8>, y: &u8) {
31 /// fn foo(x: &mut Vec<&u8>, y: &u8) {
32 /// --- --- these references are declared with different lifetimes...
34 /// ^ ...but data from `y` flows into `x` here
37 /// It has been extended for the case of structs too.
39 /// Consider the example
42 /// struct Ref<'a> { x: &'a u32 }
46 /// fn foo(mut x: Vec<Ref>, y: Ref) {
47 /// --- --- these structs are declared with different lifetimes...
49 /// ^ ...but data from `y` flows into `x` here
53 /// It will later be extended to trait objects.
54 pub(super) fn try_report_anon_anon_conflict(&self) -> Option
<ErrorGuaranteed
> {
55 let (span
, sub
, sup
) = self.regions()?
;
57 if let Some(RegionResolutionError
::ConcreteFailure(
58 SubregionOrigin
::ReferenceOutlivesReferent(..),
62 // This error doesn't make much sense in this case.
66 // Determine whether the sub and sup consist of both anonymous (elided) regions.
67 let anon_reg_sup
= self.tcx().is_suitable_region(sup
)?
;
69 let anon_reg_sub
= self.tcx().is_suitable_region(sub
)?
;
70 let scope_def_id_sup
= anon_reg_sup
.def_id
;
71 let bregion_sup
= anon_reg_sup
.boundregion
;
72 let scope_def_id_sub
= anon_reg_sub
.def_id
;
73 let bregion_sub
= anon_reg_sub
.boundregion
;
75 let ty_sup
= find_anon_type(self.tcx(), sup
, &bregion_sup
)?
;
77 let ty_sub
= find_anon_type(self.tcx(), sub
, &bregion_sub
)?
;
80 "try_report_anon_anon_conflict: found_param1={:?} sup={:?} br1={:?}",
81 ty_sub
, sup
, bregion_sup
84 "try_report_anon_anon_conflict: found_param2={:?} sub={:?} br2={:?}",
85 ty_sup
, sub
, bregion_sub
88 let (ty_sup
, ty_fndecl_sup
) = ty_sup
;
89 let (ty_sub
, ty_fndecl_sub
) = ty_sub
;
91 let AnonymousParamInfo { param: anon_param_sup, .. }
=
92 self.find_param_with_region(sup
, sup
)?
;
93 let AnonymousParamInfo { param: anon_param_sub, .. }
=
94 self.find_param_with_region(sub
, sub
)?
;
97 self.is_return_type_anon(scope_def_id_sup
, bregion_sup
, ty_fndecl_sup
);
99 self.is_return_type_anon(scope_def_id_sub
, bregion_sub
, ty_fndecl_sub
);
101 let span_label_var1
= match anon_param_sup
.pat
.simple_ident() {
102 Some(simple_ident
) => format
!(" from `{}`", simple_ident
),
103 None
=> String
::new(),
106 let span_label_var2
= match anon_param_sub
.pat
.simple_ident() {
107 Some(simple_ident
) => format
!(" into `{}`", simple_ident
),
108 None
=> String
::new(),
112 "try_report_anon_anon_conflict: sub_is_ret_type={:?} sup_is_ret_type={:?}",
113 sub_is_ret_type
, sup_is_ret_type
116 let mut err
= struct_span_err
!(self.tcx().sess
, span
, E0623
, "lifetime mismatch");
118 match (sup_is_ret_type
, sub_is_ret_type
) {
119 (ret_capture @
Some(ret_span
), _
) | (_
, ret_capture @
Some(ret_span
)) => {
121 if sup_is_ret_type
== ret_capture { ty_sub.span }
else { ty_sup.span }
;
125 "this parameter and the return type are declared with different lifetimes...",
127 err
.span_label(ret_span
, "");
128 err
.span_label(span
, format
!("...but data{} is returned here", span_label_var1
));
132 if ty_sup
.hir_id
== ty_sub
.hir_id
{
133 err
.span_label(ty_sup
.span
, "this type is declared with multiple lifetimes...");
134 err
.span_label(ty_sub
.span
, "");
135 err
.span_label(span
, "...but data with one lifetime flows into the other here");
139 "these two types are declared with different lifetimes...",
141 err
.span_label(ty_sub
.span
, "");
144 format
!("...but data{} flows{} here", span_label_var1
, span_label_var2
),
150 if suggest_adding_lifetime_params(self.tcx(), sub
, ty_sup
, ty_sub
, &mut err
) {
151 err
.note("each elided lifetime in input position becomes a distinct lifetime");
154 let reported
= err
.emit();
159 pub fn suggest_adding_lifetime_params
<'tcx
>(
164 err
: &mut Diagnostic
,
167 hir
::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. }
,
168 hir
::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. }
,
169 ) = (ty_sub
, ty_sup
) else {
173 if !lifetime_sub
.name
.is_anonymous() || !lifetime_sup
.name
.is_anonymous() {
177 let Some(anon_reg
) = tcx
.is_suitable_region(sub
) else {
181 let hir_id
= tcx
.hir().local_def_id_to_hir_id(anon_reg
.def_id
);
183 let node
= tcx
.hir().get(hir_id
);
184 let is_impl
= matches
!(&node
, hir
::Node
::ImplItem(_
));
185 let generics
= match node
{
186 hir
::Node
::Item(&hir
::Item { kind: hir::ItemKind::Fn(_, ref generics, ..), .. }
)
187 | hir
::Node
::TraitItem(&hir
::TraitItem { ref generics, .. }
)
188 | hir
::Node
::ImplItem(&hir
::ImplItem { ref generics, .. }
) => generics
,
192 let suggestion_param_name
= generics
195 .filter(|p
| matches
!(p
.kind
, GenericParamKind
::Lifetime { .. }
))
196 .map(|p
| p
.name
.ident().name
)
197 .find(|i
| *i
!= kw
::UnderscoreLifetime
);
198 let introduce_new
= suggestion_param_name
.is_none();
199 let suggestion_param_name
=
200 suggestion_param_name
.map(|n
| n
.to_string()).unwrap_or_else(|| "'a".to_owned());
202 debug
!(?lifetime_sup
.span
);
203 debug
!(?lifetime_sub
.span
);
204 let make_suggestion
= |span
: rustc_span
::Span
| {
206 (span
, format
!("{}, ", suggestion_param_name
))
207 } else if let Ok("&") = tcx
.sess
.source_map().span_to_snippet(span
).as_deref() {
208 (span
.shrink_to_hi(), format
!("{} ", suggestion_param_name
))
210 (span
, suggestion_param_name
.clone())
213 let mut suggestions
=
214 vec
![make_suggestion(lifetime_sub
.span
), make_suggestion(lifetime_sup
.span
)];
217 let new_param_suggestion
=
218 if let Some(first
) = generics
.params
.iter().find(|p
| !p
.name
.ident().span
.is_empty()) {
219 (first
.span
.shrink_to_lo(), format
!("{}, ", suggestion_param_name
))
221 (generics
.span
, format
!("<{}>", suggestion_param_name
))
224 suggestions
.push(new_param_suggestion
);
227 let mut sugg
= String
::from("consider introducing a named lifetime parameter");
229 sugg
.push_str(" and update trait if needed");
231 err
.multipart_suggestion(sugg
.as_str(), suggestions
, Applicability
::MaybeIncorrect
);