Skip to content

Commit 7bf456d

Browse files
committed
caching high hopes
1 parent 95b9dc1 commit 7bf456d

File tree

7 files changed

+105
-38
lines changed

7 files changed

+105
-38
lines changed

compiler/rustc_infer/src/infer/relate/type_relating.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
use rustc_data_structures::sso::SsoHashSet;
21
use rustc_middle::traits::solve::Goal;
32
use rustc_middle::ty::relate::{
43
Relate, RelateResult, TypeRelation, relate_args_invariantly, relate_args_with_variances,
54
};
65
use rustc_middle::ty::{self, Ty, TyCtxt, TyVar};
76
use rustc_span::Span;
7+
use rustc_type_ir::data_structures::DelayedSet;
88
use tracing::{debug, instrument};
99

1010
use super::combine::CombineFields;
@@ -17,7 +17,7 @@ pub struct TypeRelating<'combine, 'a, 'tcx> {
1717
fields: &'combine mut CombineFields<'a, 'tcx>,
1818
structurally_relate_aliases: StructurallyRelateAliases,
1919
ambient_variance: ty::Variance,
20-
cache: SsoHashSet<(ty::Variance, Ty<'tcx>, Ty<'tcx>)>,
20+
cache: DelayedSet<(ty::Variance, Ty<'tcx>, Ty<'tcx>)>,
2121
}
2222

2323
impl<'combine, 'infcx, 'tcx> TypeRelating<'combine, 'infcx, 'tcx> {
@@ -85,7 +85,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> {
8585
let a = infcx.shallow_resolve(a);
8686
let b = infcx.shallow_resolve(b);
8787

88-
if infcx.next_trait_solver() && self.cache.contains(&(self.ambient_variance, a, b)) {
88+
if self.cache.contains(&(self.ambient_variance, a, b)) {
8989
return Ok(a);
9090
}
9191

@@ -171,9 +171,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> {
171171
}
172172
}
173173

174-
if infcx.next_trait_solver() {
175-
assert!(self.cache.insert((self.ambient_variance, a, b)));
176-
}
174+
assert!(self.cache.insert((self.ambient_variance, a, b)));
177175

178176
Ok(a)
179177
}

compiler/rustc_infer/src/infer/resolve.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use rustc_middle::bug;
33
use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
44
use rustc_middle::ty::visit::TypeVisitableExt;
55
use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable};
6+
use rustc_type_ir::data_structures::DelayedMap;
67

78
use super::{FixupError, FixupResult, InferCtxt};
89

@@ -16,7 +17,7 @@ use super::{FixupError, FixupResult, InferCtxt};
1617
/// points for correctness.
1718
pub struct OpportunisticVarResolver<'a, 'tcx> {
1819
infcx: &'a InferCtxt<'tcx>,
19-
cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
20+
cache: DelayedMap<Ty<'tcx>, Ty<'tcx>>,
2021
}
2122

2223
impl<'a, 'tcx> OpportunisticVarResolver<'a, 'tcx> {
@@ -40,7 +41,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for OpportunisticVarResolver<'a, 'tcx> {
4041
} else {
4142
let shallow = self.infcx.shallow_resolve(t);
4243
let res = shallow.super_fold_with(self);
43-
assert!(self.cache.insert(t, res).is_none());
44+
assert!(self.cache.insert(t, res));
4445
res
4546
}
4647
}

compiler/rustc_middle/src/ty/fold.rs

+13-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use rustc_data_structures::fx::FxIndexMap;
2-
use rustc_data_structures::sso::SsoHashMap;
32
use rustc_hir::def_id::DefId;
3+
use rustc_type_ir::data_structures::DelayedMap;
44
pub use rustc_type_ir::fold::{
55
FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable, shift_region, shift_vars,
66
};
@@ -166,7 +166,7 @@ struct BoundVarReplacer<'tcx, D> {
166166

167167
delegate: D,
168168

169-
cache: SsoHashMap<(ty::DebruijnIndex, Ty<'tcx>), Ty<'tcx>>,
169+
cache: DelayedMap<(ty::DebruijnIndex, Ty<'tcx>), Ty<'tcx>>,
170170
}
171171

172172
impl<'tcx, D: BoundVarReplacerDelegate<'tcx>> BoundVarReplacer<'tcx, D> {
@@ -194,22 +194,23 @@ where
194194
}
195195

196196
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
197-
if let Some(&ty) = self.cache.get(&(self.current_index, t)) {
198-
return ty;
199-
}
200-
201-
let res = match *t.kind() {
197+
match *t.kind() {
202198
ty::Bound(debruijn, bound_ty) if debruijn == self.current_index => {
203199
let ty = self.delegate.replace_ty(bound_ty);
204200
debug_assert!(!ty.has_vars_bound_above(ty::INNERMOST));
205201
ty::fold::shift_vars(self.tcx, ty, self.current_index.as_u32())
206202
}
207-
_ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self),
208-
_ => t,
209-
};
203+
_ if t.has_vars_bound_at_or_above(self.current_index) => {
204+
if let Some(&ty) = self.cache.get(&(self.current_index, t)) {
205+
return ty;
206+
}
210207

211-
assert!(self.cache.insert((self.current_index, t), res).is_none());
212-
res
208+
let res = t.super_fold_with(self);
209+
assert!(self.cache.insert((self.current_index, t), res));
210+
res
211+
}
212+
_ => t,
213+
}
213214
}
214215

215216
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {

compiler/rustc_next_trait_solver/src/resolve.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use rustc_type_ir::data_structures::HashMap;
1+
use rustc_type_ir::data_structures::DelayedMap;
22
use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
33
use rustc_type_ir::inherent::*;
44
use rustc_type_ir::visit::TypeVisitableExt;
@@ -16,7 +16,7 @@ where
1616
I: Interner,
1717
{
1818
delegate: &'a D,
19-
cache: HashMap<I::Ty, I::Ty>,
19+
cache: DelayedMap<I::Ty, I::Ty>,
2020
}
2121

2222
impl<'a, D: SolverDelegate> EagerResolver<'a, D> {
@@ -48,7 +48,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for EagerResolv
4848
return ty;
4949
}
5050
let res = t.super_fold_with(self);
51-
assert!(self.cache.insert(t, res).is_none());
51+
assert!(self.cache.insert(t, res));
5252
res
5353
} else {
5454
t

compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs

+11-15
Original file line numberDiff line numberDiff line change
@@ -362,12 +362,6 @@ where
362362
goal: Goal<I, I::Predicate>,
363363
) -> Result<(NestedNormalizationGoals<I>, bool, Certainty), NoSolution> {
364364
let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
365-
366-
let num_orig_values = orig_values.iter().filter(|v| v.as_region().is_none()).count();
367-
if num_orig_values >= 128 {
368-
println!("bail due to too many orig_values: {num_orig_values}");
369-
return Ok((Default::default(), false, Certainty::overflow(false)));
370-
}
371365
let mut goal_evaluation =
372366
self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind);
373367
let canonical_response = EvalCtxt::evaluate_canonical_goal(
@@ -1049,11 +1043,7 @@ where
10491043
}
10501044

10511045
fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
1052-
if let Some(&entry) = self.cache.get(&ty) {
1053-
return entry;
1054-
}
1055-
1056-
let res = match ty.kind() {
1046+
match ty.kind() {
10571047
ty::Alias(..) if !ty.has_escaping_bound_vars() => {
10581048
let infer_ty = self.ecx.next_ty_infer();
10591049
let normalizes_to = ty::PredicateKind::AliasRelate(
@@ -1067,11 +1057,17 @@ where
10671057
);
10681058
infer_ty
10691059
}
1070-
_ => ty.super_fold_with(self),
1071-
};
1060+
_ if ty.has_aliases() => {
1061+
if let Some(&entry) = self.cache.get(&ty) {
1062+
return entry;
1063+
}
10721064

1073-
assert!(self.cache.insert(ty, res).is_none());
1074-
res
1065+
let res = ty.super_fold_with(self);
1066+
assert!(self.cache.insert(ty, res).is_none());
1067+
res
1068+
}
1069+
_ => ty,
1070+
}
10751071
}
10761072

10771073
fn fold_const(&mut self, ct: I::Const) -> I::Const {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use std::hash::Hash;
2+
3+
use crate::data_structures::{HashMap, HashSet};
4+
5+
const CACHE_CUTOFF: u32 = 16;
6+
7+
/// A hashmap which only starts hashing after ignoring the first few inputs.
8+
///
9+
/// This is used in type folders asin nearly all cases caching is not worth it
10+
/// as nearly all folded types are tiny. However, there are very rare incredibly
11+
/// large types for which caching is necessary to avoid hangs.
12+
#[derive(Debug)]
13+
pub struct DelayedMap<K, V> {
14+
cache: HashMap<K, V>,
15+
count: u32,
16+
}
17+
18+
impl<K, V> Default for DelayedMap<K, V> {
19+
fn default() -> Self {
20+
DelayedMap { cache: Default::default(), count: 0 }
21+
}
22+
}
23+
24+
impl<K: Hash + Eq, V> DelayedMap<K, V> {
25+
#[inline]
26+
pub fn insert(&mut self, key: K, value: V) -> bool {
27+
if self.count >= CACHE_CUTOFF {
28+
self.cache.insert(key, value).is_none()
29+
} else {
30+
self.count += 1;
31+
true
32+
}
33+
}
34+
35+
#[inline]
36+
pub fn get(&self, key: &K) -> Option<&V> {
37+
self.cache.get(key)
38+
}
39+
}
40+
41+
#[derive(Debug)]
42+
pub struct DelayedSet<T> {
43+
cache: HashSet<T>,
44+
count: u32,
45+
}
46+
47+
impl<T> Default for DelayedSet<T> {
48+
fn default() -> Self {
49+
DelayedSet { cache: Default::default(), count: 0 }
50+
}
51+
}
52+
53+
impl<T: Hash + Eq> DelayedSet<T> {
54+
#[inline]
55+
pub fn insert(&mut self, value: T) -> bool {
56+
if self.count >= CACHE_CUTOFF {
57+
self.cache.insert(value)
58+
} else {
59+
self.count += 1;
60+
true
61+
}
62+
}
63+
64+
#[inline]
65+
pub fn contains(&self, value: &T) -> bool {
66+
self.cache.contains(value)
67+
}
68+
}

compiler/rustc_type_ir/src/data_structures.rs renamed to compiler/rustc_type_ir/src/data_structures/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ pub use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
66
pub type IndexMap<K, V> = indexmap::IndexMap<K, V, BuildHasherDefault<FxHasher>>;
77
pub type IndexSet<V> = indexmap::IndexSet<V, BuildHasherDefault<FxHasher>>;
88

9+
mod delayed_map;
10+
911
#[cfg(feature = "nightly")]
1012
mod impl_ {
1113
pub use rustc_data_structures::sso::{SsoHashMap, SsoHashSet};
@@ -24,4 +26,5 @@ mod impl_ {
2426
}
2527
}
2628

29+
pub use delayed_map::{DelayedMap, DelayedSet};
2730
pub use impl_::*;

0 commit comments

Comments
 (0)