From f09b1facd04250135d9ad0434c73378a6c08f415 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 11 Nov 2021 12:01:12 +1100 Subject: [PATCH] Eliminate `ObligationCauseData`. This makes `Obligation` two words bigger, but avoids allocating a lot of the time. I previously tried this in #73983 and it didn't help much, but local timings look more promising now. --- .../src/infer/error_reporting/mod.rs | 22 ++--- .../mismatched_static_lifetime.rs | 6 +- .../nice_region_error/placeholder_error.rs | 2 +- .../nice_region_error/static_impl_trait.rs | 12 +-- .../trait_impl_difference.rs | 2 +- .../src/infer/error_reporting/note.rs | 4 +- compiler/rustc_infer/src/infer/mod.rs | 2 +- .../src/infer/outlives/obligations.rs | 2 +- compiler/rustc_infer/src/traits/mod.rs | 2 +- compiler/rustc_middle/src/traits/mod.rs | 82 +++++++++---------- compiler/rustc_middle/src/ty/error.rs | 2 +- .../src/traits/error_reporting/mod.rs | 62 +++++++------- .../error_reporting/on_unimplemented.rs | 4 +- .../src/traits/error_reporting/suggestions.rs | 26 +++--- .../src/traits/fulfill.rs | 2 +- .../src/traits/select/mod.rs | 3 +- .../rustc_trait_selection/src/traits/util.rs | 2 +- .../rustc_trait_selection/src/traits/wf.rs | 11 ++- compiler/rustc_typeck/src/check/coercion.rs | 2 +- .../rustc_typeck/src/check/compare_method.rs | 6 +- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 16 ++-- .../rustc_typeck/src/check/method/suggest.rs | 2 +- 22 files changed, 135 insertions(+), 139 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index a292bcd4f208f..9a76c05e4f620 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -604,7 +604,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { exp_found: Option>>, terr: &TypeError<'tcx>, ) { - match cause.code { + match *cause.code() { ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => { let ty = self.resolve_vars_if_possible(root_ty); if ty.is_suggestable() { @@ -781,7 +781,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } _ => { if let ObligationCauseCode::BindingObligation(_, binding_span) = - cause.code.peel_derives() + cause.code().peel_derives() { if matches!(terr, TypeError::RegionsPlaceholderMismatch) { err.span_note(*binding_span, "the lifetime requirement is introduced here"); @@ -1729,10 +1729,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } _ => exp_found, }; - debug!("exp_found {:?} terr {:?} cause.code {:?}", exp_found, terr, cause.code); + debug!("exp_found {:?} terr {:?} cause.code {:?}", exp_found, terr, cause.code()); if let Some(exp_found) = exp_found { let should_suggest_fixes = if let ObligationCauseCode::Pattern { root_ty, .. } = - &cause.code + cause.code() { // Skip if the root_ty of the pattern is not the same as the expected_ty. // If these types aren't equal then we've probably peeled off a layer of arrays. @@ -1827,7 +1827,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { exp_span, exp_found.expected, exp_found.found, ); - if let ObligationCauseCode::CompareImplMethodObligation { .. } = &cause.code { + if let ObligationCauseCode::CompareImplMethodObligation { .. } = cause.code() { return; } @@ -1835,7 +1835,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.get_impl_future_output_ty(exp_found.expected), self.get_impl_future_output_ty(exp_found.found), ) { - (Some(exp), Some(found)) if same_type_modulo_infer(exp, found) => match &cause.code { + (Some(exp), Some(found)) if same_type_modulo_infer(exp, found) => match cause.code() { ObligationCauseCode::IfExpression(box IfExpressionCause { then, .. }) => { diag.multipart_suggestion( "consider `await`ing on both `Future`s", @@ -1875,7 +1875,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Applicability::MaybeIncorrect, ); } - (Some(ty), _) if same_type_modulo_infer(ty, exp_found.found) => match cause.code { + (Some(ty), _) if same_type_modulo_infer(ty, exp_found.found) => match cause.code() { ObligationCauseCode::Pattern { span: Some(span), .. } | ObligationCauseCode::IfExpression(box IfExpressionCause { then: span, .. }) => { diag.span_suggestion_verbose( @@ -1927,7 +1927,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .map(|field| (field.ident.name, field.ty(self.tcx, expected_substs))) .find(|(_, ty)| same_type_modulo_infer(ty, exp_found.found)) { - if let ObligationCauseCode::Pattern { span: Some(span), .. } = cause.code { + if let ObligationCauseCode::Pattern { span: Some(span), .. } = *cause.code() { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { let suggestion = if expected_def.is_struct() { format!("{}.{}", snippet, name) @@ -2064,7 +2064,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } if let MatchExpressionArm(box MatchExpressionArmCause { source, .. }) = - trace.cause.code + *trace.cause.code() { if let hir::MatchSource::TryDesugar = source { if let Some((expected_ty, found_ty)) = self.values_str(trace.values) { @@ -2659,7 +2659,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { fn as_failure_code(&self, terr: &TypeError<'tcx>) -> FailureCode { use self::FailureCode::*; use crate::traits::ObligationCauseCode::*; - match self.code { + match self.code() { CompareImplMethodObligation { .. } => Error0308("method not compatible with trait"), CompareImplTypeObligation { .. } => Error0308("type not compatible with trait"), MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => { @@ -2694,7 +2694,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { fn as_requirement_str(&self) -> &'static str { use crate::traits::ObligationCauseCode::*; - match self.code { + match self.code() { CompareImplMethodObligation { .. } => "method type is compatible with trait", CompareImplTypeObligation { .. } => "associated type is compatible with trait", ExprAssignable => "expression is assignable", diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs index 35c8786dcd3ac..d3b47e396ec2b 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs @@ -31,15 +31,15 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { }; // If we added a "points at argument expression" obligation, we remove it here, we care // about the original obligation only. - let code = match &cause.code { + let code = match cause.code() { ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => &*parent_code, - _ => &cause.code, + _ => cause.code(), }; let (parent, impl_def_id) = match code { ObligationCauseCode::MatchImpl(parent, impl_def_id) => (parent, impl_def_id), _ => return None, }; - let binding_span = match parent.code { + let binding_span = match *parent.code() { ObligationCauseCode::BindingObligation(_def_id, binding_span) => binding_span, _ => return None, }; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index 24652a3a6bc10..7178bfa525bcb 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -208,7 +208,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { ); let mut err = self.tcx().sess.struct_span_err(span, &msg); - let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id) = cause.code { + let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id) = *cause.code() { err.span_label(span, "doesn't satisfy where-clause"); err.span_label( self.tcx().def_span(def_id), diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 51f33a206f48e..b6dff2e53e9cd 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -42,7 +42,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { sup_r, ) if **sub_r == RegionKind::ReStatic => { // This is for an implicit `'static` requirement coming from `impl dyn Trait {}`. - if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code { + if let ObligationCauseCode::UnifyReceiver(ctxt) = cause.code() { // This may have a closure and it would cause ICE // through `find_param_with_region` (#78262). let anon_reg_sup = tcx.is_suitable_region(sup_r)?; @@ -184,7 +184,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = sub_origin { if let ObligationCauseCode::ReturnValue(hir_id) - | ObligationCauseCode::BlockTailExpression(hir_id) = &cause.code + | ObligationCauseCode::BlockTailExpression(hir_id) = cause.code() { let parent_id = tcx.hir().get_parent_item(*hir_id); if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id) { @@ -226,7 +226,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let mut override_error_code = None; if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sup_origin { - if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code { + if let ObligationCauseCode::UnifyReceiver(ctxt) = cause.code() { // Handle case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a // `'static` lifetime when called as a method on a binding: `bar.qux()`. if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) { @@ -235,9 +235,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } } if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sub_origin { - let code = match &cause.code { - ObligationCauseCode::MatchImpl(parent, ..) => &parent.code, - _ => &cause.code, + let code = match cause.code() { + ObligationCauseCode::MatchImpl(parent, ..) => parent.code(), + _ => cause.code(), }; if let (ObligationCauseCode::ItemObligation(item_def_id), None) = (code, override_error_code) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index c12367409a2d1..f5fb82dbf31d2 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -36,7 +36,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ValuePairs::Types(sub_expected_found), ValuePairs::Types(sup_expected_found), CompareImplMethodObligation { trait_item_def_id, .. }, - ) = (&sub_trace.values, &sup_trace.values, &sub_trace.cause.code) + ) = (&sub_trace.values, &sup_trace.values, sub_trace.cause.code()) { if sup_expected_found == sub_expected_found { self.emit_err( diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 6600c18351fbe..82bd8890dda21 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -359,13 +359,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { match placeholder_origin { infer::Subtype(box ref trace) if matches!( - &trace.cause.code.peel_derives(), + &trace.cause.code().peel_derives(), ObligationCauseCode::BindingObligation(..) ) => { // Hack to get around the borrow checker because trace.cause has an `Rc`. if let ObligationCauseCode::BindingObligation(_, span) = - &trace.cause.code.peel_derives() + &trace.cause.code().peel_derives() { let span = *span; let mut err = self.report_concrete_failure(placeholder_origin, sub, sup); diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 9db815548d8cc..04e04e297cdd2 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1824,7 +1824,7 @@ impl<'tcx> SubregionOrigin<'tcx> { where F: FnOnce() -> Self, { - match cause.code { + match *cause.code() { traits::ObligationCauseCode::ReferenceOutlivesReferent(ref_type) => { SubregionOrigin::ReferenceOutlivesReferent(ref_type, cause.span) } diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 91a22ecc5a994..74eb263a63390 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -102,7 +102,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { infer::RelateParamBound( cause.span, sup_type, - match cause.code.peel_derives() { + match cause.code().peel_derives() { ObligationCauseCode::BindingObligation(_, span) => Some(*span), _ => None, }, diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index b4fb10370d41e..e1f3b548e97fe 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -81,7 +81,7 @@ impl TraitObligation<'_> { // `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(PredicateObligation<'_>, 32); +static_assert_size!(PredicateObligation<'_>, 48); pub type PredicateObligations<'tcx> = Vec>; diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 3e6a6b3ba4222..de5beffb5c541 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -23,9 +23,7 @@ use rustc_span::{Span, DUMMY_SP}; use smallvec::SmallVec; use std::borrow::Cow; -use std::fmt; use std::hash::{Hash, Hasher}; -use std::ops::Deref; pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache}; @@ -80,38 +78,14 @@ pub enum Reveal { /// The reason why we incurred this obligation; used for error reporting. /// -/// As the happy path does not care about this struct, storing this on the heap -/// ends up increasing performance. +/// Non-misc `ObligationCauseCode`s are stored on the heap. This gives the +/// best trade-off between keeping the type small (which makes copies cheaper) +/// while not doing too many heap allocations. /// /// We do not want to intern this as there are a lot of obligation causes which /// only live for a short period of time. -#[derive(Clone, PartialEq, Eq, Hash, Lift)] -pub struct ObligationCause<'tcx> { - /// `None` for `ObligationCause::dummy`, `Some` otherwise. - data: Option>>, -} - -const DUMMY_OBLIGATION_CAUSE_DATA: ObligationCauseData<'static> = - ObligationCauseData { span: DUMMY_SP, body_id: hir::CRATE_HIR_ID, code: MiscObligation }; - -// Correctly format `ObligationCause::dummy`. -impl<'tcx> fmt::Debug for ObligationCause<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - ObligationCauseData::fmt(self, f) - } -} - -impl<'tcx> Deref for ObligationCause<'tcx> { - type Target = ObligationCauseData<'tcx>; - - #[inline(always)] - fn deref(&self) -> &Self::Target { - self.data.as_deref().unwrap_or(&DUMMY_OBLIGATION_CAUSE_DATA) - } -} - #[derive(Clone, Debug, PartialEq, Eq, Lift)] -pub struct ObligationCauseData<'tcx> { +pub struct ObligationCause<'tcx> { pub span: Span, /// The ID of the fn body that triggered this obligation. This is @@ -122,17 +96,25 @@ pub struct ObligationCauseData<'tcx> { /// information. pub body_id: hir::HirId, - pub code: ObligationCauseCode<'tcx>, + /// `None` for `MISC_OBLIGATION_CAUSE_CODE` (a common case, occurs ~60% of + /// the time). `Some` otherwise. + code: Option>>, } -impl Hash for ObligationCauseData<'_> { +// This custom hash function speeds up hashing for `Obligation` deduplication +// greatly by skipping the `code` field, which can be large and complex. That +// shouldn't affect hash quality much since there are several other fields in +// `Obligation` which should be unique enough, especially the predicate itself +// which is hashed as an interned pointer. See #90996. +impl Hash for ObligationCause<'_> { fn hash(&self, state: &mut H) { self.body_id.hash(state); self.span.hash(state); - std::mem::discriminant(&self.code).hash(state); } } +const MISC_OBLIGATION_CAUSE_CODE: ObligationCauseCode<'static> = MiscObligation; + impl<'tcx> ObligationCause<'tcx> { #[inline] pub fn new( @@ -140,28 +122,32 @@ impl<'tcx> ObligationCause<'tcx> { body_id: hir::HirId, code: ObligationCauseCode<'tcx>, ) -> ObligationCause<'tcx> { - ObligationCause { data: Some(Lrc::new(ObligationCauseData { span, body_id, code })) } + ObligationCause { + span, + body_id, + code: if code == MISC_OBLIGATION_CAUSE_CODE { None } else { Some(Lrc::new(code)) }, + } } pub fn misc(span: Span, body_id: hir::HirId) -> ObligationCause<'tcx> { ObligationCause::new(span, body_id, MiscObligation) } - pub fn dummy_with_span(span: Span) -> ObligationCause<'tcx> { - ObligationCause::new(span, hir::CRATE_HIR_ID, MiscObligation) - } - #[inline(always)] pub fn dummy() -> ObligationCause<'tcx> { - ObligationCause { data: None } + ObligationCause { span: DUMMY_SP, body_id: hir::CRATE_HIR_ID, code: None } + } + + pub fn dummy_with_span(span: Span) -> ObligationCause<'tcx> { + ObligationCause { span, body_id: hir::CRATE_HIR_ID, code: None } } - pub fn make_mut(&mut self) -> &mut ObligationCauseData<'tcx> { - Lrc::make_mut(self.data.get_or_insert_with(|| Lrc::new(DUMMY_OBLIGATION_CAUSE_DATA))) + pub fn make_mut_code(&mut self) -> &mut ObligationCauseCode<'tcx> { + Lrc::make_mut(self.code.get_or_insert_with(|| Lrc::new(MISC_OBLIGATION_CAUSE_CODE))) } pub fn span(&self, tcx: TyCtxt<'tcx>) -> Span { - match self.code { + match *self.code() { ObligationCauseCode::CompareImplMethodObligation { .. } | ObligationCauseCode::MainFunctionType | ObligationCauseCode::StartFunctionType => { @@ -174,6 +160,18 @@ impl<'tcx> ObligationCause<'tcx> { _ => self.span, } } + + #[inline] + pub fn code(&self) -> &ObligationCauseCode<'tcx> { + self.code.as_deref().unwrap_or(&MISC_OBLIGATION_CAUSE_CODE) + } + + pub fn clone_code(&self) -> Lrc> { + match &self.code { + Some(code) => code.clone(), + None => Lrc::new(MISC_OBLIGATION_CAUSE_CODE), + } + } } #[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 1b4566fd02634..df6e739dc2011 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -519,7 +519,7 @@ impl Trait for X { proj_ty, values, body_owner_def_id, - &cause.code, + cause.code(), ); } (_, ty::Projection(proj_ty)) => { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 8833805d35c7d..b5c5724f56edc 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -205,7 +205,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.note_obligation_cause_code( &mut err, &obligation.predicate, - &obligation.cause.code, + obligation.cause.code(), &mut vec![], &mut Default::default(), ); @@ -255,7 +255,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // If this obligation was generated as a result of well-formedness checking, see if we // can get a better error message by performing HIR-based well-formedness checking. if let ObligationCauseCode::WellFormed(Some(wf_loc)) = - root_obligation.cause.code.peel_derives() + root_obligation.cause.code().peel_derives() { if let Some(cause) = self .tcx @@ -272,7 +272,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { | ObligationCauseCode::CompareImplTypeObligation { impl_item_def_id, trait_item_def_id, - } = obligation.cause.code + } = *obligation.cause.code() { self.report_extra_impl_obligation( span, @@ -295,7 +295,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } let trait_ref = trait_predicate.to_poly_trait_ref(); let (post_message, pre_message, type_def) = self - .get_parent_trait_ref(&obligation.cause.code) + .get_parent_trait_ref(obligation.cause.code()) .map(|(t, s)| { ( format!(" in `{}`", t), @@ -376,17 +376,18 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } - let explanation = - if obligation.cause.code == ObligationCauseCode::MainFunctionType { - "consider using `()`, or a `Result`".to_owned() - } else { - format!( - "{}the trait `{}` is not implemented for `{}`", - pre_message, - trait_ref.print_only_trait_path(), - trait_ref.skip_binder().self_ty(), - ) - }; + let explanation = if let ObligationCauseCode::MainFunctionType = + obligation.cause.code() + { + "consider using `()`, or a `Result`".to_owned() + } else { + format!( + "{}the trait `{}` is not implemented for `{}`", + pre_message, + trait_ref.print_only_trait_path(), + trait_ref.skip_binder().self_ty(), + ) + }; if self.suggest_add_reference_to_arg( &obligation, @@ -1305,7 +1306,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { ); let is_normalized_ty_expected = !matches!( - obligation.cause.code.peel_derives(), + obligation.cause.code().peel_derives(), ObligationCauseCode::ItemObligation(_) | ObligationCauseCode::BindingObligation(_, _) | ObligationCauseCode::ObjectCastObligation(_) @@ -1620,9 +1621,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { let predicate = self.resolve_vars_if_possible(obligation.predicate); let span = obligation.cause.span; - debug!( - ?predicate, ?obligation.cause.code, - ); + debug!(?predicate, obligation.cause.code = tracing::field::debug(&obligation.cause.code())); // Ambiguity errors are often caused as fallout from earlier errors. // We ignore them if this `infcx` is tainted in some cases below. @@ -1717,13 +1716,13 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { } } - if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code { + if let ObligationCauseCode::ItemObligation(def_id) = *obligation.cause.code() { self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id()); } else if let ( Ok(ref snippet), ObligationCauseCode::BindingObligation(ref def_id, _), ) = - (self.tcx.sess.source_map().span_to_snippet(span), &obligation.cause.code) + (self.tcx.sess.source_map().span_to_snippet(span), obligation.cause.code()) { let generics = self.tcx.generics_of(*def_id); if generics.params.iter().any(|p| p.name != kw::SelfUpper) @@ -2006,7 +2005,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { self.note_obligation_cause_code( err, &obligation.predicate, - &obligation.cause.code, + obligation.cause.code(), &mut vec![], &mut Default::default(), ); @@ -2019,15 +2018,16 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'tcx>, obligation: &PredicateObligation<'tcx>, ) { - let (pred, item_def_id, span) = - match (obligation.predicate.kind().skip_binder(), obligation.cause.code.peel_derives()) - { - ( - ty::PredicateKind::Trait(pred), - &ObligationCauseCode::BindingObligation(item_def_id, span), - ) => (pred, item_def_id, span), - _ => return, - }; + let (pred, item_def_id, span) = match ( + obligation.predicate.kind().skip_binder(), + obligation.cause.code().peel_derives(), + ) { + ( + ty::PredicateKind::Trait(pred), + &ObligationCauseCode::BindingObligation(item_def_id, span), + ) => (pred, item_def_id, span), + _ => return, + }; debug!( "suggest_unsized_bound_if_applicable: pred={:?} item_def_id={:?} span={:?}", pred, item_def_id, span diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index d9a5aea4d95fc..1540725246b51 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -129,7 +129,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.describe_enclosure(obligation.cause.body_id).map(|s| s.to_owned()), )]; - match obligation.cause.code { + match obligation.cause.code() { ObligationCauseCode::BuiltinDerivedObligation(..) | ObligationCauseCode::ImplDerivedObligation(..) | ObligationCauseCode::DerivedObligation(..) => {} @@ -141,7 +141,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } if let ObligationCauseCode::ItemObligation(item) - | ObligationCauseCode::BindingObligation(item, _) = obligation.cause.code + | ObligationCauseCode::BindingObligation(item, _) = *obligation.cause.code() { // FIXME: maybe also have some way of handling methods // from other traits? That would require name resolution, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 9c10823a844de..0f276718c16e7 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -9,7 +9,6 @@ use crate::traits::normalize_projection_type; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_data_structures::sync::Lrc; use rustc_errors::{ error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style, }; @@ -497,7 +496,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ) { // It only make sense when suggesting dereferences for arguments let code = if let ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } = - &obligation.cause.code + obligation.cause.code() { parent_code.clone() } else { @@ -662,7 +661,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } _ => return, }; - if matches!(obligation.cause.code, ObligationCauseCode::FunctionArgumentObligation { .. }) { + if matches!(obligation.cause.code(), ObligationCauseCode::FunctionArgumentObligation { .. }) + { // When the obligation error has been ensured to have been caused by // an argument, the `obligation.cause.span` points at the expression // of the argument, so we can provide a suggestion. Otherwise, we give @@ -688,13 +688,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let span = obligation.cause.span; let code = if let ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } = - &obligation.cause.code + obligation.cause.code() { - parent_code.clone() + &parent_code } else if let ExpnKind::Desugaring(DesugaringKind::ForLoop) = span.ctxt().outer_expn_data().kind { - Lrc::new(obligation.cause.code.clone()) + obligation.cause.code() } else { return false; }; @@ -805,10 +805,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { return false; }; - if let ObligationCauseCode::ImplDerivedObligation(obligation) = &*code { + if let ObligationCauseCode::ImplDerivedObligation(obligation) = code { try_borrowing(obligation.parent_trait_ref, &[]) } else if let ObligationCauseCode::BindingObligation(_, _) - | ObligationCauseCode::ItemObligation(_) = &*code + | ObligationCauseCode::ItemObligation(_) = code { try_borrowing(*poly_trait_ref, &never_suggest_borrow) } else { @@ -886,7 +886,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ) { let span = obligation.cause.span; - if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code.peel_derives() { + if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code().peel_derives() { let hir = self.tcx.hir(); if let Some(node) = hir_id.and_then(|hir_id| hir.find(hir_id)) { if let hir::Node::Expr(expr) = node { @@ -945,7 +945,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, ) { let points_at_arg = matches!( - obligation.cause.code, + obligation.cause.code(), ObligationCauseCode::FunctionArgumentObligation { .. }, ); @@ -1072,7 +1072,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { obligation: &PredicateObligation<'tcx>, trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, ) -> bool { - match obligation.cause.code.peel_derives() { + match obligation.cause.code().peel_derives() { // Only suggest `impl Trait` if the return type is unsized because it is `dyn Trait`. ObligationCauseCode::SizedReturnType => {} _ => return false, @@ -1267,7 +1267,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'_>, obligation: &PredicateObligation<'tcx>, ) { - match obligation.cause.code.peel_derives() { + match obligation.cause.code().peel_derives() { ObligationCauseCode::SizedReturnType => {} _ => return, } @@ -1461,7 +1461,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }; let mut generator = None; let mut outer_generator = None; - let mut next_code = Some(&obligation.cause.code); + let mut next_code = Some(obligation.cause.code()); let mut seen_upvar_tys_infer_tuple = false; diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 35bb7d6f06cb7..42e3f0db15e53 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -96,7 +96,7 @@ pub struct PendingPredicateObligation<'tcx> { // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(PendingPredicateObligation<'_>, 56); +static_assert_size!(PendingPredicateObligation<'_>, 72); impl<'a, 'tcx> FulfillmentContext<'tcx> { /// Creates a new fulfillment context. diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 77b8fc49a15cf..85016a701f3b1 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -29,7 +29,6 @@ use crate::traits::project::ProjectionCacheKeyExt; use crate::traits::ProjectionCacheKey; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_data_structures::sync::Lrc; use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -2384,7 +2383,7 @@ impl<'tcx> TraitObligationExt<'tcx> for TraitObligation<'tcx> { // by using -Z verbose or just a CLI argument. let derived_cause = DerivedObligationCause { parent_trait_ref: obligation.predicate.to_poly_trait_ref(), - parent_code: Lrc::new(obligation.cause.code.clone()), + parent_code: obligation.cause.clone_code(), }; let derived_code = variant(derived_cause); ObligationCause::new(obligation.cause.span, obligation.cause.body_id, derived_code) diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 3090e8a04285d..b6e653c0eea46 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -232,7 +232,7 @@ pub fn predicates_for_generics<'tcx>( debug!("predicates_for_generics(generic_bounds={:?})", generic_bounds); iter::zip(generic_bounds.predicates, generic_bounds.spans).map(move |(predicate, span)| { - let cause = match cause.code { + let cause = match *cause.code() { traits::ItemObligation(def_id) if !span.is_dummy() => traits::ObligationCause::new( cause.span, cause.body_id, diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 5875b764e9f36..4bd73ef68aa7a 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -1,7 +1,6 @@ use crate::infer::InferCtxt; use crate::opaque_types::required_region_bounds; use crate::traits; -use rustc_data_structures::sync::Lrc; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; @@ -227,7 +226,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( if let Some(impl_item_span) = items.iter().find(|item| item.ident == trait_assoc_item.ident).map(fix_span) { - cause.make_mut().span = impl_item_span; + cause.span = impl_item_span; } } } @@ -242,7 +241,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( items.iter().find(|i| i.ident == trait_assoc_item.ident).map(fix_span) }) { - cause.make_mut().span = impl_item_span; + cause.span = impl_item_span; } } } @@ -302,9 +301,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let derived_cause = traits::DerivedObligationCause { // FIXME(fee1-dead): when improving error messages, change this to PolyTraitPredicate parent_trait_ref: parent_trait_ref.map_bound(|t| t.trait_ref), - parent_code: Lrc::new(obligation.cause.code.clone()), + parent_code: obligation.cause.clone_code(), }; - cause.make_mut().code = + *cause.make_mut_code() = traits::ObligationCauseCode::DerivedObligation(derived_cause); } extend_cause_with_original_assoc_item_obligation( @@ -343,7 +342,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { if let Some(hir::ItemKind::Impl(hir::Impl { self_ty, .. })) = item.map(|i| &i.kind) { - new_cause.make_mut().span = self_ty.span; + new_cause.span = self_ty.span; } } traits::Obligation::with_depth( diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index ac18908e95bcd..6192c77d6c648 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -1444,7 +1444,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { let mut err; let mut unsized_return = false; - match cause.code { + match *cause.code() { ObligationCauseCode::ReturnNoExpression => { err = struct_span_err!( fcx.tcx.sess, diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 11560f51822f8..c942bafcf034b 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -232,7 +232,7 @@ fn compare_predicate_entailment<'tcx>( inh.register_predicates(obligations); let mut cause = cause.clone(); - cause.make_mut().span = span; + cause.span = span; inh.register_predicate(traits::Obligation::new(cause, param_env, predicate)); } @@ -293,7 +293,7 @@ fn compare_predicate_entailment<'tcx>( let (impl_err_span, trait_err_span) = extract_spans_for_error_reporting(&infcx, &terr, &cause, impl_m, trait_m); - cause.make_mut().span = impl_err_span; + cause.span = impl_err_span; let mut diag = struct_span_err!( tcx.sess, @@ -1043,7 +1043,7 @@ crate fn compare_const_impl<'tcx>( // Locate the Span containing just the type of the offending impl match tcx.hir().expect_impl_item(impl_c.def_id.expect_local()).kind { - ImplItemKind::Const(ref ty, _) => cause.make_mut().span = ty.span, + ImplItemKind::Const(ref ty, _) => cause.span = ty.span, _ => bug!("{:?} is not a impl const", impl_c), } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 38a8c1bb9f57b..11b63a99043b7 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -997,7 +997,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } result_code } - let self_: ty::subst::GenericArg<'_> = match &*unpeel_to_top(Lrc::new(error.obligation.cause.code.clone())) { + let self_: ty::subst::GenericArg<'_> = match &*unpeel_to_top(error.obligation.cause.clone_code()) { ObligationCauseCode::BuiltinDerivedObligation(code) | ObligationCauseCode::ImplDerivedObligation(code) | ObligationCauseCode::DerivedObligation(code) => { @@ -1040,18 +1040,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // We make sure that only *one* argument matches the obligation failure // and we assign the obligation's span to its expression's. - error.obligation.cause.make_mut().span = args[ref_in].span; - let code = error.obligation.cause.code.clone(); - error.obligation.cause.make_mut().code = + error.obligation.cause.span = args[ref_in].span; + let parent_code = error.obligation.cause.clone_code(); + *error.obligation.cause.make_mut_code() = ObligationCauseCode::FunctionArgumentObligation { arg_hir_id: args[ref_in].hir_id, call_hir_id: expr.hir_id, - parent_code: Lrc::new(code), + parent_code, }; - } else if error.obligation.cause.make_mut().span == call_sp { + } else if error.obligation.cause.span == call_sp { // Make function calls point at the callee, not the whole thing. if let hir::ExprKind::Call(callee, _) = expr.kind { - error.obligation.cause.make_mut().span = callee.span; + error.obligation.cause.span = callee.span; } } } @@ -1092,7 +1092,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = >::ast_ty_to_ty(self, hir_ty); let ty = self.resolve_vars_if_possible(ty); if ty == predicate.self_ty() { - error.obligation.cause.make_mut().span = hir_ty.span; + error.obligation.cause.span = hir_ty.span; } } } diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 168bdce32108a..1dcc20c29a32c 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -832,7 +832,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for (data, p, parent_p) in unsatisfied_predicates .iter() .filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c))) - .filter_map(|(p, parent, c)| match c.code { + .filter_map(|(p, parent, c)| match c.code() { ObligationCauseCode::ImplDerivedObligation(ref data) => { Some((data, p, parent)) }