1use rustc_type_ir::{
4 BoundVarIndexKind, DebruijnIndex, RegionKind, TypeFoldable, TypeFolder, TypeSuperFoldable,
5 TypeVisitableExt, inherent::IntoKind,
6};
7
8use crate::next_solver::{BoundConst, FxIndexMap};
9
10use super::{
11 Binder, BoundRegion, BoundTy, Const, ConstKind, DbInterner, Predicate, Region, SolverDefId, Ty,
12 TyKind,
13};
14
15pub trait BoundVarReplacerDelegate<'db> {
21 fn replace_region(&mut self, br: BoundRegion<'db>) -> Region<'db>;
22 fn replace_ty(&mut self, bt: BoundTy<'db>) -> Ty<'db>;
23 fn replace_const(&mut self, bv: BoundConst<'db>) -> Const<'db>;
24}
25
26pub struct FnMutDelegate<'db, 'a> {
30 pub regions: &'a mut (dyn FnMut(BoundRegion<'db>) -> Region<'db> + 'a),
31 pub types: &'a mut (dyn FnMut(BoundTy<'db>) -> Ty<'db> + 'a),
32 pub consts: &'a mut (dyn FnMut(BoundConst<'db>) -> Const<'db> + 'a),
33}
34
35impl<'db, 'a> BoundVarReplacerDelegate<'db> for FnMutDelegate<'db, 'a> {
36 fn replace_region(&mut self, br: BoundRegion<'db>) -> Region<'db> {
37 (self.regions)(br)
38 }
39 fn replace_ty(&mut self, bt: BoundTy<'db>) -> Ty<'db> {
40 (self.types)(bt)
41 }
42 fn replace_const(&mut self, bv: BoundConst<'db>) -> Const<'db> {
43 (self.consts)(bv)
44 }
45}
46
47pub(crate) struct BoundVarReplacer<'db, D> {
49 interner: DbInterner<'db>,
50 current_index: DebruijnIndex,
53
54 delegate: D,
55}
56
57impl<'db, D: BoundVarReplacerDelegate<'db>> BoundVarReplacer<'db, D> {
58 pub(crate) fn new(tcx: DbInterner<'db>, delegate: D) -> Self {
59 BoundVarReplacer { interner: tcx, current_index: DebruijnIndex::ZERO, delegate }
60 }
61}
62
63impl<'db, D> TypeFolder<DbInterner<'db>> for BoundVarReplacer<'db, D>
64where
65 D: BoundVarReplacerDelegate<'db>,
66{
67 fn cx(&self) -> DbInterner<'db> {
68 self.interner
69 }
70
71 fn fold_binder<T: TypeFoldable<DbInterner<'db>>>(
72 &mut self,
73 t: Binder<'db, T>,
74 ) -> Binder<'db, T> {
75 self.current_index.shift_in(1);
76 let t = t.super_fold_with(self);
77 self.current_index.shift_out(1);
78 t
79 }
80
81 fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> {
82 match t.kind() {
83 TyKind::Bound(BoundVarIndexKind::Bound(debruijn), bound_ty)
84 if debruijn == self.current_index =>
85 {
86 let ty = self.delegate.replace_ty(bound_ty);
87 debug_assert!(!ty.has_vars_bound_above(DebruijnIndex::ZERO));
88 rustc_type_ir::shift_vars(self.interner, ty, self.current_index.as_u32())
89 }
90 _ => {
91 if !t.has_vars_bound_at_or_above(self.current_index) {
92 t
93 } else {
94 t.super_fold_with(self)
95 }
96 }
97 }
98 }
99
100 fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
101 match r.kind() {
102 RegionKind::ReBound(BoundVarIndexKind::Bound(debruijn), br)
103 if debruijn == self.current_index =>
104 {
105 let region = self.delegate.replace_region(br);
106 if let RegionKind::ReBound(BoundVarIndexKind::Bound(debruijn1), br) = region.kind()
107 {
108 assert_eq!(debruijn1, DebruijnIndex::ZERO);
113 Region::new_bound(self.interner, debruijn, br)
114 } else {
115 region
116 }
117 }
118 _ => r,
119 }
120 }
121
122 fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> {
123 match ct.kind() {
124 ConstKind::Bound(BoundVarIndexKind::Bound(debruijn), bound_const)
125 if debruijn == self.current_index =>
126 {
127 let ct = self.delegate.replace_const(bound_const);
128 debug_assert!(!ct.has_vars_bound_above(DebruijnIndex::ZERO));
129 rustc_type_ir::shift_vars(self.interner, ct, self.current_index.as_u32())
130 }
131 _ => ct.super_fold_with(self),
132 }
133 }
134
135 fn fold_predicate(&mut self, p: Predicate<'db>) -> Predicate<'db> {
136 if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
137 }
138}
139
140pub fn fold_tys<'db, T: TypeFoldable<DbInterner<'db>>>(
141 interner: DbInterner<'db>,
142 t: T,
143 callback: impl FnMut(Ty<'db>) -> Ty<'db>,
144) -> T {
145 struct Folder<'db, F> {
146 interner: DbInterner<'db>,
147 callback: F,
148 }
149 impl<'db, F: FnMut(Ty<'db>) -> Ty<'db>> TypeFolder<DbInterner<'db>> for Folder<'db, F> {
150 fn cx(&self) -> DbInterner<'db> {
151 self.interner
152 }
153
154 fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> {
155 let t = t.super_fold_with(self);
156 (self.callback)(t)
157 }
158 }
159
160 t.fold_with(&mut Folder { interner, callback })
161}
162
163impl<'db> DbInterner<'db> {
164 pub fn instantiate_bound_regions<T, F>(
178 self,
179 value: Binder<'db, T>,
180 mut fld_r: F,
181 ) -> (T, FxIndexMap<BoundRegion<'db>, Region<'db>>)
182 where
183 F: FnMut(BoundRegion<'db>) -> Region<'db>,
184 T: TypeFoldable<DbInterner<'db>>,
185 {
186 let mut region_map = FxIndexMap::default();
187 let real_fld_r = |br: BoundRegion<'db>| *region_map.entry(br).or_insert_with(|| fld_r(br));
188 let value = self.instantiate_bound_regions_uncached(value, real_fld_r);
189 (value, region_map)
190 }
191
192 pub fn instantiate_bound_regions_uncached<T, F>(
193 self,
194 value: Binder<'db, T>,
195 mut replace_regions: F,
196 ) -> T
197 where
198 F: FnMut(BoundRegion<'db>) -> Region<'db>,
199 T: TypeFoldable<DbInterner<'db>>,
200 {
201 let value = value.skip_binder();
202 if !value.has_escaping_bound_vars() {
203 value
204 } else {
205 let delegate = FnMutDelegate {
206 regions: &mut replace_regions,
207 types: &mut |b| panic!("unexpected bound ty in binder: {b:?}"),
208 consts: &mut |b| panic!("unexpected bound ct in binder: {b:?}"),
209 };
210 let mut replacer = BoundVarReplacer::new(self, delegate);
211 value.fold_with(&mut replacer)
212 }
213 }
214
215 pub fn instantiate_bound_regions_with_erased<T>(self, value: Binder<'db, T>) -> T
218 where
219 T: TypeFoldable<DbInterner<'db>>,
220 {
221 self.instantiate_bound_regions(value, |_| Region::new_erased(self)).0
222 }
223
224 pub fn liberate_late_bound_regions<T>(
227 self,
228 all_outlive_scope: SolverDefId<'db>,
229 value: Binder<'db, T>,
230 ) -> T
231 where
232 T: TypeFoldable<DbInterner<'db>>,
233 {
234 self.instantiate_bound_regions_uncached(value, |br| {
235 Region::new_late_param(self, all_outlive_scope, br)
236 })
237 }
238}