Skip to content

Commit 9610f01

Browse files
committed
Port CanonicalInstantiator from rustc
1 parent 40e36a0 commit 9610f01

File tree

1 file changed

+80
-5
lines changed
  • src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical

1 file changed

+80
-5
lines changed

src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs

Lines changed: 80 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66
//!
77
//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
88
9-
use crate::next_solver::BoundConst;
109
use crate::next_solver::{
11-
BoundRegion, BoundTy, Canonical, CanonicalVarValues, DbInterner, fold::FnMutDelegate,
10+
BoundConst, BoundRegion, BoundTy, Canonical, CanonicalVarValues, Clauses, Const, ConstKind,
11+
DbInterner, GenericArg, Predicate, Region, RegionKind, Ty, TyKind, fold::FnMutDelegate,
1212
};
13+
use rustc_hash::FxHashMap;
1314
use rustc_type_ir::{
14-
GenericArgKind, TypeFoldable,
15-
inherent::{IntoKind, SliceLike},
15+
BoundVarIndexKind, GenericArgKind, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable,
16+
TypeVisitableExt,
17+
inherent::{GenericArg as _, IntoKind, SliceLike},
1618
};
1719

1820
pub trait CanonicalExt<'db, V> {
@@ -91,6 +93,79 @@ where
9193
},
9294
};
9395

94-
tcx.replace_escaping_bound_vars_uncached(value, delegate)
96+
let value = tcx.replace_escaping_bound_vars_uncached(value, delegate);
97+
value.fold_with(&mut CanonicalInstantiator {
98+
tcx,
99+
var_values: var_values.var_values.as_slice(),
100+
cache: Default::default(),
101+
})
102+
}
103+
}
104+
105+
/// Replaces the bound vars in a canonical binder with var values.
106+
struct CanonicalInstantiator<'db, 'a> {
107+
tcx: DbInterner<'db>,
108+
109+
// The values that the bound vars are being instantiated with.
110+
var_values: &'a [GenericArg<'db>],
111+
112+
// Because we use `BoundVarIndexKind::Canonical`, we can cache
113+
// based only on the entire ty, not worrying about a `DebruijnIndex`
114+
cache: FxHashMap<Ty<'db>, Ty<'db>>,
115+
}
116+
117+
impl<'db, 'a> TypeFolder<DbInterner<'db>> for CanonicalInstantiator<'db, 'a> {
118+
fn cx(&self) -> DbInterner<'db> {
119+
self.tcx
120+
}
121+
122+
fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> {
123+
match t.kind() {
124+
TyKind::Bound(BoundVarIndexKind::Canonical, bound_ty) => {
125+
self.var_values[bound_ty.var.as_usize()].expect_ty()
126+
}
127+
_ => {
128+
if !t.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) {
129+
t
130+
} else if let Some(&t) = self.cache.get(&t) {
131+
t
132+
} else {
133+
let res = t.super_fold_with(self);
134+
assert!(self.cache.insert(t, res).is_none());
135+
res
136+
}
137+
}
138+
}
139+
}
140+
141+
fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
142+
match r.kind() {
143+
RegionKind::ReBound(BoundVarIndexKind::Canonical, br) => {
144+
self.var_values[br.var.as_usize()].expect_region()
145+
}
146+
_ => r,
147+
}
148+
}
149+
150+
fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> {
151+
match ct.kind() {
152+
ConstKind::Bound(BoundVarIndexKind::Canonical, bound_const) => {
153+
self.var_values[bound_const.var.as_usize()].expect_const()
154+
}
155+
_ => ct.super_fold_with(self),
156+
}
157+
}
158+
159+
fn fold_predicate(&mut self, p: Predicate<'db>) -> Predicate<'db> {
160+
if p.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { p.super_fold_with(self) } else { p }
161+
}
162+
163+
fn fold_clauses(&mut self, c: Clauses<'db>) -> Clauses<'db> {
164+
if !c.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) {
165+
return c;
166+
}
167+
168+
// FIXME: We might need cache here for perf like rustc
169+
c.super_fold_with(self)
95170
}
96171
}

0 commit comments

Comments
 (0)