]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
New upstream version 1.58.1+dfsg1
[rustc.git] / compiler / rustc_infer / src / infer / error_reporting / nice_region_error / different_lifetimes.rs
CommitLineData
ff7c6d11
XL
1//! Error Reporting for Anonymous Region Lifetime Errors
2//! where both the regions are anonymous.
3
6a06907d 4use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
e1599b0c 5use crate::infer::error_reporting::nice_region_error::util::AnonymousParamInfo;
dfeec247 6use crate::infer::error_reporting::nice_region_error::NiceRegionError;
ba9703b0
XL
7use crate::infer::lexical_region_resolve::RegionResolutionError;
8use crate::infer::SubregionOrigin;
ff7c6d11 9
3c0e092e
XL
10use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
11use rustc_hir as hir;
12use rustc_hir::{GenericParamKind, Ty};
13use rustc_middle::ty::Region;
60c5eb7d 14
dc9dc135 15impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
ff7c6d11
XL
16 /// Print the error message for lifetime errors when both the concerned regions are anonymous.
17 ///
18 /// Consider a case where we have
19 ///
20 /// ```no_run
21 /// fn foo(x: &mut Vec<&u8>, y: &u8) {
22 /// x.push(y);
23 /// }
24 /// ```
25 ///
26 /// The example gives
27 ///
28 /// ```text
29 /// fn foo(x: &mut Vec<&u8>, y: &u8) {
30 /// --- --- these references are declared with different lifetimes...
31 /// x.push(y);
32 /// ^ ...but data from `y` flows into `x` here
33 /// ```
34 ///
35 /// It has been extended for the case of structs too.
36 ///
37 /// Consider the example
38 ///
39 /// ```no_run
40 /// struct Ref<'a> { x: &'a u32 }
41 /// ```
42 ///
43 /// ```text
44 /// fn foo(mut x: Vec<Ref>, y: Ref) {
45 /// --- --- these structs are declared with different lifetimes...
46 /// x.push(y);
47 /// ^ ...but data from `y` flows into `x` here
48 /// }
9fa01778 49 /// ```
ff7c6d11
XL
50 ///
51 /// It will later be extended to trait objects.
52 pub(super) fn try_report_anon_anon_conflict(&self) -> Option<ErrorReported> {
74b04a01 53 let (span, sub, sup) = self.regions()?;
ff7c6d11 54
ba9703b0
XL
55 if let Some(RegionResolutionError::ConcreteFailure(
56 SubregionOrigin::ReferenceOutlivesReferent(..),
57 ..,
58 )) = self.error
59 {
60 // This error doesn't make much sense in this case.
61 return None;
62 }
63
ff7c6d11 64 // Determine whether the sub and sup consist of both anonymous (elided) regions.
9fa01778 65 let anon_reg_sup = self.tcx().is_suitable_region(sup)?;
ff7c6d11 66
9fa01778 67 let anon_reg_sub = self.tcx().is_suitable_region(sub)?;
ff7c6d11
XL
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;
72
6a06907d 73 let ty_sup = find_anon_type(self.tcx(), sup, &bregion_sup)?;
ff7c6d11 74
6a06907d 75 let ty_sub = find_anon_type(self.tcx(), sub, &bregion_sub)?;
ff7c6d11
XL
76
77 debug!(
e1599b0c 78 "try_report_anon_anon_conflict: found_param1={:?} sup={:?} br1={:?}",
dfeec247 79 ty_sub, sup, bregion_sup
ff7c6d11
XL
80 );
81 debug!(
e1599b0c 82 "try_report_anon_anon_conflict: found_param2={:?} sub={:?} br2={:?}",
dfeec247 83 ty_sup, sub, bregion_sub
ff7c6d11
XL
84 );
85
86 let (ty_sup, ty_fndecl_sup) = ty_sup;
87 let (ty_sub, ty_fndecl_sub) = ty_sub;
88
dfeec247
XL
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)?;
ff7c6d11
XL
93
94 let sup_is_ret_type =
95 self.is_return_type_anon(scope_def_id_sup, bregion_sup, ty_fndecl_sup);
96 let sub_is_ret_type =
97 self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub);
98
e1599b0c 99 let span_label_var1 = match anon_param_sup.pat.simple_ident() {
48663c56
XL
100 Some(simple_ident) => format!(" from `{}`", simple_ident),
101 None => String::new(),
ff7c6d11
XL
102 };
103
e1599b0c 104 let span_label_var2 = match anon_param_sub.pat.simple_ident() {
48663c56
XL
105 Some(simple_ident) => format!(" into `{}`", simple_ident),
106 None => String::new(),
ff7c6d11
XL
107 };
108
29967ef6
XL
109 let (span_1, span_2, main_label, span_label, future_return_type) =
110 match (sup_is_ret_type, sub_is_ret_type) {
111 (None, None) => {
112 let (main_label_1, span_label_1) = if ty_sup.hir_id == ty_sub.hir_id {
113 (
114 "this type is declared with multiple lifetimes...".to_owned(),
115 "...but data with one lifetime flows into the other here".to_owned(),
116 )
117 } else {
118 (
119 "these two types are declared with different lifetimes...".to_owned(),
120 format!("...but data{} flows{} here", span_label_var1, span_label_var2),
121 )
122 };
123 (ty_sup.span, ty_sub.span, main_label_1, span_label_1, None)
124 }
125
126 (Some(ret_span), _) => {
127 let sup_future = self.future_return_type(scope_def_id_sup);
fc512014 128 let (return_type, action) = if sup_future.is_some() {
29967ef6
XL
129 ("returned future", "held across an await point")
130 } else {
131 ("return type", "returned")
132 };
133
ff7c6d11 134 (
29967ef6
XL
135 ty_sub.span,
136 ret_span,
137 format!(
138 "this parameter and the {} are declared with different lifetimes...",
139 return_type
140 ),
141 format!("...but data{} is {} here", span_label_var1, action),
142 sup_future,
ff7c6d11 143 )
29967ef6
XL
144 }
145 (_, Some(ret_span)) => {
146 let sub_future = self.future_return_type(scope_def_id_sub);
fc512014 147 let (return_type, action) = if sub_future.is_some() {
29967ef6
XL
148 ("returned future", "held across an await point")
149 } else {
150 ("return type", "returned")
151 };
152
ff7c6d11 153 (
29967ef6
XL
154 ty_sup.span,
155 ret_span,
156 format!(
157 "this parameter and the {} are declared with different lifetimes...",
158 return_type
159 ),
160 format!("...but data{} is {} here", span_label_var1, action),
161 sub_future,
ff7c6d11 162 )
29967ef6
XL
163 }
164 };
165
3c0e092e 166 let mut err = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch");
29967ef6 167
3c0e092e
XL
168 err.span_label(span_1, main_label);
169 err.span_label(span_2, String::new());
170 err.span_label(span, span_label);
171
172 self.suggest_adding_lifetime_params(sub, ty_sup, ty_sub, &mut err);
29967ef6
XL
173
174 if let Some(t) = future_return_type {
175 let snip = self
176 .tcx()
177 .sess
178 .source_map()
179 .span_to_snippet(t.span)
180 .ok()
181 .and_then(|s| match (&t.kind, s.as_str()) {
182 (rustc_hir::TyKind::Tup(&[]), "") => Some("()".to_string()),
183 (_, "") => None,
184 _ => Some(s),
185 })
3c0e092e 186 .unwrap_or_else(|| "{unnamed_type}".to_string());
29967ef6 187
3c0e092e 188 err.span_label(
29967ef6
XL
189 t.span,
190 &format!("this `async fn` implicitly returns an `impl Future<Output = {}>`", snip),
191 );
192 }
3c0e092e 193 err.emit();
ba9703b0 194 Some(ErrorReported)
ff7c6d11 195 }
3c0e092e
XL
196
197 fn suggest_adding_lifetime_params(
198 &self,
199 sub: Region<'tcx>,
200 ty_sup: &Ty<'_>,
201 ty_sub: &Ty<'_>,
202 err: &mut DiagnosticBuilder<'_>,
203 ) {
204 if let (
205 hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
206 hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
207 ) = (ty_sub, ty_sup)
208 {
209 if lifetime_sub.name.is_elided() && lifetime_sup.name.is_elided() {
210 if let Some(anon_reg) = self.tcx().is_suitable_region(sub) {
211 let hir_id = self.tcx().hir().local_def_id_to_hir_id(anon_reg.def_id);
212 if let hir::Node::Item(&hir::Item {
213 kind: hir::ItemKind::Fn(_, ref generics, ..),
214 ..
215 }) = self.tcx().hir().get(hir_id)
216 {
217 let (suggestion_param_name, introduce_new) = generics
218 .params
219 .iter()
220 .find(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
221 .and_then(|p| self.tcx().sess.source_map().span_to_snippet(p.span).ok())
222 .map(|name| (name, false))
223 .unwrap_or_else(|| ("'a".to_string(), true));
224
225 let mut suggestions = vec![
226 if let hir::LifetimeName::Underscore = lifetime_sub.name {
227 (lifetime_sub.span, suggestion_param_name.clone())
228 } else {
229 (
230 lifetime_sub.span.shrink_to_hi(),
231 suggestion_param_name.clone() + " ",
232 )
233 },
234 if let hir::LifetimeName::Underscore = lifetime_sup.name {
235 (lifetime_sup.span, suggestion_param_name.clone())
236 } else {
237 (
238 lifetime_sup.span.shrink_to_hi(),
239 suggestion_param_name.clone() + " ",
240 )
241 },
242 ];
243
244 if introduce_new {
245 let new_param_suggestion = match &generics.params {
246 [] => (generics.span, format!("<{}>", suggestion_param_name)),
247 [first, ..] => (
248 first.span.shrink_to_lo(),
249 format!("{}, ", suggestion_param_name),
250 ),
251 };
252
253 suggestions.push(new_param_suggestion);
254 }
255
256 err.multipart_suggestion(
257 "consider introducing a named lifetime parameter",
258 suggestions,
259 Applicability::MaybeIncorrect,
260 );
261 err.note(
262 "each elided lifetime in input position becomes a distinct lifetime",
263 );
264 }
265 }
266 }
267 }
268 }
ff7c6d11 269}