2 ActualImplExpectedKind, ActualImplExpectedLifetimeKind, ActualImplExplNotes,
3 TraitPlaceholderMismatch, TyOrSig,
5 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
6 use crate::infer::lexical_region_resolve::RegionResolutionError;
7 use crate::infer::ValuePairs;
8 use crate::infer::{SubregionOrigin, TypeTrace};
9 use crate::traits::{ObligationCause, ObligationCauseCode};
10 use rustc_data_structures::intern::Interned;
11 use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, IntoDiagnosticArg};
12 use rustc_hir::def::Namespace;
13 use rustc_hir::def_id::DefId;
14 use rustc_middle::ty::error::ExpectedFound;
15 use rustc_middle::ty::print::{FmtPrinter, Print, RegionHighlightMode};
16 use rustc_middle::ty::subst::SubstsRef;
17 use rustc_middle::ty::{self, RePlaceholder, ReVar, Region, TyCtxt};
21 // HACK(eddyb) maybe move this in a more central location.
22 #[derive(Copy, Clone)]
23 pub struct Highlighted<'tcx, T> {
25 highlight: RegionHighlightMode<'tcx>,
29 impl<'tcx, T> IntoDiagnosticArg for Highlighted<'tcx, T>
31 T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>, Error = fmt::Error, Output = FmtPrinter<'a, 'tcx>>,
33 fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
34 rustc_errors::DiagnosticArgValue::Str(self.to_string().into())
38 impl<'tcx, T> Highlighted<'tcx, T> {
39 fn map<U>(self, f: impl FnOnce(T) -> U) -> Highlighted<'tcx, U> {
40 Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value) }
44 impl<'tcx, T> fmt::Display for Highlighted<'tcx, T>
46 T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>, Error = fmt::Error, Output = FmtPrinter<'a, 'tcx>>,
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS);
50 printer.region_highlight_mode = self.highlight;
52 let s = self.value.print(printer)?.into_buffer();
57 impl<'tcx> NiceRegionError<'_, 'tcx> {
58 /// When given a `ConcreteFailure` for a function with arguments containing a named region and
59 /// an anonymous region, emit a descriptive diagnostic error.
60 pub(super) fn try_report_placeholder_conflict(
62 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
64 ///////////////////////////////////////////////////////////////////////////
65 // NB. The ordering of cases in this match is very
66 // sensitive, because we are often matching against
67 // specific cases and then using an `_` to match all
70 ///////////////////////////////////////////////////////////////////////////
71 // Check for errors from comparing trait failures -- first
72 // with two placeholders, then with one.
73 Some(RegionResolutionError::SubSupConflict(
76 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
77 sub_placeholder @ Region(Interned(RePlaceholder(_), _)),
79 sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
81 )) => self.try_report_trait_placeholder_mismatch(
82 Some(self.tcx().mk_region(ReVar(*vid))),
84 Some(*sub_placeholder),
85 Some(*sup_placeholder),
89 Some(RegionResolutionError::SubSupConflict(
92 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
93 sub_placeholder @ Region(Interned(RePlaceholder(_), _)),
97 )) => self.try_report_trait_placeholder_mismatch(
98 Some(self.tcx().mk_region(ReVar(*vid))),
100 Some(*sub_placeholder),
105 Some(RegionResolutionError::SubSupConflict(
108 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
111 sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
113 )) => self.try_report_trait_placeholder_mismatch(
114 Some(self.tcx().mk_region(ReVar(*vid))),
117 Some(*sup_placeholder),
121 Some(RegionResolutionError::SubSupConflict(
126 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
127 sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
129 )) => self.try_report_trait_placeholder_mismatch(
130 Some(self.tcx().mk_region(ReVar(*vid))),
133 Some(*sup_placeholder),
137 Some(RegionResolutionError::UpperBoundUniverseConflict(
141 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
142 sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
143 )) => self.try_report_trait_placeholder_mismatch(
144 Some(self.tcx().mk_region(ReVar(*vid))),
147 Some(*sup_placeholder),
151 Some(RegionResolutionError::ConcreteFailure(
152 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
153 sub_region @ Region(Interned(RePlaceholder(_), _)),
154 sup_region @ Region(Interned(RePlaceholder(_), _)),
155 )) => self.try_report_trait_placeholder_mismatch(
163 Some(RegionResolutionError::ConcreteFailure(
164 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
165 sub_region @ Region(Interned(RePlaceholder(_), _)),
167 )) => self.try_report_trait_placeholder_mismatch(
168 (!sup_region.has_name()).then_some(*sup_region),
175 Some(RegionResolutionError::ConcreteFailure(
176 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
178 sup_region @ Region(Interned(RePlaceholder(_), _)),
179 )) => self.try_report_trait_placeholder_mismatch(
180 (!sub_region.has_name()).then_some(*sub_region),
191 fn try_report_trait_placeholder_mismatch(
193 vid: Option<Region<'tcx>>,
194 cause: &ObligationCause<'tcx>,
195 sub_placeholder: Option<Region<'tcx>>,
196 sup_placeholder: Option<Region<'tcx>>,
197 value_pairs: &ValuePairs<'tcx>,
198 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
199 let (expected_substs, found_substs, trait_def_id) = match value_pairs {
200 ValuePairs::TraitRefs(ExpectedFound { expected, found })
201 if expected.def_id == found.def_id =>
203 (expected.substs, found.substs, expected.def_id)
205 ValuePairs::PolyTraitRefs(ExpectedFound { expected, found })
206 if expected.def_id() == found.def_id() =>
208 // It's possible that the placeholders come from a binder
209 // outside of this value pair. Use `no_bound_vars` as a
210 // simple heuristic for that.
211 (expected.no_bound_vars()?.substs, found.no_bound_vars()?.substs, expected.def_id())
216 Some(self.report_trait_placeholder_mismatch(
227 // error[E0308]: implementation of `Foo` does not apply to enough lifetimes
228 // --> /home/nmatsakis/tmp/foo.rs:12:5
230 // 12 | all::<&'static u32>();
231 // | ^^^^^^^^^^^^^^^^^^^ lifetime mismatch
233 // = note: Due to a where-clause on the function `all`,
234 // = note: `T` must implement `...` for any two lifetimes `'1` and `'2`.
235 // = note: However, the type `T` only implements `...` for some specific lifetime `'2`.
236 #[instrument(level = "debug", skip(self))]
237 fn report_trait_placeholder_mismatch(
239 vid: Option<Region<'tcx>>,
240 cause: &ObligationCause<'tcx>,
241 sub_placeholder: Option<Region<'tcx>>,
242 sup_placeholder: Option<Region<'tcx>>,
244 expected_substs: SubstsRef<'tcx>,
245 actual_substs: SubstsRef<'tcx>,
246 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
247 let span = cause.span();
249 let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) =
250 if let ObligationCauseCode::ItemObligation(def_id)
251 | ObligationCauseCode::ExprItemObligation(def_id, ..) = *cause.code()
256 Some(self.tcx().def_span(def_id)),
258 self.tcx().def_path_str(def_id),
261 (false, None, None, Some(span), String::new())
264 let expected_trait_ref = self
266 .resolve_vars_if_possible(self.cx.tcx.mk_trait_ref(trait_def_id, expected_substs));
267 let actual_trait_ref =
268 self.cx.resolve_vars_if_possible(self.cx.tcx.mk_trait_ref(trait_def_id, actual_substs));
270 // Search the expected and actual trait references to see (a)
271 // whether the sub/sup placeholders appear in them (sometimes
272 // you have a trait ref like `T: Foo<fn(&u8)>`, where the
273 // placeholder was created as part of an inner type) and (b)
274 // whether the inference variable appears. In each case,
275 // assign a counter value in each case if so.
277 let mut has_sub = None;
278 let mut has_sup = None;
280 let mut actual_has_vid = None;
281 let mut expected_has_vid = None;
283 self.tcx().for_each_free_region(&expected_trait_ref, |r| {
284 if Some(r) == sub_placeholder && has_sub.is_none() {
285 has_sub = Some(counter);
287 } else if Some(r) == sup_placeholder && has_sup.is_none() {
288 has_sup = Some(counter);
292 if Some(r) == vid && expected_has_vid.is_none() {
293 expected_has_vid = Some(counter);
298 self.tcx().for_each_free_region(&actual_trait_ref, |r| {
299 if Some(r) == vid && actual_has_vid.is_none() {
300 actual_has_vid = Some(counter);
305 let actual_self_ty_has_vid =
306 self.tcx().any_free_region_meets(&actual_trait_ref.self_ty(), |r| Some(r) == vid);
308 let expected_self_ty_has_vid =
309 self.tcx().any_free_region_meets(&expected_trait_ref.self_ty(), |r| Some(r) == vid);
311 let any_self_ty_has_vid = actual_self_ty_has_vid || expected_self_ty_has_vid;
318 ?actual_self_ty_has_vid,
319 ?expected_self_ty_has_vid,
322 let actual_impl_expl_notes = self.explain_actual_impl_that_was_found(
336 let diag = TraitPlaceholderMismatch {
342 trait_def_id: self.tcx().def_path_str(trait_def_id),
343 actual_impl_expl_notes,
346 self.tcx().sess.create_err(diag)
349 /// Add notes with details about the expected and actual trait refs, with attention to cases
350 /// when placeholder regions are involved: either the trait or the self type containing
351 /// them needs to be mentioned the closest to the placeholders.
352 /// This makes the error messages read better, however at the cost of some complexity
353 /// due to the number of combinations we have to deal with.
354 fn explain_actual_impl_that_was_found(
356 sub_placeholder: Option<Region<'tcx>>,
357 sup_placeholder: Option<Region<'tcx>>,
358 has_sub: Option<usize>,
359 has_sup: Option<usize>,
360 expected_trait_ref: ty::TraitRef<'tcx>,
361 actual_trait_ref: ty::TraitRef<'tcx>,
362 vid: Option<Region<'tcx>>,
363 expected_has_vid: Option<usize>,
364 actual_has_vid: Option<usize>,
365 any_self_ty_has_vid: bool,
366 leading_ellipsis: bool,
367 ) -> Vec<ActualImplExplNotes<'tcx>> {
368 // The weird thing here with the `maybe_highlighting_region` calls and the
369 // the match inside is meant to be like this:
371 // - The match checks whether the given things (placeholders, etc) appear
372 // in the types are about to print
373 // - Meanwhile, the `maybe_highlighting_region` calls set up
374 // highlights so that, if they do appear, we will replace
375 // them `'0` and whatever. (This replacement takes place
376 // inside the closure given to `maybe_highlighting_region`.)
378 // There is some duplication between the calls -- i.e., the
379 // `maybe_highlighting_region` checks if (e.g.) `has_sub` is
380 // None, an then we check again inside the closure, but this
381 // setup sort of minimized the number of calls and so form.
383 let highlight_trait_ref = |trait_ref| Highlighted {
385 highlight: RegionHighlightMode::new(self.tcx()),
389 let same_self_type = actual_trait_ref.self_ty() == expected_trait_ref.self_ty();
391 let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref);
392 expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub);
393 expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup);
395 let passive_voice = match (has_sub, has_sup) {
396 (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,
398 expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);
399 match expected_has_vid {
401 None => any_self_ty_has_vid,
406 let (kind, ty_or_sig, trait_path) = if same_self_type {
407 let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty());
408 self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);
410 if self_ty.value.is_closure()
411 && self.tcx().is_fn_trait(expected_trait_ref.value.def_id)
413 let closure_sig = self_ty.map(|closure| {
414 if let ty::Closure(_, substs) = closure.kind() {
415 self.tcx().signature_unclosure(
416 substs.as_closure().sig(),
417 rustc_hir::Unsafety::Normal,
420 bug!("type is not longer closure");
424 ActualImplExpectedKind::Signature,
425 TyOrSig::ClosureSig(closure_sig),
426 expected_trait_ref.map(|tr| tr.print_only_trait_path()),
430 ActualImplExpectedKind::Other,
431 TyOrSig::Ty(self_ty),
432 expected_trait_ref.map(|tr| tr.print_only_trait_path()),
435 } else if passive_voice {
437 ActualImplExpectedKind::Passive,
438 TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())),
439 expected_trait_ref.map(|tr| tr.print_only_trait_path()),
443 ActualImplExpectedKind::Other,
444 TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())),
445 expected_trait_ref.map(|tr| tr.print_only_trait_path()),
449 let (lt_kind, lifetime_1, lifetime_2) = match (has_sub, has_sup) {
450 (Some(n1), Some(n2)) => {
451 (ActualImplExpectedLifetimeKind::Two, std::cmp::min(n1, n2), std::cmp::max(n1, n2))
453 (Some(n), _) | (_, Some(n)) => (ActualImplExpectedLifetimeKind::Any, n, 0),
455 if let Some(n) = expected_has_vid {
456 (ActualImplExpectedLifetimeKind::Some, n, 0)
458 (ActualImplExpectedLifetimeKind::Nothing, 0, 0)
463 let note_1 = ActualImplExplNotes::new_expected(
473 let mut actual_trait_ref = highlight_trait_ref(actual_trait_ref);
474 actual_trait_ref.highlight.maybe_highlighting_region(vid, actual_has_vid);
476 let passive_voice = match actual_has_vid {
477 Some(_) => any_self_ty_has_vid,
481 let trait_path = actual_trait_ref.map(|tr| tr.print_only_trait_path());
482 let ty = actual_trait_ref.map(|tr| tr.self_ty()).to_string();
483 let has_lifetime = actual_has_vid.is_some();
484 let lifetime = actual_has_vid.unwrap_or_default();
486 let note_2 = if same_self_type {
487 ActualImplExplNotes::ButActuallyImplementsTrait { trait_path, has_lifetime, lifetime }
488 } else if passive_voice {
489 ActualImplExplNotes::ButActuallyImplementedForTy {
496 ActualImplExplNotes::ButActuallyTyImplements { trait_path, ty, has_lifetime, lifetime }