|
6 | 6 | //! |
7 | 7 | //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html |
8 | 8 |
|
9 | | -use crate::next_solver::BoundConst; |
10 | 9 | 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, |
12 | 12 | }; |
| 13 | +use rustc_hash::FxHashMap; |
13 | 14 | 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}, |
16 | 18 | }; |
17 | 19 |
|
18 | 20 | pub trait CanonicalExt<'db, V> { |
|
91 | 93 | }, |
92 | 94 | }; |
93 | 95 |
|
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) |
95 | 170 | } |
96 | 171 | } |
0 commit comments