]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
New upstream version 1.66.0+dfsg1
[rustc.git] / compiler / rustc_infer / src / infer / error_reporting / nice_region_error / placeholder_error.rs
CommitLineData
9fa01778
XL
1use crate::infer::error_reporting::nice_region_error::NiceRegionError;
2use crate::infer::lexical_region_resolve::RegionResolutionError;
3use crate::infer::ValuePairs;
4use crate::infer::{SubregionOrigin, TypeTrace};
5use crate::traits::{ObligationCause, ObligationCauseCode};
5099ac24 6use rustc_data_structures::intern::Interned;
5e7ed085 7use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
dfeec247
XL
8use rustc_hir::def::Namespace;
9use rustc_hir::def_id::DefId;
ba9703b0
XL
10use rustc_middle::ty::error::ExpectedFound;
11use rustc_middle::ty::print::{FmtPrinter, Print, RegionHighlightMode};
12use rustc_middle::ty::subst::SubstsRef;
5099ac24 13use rustc_middle::ty::{self, RePlaceholder, ReVar, Region, TyCtxt};
532ac7d7
XL
14
15use std::fmt::{self, Write};
0731742a 16
a2a8927a 17impl<'tcx> NiceRegionError<'_, 'tcx> {
0731742a 18 /// When given a `ConcreteFailure` for a function with arguments containing a named region and
9fa01778 19 /// an anonymous region, emit a descriptive diagnostic error.
5e7ed085
FG
20 pub(super) fn try_report_placeholder_conflict(
21 &self,
22 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
0731742a
XL
23 match &self.error {
24 ///////////////////////////////////////////////////////////////////////////
25 // NB. The ordering of cases in this match is very
26 // sensitive, because we are often matching against
27 // specific cases and then using an `_` to match all
28 // others.
29
30 ///////////////////////////////////////////////////////////////////////////
31 // Check for errors from comparing trait failures -- first
32 // with two placeholders, then with one.
33 Some(RegionResolutionError::SubSupConflict(
34 vid,
35 _,
6a06907d 36 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
5099ac24 37 sub_placeholder @ Region(Interned(RePlaceholder(_), _)),
0731742a 38 _,
5099ac24 39 sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
a2a8927a 40 _,
6a06907d 41 )) => self.try_report_trait_placeholder_mismatch(
5099ac24 42 Some(self.tcx().mk_region(ReVar(*vid))),
9fa01778 43 cause,
5099ac24
FG
44 Some(*sub_placeholder),
45 Some(*sup_placeholder),
6a06907d
XL
46 values,
47 ),
0731742a
XL
48
49 Some(RegionResolutionError::SubSupConflict(
50 vid,
51 _,
6a06907d 52 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
5099ac24 53 sub_placeholder @ Region(Interned(RePlaceholder(_), _)),
0731742a
XL
54 _,
55 _,
a2a8927a 56 _,
6a06907d 57 )) => self.try_report_trait_placeholder_mismatch(
5099ac24 58 Some(self.tcx().mk_region(ReVar(*vid))),
9fa01778 59 cause,
5099ac24 60 Some(*sub_placeholder),
9fa01778 61 None,
6a06907d
XL
62 values,
63 ),
0731742a
XL
64
65 Some(RegionResolutionError::SubSupConflict(
66 vid,
67 _,
6a06907d 68 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
0731742a
XL
69 _,
70 _,
5099ac24 71 sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
a2a8927a 72 _,
6a06907d 73 )) => self.try_report_trait_placeholder_mismatch(
5099ac24 74 Some(self.tcx().mk_region(ReVar(*vid))),
9fa01778
XL
75 cause,
76 None,
77 Some(*sup_placeholder),
6a06907d
XL
78 values,
79 ),
9fa01778
XL
80
81 Some(RegionResolutionError::SubSupConflict(
82 vid,
83 _,
84 _,
85 _,
6a06907d 86 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
5099ac24 87 sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
a2a8927a 88 _,
6a06907d 89 )) => self.try_report_trait_placeholder_mismatch(
5099ac24 90 Some(self.tcx().mk_region(ReVar(*vid))),
9fa01778
XL
91 cause,
92 None,
93 Some(*sup_placeholder),
6a06907d
XL
94 values,
95 ),
0731742a 96
74b04a01
XL
97 Some(RegionResolutionError::UpperBoundUniverseConflict(
98 vid,
99 _,
100 _,
6a06907d 101 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
5099ac24 102 sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
6a06907d 103 )) => self.try_report_trait_placeholder_mismatch(
5099ac24 104 Some(self.tcx().mk_region(ReVar(*vid))),
74b04a01
XL
105 cause,
106 None,
107 Some(*sup_placeholder),
6a06907d
XL
108 values,
109 ),
74b04a01 110
0731742a 111 Some(RegionResolutionError::ConcreteFailure(
6a06907d 112 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
5099ac24
FG
113 sub_region @ Region(Interned(RePlaceholder(_), _)),
114 sup_region @ Region(Interned(RePlaceholder(_), _)),
6a06907d 115 )) => self.try_report_trait_placeholder_mismatch(
9fa01778
XL
116 None,
117 cause,
118 Some(*sub_region),
119 Some(*sup_region),
6a06907d
XL
120 values,
121 ),
0731742a
XL
122
123 Some(RegionResolutionError::ConcreteFailure(
6a06907d 124 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
5099ac24 125 sub_region @ Region(Interned(RePlaceholder(_), _)),
0731742a 126 sup_region,
6a06907d 127 )) => self.try_report_trait_placeholder_mismatch(
5099ac24 128 (!sup_region.has_name()).then_some(*sup_region),
9fa01778 129 cause,
5099ac24 130 Some(*sub_region),
9fa01778 131 None,
6a06907d
XL
132 values,
133 ),
0731742a
XL
134
135 Some(RegionResolutionError::ConcreteFailure(
6a06907d 136 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
0731742a 137 sub_region,
5099ac24 138 sup_region @ Region(Interned(RePlaceholder(_), _)),
6a06907d 139 )) => self.try_report_trait_placeholder_mismatch(
5099ac24 140 (!sub_region.has_name()).then_some(*sub_region),
9fa01778
XL
141 cause,
142 None,
5099ac24 143 Some(*sup_region),
6a06907d
XL
144 values,
145 ),
0731742a
XL
146
147 _ => None,
148 }
149 }
150
6a06907d
XL
151 fn try_report_trait_placeholder_mismatch(
152 &self,
5099ac24 153 vid: Option<Region<'tcx>>,
6a06907d 154 cause: &ObligationCause<'tcx>,
5099ac24
FG
155 sub_placeholder: Option<Region<'tcx>>,
156 sup_placeholder: Option<Region<'tcx>>,
6a06907d 157 value_pairs: &ValuePairs<'tcx>,
5e7ed085 158 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
6a06907d
XL
159 let (expected_substs, found_substs, trait_def_id) = match value_pairs {
160 ValuePairs::TraitRefs(ExpectedFound { expected, found })
161 if expected.def_id == found.def_id =>
162 {
163 (expected.substs, found.substs, expected.def_id)
164 }
165 ValuePairs::PolyTraitRefs(ExpectedFound { expected, found })
166 if expected.def_id() == found.def_id() =>
167 {
168 // It's possible that the placeholders come from a binder
169 // outside of this value pair. Use `no_bound_vars` as a
170 // simple heuristic for that.
171 (expected.no_bound_vars()?.substs, found.no_bound_vars()?.substs, expected.def_id())
172 }
173 _ => return None,
174 };
175
176 Some(self.report_trait_placeholder_mismatch(
177 vid,
178 cause,
179 sub_placeholder,
180 sup_placeholder,
181 trait_def_id,
182 expected_substs,
183 found_substs,
184 ))
185 }
186
0731742a
XL
187 // error[E0308]: implementation of `Foo` does not apply to enough lifetimes
188 // --> /home/nmatsakis/tmp/foo.rs:12:5
189 // |
190 // 12 | all::<&'static u32>();
191 // | ^^^^^^^^^^^^^^^^^^^ lifetime mismatch
192 // |
193 // = note: Due to a where-clause on the function `all`,
194 // = note: `T` must implement `...` for any two lifetimes `'1` and `'2`.
195 // = note: However, the type `T` only implements `...` for some specific lifetime `'2`.
6a06907d
XL
196 #[instrument(level = "debug", skip(self))]
197 fn report_trait_placeholder_mismatch(
0731742a 198 &self,
5099ac24 199 vid: Option<Region<'tcx>>,
0731742a 200 cause: &ObligationCause<'tcx>,
5099ac24
FG
201 sub_placeholder: Option<Region<'tcx>>,
202 sup_placeholder: Option<Region<'tcx>>,
0731742a 203 trait_def_id: DefId,
532ac7d7
XL
204 expected_substs: SubstsRef<'tcx>,
205 actual_substs: SubstsRef<'tcx>,
5e7ed085 206 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
064997fb 207 let span = cause.span();
e1599b0c
XL
208 let msg = format!(
209 "implementation of `{}` is not general enough",
210 self.tcx().def_path_str(trait_def_id),
211 );
212 let mut err = self.tcx().sess.struct_span_err(span, &msg);
0731742a 213
f2b60f7d
FG
214 let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id)
215 | ObligationCauseCode::ExprItemObligation(def_id, ..) =
216 *cause.code()
217 {
e1599b0c
XL
218 err.span_label(span, "doesn't satisfy where-clause");
219 err.span_label(
220 self.tcx().def_span(def_id),
221 &format!("due to a where-clause on `{}`...", self.tcx().def_path_str(def_id)),
222 );
223 true
224 } else {
225 err.span_label(span, &msg);
226 false
227 };
0731742a 228
2b03887a 229 let expected_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef {
0731742a
XL
230 def_id: trait_def_id,
231 substs: expected_substs,
9fa01778 232 });
fc512014 233 let actual_trait_ref = self
2b03887a 234 .cx
fc512014 235 .resolve_vars_if_possible(ty::TraitRef { def_id: trait_def_id, substs: actual_substs });
0731742a
XL
236
237 // Search the expected and actual trait references to see (a)
238 // whether the sub/sup placeholders appear in them (sometimes
239 // you have a trait ref like `T: Foo<fn(&u8)>`, where the
240 // placeholder was created as part of an inner type) and (b)
241 // whether the inference variable appears. In each case,
242 // assign a counter value in each case if so.
243 let mut counter = 0;
244 let mut has_sub = None;
245 let mut has_sup = None;
0731742a 246
9fa01778
XL
247 let mut actual_has_vid = None;
248 let mut expected_has_vid = None;
249
250 self.tcx().for_each_free_region(&expected_trait_ref, |r| {
0731742a
XL
251 if Some(r) == sub_placeholder && has_sub.is_none() {
252 has_sub = Some(counter);
253 counter += 1;
254 } else if Some(r) == sup_placeholder && has_sup.is_none() {
255 has_sup = Some(counter);
256 counter += 1;
257 }
9fa01778
XL
258
259 if Some(r) == vid && expected_has_vid.is_none() {
260 expected_has_vid = Some(counter);
261 counter += 1;
262 }
0731742a
XL
263 });
264
9fa01778
XL
265 self.tcx().for_each_free_region(&actual_trait_ref, |r| {
266 if Some(r) == vid && actual_has_vid.is_none() {
267 actual_has_vid = Some(counter);
0731742a
XL
268 counter += 1;
269 }
270 });
271
dfeec247
XL
272 let actual_self_ty_has_vid =
273 self.tcx().any_free_region_meets(&actual_trait_ref.self_ty(), |r| Some(r) == vid);
0731742a 274
dfeec247
XL
275 let expected_self_ty_has_vid =
276 self.tcx().any_free_region_meets(&expected_trait_ref.self_ty(), |r| Some(r) == vid);
9fa01778
XL
277
278 let any_self_ty_has_vid = actual_self_ty_has_vid || expected_self_ty_has_vid;
279
9fa01778 280 debug!(
6a06907d
XL
281 ?actual_has_vid,
282 ?expected_has_vid,
283 ?has_sub,
284 ?has_sup,
285 ?actual_self_ty_has_vid,
286 ?expected_self_ty_has_vid,
9fa01778
XL
287 );
288
289 self.explain_actual_impl_that_was_found(
290 &mut err,
291 sub_placeholder,
292 sup_placeholder,
293 has_sub,
294 has_sup,
295 expected_trait_ref,
296 actual_trait_ref,
297 vid,
298 expected_has_vid,
299 actual_has_vid,
300 any_self_ty_has_vid,
e1599b0c 301 leading_ellipsis,
9fa01778
XL
302 );
303
304 err
305 }
306
307 /// Add notes with details about the expected and actual trait refs, with attention to cases
308 /// when placeholder regions are involved: either the trait or the self type containing
309 /// them needs to be mentioned the closest to the placeholders.
310 /// This makes the error messages read better, however at the cost of some complexity
311 /// due to the number of combinations we have to deal with.
312 fn explain_actual_impl_that_was_found(
313 &self,
5e7ed085 314 err: &mut Diagnostic,
5099ac24
FG
315 sub_placeholder: Option<Region<'tcx>>,
316 sup_placeholder: Option<Region<'tcx>>,
9fa01778
XL
317 has_sub: Option<usize>,
318 has_sup: Option<usize>,
532ac7d7
XL
319 expected_trait_ref: ty::TraitRef<'tcx>,
320 actual_trait_ref: ty::TraitRef<'tcx>,
5099ac24 321 vid: Option<Region<'tcx>>,
9fa01778
XL
322 expected_has_vid: Option<usize>,
323 actual_has_vid: Option<usize>,
324 any_self_ty_has_vid: bool,
e1599b0c 325 leading_ellipsis: bool,
9fa01778 326 ) {
532ac7d7
XL
327 // HACK(eddyb) maybe move this in a more central location.
328 #[derive(Copy, Clone)]
dc9dc135
XL
329 struct Highlighted<'tcx, T> {
330 tcx: TyCtxt<'tcx>,
5099ac24 331 highlight: RegionHighlightMode<'tcx>,
532ac7d7
XL
332 value: T,
333 }
334
dc9dc135
XL
335 impl<'tcx, T> Highlighted<'tcx, T> {
336 fn map<U>(self, f: impl FnOnce(T) -> U) -> Highlighted<'tcx, U> {
dfeec247 337 Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value) }
532ac7d7
XL
338 }
339 }
340
dc9dc135
XL
341 impl<'tcx, T> fmt::Display for Highlighted<'tcx, T>
342 where
5e7ed085 343 T: for<'a> Print<
dc9dc135 344 'tcx,
5e7ed085 345 FmtPrinter<'a, 'tcx>,
532ac7d7 346 Error = fmt::Error,
5e7ed085 347 Output = FmtPrinter<'a, 'tcx>,
532ac7d7
XL
348 >,
349 {
350 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
5e7ed085 351 let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS);
532ac7d7
XL
352 printer.region_highlight_mode = self.highlight;
353
5e7ed085
FG
354 let s = self.value.print(printer)?.into_buffer();
355 f.write_str(&s)
532ac7d7
XL
356 }
357 }
358
9fa01778
XL
359 // The weird thing here with the `maybe_highlighting_region` calls and the
360 // the match inside is meant to be like this:
361 //
362 // - The match checks whether the given things (placeholders, etc) appear
363 // in the types are about to print
364 // - Meanwhile, the `maybe_highlighting_region` calls set up
365 // highlights so that, if they do appear, we will replace
366 // them `'0` and whatever. (This replacement takes place
367 // inside the closure given to `maybe_highlighting_region`.)
368 //
369 // There is some duplication between the calls -- i.e., the
370 // `maybe_highlighting_region` checks if (e.g.) `has_sub` is
371 // None, an then we check again inside the closure, but this
372 // setup sort of minimized the number of calls and so form.
373
532ac7d7
XL
374 let highlight_trait_ref = |trait_ref| Highlighted {
375 tcx: self.tcx(),
5099ac24 376 highlight: RegionHighlightMode::new(self.tcx()),
532ac7d7
XL
377 value: trait_ref,
378 };
9fa01778 379
6a06907d
XL
380 let same_self_type = actual_trait_ref.self_ty() == expected_trait_ref.self_ty();
381
532ac7d7
XL
382 let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref);
383 expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub);
384 expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup);
385 err.note(&{
386 let passive_voice = match (has_sub, has_sup) {
387 (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,
388 (None, None) => {
389 expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);
390 match expected_has_vid {
391 Some(_) => true,
392 None => any_self_ty_has_vid,
0731742a
XL
393 }
394 }
532ac7d7 395 };
0731742a 396
6a06907d
XL
397 let mut note = if same_self_type {
398 let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty());
399 self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);
400
401 if self_ty.value.is_closure()
402 && self
403 .tcx()
404 .fn_trait_kind_from_lang_item(expected_trait_ref.value.def_id)
405 .is_some()
406 {
407 let closure_sig = self_ty.map(|closure| {
408 if let ty::Closure(_, substs) = closure.kind() {
409 self.tcx().signature_unclosure(
410 substs.as_closure().sig(),
411 rustc_hir::Unsafety::Normal,
412 )
413 } else {
414 bug!("type is not longer closure");
415 }
416 });
417
418 format!(
419 "{}closure with signature `{}` must implement `{}`",
420 if leading_ellipsis { "..." } else { "" },
421 closure_sig,
422 expected_trait_ref.map(|tr| tr.print_only_trait_path()),
423 )
424 } else {
425 format!(
426 "{}`{}` must implement `{}`",
427 if leading_ellipsis { "..." } else { "" },
428 self_ty,
429 expected_trait_ref.map(|tr| tr.print_only_trait_path()),
430 )
431 }
432 } else if passive_voice {
532ac7d7 433 format!(
e1599b0c
XL
434 "{}`{}` would have to be implemented for the type `{}`",
435 if leading_ellipsis { "..." } else { "" },
60c5eb7d 436 expected_trait_ref.map(|tr| tr.print_only_trait_path()),
532ac7d7
XL
437 expected_trait_ref.map(|tr| tr.self_ty()),
438 )
439 } else {
440 format!(
e1599b0c
XL
441 "{}`{}` must implement `{}`",
442 if leading_ellipsis { "..." } else { "" },
532ac7d7 443 expected_trait_ref.map(|tr| tr.self_ty()),
60c5eb7d 444 expected_trait_ref.map(|tr| tr.print_only_trait_path()),
532ac7d7
XL
445 )
446 };
447
448 match (has_sub, has_sup) {
449 (Some(n1), Some(n2)) => {
dfeec247
XL
450 let _ = write!(
451 note,
e1599b0c 452 ", for any two lifetimes `'{}` and `'{}`...",
532ac7d7
XL
453 std::cmp::min(n1, n2),
454 std::cmp::max(n1, n2),
455 );
0731742a 456 }
532ac7d7 457 (Some(n), _) | (_, Some(n)) => {
dfeec247
XL
458 let _ = write!(note, ", for any lifetime `'{}`...", n,);
459 }
460 (None, None) => {
461 if let Some(n) = expected_has_vid {
462 let _ = write!(note, ", for some specific lifetime `'{}`...", n,);
463 }
532ac7d7 464 }
532ac7d7
XL
465 }
466
467 note
468 });
469
470 let mut actual_trait_ref = highlight_trait_ref(actual_trait_ref);
471 actual_trait_ref.highlight.maybe_highlighting_region(vid, actual_has_vid);
472 err.note(&{
473 let passive_voice = match actual_has_vid {
474 Some(_) => any_self_ty_has_vid,
475 None => true,
476 };
477
6a06907d
XL
478 let mut note = if same_self_type {
479 format!(
480 "...but it actually implements `{}`",
481 actual_trait_ref.map(|tr| tr.print_only_trait_path()),
482 )
483 } else if passive_voice {
532ac7d7 484 format!(
e1599b0c 485 "...but `{}` is actually implemented for the type `{}`",
60c5eb7d 486 actual_trait_ref.map(|tr| tr.print_only_trait_path()),
532ac7d7
XL
487 actual_trait_ref.map(|tr| tr.self_ty()),
488 )
489 } else {
490 format!(
e1599b0c 491 "...but `{}` actually implements `{}`",
532ac7d7 492 actual_trait_ref.map(|tr| tr.self_ty()),
60c5eb7d 493 actual_trait_ref.map(|tr| tr.print_only_trait_path()),
532ac7d7
XL
494 )
495 };
496
497 if let Some(n) = actual_has_vid {
498 let _ = write!(note, ", for some specific lifetime `'{}`", n);
499 }
500
501 note
502 });
0731742a
XL
503 }
504}