Skip to content

Commit a74d247

Browse files
Cache but dont cache highest_var_in_clauses
1 parent 100199c commit a74d247

File tree

2 files changed

+155
-20
lines changed

2 files changed

+155
-20
lines changed

compiler/rustc_infer/src/infer/canonical/instantiate.rs

Lines changed: 151 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@
77
//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
88
99
use rustc_macros::extension;
10-
use rustc_middle::bug;
11-
use rustc_middle::ty::{self, FnMutDelegate, GenericArgKind, TyCtxt, TypeFoldable};
10+
use rustc_middle::ty::{
11+
self, DelayedMap, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable,
12+
TypeVisitableExt, TypeVisitor,
13+
};
14+
use rustc_type_ir::TypeVisitable;
1215

1316
use crate::infer::canonical::{Canonical, CanonicalVarValues};
1417

@@ -58,23 +61,151 @@ where
5861
T: TypeFoldable<TyCtxt<'tcx>>,
5962
{
6063
if var_values.var_values.is_empty() {
61-
value
62-
} else {
63-
let delegate = FnMutDelegate {
64-
regions: &mut |br: ty::BoundRegion| match var_values[br.var].kind() {
65-
GenericArgKind::Lifetime(l) => l,
66-
r => bug!("{:?} is a region but value is {:?}", br, r),
67-
},
68-
types: &mut |bound_ty: ty::BoundTy| match var_values[bound_ty.var].kind() {
69-
GenericArgKind::Type(ty) => ty,
70-
r => bug!("{:?} is a type but value is {:?}", bound_ty, r),
71-
},
72-
consts: &mut |bound_ct: ty::BoundVar| match var_values[bound_ct].kind() {
73-
GenericArgKind::Const(ct) => ct,
74-
c => bug!("{:?} is a const but value is {:?}", bound_ct, c),
75-
},
76-
};
77-
78-
tcx.replace_escaping_bound_vars_uncached(value, delegate)
64+
return value;
7965
}
66+
67+
value.fold_with(&mut BoundVarReplacer {
68+
tcx,
69+
current_index: ty::INNERMOST,
70+
var_values: var_values.var_values,
71+
cache: Default::default(),
72+
})
73+
}
74+
75+
/// Replaces the escaping bound vars (late bound regions or bound types) in a type.
76+
struct BoundVarReplacer<'tcx> {
77+
tcx: TyCtxt<'tcx>,
78+
79+
/// As with `RegionFolder`, represents the index of a binder *just outside*
80+
/// the ones we have visited.
81+
current_index: ty::DebruijnIndex,
82+
83+
var_values: ty::GenericArgsRef<'tcx>,
84+
85+
/// This cache only tracks the `DebruijnIndex` and assumes that it does not matter
86+
/// for the delegate how often its methods get used.
87+
cache: DelayedMap<(ty::DebruijnIndex, Ty<'tcx>), Ty<'tcx>>,
88+
}
89+
90+
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'tcx> {
91+
fn cx(&self) -> TyCtxt<'tcx> {
92+
self.tcx
93+
}
94+
95+
fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
96+
&mut self,
97+
t: ty::Binder<'tcx, T>,
98+
) -> ty::Binder<'tcx, T> {
99+
self.current_index.shift_in(1);
100+
let t = t.super_fold_with(self);
101+
self.current_index.shift_out(1);
102+
t
103+
}
104+
105+
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
106+
match *t.kind() {
107+
ty::Bound(debruijn, bound_ty) if debruijn == self.current_index => {
108+
self.var_values[bound_ty.var.as_usize()].expect_ty()
109+
}
110+
_ => {
111+
if !t.has_vars_bound_at_or_above(self.current_index) {
112+
t
113+
} else if let Some(&t) = self.cache.get(&(self.current_index, t)) {
114+
t
115+
} else {
116+
let res = t.super_fold_with(self);
117+
assert!(self.cache.insert((self.current_index, t), res));
118+
res
119+
}
120+
}
121+
}
122+
}
123+
124+
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
125+
match r.kind() {
126+
ty::ReBound(debruijn, br) if debruijn == self.current_index => {
127+
self.var_values[br.var.as_usize()].expect_region()
128+
}
129+
_ => r,
130+
}
131+
}
132+
133+
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
134+
match ct.kind() {
135+
ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => {
136+
self.var_values[bound_const.as_usize()].expect_const()
137+
}
138+
_ => ct.super_fold_with(self),
139+
}
140+
}
141+
142+
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
143+
if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
144+
}
145+
146+
fn fold_clauses(&mut self, c: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> {
147+
if c.has_vars_bound_at_or_above(self.current_index) {
148+
if self.current_index == ty::INNERMOST {
149+
let index = highest_var_in_clauses(c);
150+
let c_args = &self.var_values[..=index];
151+
if let Some(c) = self.tcx.clauses_cache.lock().get(&(c, c_args)) {
152+
c
153+
} else {
154+
let folded = c.super_fold_with(self);
155+
self.tcx.clauses_cache.lock().insert((c, c_args), folded);
156+
folded
157+
}
158+
} else {
159+
c.super_fold_with(self)
160+
}
161+
} else {
162+
c
163+
}
164+
}
165+
}
166+
167+
fn highest_var_in_clauses<'tcx>(c: ty::Clauses<'tcx>) -> usize {
168+
struct HighestVarInClauses {
169+
max_var: usize,
170+
current_index: ty::DebruijnIndex,
171+
}
172+
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HighestVarInClauses {
173+
fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
174+
&mut self,
175+
t: &ty::Binder<'tcx, T>,
176+
) -> Self::Result {
177+
self.current_index.shift_in(1);
178+
let t = t.super_visit_with(self);
179+
self.current_index.shift_out(1);
180+
t
181+
}
182+
fn visit_ty(&mut self, t: Ty<'tcx>) {
183+
if let ty::Bound(debruijn, bound_ty) = *t.kind()
184+
&& debruijn == self.current_index
185+
{
186+
self.max_var = self.max_var.max(bound_ty.var.as_usize());
187+
} else if t.has_vars_bound_at_or_above(self.current_index) {
188+
t.super_visit_with(self);
189+
}
190+
}
191+
fn visit_region(&mut self, r: ty::Region<'tcx>) {
192+
if let ty::ReBound(debruijn, bound_region) = r.kind()
193+
&& debruijn == self.current_index
194+
{
195+
self.max_var = self.max_var.max(bound_region.var.as_usize());
196+
}
197+
}
198+
fn visit_const(&mut self, ct: ty::Const<'tcx>) {
199+
if let ty::ConstKind::Bound(debruijn, bound_const) = ct.kind()
200+
&& debruijn == self.current_index
201+
{
202+
self.max_var = self.max_var.max(bound_const.as_usize());
203+
} else if ct.has_vars_bound_at_or_above(self.current_index) {
204+
ct.super_visit_with(self);
205+
}
206+
}
207+
}
208+
let mut visitor = HighestVarInClauses { max_var: 0, current_index: ty::INNERMOST };
209+
c.visit_with(&mut visitor);
210+
visitor.max_var
80211
}

compiler/rustc_middle/src/ty/context.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1460,6 +1460,9 @@ pub struct GlobalCtxt<'tcx> {
14601460

14611461
pub canonical_param_env_cache: CanonicalParamEnvCache<'tcx>,
14621462

1463+
pub clauses_cache:
1464+
Lock<FxHashMap<(ty::Clauses<'tcx>, &'tcx [ty::GenericArg<'tcx>]), ty::Clauses<'tcx>>>,
1465+
14631466
/// Data layout specification for the current target.
14641467
pub data_layout: TargetDataLayout,
14651468

@@ -1707,6 +1710,7 @@ impl<'tcx> TyCtxt<'tcx> {
17071710
new_solver_evaluation_cache: Default::default(),
17081711
new_solver_canonical_param_env_cache: Default::default(),
17091712
canonical_param_env_cache: Default::default(),
1713+
clauses_cache: Default::default(),
17101714
data_layout,
17111715
alloc_map: interpret::AllocMap::new(),
17121716
current_gcx,

0 commit comments

Comments
 (0)