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::diagnostics::{14 ActualImplExpectedKind, ActualImplExpectedLifetimeKind, ActualImplExplNotes,15 TraitPlaceholderMismatch, TyOrSig,16};17use crate::error_reporting::infer::nice_region_error::NiceRegionError;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(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(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(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(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(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(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(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(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 let mut err = 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 });344345 let mut current_code = cause.code();346 let mut coroutine_def_id = None;347348 loop {349 match current_code {350 ObligationCauseCode::MatchImpl(inner_cause, _) => {351 current_code = inner_cause.code();352 }353 ObligationCauseCode::BuiltinDerived(derived) => {354 let self_ty = derived.parent_trait_pred.skip_binder().self_ty();355356 if let ty::Coroutine(def_id, _) | ty::CoroutineWitness(def_id, _) =357 self_ty.kind()358 {359 coroutine_def_id = Some(*def_id);360 break;361 }362363 current_code = &derived.parent_code;364 }365 _ => break,366 }367 }368369 if let Some(def_id) = coroutine_def_id {370 if self.tcx().trait_is_auto(trait_def_id) {371 let c_span = self.tcx().def_span(def_id);372 let descr = self.tcx().def_descr(def_id);373 let trait_name = self.tcx().def_path_str(trait_def_id);374375 err.span_label(376 c_span,377 format!("this {descr} captures a value whose type is not `{trait_name}`"),378 );379 }380 }381382 err383 }384385 /// Add notes with details about the expected and actual trait refs, with attention to cases386 /// when placeholder regions are involved: either the trait or the self type containing387 /// them needs to be mentioned the closest to the placeholders.388 /// This makes the error messages read better, however at the cost of some complexity389 /// due to the number of combinations we have to deal with.390 fn explain_actual_impl_that_was_found(391 &self,392 sub_placeholder: Option<Region<'tcx>>,393 sup_placeholder: Option<Region<'tcx>>,394 has_sub: Option<usize>,395 has_sup: Option<usize>,396 expected_trait_ref: ty::TraitRef<'tcx>,397 actual_trait_ref: ty::TraitRef<'tcx>,398 vid: Option<Region<'tcx>>,399 expected_has_vid: Option<usize>,400 actual_has_vid: Option<usize>,401 any_self_ty_has_vid: bool,402 leading_ellipsis: bool,403 ) -> Vec<ActualImplExplNotes<'tcx>> {404 // The weird thing here with the `maybe_highlighting_region` calls and the405 // the match inside is meant to be like this:406 //407 // - The match checks whether the given things (placeholders, etc) appear408 // in the types are about to print409 // - Meanwhile, the `maybe_highlighting_region` calls set up410 // highlights so that, if they do appear, we will replace411 // them `'0` and whatever. (This replacement takes place412 // inside the closure given to `maybe_highlighting_region`.)413 //414 // There is some duplication between the calls -- i.e., the415 // `maybe_highlighting_region` checks if (e.g.) `has_sub` is416 // None, an then we check again inside the closure, but this417 // setup sort of minimized the number of calls and so form.418419 let highlight_trait_ref = |trait_ref| Highlighted {420 tcx: self.tcx(),421 highlight: RegionHighlightMode::default(),422 value: trait_ref,423 ns: Namespace::TypeNS,424 };425426 let same_self_type = actual_trait_ref.self_ty() == expected_trait_ref.self_ty();427428 let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref);429 expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub);430 expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup);431432 let passive_voice = match (has_sub, has_sup) {433 (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,434 (None, None) => {435 expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);436 match expected_has_vid {437 Some(_) => true,438 None => any_self_ty_has_vid,439 }440 }441 };442443 let (kind, ty_or_sig, trait_path) = if same_self_type {444 let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty());445 self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);446447 if self_ty.value.is_closure() && self.tcx().is_fn_trait(expected_trait_ref.value.def_id)448 {449 let closure_sig = self_ty.map(|closure| {450 if let ty::Closure(_, args) = closure.kind() {451 self.tcx()452 .signature_unclosure(args.as_closure().sig(), rustc_hir::Safety::Safe)453 } else {454 bug!("type is not longer closure");455 }456 });457 (458 ActualImplExpectedKind::Signature,459 TyOrSig::ClosureSig(closure_sig),460 expected_trait_ref.map(|tr| tr.print_only_trait_path()),461 )462 } else {463 (464 ActualImplExpectedKind::Other,465 TyOrSig::Ty(self_ty),466 expected_trait_ref.map(|tr| tr.print_only_trait_path()),467 )468 }469 } else if passive_voice {470 (471 ActualImplExpectedKind::Passive,472 TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())),473 expected_trait_ref.map(|tr| tr.print_only_trait_path()),474 )475 } else {476 (477 ActualImplExpectedKind::Other,478 TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())),479 expected_trait_ref.map(|tr| tr.print_only_trait_path()),480 )481 };482483 let (lt_kind, lifetime_1, lifetime_2) = match (has_sub, has_sup) {484 (Some(n1), Some(n2)) => {485 (ActualImplExpectedLifetimeKind::Two, std::cmp::min(n1, n2), std::cmp::max(n1, n2))486 }487 (Some(n), _) | (_, Some(n)) => (ActualImplExpectedLifetimeKind::Any, n, 0),488 (None, None) => {489 if let Some(n) = expected_has_vid {490 (ActualImplExpectedLifetimeKind::Some, n, 0)491 } else {492 (ActualImplExpectedLifetimeKind::Nothing, 0, 0)493 }494 }495 };496497 let note_1 = ActualImplExplNotes::new_expected(498 kind,499 lt_kind,500 leading_ellipsis,501 ty_or_sig,502 trait_path,503 lifetime_1,504 lifetime_2,505 );506507 let mut actual_trait_ref = highlight_trait_ref(actual_trait_ref);508 actual_trait_ref.highlight.maybe_highlighting_region(vid, actual_has_vid);509510 let passive_voice = match actual_has_vid {511 Some(_) => any_self_ty_has_vid,512 None => true,513 };514515 let trait_path = actual_trait_ref.map(|tr| tr.print_only_trait_path());516 let ty = actual_trait_ref.map(|tr| tr.self_ty()).to_string();517 let has_lifetime = actual_has_vid.is_some();518 let lifetime = actual_has_vid.unwrap_or_default();519520 let note_2 = if same_self_type {521 ActualImplExplNotes::ButActuallyImplementsTrait { trait_path, has_lifetime, lifetime }522 } else if passive_voice {523 ActualImplExplNotes::ButActuallyImplementedForTy {524 trait_path,525 ty,526 has_lifetime,527 lifetime,528 }529 } else {530 ActualImplExplNotes::ButActuallyTyImplements { trait_path, ty, has_lifetime, lifetime }531 };532533 vec![note_1, note_2]534 }535}
Findings
✓ No findings reported for this file.