1use rustc_data_structures::fx::FxIndexMap;
2use rustc_hir::def_id::DefId;
3use rustc_type_ir::data_structures::DelayedMap;
4
5use crate::ty::region::RegionExt;
6use crate::ty::{
7 self, Binder, BoundTy, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
8 TypeVisitableExt,
9};
10
11pub struct BottomUpFolder<'tcx, F, G, H>
15where
16 F: FnMut(Ty<'tcx>) -> Ty<'tcx>,
17 G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>,
18 H: FnMut(ty::Const<'tcx>) -> ty::Const<'tcx>,
19{
20 pub tcx: TyCtxt<'tcx>,
21 pub ty_op: F,
22 pub lt_op: G,
23 pub ct_op: H,
24}
25
26impl<'tcx, F, G, H> TypeFolder<TyCtxt<'tcx>> for BottomUpFolder<'tcx, F, G, H>
27where
28 F: FnMut(Ty<'tcx>) -> Ty<'tcx>,
29 G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>,
30 H: FnMut(ty::Const<'tcx>) -> ty::Const<'tcx>,
31{
32 fn cx(&self) -> TyCtxt<'tcx> {
33 self.tcx
34 }
35
36 fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
37 let t = ty.super_fold_with(self);
38 (self.ty_op)(t)
39 }
40
41 fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
42 (self.lt_op)(r)
45 }
46
47 fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
48 let ct = ct.super_fold_with(self);
49 (self.ct_op)(ct)
50 }
51}
52
53pub trait BoundVarReplacerDelegate<'tcx> {
62 fn replace_region(&mut self, br: ty::BoundRegion<'tcx>) -> ty::Region<'tcx>;
63 fn replace_ty(&mut self, bt: ty::BoundTy<'tcx>) -> Ty<'tcx>;
64 fn replace_const(&mut self, bc: ty::BoundConst<'tcx>) -> ty::Const<'tcx>;
65}
66
67pub struct FnMutDelegate<'a, 'tcx> {
71 pub regions: &'a mut (dyn FnMut(ty::BoundRegion<'tcx>) -> ty::Region<'tcx> + 'a),
72 pub types: &'a mut (dyn FnMut(ty::BoundTy<'tcx>) -> Ty<'tcx> + 'a),
73 pub consts: &'a mut (dyn FnMut(ty::BoundConst<'tcx>) -> ty::Const<'tcx> + 'a),
74}
75
76impl<'a, 'tcx> BoundVarReplacerDelegate<'tcx> for FnMutDelegate<'a, 'tcx> {
77 fn replace_region(&mut self, br: ty::BoundRegion<'tcx>) -> ty::Region<'tcx> {
78 (self.regions)(br)
79 }
80 fn replace_ty(&mut self, bt: ty::BoundTy<'tcx>) -> Ty<'tcx> {
81 (self.types)(bt)
82 }
83 fn replace_const(&mut self, bc: ty::BoundConst<'tcx>) -> ty::Const<'tcx> {
84 (self.consts)(bc)
85 }
86}
87
88struct BoundVarReplacer<'tcx, D> {
90 tcx: TyCtxt<'tcx>,
91
92 current_index: ty::DebruijnIndex,
95
96 delegate: D,
97
98 cache: DelayedMap<(ty::DebruijnIndex, Ty<'tcx>), Ty<'tcx>>,
101}
102
103impl<'tcx, D: BoundVarReplacerDelegate<'tcx>> BoundVarReplacer<'tcx, D> {
104 fn new(tcx: TyCtxt<'tcx>, delegate: D) -> Self {
105 BoundVarReplacer { tcx, current_index: ty::INNERMOST, delegate, cache: Default::default() }
106 }
107}
108
109impl<'tcx, D> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'tcx, D>
110where
111 D: BoundVarReplacerDelegate<'tcx>,
112{
113 fn cx(&self) -> TyCtxt<'tcx> {
114 self.tcx
115 }
116
117 fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
118 &mut self,
119 t: ty::Binder<'tcx, T>,
120 ) -> ty::Binder<'tcx, T> {
121 self.current_index.shift_in(1);
122 let t = t.super_fold_with(self);
123 self.current_index.shift_out(1);
124 t
125 }
126
127 fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
128 match *t.kind() {
129 ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_ty)
130 if debruijn == self.current_index =>
131 {
132 let ty = self.delegate.replace_ty(bound_ty);
133 if true {
if !!ty.has_vars_bound_above(ty::INNERMOST) {
::core::panicking::panic("assertion failed: !ty.has_vars_bound_above(ty::INNERMOST)")
};
};debug_assert!(!ty.has_vars_bound_above(ty::INNERMOST));
134 ty::shift_vars(self.tcx, ty, self.current_index.as_u32())
135 }
136 _ => {
137 if !t.has_vars_bound_at_or_above(self.current_index) {
138 t
139 } else if let Some(&t) = self.cache.get(&(self.current_index, t)) {
140 t
141 } else {
142 let res = t.super_fold_with(self);
143 if !self.cache.insert((self.current_index, t), res) {
::core::panicking::panic("assertion failed: self.cache.insert((self.current_index, t), res)")
};assert!(self.cache.insert((self.current_index, t), res));
144 res
145 }
146 }
147 }
148 }
149
150 fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
151 match r.kind() {
152 ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br)
153 if debruijn == self.current_index =>
154 {
155 let region = self.delegate.replace_region(br);
156 if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn1), br) = region.kind() {
157 {
match (&debruijn1, &ty::INNERMOST) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(debruijn1, ty::INNERMOST);
162 ty::Region::new_bound(self.tcx, debruijn, br)
163 } else {
164 region
165 }
166 }
167 _ => r,
168 }
169 }
170
171 fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
172 match ct.kind() {
173 ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_const)
174 if debruijn == self.current_index =>
175 {
176 let ct = self.delegate.replace_const(bound_const);
177 if true {
if !!ct.has_vars_bound_above(ty::INNERMOST) {
::core::panicking::panic("assertion failed: !ct.has_vars_bound_above(ty::INNERMOST)")
};
};debug_assert!(!ct.has_vars_bound_above(ty::INNERMOST));
178 ty::shift_vars(self.tcx, ct, self.current_index.as_u32())
179 }
180 _ => ct.super_fold_with(self),
181 }
182 }
183
184 fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
185 if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
186 }
187
188 fn fold_clauses(&mut self, c: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> {
189 if c.has_vars_bound_at_or_above(self.current_index) { c.super_fold_with(self) } else { c }
190 }
191}
192
193impl<'tcx> TyCtxt<'tcx> {
194 pub fn instantiate_bound_regions<T, F>(
208 self,
209 value: Binder<'tcx, T>,
210 mut fld_r: F,
211 ) -> (T, FxIndexMap<ty::BoundRegion<'tcx>, ty::Region<'tcx>>)
212 where
213 F: FnMut(ty::BoundRegion<'tcx>) -> ty::Region<'tcx>,
214 T: TypeFoldable<TyCtxt<'tcx>>,
215 {
216 let mut region_map = FxIndexMap::default();
217 let real_fld_r =
218 |br: ty::BoundRegion<'tcx>| *region_map.entry(br).or_insert_with(|| fld_r(br));
219 let value = self.instantiate_bound_regions_uncached(value, real_fld_r);
220 (value, region_map)
221 }
222
223 pub fn instantiate_bound_regions_uncached<T, F>(
224 self,
225 value: Binder<'tcx, T>,
226 mut replace_regions: F,
227 ) -> T
228 where
229 F: FnMut(ty::BoundRegion<'tcx>) -> ty::Region<'tcx>,
230 T: TypeFoldable<TyCtxt<'tcx>>,
231 {
232 let value = value.skip_binder();
233 if !value.has_escaping_bound_vars() {
234 value
235 } else {
236 let delegate = FnMutDelegate {
237 regions: &mut replace_regions,
238 types: &mut |b| crate::util::bug::bug_fmt(format_args!("unexpected bound ty in binder: {0:?}",
b))bug!("unexpected bound ty in binder: {b:?}"),
239 consts: &mut |b| crate::util::bug::bug_fmt(format_args!("unexpected bound ct in binder: {0:?}",
b))bug!("unexpected bound ct in binder: {b:?}"),
240 };
241 let mut replacer = BoundVarReplacer::new(self, delegate);
242 value.fold_with(&mut replacer)
243 }
244 }
245
246 pub fn replace_escaping_bound_vars_uncached<T: TypeFoldable<TyCtxt<'tcx>>>(
250 self,
251 value: T,
252 delegate: impl BoundVarReplacerDelegate<'tcx>,
253 ) -> T {
254 if !value.has_escaping_bound_vars() {
255 value
256 } else {
257 let mut replacer = BoundVarReplacer::new(self, delegate);
258 value.fold_with(&mut replacer)
259 }
260 }
261
262 pub fn replace_bound_vars_uncached<T: TypeFoldable<TyCtxt<'tcx>>>(
266 self,
267 value: Binder<'tcx, T>,
268 delegate: impl BoundVarReplacerDelegate<'tcx>,
269 ) -> T {
270 self.replace_escaping_bound_vars_uncached(value.skip_binder(), delegate)
271 }
272
273 pub fn liberate_late_bound_regions<T>(
276 self,
277 all_outlive_scope: DefId,
278 value: ty::Binder<'tcx, T>,
279 ) -> T
280 where
281 T: TypeFoldable<TyCtxt<'tcx>>,
282 {
283 self.instantiate_bound_regions_uncached(value, |br| {
284 let kind = ty::LateParamRegionKind::from_bound(br.var, br.kind);
285 ty::Region::new_late_param(self, all_outlive_scope, kind)
286 })
287 }
288
289 pub fn shift_bound_var_indices<T>(self, bound_vars: usize, value: T) -> T
290 where
291 T: TypeFoldable<TyCtxt<'tcx>>,
292 {
293 let shift_bv = |bv: ty::BoundVar| bv + bound_vars;
294 self.replace_escaping_bound_vars_uncached(
295 value,
296 FnMutDelegate {
297 regions: &mut |r: ty::BoundRegion<'tcx>| {
298 ty::Region::new_bound(
299 self,
300 ty::INNERMOST,
301 ty::BoundRegion { var: shift_bv(r.var), kind: r.kind },
302 )
303 },
304 types: &mut |t: ty::BoundTy<'tcx>| {
305 Ty::new_bound(
306 self,
307 ty::INNERMOST,
308 ty::BoundTy { var: shift_bv(t.var), kind: t.kind },
309 )
310 },
311 consts: &mut |c| {
312 ty::Const::new_bound(self, ty::INNERMOST, ty::BoundConst::new(shift_bv(c.var)))
313 },
314 },
315 )
316 }
317
318 pub fn instantiate_bound_regions_with_erased<T>(self, value: Binder<'tcx, T>) -> T
321 where
322 T: TypeFoldable<TyCtxt<'tcx>>,
323 {
324 self.instantiate_bound_regions(value, |_| self.lifetimes.re_erased).0
325 }
326
327 pub fn anonymize_bound_vars<T>(self, value: Binder<'tcx, T>) -> Binder<'tcx, T>
329 where
330 T: TypeFoldable<TyCtxt<'tcx>>,
331 {
332 struct Anonymize<'a, 'tcx> {
333 tcx: TyCtxt<'tcx>,
334 map: &'a mut FxIndexMap<ty::BoundVar, ty::BoundVariableKind<'tcx>>,
335 }
336 impl<'tcx> BoundVarReplacerDelegate<'tcx> for Anonymize<'_, 'tcx> {
337 fn replace_region(&mut self, br: ty::BoundRegion<'tcx>) -> ty::Region<'tcx> {
338 let entry = self.map.entry(br.var);
339 let index = entry.index();
340 let var = ty::BoundVar::from_usize(index);
341 let kind = entry
342 .or_insert_with(|| ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon))
343 .expect_region();
344 let br = ty::BoundRegion { var, kind };
345 ty::Region::new_bound(self.tcx, ty::INNERMOST, br)
346 }
347 fn replace_ty(&mut self, bt: ty::BoundTy<'tcx>) -> Ty<'tcx> {
348 let entry = self.map.entry(bt.var);
349 let index = entry.index();
350 let var = ty::BoundVar::from_usize(index);
351 let kind = entry
352 .or_insert_with(|| ty::BoundVariableKind::Ty(ty::BoundTyKind::Anon))
353 .expect_ty();
354 Ty::new_bound(self.tcx, ty::INNERMOST, BoundTy { var, kind })
355 }
356 fn replace_const(&mut self, bc: ty::BoundConst<'tcx>) -> ty::Const<'tcx> {
357 let entry = self.map.entry(bc.var);
358 let index = entry.index();
359 let var = ty::BoundVar::from_usize(index);
360 let () = entry.or_insert_with(|| ty::BoundVariableKind::Const).expect_const();
361 ty::Const::new_bound(self.tcx, ty::INNERMOST, ty::BoundConst::new(var))
362 }
363 }
364
365 let mut map = Default::default();
366 let delegate = Anonymize { tcx: self, map: &mut map };
367 let inner = self.replace_escaping_bound_vars_uncached(value.skip_binder(), delegate);
368 let bound_vars = self.mk_bound_variable_kinds_from_iter(map.into_values());
369 Binder::bind_with_vars(inner, bound_vars)
370 }
371}