diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index a74016e220e62..a3336ee1f88c1 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -248,6 +248,11 @@ impl<'tcx> TypeRelation<'tcx> for SimpleEqRelation<'tcx> { self.param_env } + #[inline] + fn fast_equate(&self) -> bool { + true + } + fn tag(&self) -> &'static str { "dropck::SimpleEqRelation" } diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 37f071a19acd6..181562722c379 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -525,6 +525,11 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { self.param_env } + #[inline] + fn fast_equate(&self) -> bool { + false + } + fn tag(&self) -> &'static str { "Generalizer" } @@ -802,6 +807,11 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { self.param_env } + #[inline] + fn fast_equate(&self) -> bool { + false + } + fn tag(&self) -> &'static str { "ConstInferUnifier" } diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs index 59728148a84c4..f7ae6d3882547 100644 --- a/compiler/rustc_infer/src/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -32,6 +32,11 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { self.fields.tcx() } + #[inline] + fn fast_equate(&self) -> bool { + true + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 22f32251f6df0..92f79a1c070a9 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2945,6 +2945,11 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { "SameTypeModuloInfer" } + #[inline] + fn fast_equate(&self) -> bool { + true + } + fn a_is_expected(&self) -> bool { true } diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs index 6ffefcb7a286a..3ea012d7c05c0 100644 --- a/compiler/rustc_infer/src/infer/glb.rs +++ b/compiler/rustc_infer/src/infer/glb.rs @@ -34,6 +34,11 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> { self.fields.tcx() } + #[inline] + fn fast_equate(&self) -> bool { + true + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env } diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs index d6e56fcb7fd27..30414a742b086 100644 --- a/compiler/rustc_infer/src/infer/lub.rs +++ b/compiler/rustc_infer/src/infer/lub.rs @@ -34,6 +34,11 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> { self.fields.tcx() } + #[inline] + fn fast_equate(&self) -> bool { + true + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env } diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 600f94f095eac..01133271568bb 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -535,6 +535,11 @@ where self.delegate.param_env() } + #[inline] + fn fast_equate(&self) -> bool { + false + } + fn tag(&self) -> &'static str { "nll::subtype" } @@ -901,6 +906,11 @@ where self.delegate.param_env() } + #[inline] + fn fast_equate(&self) -> bool { + false + } + fn tag(&self) -> &'static str { "nll::generalizer" } diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index a5c21f0fb9b50..25acaf0343876 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -142,6 +142,10 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { fn param_env(&self) -> ty::ParamEnv<'tcx> { self.param_env } + #[inline] + fn fast_equate(&self) -> bool { + false + } fn a_is_expected(&self) -> bool { true } // irrelevant diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index 8c8445a4d9eb8..da2b792e71624 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -43,6 +43,11 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { self.fields.param_env } + #[inline] + fn fast_equate(&self) -> bool { + true + } + fn a_is_expected(&self) -> bool { self.a_is_expected } diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs index e6aab30a150de..00a1918041608 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_middle/src/ty/_match.rs @@ -39,6 +39,10 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { fn param_env(&self) -> ty::ParamEnv<'tcx> { self.param_env } + #[inline] + fn fast_equate(&self) -> bool { + false + } fn a_is_expected(&self) -> bool { true } // irrelevant diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index c083a405e3cfb..a939099a5c2c9 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -28,6 +28,9 @@ pub trait TypeRelation<'tcx>: Sized { /// Returns a static string we can use for printouts. fn tag(&self) -> &'static str; + /// Returns whether or not structural equality can be used to fast-path this relation + fn fast_equate(&self) -> bool; + /// Returns `true` if the value `a` is the "expected" type in the /// relation. Just affects error messages. fn a_is_expected(&self) -> bool; @@ -140,6 +143,10 @@ pub fn relate_substs<'tcx, R: TypeRelation<'tcx>>( a_subst: SubstsRef<'tcx>, b_subst: SubstsRef<'tcx>, ) -> RelateResult<'tcx, SubstsRef<'tcx>> { + if relation.fast_equate() && a_subst == b_subst { + return Ok(a_subst); + } + relation.tcx().mk_substs(iter::zip(a_subst, b_subst).map(|(a, b)| { relation.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b) })) @@ -152,6 +159,10 @@ pub fn relate_substs_with_variances<'tcx, R: TypeRelation<'tcx>>( a_subst: SubstsRef<'tcx>, b_subst: SubstsRef<'tcx>, ) -> RelateResult<'tcx, SubstsRef<'tcx>> { + if relation.fast_equate() && a_subst == b_subst { + return Ok(a_subst); + } + let tcx = relation.tcx(); let mut cached_ty = None; @@ -345,7 +356,7 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> { } } -#[derive(Copy, Debug, Clone, TypeFoldable, TypeVisitable)] +#[derive(Copy, Debug, Clone, PartialEq, Eq, TypeFoldable, TypeVisitable)] struct GeneratorWitness<'tcx>(&'tcx ty::List>); impl<'tcx> Relate<'tcx> for GeneratorWitness<'tcx> { @@ -354,6 +365,10 @@ impl<'tcx> Relate<'tcx> for GeneratorWitness<'tcx> { a: GeneratorWitness<'tcx>, b: GeneratorWitness<'tcx>, ) -> RelateResult<'tcx, GeneratorWitness<'tcx>> { + if relation.fast_equate() && a == b { + return Ok(a); + } + assert_eq!(a.0.len(), b.0.len()); let tcx = relation.tcx(); let types = tcx.mk_type_list(iter::zip(a.0, b.0).map(|(a, b)| relation.relate(a, b)))?; @@ -655,6 +670,10 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List RelateResult<'tcx, Self> { + if relation.fast_equate() && a == b { + return Ok(a); + } + let tcx = relation.tcx(); // FIXME: this is wasteful, but want to do a perf run to see how slow it is. @@ -799,9 +818,9 @@ impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> { b: ty::TraitPredicate<'tcx>, ) -> RelateResult<'tcx, ty::TraitPredicate<'tcx>> { Ok(ty::TraitPredicate { - trait_ref: relation.relate(a.trait_ref, b.trait_ref)?, constness: relation.relate(a.constness, b.constness)?, polarity: relation.relate(a.polarity, b.polarity)?, + trait_ref: relation.relate(a.trait_ref, b.trait_ref)?, }) } }