1use std::fmt;23use rustc_data_structures::intern::Interned;4use rustc_errors::{Diag, IntoDiagArg};5use rustc_hir::def::Namespace;6use rustc_hir::def_id::{CRATE_DEF_ID, DefId};7use rustc_middle::bug;8use rustc_middle::ty::error::ExpectedFound;9use rustc_middle::ty::print::{FmtPrinter, Print, PrintTraitRefExt as _, RegionHighlightMode};10use rustc_middle::ty::{self, GenericArgsRef, RePlaceholder, Region, TyCtxt};11use tracing::{debug, instrument};1213use crate::error_reporting::infer::nice_region_error::NiceRegionError;14use crate::errors::{15 ActualImplExpectedKind, ActualImplExpectedLifetimeKind, ActualImplExplNotes,16 TraitPlaceholderMismatch, TyOrSig,17};18use crate::infer::{RegionResolutionError, SubregionOrigin, TypeTrace, ValuePairs};19use crate::traits::{ObligationCause, ObligationCauseCode};2021#[derive(Copy, Clone)]22pub(crate) struct Highlighted<'tcx, T> {23 pub tcx: TyCtxt<'tcx>,24 pub highlight: RegionHighlightMode<'tcx>,25 pub value: T,26 pub ns: Namespace,27}2829impl<'tcx, T> IntoDiagArg for Highlighted<'tcx, T>30where31 T: for<'a> Print<FmtPrinter<'a, 'tcx>>,32{33 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {34 rustc_errors::DiagArgValue::Str(self.to_string().into())35 }36}3738impl<'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), ns: self.ns }41 }42}4344impl<'tcx, T> fmt::Display for Highlighted<'tcx, T>45where46 T: for<'a> Print<FmtPrinter<'a, 'tcx>>,47{48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {49 let mut p = ty::print::FmtPrinter::new(self.tcx, self.ns);50 p.region_highlight_mode = self.highlight;5152 self.value.print(&mut p)?;53 f.write_str(&p.into_buffer())54 }55}5657impl<'tcx> NiceRegionError<'_, 'tcx> {58 /// When given a `ConcreteFailure` for a function with arguments containing a named region and59 /// an anonymous region, emit a descriptive diagnostic error.60 pub(super) fn try_report_placeholder_conflict(&self) -> Option<Diag<'tcx>> {61 match &self.error {62 ///////////////////////////////////////////////////////////////////////////63 // NB. The ordering of cases in this match is very64 // sensitive, because we are often matching against65 // specific cases and then using an `_` to match all66 // others.6768 ///////////////////////////////////////////////////////////////////////////69 // Check for errors from comparing trait failures -- first70 // with two placeholders, then with one.71 Some(RegionResolutionError::SubSupConflict(72 vid,73 _,74 SubregionOrigin::Subtype(box TypeTrace { cause, values }),75 sub_placeholder @ Region(Interned(RePlaceholder(_), _)),76 _,77 sup_placeholder @ Region(Interned(RePlaceholder(_), _)),78 _,79 )) => self.try_report_trait_placeholder_mismatch(80 Some(ty::Region::new_var(self.tcx(), *vid)),81 cause,82 Some(*sub_placeholder),83 Some(*sup_placeholder),84 values,85 ),8687 Some(RegionResolutionError::SubSupConflict(88 vid,89 _,90 SubregionOrigin::Subtype(box TypeTrace { cause, values }),91 sub_placeholder @ Region(Interned(RePlaceholder(_), _)),92 _,93 _,94 _,95 )) => self.try_report_trait_placeholder_mismatch(96 Some(ty::Region::new_var(self.tcx(), *vid)),97 cause,98 Some(*sub_placeholder),99 None,100 values,101 ),102103 Some(RegionResolutionError::SubSupConflict(104 vid,105 _,106 SubregionOrigin::Subtype(box TypeTrace { cause, values }),107 _,108 _,109 sup_placeholder @ Region(Interned(RePlaceholder(_), _)),110 _,111 )) => self.try_report_trait_placeholder_mismatch(112 Some(ty::Region::new_var(self.tcx(), *vid)),113 cause,114 None,115 Some(*sup_placeholder),116 values,117 ),118119 Some(RegionResolutionError::SubSupConflict(120 vid,121 _,122 _,123 _,124 SubregionOrigin::Subtype(box TypeTrace { cause, values }),125 sup_placeholder @ Region(Interned(RePlaceholder(_), _)),126 _,127 )) => self.try_report_trait_placeholder_mismatch(128 Some(ty::Region::new_var(self.tcx(), *vid)),129 cause,130 None,131 Some(*sup_placeholder),132 values,133 ),134135 Some(RegionResolutionError::UpperBoundUniverseConflict(136 vid,137 _,138 _,139 SubregionOrigin::Subtype(box TypeTrace { cause, values }),140 sup_placeholder @ Region(Interned(RePlaceholder(_), _)),141 )) => self.try_report_trait_placeholder_mismatch(142 Some(ty::Region::new_var(self.tcx(), *vid)),143 cause,144 None,145 Some(*sup_placeholder),146 values,147 ),148149 Some(RegionResolutionError::ConcreteFailure(150 SubregionOrigin::Subtype(box TypeTrace { cause, values }),151 sub_region @ Region(Interned(RePlaceholder(_), _)),152 sup_region @ Region(Interned(RePlaceholder(_), _)),153 )) => self.try_report_trait_placeholder_mismatch(154 None,155 cause,156 Some(*sub_region),157 Some(*sup_region),158 values,159 ),160161 Some(RegionResolutionError::ConcreteFailure(162 SubregionOrigin::Subtype(box TypeTrace { cause, values }),163 sub_region @ Region(Interned(RePlaceholder(_), _)),164 sup_region,165 )) => self.try_report_trait_placeholder_mismatch(166 (!sup_region.is_named(self.tcx())).then_some(*sup_region),167 cause,168 Some(*sub_region),169 None,170 values,171 ),172173 Some(RegionResolutionError::ConcreteFailure(174 SubregionOrigin::Subtype(box TypeTrace { cause, values }),175 sub_region,176 sup_region @ Region(Interned(RePlaceholder(_), _)),177 )) => self.try_report_trait_placeholder_mismatch(178 (!sub_region.is_named(self.tcx())).then_some(*sub_region),179 cause,180 None,181 Some(*sup_region),182 values,183 ),184185 _ => None,186 }187 }188189 fn try_report_trait_placeholder_mismatch(190 &self,191 vid: Option<Region<'tcx>>,192 cause: &ObligationCause<'tcx>,193 sub_placeholder: Option<Region<'tcx>>,194 sup_placeholder: Option<Region<'tcx>>,195 value_pairs: &ValuePairs<'tcx>,196 ) -> Option<Diag<'tcx>> {197 let (expected_args, found_args, trait_def_id) = match value_pairs {198 ValuePairs::TraitRefs(ExpectedFound { expected, found })199 if expected.def_id == found.def_id =>200 {201 // It's possible that the placeholders come from a binder202 // outside of this value pair. Use `no_bound_vars` as a203 // simple heuristic for that.204 (expected.args, found.args, expected.def_id)205 }206 _ => return None,207 };208209 Some(self.report_trait_placeholder_mismatch(210 vid,211 cause,212 sub_placeholder,213 sup_placeholder,214 trait_def_id,215 expected_args,216 found_args,217 ))218 }219220 // error[E0308]: implementation of `Foo` does not apply to enough lifetimes221 // --> /home/nmatsakis/tmp/foo.rs:12:5222 // |223 // 12 | all::<&'static u32>();224 // | ^^^^^^^^^^^^^^^^^^^ lifetime mismatch225 // |226 // = note: Due to a where-clause on the function `all`,227 // = note: `T` must implement `...` for any two lifetimes `'1` and `'2`.228 // = note: However, the type `T` only implements `...` for some specific lifetime `'2`.229 #[instrument(level = "debug", skip(self))]230 fn report_trait_placeholder_mismatch(231 &self,232 vid: Option<Region<'tcx>>,233 cause: &ObligationCause<'tcx>,234 sub_placeholder: Option<Region<'tcx>>,235 sup_placeholder: Option<Region<'tcx>>,236 trait_def_id: DefId,237 expected_args: GenericArgsRef<'tcx>,238 actual_args: GenericArgsRef<'tcx>,239 ) -> Diag<'tcx> {240 let span = cause.span;241242 let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) =243 if let ObligationCauseCode::WhereClause(def_id, span)244 | ObligationCauseCode::WhereClauseInExpr(def_id, span, ..) = *cause.code()245 && def_id != CRATE_DEF_ID.to_def_id()246 {247 (248 true,249 Some(span),250 Some(self.tcx().def_span(def_id)),251 None,252 self.tcx().def_path_str(def_id),253 )254 } else {255 (false, None, None, Some(span), String::new())256 };257258 let expected_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef::new_from_args(259 self.cx.tcx,260 trait_def_id,261 expected_args,262 ));263 let actual_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef::new_from_args(264 self.cx.tcx,265 trait_def_id,266 actual_args,267 ));268269 // Search the expected and actual trait references to see (a)270 // whether the sub/sup placeholders appear in them (sometimes271 // you have a trait ref like `T: Foo<fn(&u8)>`, where the272 // placeholder was created as part of an inner type) and (b)273 // whether the inference variable appears. In each case,274 // assign a counter value in each case if so.275 let mut counter = 0;276 let mut has_sub = None;277 let mut has_sup = None;278279 let mut actual_has_vid = None;280 let mut expected_has_vid = None;281282 self.tcx().for_each_free_region(&expected_trait_ref, |r| {283 if Some(r) == sub_placeholder && has_sub.is_none() {284 has_sub = Some(counter);285 counter += 1;286 } else if Some(r) == sup_placeholder && has_sup.is_none() {287 has_sup = Some(counter);288 counter += 1;289 }290291 if Some(r) == vid && expected_has_vid.is_none() {292 expected_has_vid = Some(counter);293 counter += 1;294 }295 });296297 self.tcx().for_each_free_region(&actual_trait_ref, |r| {298 if Some(r) == vid && actual_has_vid.is_none() {299 actual_has_vid = Some(counter);300 counter += 1;301 }302 });303304 let actual_self_ty_has_vid =305 self.tcx().any_free_region_meets(&actual_trait_ref.self_ty(), |r| Some(r) == vid);306307 let expected_self_ty_has_vid =308 self.tcx().any_free_region_meets(&expected_trait_ref.self_ty(), |r| Some(r) == vid);309310 let any_self_ty_has_vid = actual_self_ty_has_vid || expected_self_ty_has_vid;311312 debug!(313 ?actual_has_vid,314 ?expected_has_vid,315 ?has_sub,316 ?has_sup,317 ?actual_self_ty_has_vid,318 ?expected_self_ty_has_vid,319 );320321 let actual_impl_expl_notes = self.explain_actual_impl_that_was_found(322 sub_placeholder,323 sup_placeholder,324 has_sub,325 has_sup,326 expected_trait_ref,327 actual_trait_ref,328 vid,329 expected_has_vid,330 actual_has_vid,331 any_self_ty_has_vid,332 leading_ellipsis,333 );334335 self.tcx().dcx().create_err(TraitPlaceholderMismatch {336 span,337 satisfy_span,338 where_span,339 dup_span,340 def_id,341 trait_def_id: self.tcx().def_path_str(trait_def_id),342 actual_impl_expl_notes,343 })344 }345346 /// Add notes with details about the expected and actual trait refs, with attention to cases347 /// when placeholder regions are involved: either the trait or the self type containing348 /// them needs to be mentioned the closest to the placeholders.349 /// This makes the error messages read better, however at the cost of some complexity350 /// due to the number of combinations we have to deal with.351 fn explain_actual_impl_that_was_found(352 &self,353 sub_placeholder: Option<Region<'tcx>>,354 sup_placeholder: Option<Region<'tcx>>,355 has_sub: Option<usize>,356 has_sup: Option<usize>,357 expected_trait_ref: ty::TraitRef<'tcx>,358 actual_trait_ref: ty::TraitRef<'tcx>,359 vid: Option<Region<'tcx>>,360 expected_has_vid: Option<usize>,361 actual_has_vid: Option<usize>,362 any_self_ty_has_vid: bool,363 leading_ellipsis: bool,364 ) -> Vec<ActualImplExplNotes<'tcx>> {365 // The weird thing here with the `maybe_highlighting_region` calls and the366 // the match inside is meant to be like this:367 //368 // - The match checks whether the given things (placeholders, etc) appear369 // in the types are about to print370 // - Meanwhile, the `maybe_highlighting_region` calls set up371 // highlights so that, if they do appear, we will replace372 // them `'0` and whatever. (This replacement takes place373 // inside the closure given to `maybe_highlighting_region`.)374 //375 // There is some duplication between the calls -- i.e., the376 // `maybe_highlighting_region` checks if (e.g.) `has_sub` is377 // None, an then we check again inside the closure, but this378 // setup sort of minimized the number of calls and so form.379380 let highlight_trait_ref = |trait_ref| Highlighted {381 tcx: self.tcx(),382 highlight: RegionHighlightMode::default(),383 value: trait_ref,384 ns: Namespace::TypeNS,385 };386387 let same_self_type = actual_trait_ref.self_ty() == expected_trait_ref.self_ty();388389 let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref);390 expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub);391 expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup);392393 let passive_voice = match (has_sub, has_sup) {394 (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,395 (None, None) => {396 expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);397 match expected_has_vid {398 Some(_) => true,399 None => any_self_ty_has_vid,400 }401 }402 };403404 let (kind, ty_or_sig, trait_path) = if same_self_type {405 let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty());406 self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);407408 if self_ty.value.is_closure() && self.tcx().is_fn_trait(expected_trait_ref.value.def_id)409 {410 let closure_sig = self_ty.map(|closure| {411 if let ty::Closure(_, args) = closure.kind() {412 self.tcx()413 .signature_unclosure(args.as_closure().sig(), rustc_hir::Safety::Safe)414 } else {415 bug!("type is not longer closure");416 }417 });418 (419 ActualImplExpectedKind::Signature,420 TyOrSig::ClosureSig(closure_sig),421 expected_trait_ref.map(|tr| tr.print_only_trait_path()),422 )423 } else {424 (425 ActualImplExpectedKind::Other,426 TyOrSig::Ty(self_ty),427 expected_trait_ref.map(|tr| tr.print_only_trait_path()),428 )429 }430 } else if passive_voice {431 (432 ActualImplExpectedKind::Passive,433 TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())),434 expected_trait_ref.map(|tr| tr.print_only_trait_path()),435 )436 } else {437 (438 ActualImplExpectedKind::Other,439 TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())),440 expected_trait_ref.map(|tr| tr.print_only_trait_path()),441 )442 };443444 let (lt_kind, lifetime_1, lifetime_2) = match (has_sub, has_sup) {445 (Some(n1), Some(n2)) => {446 (ActualImplExpectedLifetimeKind::Two, std::cmp::min(n1, n2), std::cmp::max(n1, n2))447 }448 (Some(n), _) | (_, Some(n)) => (ActualImplExpectedLifetimeKind::Any, n, 0),449 (None, None) => {450 if let Some(n) = expected_has_vid {451 (ActualImplExpectedLifetimeKind::Some, n, 0)452 } else {453 (ActualImplExpectedLifetimeKind::Nothing, 0, 0)454 }455 }456 };457458 let note_1 = ActualImplExplNotes::new_expected(459 kind,460 lt_kind,461 leading_ellipsis,462 ty_or_sig,463 trait_path,464 lifetime_1,465 lifetime_2,466 );467468 let mut actual_trait_ref = highlight_trait_ref(actual_trait_ref);469 actual_trait_ref.highlight.maybe_highlighting_region(vid, actual_has_vid);470471 let passive_voice = match actual_has_vid {472 Some(_) => any_self_ty_has_vid,473 None => true,474 };475476 let trait_path = actual_trait_ref.map(|tr| tr.print_only_trait_path());477 let ty = actual_trait_ref.map(|tr| tr.self_ty()).to_string();478 let has_lifetime = actual_has_vid.is_some();479 let lifetime = actual_has_vid.unwrap_or_default();480481 let note_2 = if same_self_type {482 ActualImplExplNotes::ButActuallyImplementsTrait { trait_path, has_lifetime, lifetime }483 } else if passive_voice {484 ActualImplExplNotes::ButActuallyImplementedForTy {485 trait_path,486 ty,487 has_lifetime,488 lifetime,489 }490 } else {491 ActualImplExplNotes::ButActuallyTyImplements { trait_path, ty, has_lifetime, lifetime }492 };493494 vec![note_1, note_2]495 }496}