]>
Commit | Line | Data |
---|---|---|
ff7c6d11 XL |
1 | //! Error Reporting for Anonymous Region Lifetime Errors |
2 | //! where both the regions are anonymous. | |
3 | ||
6a06907d | 4 | use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type; |
e1599b0c | 5 | use crate::infer::error_reporting::nice_region_error::util::AnonymousParamInfo; |
dfeec247 | 6 | use crate::infer::error_reporting::nice_region_error::NiceRegionError; |
ba9703b0 XL |
7 | use crate::infer::lexical_region_resolve::RegionResolutionError; |
8 | use crate::infer::SubregionOrigin; | |
ff7c6d11 | 9 | |
ba9703b0 | 10 | use rustc_errors::{struct_span_err, ErrorReported}; |
60c5eb7d | 11 | |
dc9dc135 | 12 | impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { |
ff7c6d11 XL |
13 | /// Print the error message for lifetime errors when both the concerned regions are anonymous. |
14 | /// | |
15 | /// Consider a case where we have | |
16 | /// | |
17 | /// ```no_run | |
18 | /// fn foo(x: &mut Vec<&u8>, y: &u8) { | |
19 | /// x.push(y); | |
20 | /// } | |
21 | /// ``` | |
22 | /// | |
23 | /// The example gives | |
24 | /// | |
25 | /// ```text | |
26 | /// fn foo(x: &mut Vec<&u8>, y: &u8) { | |
27 | /// --- --- these references are declared with different lifetimes... | |
28 | /// x.push(y); | |
29 | /// ^ ...but data from `y` flows into `x` here | |
30 | /// ``` | |
31 | /// | |
32 | /// It has been extended for the case of structs too. | |
33 | /// | |
34 | /// Consider the example | |
35 | /// | |
36 | /// ```no_run | |
37 | /// struct Ref<'a> { x: &'a u32 } | |
38 | /// ``` | |
39 | /// | |
40 | /// ```text | |
41 | /// fn foo(mut x: Vec<Ref>, y: Ref) { | |
42 | /// --- --- these structs are declared with different lifetimes... | |
43 | /// x.push(y); | |
44 | /// ^ ...but data from `y` flows into `x` here | |
45 | /// } | |
9fa01778 | 46 | /// ``` |
ff7c6d11 XL |
47 | /// |
48 | /// It will later be extended to trait objects. | |
49 | pub(super) fn try_report_anon_anon_conflict(&self) -> Option<ErrorReported> { | |
74b04a01 | 50 | let (span, sub, sup) = self.regions()?; |
ff7c6d11 | 51 | |
ba9703b0 XL |
52 | if let Some(RegionResolutionError::ConcreteFailure( |
53 | SubregionOrigin::ReferenceOutlivesReferent(..), | |
54 | .., | |
55 | )) = self.error | |
56 | { | |
57 | // This error doesn't make much sense in this case. | |
58 | return None; | |
59 | } | |
60 | ||
ff7c6d11 | 61 | // Determine whether the sub and sup consist of both anonymous (elided) regions. |
9fa01778 | 62 | let anon_reg_sup = self.tcx().is_suitable_region(sup)?; |
ff7c6d11 | 63 | |
9fa01778 | 64 | let anon_reg_sub = self.tcx().is_suitable_region(sub)?; |
ff7c6d11 XL |
65 | let scope_def_id_sup = anon_reg_sup.def_id; |
66 | let bregion_sup = anon_reg_sup.boundregion; | |
67 | let scope_def_id_sub = anon_reg_sub.def_id; | |
68 | let bregion_sub = anon_reg_sub.boundregion; | |
69 | ||
6a06907d | 70 | let ty_sup = find_anon_type(self.tcx(), sup, &bregion_sup)?; |
ff7c6d11 | 71 | |
6a06907d | 72 | let ty_sub = find_anon_type(self.tcx(), sub, &bregion_sub)?; |
ff7c6d11 XL |
73 | |
74 | debug!( | |
e1599b0c | 75 | "try_report_anon_anon_conflict: found_param1={:?} sup={:?} br1={:?}", |
dfeec247 | 76 | ty_sub, sup, bregion_sup |
ff7c6d11 XL |
77 | ); |
78 | debug!( | |
e1599b0c | 79 | "try_report_anon_anon_conflict: found_param2={:?} sub={:?} br2={:?}", |
dfeec247 | 80 | ty_sup, sub, bregion_sub |
ff7c6d11 XL |
81 | ); |
82 | ||
83 | let (ty_sup, ty_fndecl_sup) = ty_sup; | |
84 | let (ty_sub, ty_fndecl_sub) = ty_sub; | |
85 | ||
dfeec247 XL |
86 | let AnonymousParamInfo { param: anon_param_sup, .. } = |
87 | self.find_param_with_region(sup, sup)?; | |
88 | let AnonymousParamInfo { param: anon_param_sub, .. } = | |
89 | self.find_param_with_region(sub, sub)?; | |
ff7c6d11 XL |
90 | |
91 | let sup_is_ret_type = | |
92 | self.is_return_type_anon(scope_def_id_sup, bregion_sup, ty_fndecl_sup); | |
93 | let sub_is_ret_type = | |
94 | self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub); | |
95 | ||
e1599b0c | 96 | let span_label_var1 = match anon_param_sup.pat.simple_ident() { |
48663c56 XL |
97 | Some(simple_ident) => format!(" from `{}`", simple_ident), |
98 | None => String::new(), | |
ff7c6d11 XL |
99 | }; |
100 | ||
e1599b0c | 101 | let span_label_var2 = match anon_param_sub.pat.simple_ident() { |
48663c56 XL |
102 | Some(simple_ident) => format!(" into `{}`", simple_ident), |
103 | None => String::new(), | |
ff7c6d11 XL |
104 | }; |
105 | ||
29967ef6 XL |
106 | let (span_1, span_2, main_label, span_label, future_return_type) = |
107 | match (sup_is_ret_type, sub_is_ret_type) { | |
108 | (None, None) => { | |
109 | let (main_label_1, span_label_1) = if ty_sup.hir_id == ty_sub.hir_id { | |
110 | ( | |
111 | "this type is declared with multiple lifetimes...".to_owned(), | |
112 | "...but data with one lifetime flows into the other here".to_owned(), | |
113 | ) | |
114 | } else { | |
115 | ( | |
116 | "these two types are declared with different lifetimes...".to_owned(), | |
117 | format!("...but data{} flows{} here", span_label_var1, span_label_var2), | |
118 | ) | |
119 | }; | |
120 | (ty_sup.span, ty_sub.span, main_label_1, span_label_1, None) | |
121 | } | |
122 | ||
123 | (Some(ret_span), _) => { | |
124 | let sup_future = self.future_return_type(scope_def_id_sup); | |
fc512014 | 125 | let (return_type, action) = if sup_future.is_some() { |
29967ef6 XL |
126 | ("returned future", "held across an await point") |
127 | } else { | |
128 | ("return type", "returned") | |
129 | }; | |
130 | ||
ff7c6d11 | 131 | ( |
29967ef6 XL |
132 | ty_sub.span, |
133 | ret_span, | |
134 | format!( | |
135 | "this parameter and the {} are declared with different lifetimes...", | |
136 | return_type | |
137 | ), | |
138 | format!("...but data{} is {} here", span_label_var1, action), | |
139 | sup_future, | |
ff7c6d11 | 140 | ) |
29967ef6 XL |
141 | } |
142 | (_, Some(ret_span)) => { | |
143 | let sub_future = self.future_return_type(scope_def_id_sub); | |
fc512014 | 144 | let (return_type, action) = if sub_future.is_some() { |
29967ef6 XL |
145 | ("returned future", "held across an await point") |
146 | } else { | |
147 | ("return type", "returned") | |
148 | }; | |
149 | ||
ff7c6d11 | 150 | ( |
29967ef6 XL |
151 | ty_sup.span, |
152 | ret_span, | |
153 | format!( | |
154 | "this parameter and the {} are declared with different lifetimes...", | |
155 | return_type | |
156 | ), | |
157 | format!("...but data{} is {} here", span_label_var1, action), | |
158 | sub_future, | |
ff7c6d11 | 159 | ) |
29967ef6 XL |
160 | } |
161 | }; | |
162 | ||
163 | let mut e = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch"); | |
164 | ||
165 | e.span_label(span_1, main_label); | |
166 | e.span_label(span_2, String::new()); | |
167 | e.span_label(span, span_label); | |
168 | ||
169 | if let Some(t) = future_return_type { | |
170 | let snip = self | |
171 | .tcx() | |
172 | .sess | |
173 | .source_map() | |
174 | .span_to_snippet(t.span) | |
175 | .ok() | |
176 | .and_then(|s| match (&t.kind, s.as_str()) { | |
177 | (rustc_hir::TyKind::Tup(&[]), "") => Some("()".to_string()), | |
178 | (_, "") => None, | |
179 | _ => Some(s), | |
180 | }) | |
181 | .unwrap_or("{unnamed_type}".to_string()); | |
182 | ||
183 | e.span_label( | |
184 | t.span, | |
185 | &format!("this `async fn` implicitly returns an `impl Future<Output = {}>`", snip), | |
186 | ); | |
187 | } | |
188 | e.emit(); | |
ba9703b0 | 189 | Some(ErrorReported) |
ff7c6d11 XL |
190 | } |
191 | } |