This commit is contained in:
lcnr 2024-10-02 14:39:43 +02:00
parent a7b114420c
commit 1a04a317c4
5 changed files with 31 additions and 23 deletions

View File

@ -14,14 +14,16 @@ use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin};
/// Enforce that `a` is equal to or a subtype of `b`. /// Enforce that `a` is equal to or a subtype of `b`.
pub struct TypeRelating<'combine, 'a, 'tcx> { pub struct TypeRelating<'combine, 'a, 'tcx> {
// Partially mutable. // Immutable except for the `InferCtxt` and the
// resulting nested `goals`.
fields: &'combine mut CombineFields<'a, 'tcx>, fields: &'combine mut CombineFields<'a, 'tcx>,
// Immutable fields. // Immutable field.
structurally_relate_aliases: StructurallyRelateAliases, structurally_relate_aliases: StructurallyRelateAliases,
// Mutable field.
ambient_variance: ty::Variance, ambient_variance: ty::Variance,
/// The cache has only tracks the `ambient_variance` as its the /// The cache only tracks the `ambient_variance` as it's the
/// only field which is mutable and which meaningfully changes /// only field which is mutable and which meaningfully changes
/// the result when relating types. /// the result when relating types.
/// ///

View File

@ -210,16 +210,17 @@ where
debug_assert!(!ty.has_vars_bound_above(ty::INNERMOST)); debug_assert!(!ty.has_vars_bound_above(ty::INNERMOST));
ty::fold::shift_vars(self.tcx, ty, self.current_index.as_u32()) ty::fold::shift_vars(self.tcx, ty, self.current_index.as_u32())
} }
_ if t.has_vars_bound_at_or_above(self.current_index) => { _ => {
if let Some(&ty) = self.cache.get(&(self.current_index, t)) { if !t.has_vars_bound_at_or_above(self.current_index) {
return ty; t
} else if let Some(&t) = self.cache.get(&(self.current_index, t)) {
t
} else {
let res = t.super_fold_with(self);
assert!(self.cache.insert((self.current_index, t), res));
res
} }
let res = t.super_fold_with(self);
assert!(self.cache.insert((self.current_index, t), res));
res
} }
_ => t,
} }
} }

View File

@ -42,17 +42,19 @@ pub enum CanonicalizeMode {
pub struct Canonicalizer<'a, D: SolverDelegate<Interner = I>, I: Interner> { pub struct Canonicalizer<'a, D: SolverDelegate<Interner = I>, I: Interner> {
delegate: &'a D, delegate: &'a D,
// Immutable field.
canonicalize_mode: CanonicalizeMode, canonicalize_mode: CanonicalizeMode,
// Mutable fields.
variables: &'a mut Vec<I::GenericArg>, variables: &'a mut Vec<I::GenericArg>,
variable_lookup_table: HashMap<I::GenericArg, usize>,
primitive_var_infos: Vec<CanonicalVarInfo<I>>, primitive_var_infos: Vec<CanonicalVarInfo<I>>,
variable_lookup_table: HashMap<I::GenericArg, usize>,
binder_index: ty::DebruijnIndex, binder_index: ty::DebruijnIndex,
/// We only use the debruijn index during lookup as all other fields /// We only use the debruijn index during lookup. We don't need to
/// should not be impacted by whether a type is folded once or multiple /// track the `variables` as each generic arg only results in a single
/// times. /// bound variable regardless of how many times it is encountered.
cache: HashMap<(ty::DebruijnIndex, I::Ty), I::Ty>, cache: HashMap<(ty::DebruijnIndex, I::Ty), I::Ty>,
} }

View File

@ -16,6 +16,8 @@ where
I: Interner, I: Interner,
{ {
delegate: &'a D, delegate: &'a D,
/// We're able to use a cache here as the folder does not have any
/// mutable state.
cache: DelayedMap<I::Ty, I::Ty>, cache: DelayedMap<I::Ty, I::Ty>,
} }

View File

@ -1057,16 +1057,17 @@ where
); );
infer_ty infer_ty
} }
_ if ty.has_aliases() => { _ => {
if let Some(&entry) = self.cache.get(&ty) { if !ty.has_aliases() {
ty
} else if let Some(&entry) = self.cache.get(&ty) {
return entry; return entry;
} else {
let res = ty.super_fold_with(self);
assert!(self.cache.insert(ty, res).is_none());
res
} }
let res = ty.super_fold_with(self);
assert!(self.cache.insert(ty, res).is_none());
res
} }
_ => ty,
} }
} }