]>
Commit | Line | Data |
---|---|---|
74b04a01 | 1 | use crate::infer::error_reporting::{note_and_explain_region, ObligationCauseExt}; |
9fa01778 | 2 | use crate::infer::{self, InferCtxt, SubregionOrigin}; |
dfeec247 | 3 | use rustc_errors::{struct_span_err, DiagnosticBuilder}; |
5869c6ff | 4 | use rustc_middle::traits::ObligationCauseCode; |
ba9703b0 XL |
5 | use rustc_middle::ty::error::TypeError; |
6 | use rustc_middle::ty::{self, Region}; | |
60c5eb7d | 7 | |
dc9dc135 | 8 | impl<'a, 'tcx> InferCtxt<'a, 'tcx> { |
dfeec247 XL |
9 | pub(super) fn note_region_origin( |
10 | &self, | |
11 | err: &mut DiagnosticBuilder<'_>, | |
12 | origin: &SubregionOrigin<'tcx>, | |
13 | ) { | |
f9f354fc XL |
14 | let mut label_or_note = |span, msg| { |
15 | let sub_count = err.children.iter().filter(|d| d.span.is_dummy()).count(); | |
16 | let expanded_sub_count = err.children.iter().filter(|d| !d.span.is_dummy()).count(); | |
17 | let span_is_primary = err.span.primary_spans().iter().all(|&sp| sp == span); | |
18 | if span_is_primary && sub_count == 0 && expanded_sub_count == 0 { | |
19 | err.span_label(span, msg); | |
20 | } else if span_is_primary && expanded_sub_count == 0 { | |
21 | err.note(msg); | |
22 | } else { | |
23 | err.span_note(span, msg); | |
24 | } | |
25 | }; | |
8bb4bdeb XL |
26 | match *origin { |
27 | infer::Subtype(ref trace) => { | |
fc512014 | 28 | if let Some((expected, found)) = self.values_str(trace.values) { |
f9f354fc | 29 | label_or_note( |
60c5eb7d | 30 | trace.cause.span, |
dfeec247 | 31 | &format!("...so that the {}", trace.cause.as_requirement_str()), |
60c5eb7d XL |
32 | ); |
33 | ||
dfeec247 | 34 | err.note_expected_found(&"", expected, &"", found); |
8bb4bdeb XL |
35 | } else { |
36 | // FIXME: this really should be handled at some earlier stage. Our | |
37 | // handling of region checking when type errors are present is | |
38 | // *terrible*. | |
39 | ||
f9f354fc | 40 | label_or_note( |
dfeec247 XL |
41 | trace.cause.span, |
42 | &format!("...so that {}", trace.cause.as_requirement_str()), | |
43 | ); | |
8bb4bdeb XL |
44 | } |
45 | } | |
46 | infer::Reborrow(span) => { | |
f9f354fc | 47 | label_or_note(span, "...so that reference does not outlive borrowed content"); |
8bb4bdeb XL |
48 | } |
49 | infer::ReborrowUpvar(span, ref upvar_id) => { | |
dc9dc135 | 50 | let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id); |
f9f354fc | 51 | label_or_note(span, &format!("...so that closure can access `{}`", var_name)); |
8bb4bdeb XL |
52 | } |
53 | infer::RelateObjectBound(span) => { | |
f9f354fc | 54 | label_or_note(span, "...so that it can be closed over into an object"); |
8bb4bdeb | 55 | } |
8bb4bdeb | 56 | infer::DataBorrowed(ty, span) => { |
f9f354fc | 57 | label_or_note( |
dfeec247 XL |
58 | span, |
59 | &format!( | |
60 | "...so that the type `{}` is not borrowed for too long", | |
61 | self.ty_to_string(ty) | |
62 | ), | |
63 | ); | |
8bb4bdeb XL |
64 | } |
65 | infer::ReferenceOutlivesReferent(ty, span) => { | |
f9f354fc | 66 | label_or_note( |
dfeec247 XL |
67 | span, |
68 | &format!( | |
f9f354fc | 69 | "...so that the reference type `{}` does not outlive the data it points at", |
dfeec247 XL |
70 | self.ty_to_string(ty) |
71 | ), | |
72 | ); | |
8bb4bdeb | 73 | } |
94222f64 | 74 | infer::RelateParamBound(span, t, opt_span) => { |
f9f354fc | 75 | label_or_note( |
dfeec247 XL |
76 | span, |
77 | &format!( | |
94222f64 XL |
78 | "...so that the type `{}` will meet its required lifetime bounds{}", |
79 | self.ty_to_string(t), | |
80 | if opt_span.is_some() { "..." } else { "" }, | |
dfeec247 XL |
81 | ), |
82 | ); | |
94222f64 XL |
83 | if let Some(span) = opt_span { |
84 | err.span_note(span, "...that is required by this bound"); | |
85 | } | |
8bb4bdeb XL |
86 | } |
87 | infer::RelateRegionParamBound(span) => { | |
f9f354fc | 88 | label_or_note( |
dfeec247 XL |
89 | span, |
90 | "...so that the declared lifetime parameter bounds are satisfied", | |
91 | ); | |
8bb4bdeb | 92 | } |
8bb4bdeb | 93 | infer::CompareImplMethodObligation { span, .. } => { |
f9f354fc | 94 | label_or_note( |
dfeec247 | 95 | span, |
f9f354fc | 96 | "...so that the definition in impl matches the definition from the trait", |
dfeec247 | 97 | ); |
8bb4bdeb | 98 | } |
c295e0f8 XL |
99 | infer::CompareImplTypeObligation { span, .. } => { |
100 | label_or_note( | |
101 | span, | |
102 | "...so that the definition in impl matches the definition from the trait", | |
103 | ); | |
104 | } | |
5099ac24 FG |
105 | infer::CheckAssociatedTypeBounds { ref parent, .. } => { |
106 | self.note_region_origin(err, &parent); | |
107 | } | |
8bb4bdeb XL |
108 | } |
109 | } | |
110 | ||
dfeec247 XL |
111 | pub(super) fn report_concrete_failure( |
112 | &self, | |
dfeec247 XL |
113 | origin: SubregionOrigin<'tcx>, |
114 | sub: Region<'tcx>, | |
115 | sup: Region<'tcx>, | |
116 | ) -> DiagnosticBuilder<'tcx> { | |
8bb4bdeb | 117 | match origin { |
e1599b0c | 118 | infer::Subtype(box trace) => { |
8bb4bdeb | 119 | let terr = TypeError::RegionsDoesNotOutlive(sup, sub); |
ea8adc8c | 120 | let mut err = self.report_and_explain_type_error(trace, &terr); |
5099ac24 | 121 | match (*sub, *sup) { |
5869c6ff XL |
122 | (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {} |
123 | (ty::RePlaceholder(_), _) => { | |
124 | note_and_explain_region( | |
125 | self.tcx, | |
126 | &mut err, | |
127 | "", | |
128 | sup, | |
129 | " doesn't meet the lifetime requirements", | |
94222f64 | 130 | None, |
5869c6ff XL |
131 | ); |
132 | } | |
133 | (_, ty::RePlaceholder(_)) => { | |
134 | note_and_explain_region( | |
135 | self.tcx, | |
136 | &mut err, | |
137 | "the required lifetime does not necessarily outlive ", | |
138 | sub, | |
139 | "", | |
94222f64 | 140 | None, |
5869c6ff XL |
141 | ); |
142 | } | |
143 | _ => { | |
94222f64 | 144 | note_and_explain_region(self.tcx, &mut err, "", sup, "...", None); |
5869c6ff XL |
145 | note_and_explain_region( |
146 | self.tcx, | |
147 | &mut err, | |
148 | "...does not necessarily outlive ", | |
149 | sub, | |
150 | "", | |
94222f64 | 151 | None, |
5869c6ff XL |
152 | ); |
153 | } | |
154 | } | |
ea8adc8c | 155 | err |
8bb4bdeb XL |
156 | } |
157 | infer::Reborrow(span) => { | |
dfeec247 XL |
158 | let mut err = struct_span_err!( |
159 | self.tcx.sess, | |
160 | span, | |
161 | E0312, | |
f9f354fc | 162 | "lifetime of reference outlives lifetime of borrowed content..." |
dfeec247 XL |
163 | ); |
164 | note_and_explain_region( | |
165 | self.tcx, | |
dfeec247 XL |
166 | &mut err, |
167 | "...the reference is valid for ", | |
168 | sub, | |
169 | "...", | |
94222f64 | 170 | None, |
dfeec247 XL |
171 | ); |
172 | note_and_explain_region( | |
173 | self.tcx, | |
dfeec247 XL |
174 | &mut err, |
175 | "...but the borrowed content is only valid for ", | |
176 | sup, | |
177 | "", | |
94222f64 | 178 | None, |
dfeec247 | 179 | ); |
8bb4bdeb XL |
180 | err |
181 | } | |
182 | infer::ReborrowUpvar(span, ref upvar_id) => { | |
dc9dc135 | 183 | let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id); |
dfeec247 XL |
184 | let mut err = struct_span_err!( |
185 | self.tcx.sess, | |
186 | span, | |
187 | E0313, | |
f9f354fc | 188 | "lifetime of borrowed pointer outlives lifetime of captured variable `{}`...", |
dfeec247 XL |
189 | var_name |
190 | ); | |
191 | note_and_explain_region( | |
192 | self.tcx, | |
dfeec247 XL |
193 | &mut err, |
194 | "...the borrowed pointer is valid for ", | |
195 | sub, | |
196 | "...", | |
94222f64 | 197 | None, |
dfeec247 XL |
198 | ); |
199 | note_and_explain_region( | |
200 | self.tcx, | |
ea8adc8c XL |
201 | &mut err, |
202 | &format!("...but `{}` is only valid for ", var_name), | |
203 | sup, | |
dfeec247 | 204 | "", |
94222f64 | 205 | None, |
dfeec247 | 206 | ); |
8bb4bdeb XL |
207 | err |
208 | } | |
8bb4bdeb | 209 | infer::RelateObjectBound(span) => { |
dfeec247 XL |
210 | let mut err = struct_span_err!( |
211 | self.tcx.sess, | |
212 | span, | |
213 | E0476, | |
f9f354fc XL |
214 | "lifetime of the source pointer does not outlive lifetime bound of the \ |
215 | object type" | |
dfeec247 | 216 | ); |
94222f64 XL |
217 | note_and_explain_region( |
218 | self.tcx, | |
219 | &mut err, | |
220 | "object type is valid for ", | |
221 | sub, | |
222 | "", | |
223 | None, | |
224 | ); | |
dfeec247 XL |
225 | note_and_explain_region( |
226 | self.tcx, | |
dfeec247 XL |
227 | &mut err, |
228 | "source pointer is only valid for ", | |
229 | sup, | |
230 | "", | |
94222f64 | 231 | None, |
dfeec247 | 232 | ); |
8bb4bdeb XL |
233 | err |
234 | } | |
94222f64 | 235 | infer::RelateParamBound(span, ty, opt_span) => { |
dfeec247 XL |
236 | let mut err = struct_span_err!( |
237 | self.tcx.sess, | |
238 | span, | |
239 | E0477, | |
f9f354fc | 240 | "the type `{}` does not fulfill the required lifetime", |
dfeec247 XL |
241 | self.ty_to_string(ty) |
242 | ); | |
7cac9316 | 243 | match *sub { |
94222f64 XL |
244 | ty::ReStatic => note_and_explain_region( |
245 | self.tcx, | |
246 | &mut err, | |
247 | "type must satisfy ", | |
248 | sub, | |
249 | if opt_span.is_some() { " as required by this binding" } else { "" }, | |
250 | opt_span, | |
251 | ), | |
252 | _ => note_and_explain_region( | |
253 | self.tcx, | |
254 | &mut err, | |
255 | "type must outlive ", | |
256 | sub, | |
257 | if opt_span.is_some() { " as required by this binding" } else { "" }, | |
258 | opt_span, | |
259 | ), | |
7cac9316 | 260 | } |
8bb4bdeb XL |
261 | err |
262 | } | |
263 | infer::RelateRegionParamBound(span) => { | |
264 | let mut err = | |
265 | struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied"); | |
dfeec247 XL |
266 | note_and_explain_region( |
267 | self.tcx, | |
dfeec247 XL |
268 | &mut err, |
269 | "lifetime parameter instantiated with ", | |
270 | sup, | |
271 | "", | |
94222f64 | 272 | None, |
dfeec247 XL |
273 | ); |
274 | note_and_explain_region( | |
275 | self.tcx, | |
dfeec247 XL |
276 | &mut err, |
277 | "but lifetime parameter must outlive ", | |
278 | sub, | |
279 | "", | |
94222f64 | 280 | None, |
dfeec247 | 281 | ); |
8bb4bdeb XL |
282 | err |
283 | } | |
8bb4bdeb | 284 | infer::DataBorrowed(ty, span) => { |
dfeec247 XL |
285 | let mut err = struct_span_err!( |
286 | self.tcx.sess, | |
287 | span, | |
288 | E0490, | |
289 | "a value of type `{}` is borrowed for too long", | |
290 | self.ty_to_string(ty) | |
291 | ); | |
94222f64 XL |
292 | note_and_explain_region( |
293 | self.tcx, | |
294 | &mut err, | |
295 | "the type is valid for ", | |
296 | sub, | |
297 | "", | |
298 | None, | |
299 | ); | |
300 | note_and_explain_region( | |
301 | self.tcx, | |
302 | &mut err, | |
303 | "but the borrow lasts for ", | |
304 | sup, | |
305 | "", | |
306 | None, | |
307 | ); | |
8bb4bdeb XL |
308 | err |
309 | } | |
310 | infer::ReferenceOutlivesReferent(ty, span) => { | |
dfeec247 XL |
311 | let mut err = struct_span_err!( |
312 | self.tcx.sess, | |
313 | span, | |
314 | E0491, | |
74b04a01 | 315 | "in type `{}`, reference has a longer lifetime than the data it references", |
dfeec247 XL |
316 | self.ty_to_string(ty) |
317 | ); | |
94222f64 XL |
318 | note_and_explain_region( |
319 | self.tcx, | |
320 | &mut err, | |
321 | "the pointer is valid for ", | |
322 | sub, | |
323 | "", | |
324 | None, | |
325 | ); | |
dfeec247 XL |
326 | note_and_explain_region( |
327 | self.tcx, | |
dfeec247 XL |
328 | &mut err, |
329 | "but the referenced data is only valid for ", | |
330 | sup, | |
331 | "", | |
94222f64 | 332 | None, |
dfeec247 | 333 | ); |
8bb4bdeb XL |
334 | err |
335 | } | |
3c0e092e XL |
336 | infer::CompareImplMethodObligation { span, impl_item_def_id, trait_item_def_id } => { |
337 | self.report_extra_impl_obligation( | |
338 | span, | |
339 | impl_item_def_id, | |
340 | trait_item_def_id, | |
341 | &format!("`{}: {}`", sup, sub), | |
342 | ) | |
343 | } | |
344 | infer::CompareImplTypeObligation { span, impl_item_def_id, trait_item_def_id } => self | |
345 | .report_extra_impl_obligation( | |
346 | span, | |
347 | impl_item_def_id, | |
348 | trait_item_def_id, | |
349 | &format!("`{}: {}`", sup, sub), | |
350 | ), | |
5099ac24 FG |
351 | infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => { |
352 | let mut err = self.report_concrete_failure(*parent, sub, sup); | |
353 | ||
354 | let trait_item_span = self.tcx.def_span(trait_item_def_id); | |
355 | let item_name = self.tcx.item_name(impl_item_def_id); | |
356 | err.span_label( | |
357 | trait_item_span, | |
358 | format!("definition of `{}` from trait", item_name), | |
359 | ); | |
360 | ||
361 | let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id); | |
362 | let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id); | |
363 | ||
364 | let impl_predicates: rustc_data_structures::stable_set::FxHashSet<_> = | |
365 | impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect(); | |
366 | let clauses: Vec<_> = trait_predicates | |
367 | .predicates | |
368 | .into_iter() | |
369 | .filter(|&(pred, _)| !impl_predicates.contains(pred)) | |
370 | .map(|(pred, _)| format!("{}", pred)) | |
371 | .collect(); | |
372 | ||
373 | if !clauses.is_empty() { | |
374 | let where_clause_span = self | |
375 | .tcx | |
376 | .hir() | |
377 | .get_generics(impl_item_def_id.expect_local()) | |
378 | .unwrap() | |
379 | .where_clause | |
380 | .tail_span_for_suggestion(); | |
381 | ||
382 | let suggestion = format!( | |
383 | "{} {}", | |
384 | if !impl_predicates.is_empty() { "," } else { " where" }, | |
385 | clauses.join(", "), | |
386 | ); | |
387 | err.span_suggestion( | |
388 | where_clause_span, | |
389 | &format!( | |
390 | "try copying {} from the trait", | |
391 | if clauses.len() > 1 { "these clauses" } else { "this clause" } | |
392 | ), | |
393 | suggestion, | |
394 | rustc_errors::Applicability::MaybeIncorrect, | |
395 | ); | |
396 | } | |
397 | ||
398 | err | |
399 | } | |
8bb4bdeb XL |
400 | } |
401 | } | |
0731742a XL |
402 | |
403 | pub(super) fn report_placeholder_failure( | |
404 | &self, | |
0731742a XL |
405 | placeholder_origin: SubregionOrigin<'tcx>, |
406 | sub: Region<'tcx>, | |
407 | sup: Region<'tcx>, | |
408 | ) -> DiagnosticBuilder<'tcx> { | |
409 | // I can't think how to do better than this right now. -nikomatsakis | |
5869c6ff | 410 | debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure"); |
0731742a | 411 | match placeholder_origin { |
5869c6ff XL |
412 | infer::Subtype(box ref trace) |
413 | if matches!( | |
a2a8927a | 414 | &trace.cause.code().peel_derives(), |
5869c6ff XL |
415 | ObligationCauseCode::BindingObligation(..) |
416 | ) => | |
417 | { | |
418 | // Hack to get around the borrow checker because trace.cause has an `Rc`. | |
419 | if let ObligationCauseCode::BindingObligation(_, span) = | |
a2a8927a | 420 | &trace.cause.code().peel_derives() |
5869c6ff XL |
421 | { |
422 | let span = *span; | |
423 | let mut err = self.report_concrete_failure(placeholder_origin, sub, sup); | |
424 | err.span_note(span, "the lifetime requirement is introduced here"); | |
425 | err | |
426 | } else { | |
427 | unreachable!() | |
428 | } | |
429 | } | |
e1599b0c | 430 | infer::Subtype(box trace) => { |
0731742a | 431 | let terr = TypeError::RegionsPlaceholderMismatch; |
5869c6ff | 432 | return self.report_and_explain_type_error(trace, &terr); |
0731742a | 433 | } |
5869c6ff | 434 | _ => return self.report_concrete_failure(placeholder_origin, sub, sup), |
0731742a XL |
435 | } |
436 | } | |
8bb4bdeb | 437 | } |