From 856c616874e0d428fbe3e6afa046678ebc09594c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 27 Nov 2024 03:30:21 +0000 Subject: [PATCH] Cache in DeepRejectCtxt --- .../src/traits/coherence.rs | 2 +- .../src/traits/effects.rs | 2 +- .../src/traits/project.rs | 2 +- .../src/traits/select/candidate_assembly.rs | 4 +- compiler/rustc_type_ir/src/fast_reject.rs | 45 ++++++++++++++----- src/librustdoc/html/render/write_shared.rs | 2 +- 6 files changed, 40 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index a98871b2d60a4..af65a4741b739 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -98,7 +98,7 @@ pub fn overlapping_impls( // Before doing expensive operations like entering an inference context, do // a quick check via fast_reject to tell if the impl headers could possibly // unify. - let drcx = DeepRejectCtxt::relate_infer_infer(tcx); + let mut drcx = DeepRejectCtxt::relate_infer_infer(tcx); let impl1_ref = tcx.impl_trait_ref(impl1_def_id); let impl2_ref = tcx.impl_trait_ref(impl2_def_id); let may_overlap = match (impl1_ref, impl2_ref) { diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index 07fb2efb7fed3..e1f1cb27c3618 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -79,7 +79,7 @@ fn evaluate_host_effect_from_bounds<'tcx>( obligation: &HostEffectObligation<'tcx>, ) -> Result>, EvaluationFailure> { let infcx = selcx.infcx; - let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx()); + let mut drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx()); let mut candidate = None; for predicate in obligation.param_env.caller_bounds() { diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 2864f277df578..d305d81b6414f 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -866,7 +866,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( potentially_unnormalized_candidates: bool, ) { let infcx = selcx.infcx; - let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx()); + let mut drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx()); for predicate in env_predicates { let bound_predicate = predicate.kind(); if let ty::ClauseKind::Projection(data) = predicate.kind().skip_binder() { diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 32b4567aba4f0..8503af4fbd219 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -232,7 +232,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .filter(|p| p.def_id() == stack.obligation.predicate.def_id()) .filter(|p| p.polarity() == stack.obligation.predicate.polarity()); - let drcx = DeepRejectCtxt::relate_rigid_rigid(self.tcx()); + let mut drcx = DeepRejectCtxt::relate_rigid_rigid(self.tcx()); let obligation_args = stack.obligation.predicate.skip_binder().trait_ref.args; // Keep only those bounds which may apply, and propagate overflow if it occurs. for bound in bounds { @@ -548,7 +548,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &PolyTraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) { - let drcx = DeepRejectCtxt::relate_rigid_infer(self.tcx()); + let mut drcx = DeepRejectCtxt::relate_rigid_infer(self.tcx()); let obligation_args = obligation.predicate.skip_binder().trait_ref.args; self.tcx().for_each_relevant_impl( obligation.predicate.def_id(), diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs index 2c8e47bcbca2a..531c901876ef8 100644 --- a/compiler/rustc_type_ir/src/fast_reject.rs +++ b/compiler/rustc_type_ir/src/fast_reject.rs @@ -11,6 +11,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHas #[cfg(feature = "nightly")] use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +use crate::data_structures::DelayedSet; use crate::inherent::*; use crate::visit::TypeVisitableExt as _; use crate::{self as ty, Interner}; @@ -181,33 +182,34 @@ impl SimplifiedType { /// We also use this function during coherence. For coherence the /// impls only have to overlap for some value, so we treat parameters /// on both sides like inference variables. -#[derive(Debug, Clone, Copy)] +#[derive(Debug)] pub struct DeepRejectCtxt< I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_WITH_INFER: bool, > { _interner: PhantomData, + cache: DelayedSet<(I::Ty, I::Ty)>, } impl DeepRejectCtxt { /// Treat parameters in both the lhs and the rhs as rigid. pub fn relate_rigid_rigid(_interner: I) -> DeepRejectCtxt { - DeepRejectCtxt { _interner: PhantomData } + DeepRejectCtxt { _interner: PhantomData, cache: Default::default() } } } impl DeepRejectCtxt { /// Treat parameters in both the lhs and the rhs as infer vars. pub fn relate_infer_infer(_interner: I) -> DeepRejectCtxt { - DeepRejectCtxt { _interner: PhantomData } + DeepRejectCtxt { _interner: PhantomData, cache: Default::default() } } } impl DeepRejectCtxt { /// Treat parameters in the lhs as rigid, and in rhs as infer vars. pub fn relate_rigid_infer(_interner: I) -> DeepRejectCtxt { - DeepRejectCtxt { _interner: PhantomData } + DeepRejectCtxt { _interner: PhantomData, cache: Default::default() } } } @@ -215,7 +217,7 @@ impl { pub fn args_may_unify( - self, + &mut self, obligation_args: I::GenericArgs, impl_args: I::GenericArgs, ) -> bool { @@ -234,17 +236,32 @@ impl bool { + pub fn types_may_unify(&mut self, lhs: I::Ty, rhs: I::Ty) -> bool { + if self.cache.contains(&(lhs, rhs)) { + return true; + } + match rhs.kind() { // Start by checking whether the `rhs` type may unify with // pretty much everything. Just return `true` in that case. ty::Param(_) => { if INSTANTIATE_RHS_WITH_INFER { + self.cache.insert((lhs, rhs)); + return true; + } + } + ty::Error(_) | ty::Alias(..) | ty::Bound(..) => { + self.cache.insert((lhs, rhs)); + return true; + } + ty::Infer(var) => { + if self.var_and_ty_may_unify(var, lhs) { + self.cache.insert((lhs, rhs)); return true; + } else { + return false; } } - ty::Error(_) | ty::Alias(..) | ty::Bound(..) => return true, - ty::Infer(var) => return self.var_and_ty_may_unify(var, lhs), // These types only unify with inference variables or their own // variant. @@ -274,7 +291,7 @@ impl match rhs.kind() { ty::Ref(_, rhs_ty, rhs_mutbl) => { lhs_mutbl == rhs_mutbl && self.types_may_unify(lhs_ty, rhs_ty) @@ -414,10 +431,16 @@ impl true, + }; + + if may_unify { + self.cache.insert((lhs, rhs)); } + + may_unify } - pub fn consts_may_unify(self, lhs: I::Const, rhs: I::Const) -> bool { + pub fn consts_may_unify(&mut self, lhs: I::Const, rhs: I::Const) -> bool { match rhs.kind() { ty::ConstKind::Param(_) => { if INSTANTIATE_RHS_WITH_INFER { @@ -465,7 +488,7 @@ impl bool { + fn var_and_ty_may_unify(&mut self, var: ty::InferTy, ty: I::Ty) -> bool { if !ty.is_known_rigid() { return true; } diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index c82f7e9aaf927..a178fcd3c276b 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -918,7 +918,7 @@ impl<'cx, 'cache, 'item> DocVisitor<'item> for TypeImplCollector<'cx, 'cache, 'i // Be aware of `tests/rustdoc/type-alias/deeply-nested-112515.rs` which might regress. let Some(impl_did) = impl_item_id.as_def_id() else { continue }; let for_ty = self.cx.tcx().type_of(impl_did).skip_binder(); - let reject_cx = DeepRejectCtxt::relate_infer_infer(self.cx.tcx()); + let mut reject_cx = DeepRejectCtxt::relate_infer_infer(self.cx.tcx()); if !reject_cx.types_may_unify(aliased_ty, for_ty) { continue; }