1 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
2 use crate::infer::lexical_region_resolve::RegionResolutionError;
3 use crate::infer::ValuePairs;
4 use crate::infer::{SubregionOrigin, TypeTrace};
5 use crate::traits::{ObligationCause, ObligationCauseCode};
6 use rustc_data_structures::intern::Interned;
7 use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
8 use rustc_hir::def::Namespace;
9 use rustc_hir::def_id::DefId;
10 use rustc_middle::ty::error::ExpectedFound;
11 use rustc_middle::ty::print::{FmtPrinter, Print, RegionHighlightMode};
12 use rustc_middle::ty::subst::SubstsRef;
13 use rustc_middle::ty::{self, RePlaceholder, ReVar, Region, TyCtxt};
15 use std::fmt::{self, Write};
17 impl<'tcx> NiceRegionError<'_, 'tcx> {
18 /// When given a `ConcreteFailure` for a function with arguments containing a named region and
19 /// an anonymous region, emit a descriptive diagnostic error.
20 pub(super) fn try_report_placeholder_conflict(
22 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
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
30 ///////////////////////////////////////////////////////////////////////////
31 // Check for errors from comparing trait failures -- first
32 // with two placeholders, then with one.
33 Some(RegionResolutionError::SubSupConflict(
36 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
37 sub_placeholder @ Region(Interned(RePlaceholder(_), _)),
39 sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
41 )) => self.try_report_trait_placeholder_mismatch(
42 Some(self.tcx().mk_region(ReVar(*vid))),
44 Some(*sub_placeholder),
45 Some(*sup_placeholder),
49 Some(RegionResolutionError::SubSupConflict(
52 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
53 sub_placeholder @ Region(Interned(RePlaceholder(_), _)),
57 )) => self.try_report_trait_placeholder_mismatch(
58 Some(self.tcx().mk_region(ReVar(*vid))),
60 Some(*sub_placeholder),
65 Some(RegionResolutionError::SubSupConflict(
68 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
71 sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
73 )) => self.try_report_trait_placeholder_mismatch(
74 Some(self.tcx().mk_region(ReVar(*vid))),
77 Some(*sup_placeholder),
81 Some(RegionResolutionError::SubSupConflict(
86 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
87 sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
89 )) => self.try_report_trait_placeholder_mismatch(
90 Some(self.tcx().mk_region(ReVar(*vid))),
93 Some(*sup_placeholder),
97 Some(RegionResolutionError::UpperBoundUniverseConflict(
101 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
102 sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
103 )) => self.try_report_trait_placeholder_mismatch(
104 Some(self.tcx().mk_region(ReVar(*vid))),
107 Some(*sup_placeholder),
111 Some(RegionResolutionError::ConcreteFailure(
112 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
113 sub_region @ Region(Interned(RePlaceholder(_), _)),
114 sup_region @ Region(Interned(RePlaceholder(_), _)),
115 )) => self.try_report_trait_placeholder_mismatch(
123 Some(RegionResolutionError::ConcreteFailure(
124 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
125 sub_region @ Region(Interned(RePlaceholder(_), _)),
127 )) => self.try_report_trait_placeholder_mismatch(
128 (!sup_region.has_name()).then_some(*sup_region),
135 Some(RegionResolutionError::ConcreteFailure(
136 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
138 sup_region @ Region(Interned(RePlaceholder(_), _)),
139 )) => self.try_report_trait_placeholder_mismatch(
140 (!sub_region.has_name()).then_some(*sub_region),
151 fn try_report_trait_placeholder_mismatch(
153 vid: Option<Region<'tcx>>,
154 cause: &ObligationCause<'tcx>,
155 sub_placeholder: Option<Region<'tcx>>,
156 sup_placeholder: Option<Region<'tcx>>,
157 value_pairs: &ValuePairs<'tcx>,
158 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
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 =>
163 (expected.substs, found.substs, expected.def_id)
165 ValuePairs::PolyTraitRefs(ExpectedFound { expected, found })
166 if expected.def_id() == found.def_id() =>
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())
176 Some(self.report_trait_placeholder_mismatch(
187 // error[E0308]: implementation of `Foo` does not apply to enough lifetimes
188 // --> /home/nmatsakis/tmp/foo.rs:12:5
190 // 12 | all::<&'static u32>();
191 // | ^^^^^^^^^^^^^^^^^^^ lifetime mismatch
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`.
196 #[instrument(level = "debug", skip(self))]
197 fn report_trait_placeholder_mismatch(
199 vid: Option<Region<'tcx>>,
200 cause: &ObligationCause<'tcx>,
201 sub_placeholder: Option<Region<'tcx>>,
202 sup_placeholder: Option<Region<'tcx>>,
204 expected_substs: SubstsRef<'tcx>,
205 actual_substs: SubstsRef<'tcx>,
206 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
207 let span = cause.span();
209 "implementation of `{}` is not general enough",
210 self.tcx().def_path_str(trait_def_id),
212 let mut err = self.tcx().sess.struct_span_err(span, &msg);
214 let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id) = *cause.code() {
215 err.span_label(span, "doesn't satisfy where-clause");
217 self.tcx().def_span(def_id),
218 &format!("due to a where-clause on `{}`...", self.tcx().def_path_str(def_id)),
222 err.span_label(span, &msg);
226 let expected_trait_ref = self.infcx.resolve_vars_if_possible(ty::TraitRef {
227 def_id: trait_def_id,
228 substs: expected_substs,
230 let actual_trait_ref = self
232 .resolve_vars_if_possible(ty::TraitRef { def_id: trait_def_id, substs: actual_substs });
234 // Search the expected and actual trait references to see (a)
235 // whether the sub/sup placeholders appear in them (sometimes
236 // you have a trait ref like `T: Foo<fn(&u8)>`, where the
237 // placeholder was created as part of an inner type) and (b)
238 // whether the inference variable appears. In each case,
239 // assign a counter value in each case if so.
241 let mut has_sub = None;
242 let mut has_sup = None;
244 let mut actual_has_vid = None;
245 let mut expected_has_vid = None;
247 self.tcx().for_each_free_region(&expected_trait_ref, |r| {
248 if Some(r) == sub_placeholder && has_sub.is_none() {
249 has_sub = Some(counter);
251 } else if Some(r) == sup_placeholder && has_sup.is_none() {
252 has_sup = Some(counter);
256 if Some(r) == vid && expected_has_vid.is_none() {
257 expected_has_vid = Some(counter);
262 self.tcx().for_each_free_region(&actual_trait_ref, |r| {
263 if Some(r) == vid && actual_has_vid.is_none() {
264 actual_has_vid = Some(counter);
269 let actual_self_ty_has_vid =
270 self.tcx().any_free_region_meets(&actual_trait_ref.self_ty(), |r| Some(r) == vid);
272 let expected_self_ty_has_vid =
273 self.tcx().any_free_region_meets(&expected_trait_ref.self_ty(), |r| Some(r) == vid);
275 let any_self_ty_has_vid = actual_self_ty_has_vid || expected_self_ty_has_vid;
282 ?actual_self_ty_has_vid,
283 ?expected_self_ty_has_vid,
286 self.explain_actual_impl_that_was_found(
304 /// Add notes with details about the expected and actual trait refs, with attention to cases
305 /// when placeholder regions are involved: either the trait or the self type containing
306 /// them needs to be mentioned the closest to the placeholders.
307 /// This makes the error messages read better, however at the cost of some complexity
308 /// due to the number of combinations we have to deal with.
309 fn explain_actual_impl_that_was_found(
311 err: &mut Diagnostic,
312 sub_placeholder: Option<Region<'tcx>>,
313 sup_placeholder: Option<Region<'tcx>>,
314 has_sub: Option<usize>,
315 has_sup: Option<usize>,
316 expected_trait_ref: ty::TraitRef<'tcx>,
317 actual_trait_ref: ty::TraitRef<'tcx>,
318 vid: Option<Region<'tcx>>,
319 expected_has_vid: Option<usize>,
320 actual_has_vid: Option<usize>,
321 any_self_ty_has_vid: bool,
322 leading_ellipsis: bool,
324 // HACK(eddyb) maybe move this in a more central location.
325 #[derive(Copy, Clone)]
326 struct Highlighted<'tcx, T> {
328 highlight: RegionHighlightMode<'tcx>,
332 impl<'tcx, T> Highlighted<'tcx, T> {
333 fn map<U>(self, f: impl FnOnce(T) -> U) -> Highlighted<'tcx, U> {
334 Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value) }
338 impl<'tcx, T> fmt::Display for Highlighted<'tcx, T>
342 FmtPrinter<'a, 'tcx>,
344 Output = FmtPrinter<'a, 'tcx>,
347 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
348 let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS);
349 printer.region_highlight_mode = self.highlight;
351 let s = self.value.print(printer)?.into_buffer();
356 // The weird thing here with the `maybe_highlighting_region` calls and the
357 // the match inside is meant to be like this:
359 // - The match checks whether the given things (placeholders, etc) appear
360 // in the types are about to print
361 // - Meanwhile, the `maybe_highlighting_region` calls set up
362 // highlights so that, if they do appear, we will replace
363 // them `'0` and whatever. (This replacement takes place
364 // inside the closure given to `maybe_highlighting_region`.)
366 // There is some duplication between the calls -- i.e., the
367 // `maybe_highlighting_region` checks if (e.g.) `has_sub` is
368 // None, an then we check again inside the closure, but this
369 // setup sort of minimized the number of calls and so form.
371 let highlight_trait_ref = |trait_ref| Highlighted {
373 highlight: RegionHighlightMode::new(self.tcx()),
377 let same_self_type = actual_trait_ref.self_ty() == expected_trait_ref.self_ty();
379 let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref);
380 expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub);
381 expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup);
383 let passive_voice = match (has_sub, has_sup) {
384 (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,
386 expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);
387 match expected_has_vid {
389 None => any_self_ty_has_vid,
394 let mut note = if same_self_type {
395 let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty());
396 self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);
398 if self_ty.value.is_closure()
401 .fn_trait_kind_from_lang_item(expected_trait_ref.value.def_id)
404 let closure_sig = self_ty.map(|closure| {
405 if let ty::Closure(_, substs) = closure.kind() {
406 self.tcx().signature_unclosure(
407 substs.as_closure().sig(),
408 rustc_hir::Unsafety::Normal,
411 bug!("type is not longer closure");
416 "{}closure with signature `{}` must implement `{}`",
417 if leading_ellipsis { "..." } else { "" },
419 expected_trait_ref.map(|tr| tr.print_only_trait_path()),
423 "{}`{}` must implement `{}`",
424 if leading_ellipsis { "..." } else { "" },
426 expected_trait_ref.map(|tr| tr.print_only_trait_path()),
429 } else if passive_voice {
431 "{}`{}` would have to be implemented for the type `{}`",
432 if leading_ellipsis { "..." } else { "" },
433 expected_trait_ref.map(|tr| tr.print_only_trait_path()),
434 expected_trait_ref.map(|tr| tr.self_ty()),
438 "{}`{}` must implement `{}`",
439 if leading_ellipsis { "..." } else { "" },
440 expected_trait_ref.map(|tr| tr.self_ty()),
441 expected_trait_ref.map(|tr| tr.print_only_trait_path()),
445 match (has_sub, has_sup) {
446 (Some(n1), Some(n2)) => {
449 ", for any two lifetimes `'{}` and `'{}`...",
450 std::cmp::min(n1, n2),
451 std::cmp::max(n1, n2),
454 (Some(n), _) | (_, Some(n)) => {
455 let _ = write!(note, ", for any lifetime `'{}`...", n,);
458 if let Some(n) = expected_has_vid {
459 let _ = write!(note, ", for some specific lifetime `'{}`...", n,);
467 let mut actual_trait_ref = highlight_trait_ref(actual_trait_ref);
468 actual_trait_ref.highlight.maybe_highlighting_region(vid, actual_has_vid);
470 let passive_voice = match actual_has_vid {
471 Some(_) => any_self_ty_has_vid,
475 let mut note = if same_self_type {
477 "...but it actually implements `{}`",
478 actual_trait_ref.map(|tr| tr.print_only_trait_path()),
480 } else if passive_voice {
482 "...but `{}` is actually implemented for the type `{}`",
483 actual_trait_ref.map(|tr| tr.print_only_trait_path()),
484 actual_trait_ref.map(|tr| tr.self_ty()),
488 "...but `{}` actually implements `{}`",
489 actual_trait_ref.map(|tr| tr.self_ty()),
490 actual_trait_ref.map(|tr| tr.print_only_trait_path()),
494 if let Some(n) = actual_has_vid {
495 let _ = write!(note, ", for some specific lifetime `'{}`", n);