Skip to content

Commit

Permalink
Cache in DeepRejectCtxt
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Nov 27, 2024
1 parent ef407ce commit f631ca8
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 17 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/traits/coherence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/traits/effects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ fn evaluate_host_effect_from_bounds<'tcx>(
obligation: &HostEffectObligation<'tcx>,
) -> Result<ThinVec<PredicateObligation<'tcx>>, 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() {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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(),
Expand Down
45 changes: 34 additions & 11 deletions compiler/rustc_type_ir/src/fast_reject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -181,41 +182,42 @@ impl<DefId> SimplifiedType<DefId> {
/// 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<I>,
cache: DelayedSet<(I::Ty, I::Ty)>,
}

impl<I: Interner> DeepRejectCtxt<I, false, false> {
/// Treat parameters in both the lhs and the rhs as rigid.
pub fn relate_rigid_rigid(_interner: I) -> DeepRejectCtxt<I, false, false> {
DeepRejectCtxt { _interner: PhantomData }
DeepRejectCtxt { _interner: PhantomData, cache: Default::default() }
}
}

impl<I: Interner> DeepRejectCtxt<I, true, true> {
/// Treat parameters in both the lhs and the rhs as infer vars.
pub fn relate_infer_infer(_interner: I) -> DeepRejectCtxt<I, true, true> {
DeepRejectCtxt { _interner: PhantomData }
DeepRejectCtxt { _interner: PhantomData, cache: Default::default() }
}
}

impl<I: Interner> DeepRejectCtxt<I, false, true> {
/// Treat parameters in the lhs as rigid, and in rhs as infer vars.
pub fn relate_rigid_infer(_interner: I) -> DeepRejectCtxt<I, false, true> {
DeepRejectCtxt { _interner: PhantomData }
DeepRejectCtxt { _interner: PhantomData, cache: Default::default() }
}
}

impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_WITH_INFER: bool>
DeepRejectCtxt<I, INSTANTIATE_LHS_WITH_INFER, INSTANTIATE_RHS_WITH_INFER>
{
pub fn args_may_unify(
self,
&mut self,
obligation_args: I::GenericArgs,
impl_args: I::GenericArgs,
) -> bool {
Expand All @@ -234,17 +236,32 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
})
}

pub fn types_may_unify(self, lhs: I::Ty, rhs: I::Ty) -> 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.
Expand Down Expand Up @@ -274,7 +291,7 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
};

// For purely rigid types, use structural equivalence.
match lhs.kind() {
let may_unify = match lhs.kind() {
ty::Ref(_, lhs_ty, lhs_mutbl) => match rhs.kind() {
ty::Ref(_, rhs_ty, rhs_mutbl) => {
lhs_mutbl == rhs_mutbl && self.types_may_unify(lhs_ty, rhs_ty)
Expand Down Expand Up @@ -414,10 +431,16 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
}

ty::Error(..) => 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 {
Expand Down Expand Up @@ -465,7 +488,7 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
}
}

fn var_and_ty_may_unify(self, var: ty::InferTy, ty: I::Ty) -> bool {
fn var_and_ty_may_unify(&mut self, var: ty::InferTy, ty: I::Ty) -> bool {
if !ty.is_known_rigid() {
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/html/render/write_shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down

0 comments on commit f631ca8

Please sign in to comment.