1use rustc_data_structures::fx::FxIndexMap;
2use rustc_hir::def_id::DefId;
3use rustc_span::bug;
4use rustc_type_ir::{BoundVarReplacerDelegate, FnMutDelegate};
5
6use crate::ty::{self, Binder, BoundTy, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable};
7
8pub struct BottomUpFolder<'tcx, F, G, H>
12where
13 F: FnMut(Ty<'tcx>) -> Ty<'tcx>,
14 G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>,
15 H: FnMut(ty::Const<'tcx>) -> ty::Const<'tcx>,
16{
17 pub tcx: TyCtxt<'tcx>,
18 pub ty_op: F,
19 pub lt_op: G,
20 pub ct_op: H,
21}
22
23impl<'tcx, F, G, H> TypeFolder<TyCtxt<'tcx>> for BottomUpFolder<'tcx, F, G, H>
24where
25 F: FnMut(Ty<'tcx>) -> Ty<'tcx>,
26 G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>,
27 H: FnMut(ty::Const<'tcx>) -> ty::Const<'tcx>,
28{
29 fn cx(&self) -> TyCtxt<'tcx> {
30 self.tcx
31 }
32
33 fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
34 let t = ty.super_fold_with(self);
35 (self.ty_op)(t)
36 }
37
38 fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
39 (self.lt_op)(r)
42 }
43
44 fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
45 let ct = ct.super_fold_with(self);
46 (self.ct_op)(ct)
47 }
48}
49
50impl<'tcx> TyCtxt<'tcx> {
51 pub fn instantiate_bound_regions<T, F>(
65 self,
66 value: Binder<'tcx, T>,
67 mut fld_r: F,
68 ) -> (T, FxIndexMap<ty::BoundRegion<'tcx>, ty::Region<'tcx>>)
69 where
70 F: FnMut(ty::BoundRegion<'tcx>) -> ty::Region<'tcx>,
71 T: TypeFoldable<TyCtxt<'tcx>>,
72 {
73 let mut region_map = FxIndexMap::default();
74 let real_fld_r =
75 |br: ty::BoundRegion<'tcx>| *region_map.entry(br).or_insert_with(|| fld_r(br));
76 let value = self.instantiate_bound_regions_uncached(value, real_fld_r);
77 (value, region_map)
78 }
79
80 pub fn instantiate_bound_regions_uncached<T, F>(
81 self,
82 value: Binder<'tcx, T>,
83 mut replace_regions: F,
84 ) -> T
85 where
86 F: FnMut(ty::BoundRegion<'tcx>) -> ty::Region<'tcx>,
87 T: TypeFoldable<TyCtxt<'tcx>>,
88 {
89 let delegate = FnMutDelegate {
90 regions: &mut replace_regions,
91 types: &mut |b| ::rustc_span::macros::bug_impl(None,
format_args!("unexpected bound ty in binder: {0:?}", b),
Location::caller())bug!("unexpected bound ty in binder: {b:?}"),
92 consts: &mut |b| ::rustc_span::macros::bug_impl(None,
format_args!("unexpected bound ct in binder: {0:?}", b),
Location::caller())bug!("unexpected bound ct in binder: {b:?}"),
93 };
94 rustc_type_ir::replace_escaping_bound_vars_uncached(self, value.skip_binder(), delegate)
95 }
96
97 pub fn replace_escaping_bound_vars_uncached<T: TypeFoldable<TyCtxt<'tcx>>>(
99 self,
100 value: T,
101 delegate: impl BoundVarReplacerDelegate<TyCtxt<'tcx>>,
102 ) -> T {
103 rustc_type_ir::replace_escaping_bound_vars_uncached(self, value, delegate)
104 }
105
106 pub fn replace_bound_vars_uncached<T: TypeFoldable<TyCtxt<'tcx>>>(
108 self,
109 value: Binder<'tcx, T>,
110 delegate: impl BoundVarReplacerDelegate<TyCtxt<'tcx>>,
111 ) -> T {
112 self.replace_escaping_bound_vars_uncached(value.skip_binder(), delegate)
113 }
114
115 pub fn liberate_late_bound_regions<T>(
118 self,
119 all_outlive_scope: DefId,
120 value: ty::Binder<'tcx, T>,
121 ) -> T
122 where
123 T: TypeFoldable<TyCtxt<'tcx>>,
124 {
125 self.instantiate_bound_regions_uncached(value, |br| {
126 let kind = ty::LateParamRegionKind::from_bound(br.var, br.kind);
127 ty::Region::new_late_param(self, all_outlive_scope, kind)
128 })
129 }
130
131 pub fn shift_bound_var_indices<T>(self, bound_vars: usize, value: T) -> T
132 where
133 T: TypeFoldable<TyCtxt<'tcx>>,
134 {
135 rustc_type_ir::shift_bound_var_indices(self, bound_vars, value)
136 }
137
138 pub fn instantiate_bound_regions_with_erased<T>(self, value: Binder<'tcx, T>) -> T
141 where
142 T: TypeFoldable<TyCtxt<'tcx>>,
143 {
144 self.instantiate_bound_regions(value, |_| self.lifetimes.re_erased).0
145 }
146
147 pub fn anonymize_bound_vars<T>(self, value: Binder<'tcx, T>) -> Binder<'tcx, T>
149 where
150 T: TypeFoldable<TyCtxt<'tcx>>,
151 {
152 struct Anonymize<'a, 'tcx> {
153 tcx: TyCtxt<'tcx>,
154 map: &'a mut FxIndexMap<ty::BoundVar, ty::BoundVariableKind<'tcx>>,
155 }
156 impl<'tcx> BoundVarReplacerDelegate<TyCtxt<'tcx>> for Anonymize<'_, 'tcx> {
157 fn replace_region(&mut self, br: ty::BoundRegion<'tcx>) -> ty::Region<'tcx> {
158 let entry = self.map.entry(br.var);
159 let index = entry.index();
160 let var = ty::BoundVar::from_usize(index);
161 let kind = entry
162 .or_insert_with(|| ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon))
163 .expect_region();
164 let br = ty::BoundRegion { var, kind };
165 ty::Region::new_bound(self.tcx, ty::INNERMOST, br)
166 }
167 fn replace_ty(&mut self, bt: ty::BoundTy<'tcx>) -> Ty<'tcx> {
168 let entry = self.map.entry(bt.var);
169 let index = entry.index();
170 let var = ty::BoundVar::from_usize(index);
171 let kind = entry
172 .or_insert_with(|| ty::BoundVariableKind::Ty(ty::BoundTyKind::Anon))
173 .expect_ty();
174 Ty::new_bound(self.tcx, ty::INNERMOST, BoundTy { var, kind })
175 }
176 fn replace_const(&mut self, bc: ty::BoundConst<'tcx>) -> ty::Const<'tcx> {
177 let entry = self.map.entry(bc.var);
178 let index = entry.index();
179 let var = ty::BoundVar::from_usize(index);
180 let () = entry.or_insert_with(|| ty::BoundVariableKind::Const).expect_const();
181 ty::Const::new_bound(self.tcx, ty::INNERMOST, ty::BoundConst::new(var))
182 }
183 }
184
185 let mut map = Default::default();
186 let delegate = Anonymize { tcx: self, map: &mut map };
187 let inner = self.replace_escaping_bound_vars_uncached(value.skip_binder(), delegate);
188 let bound_vars = self.mk_bound_variable_kinds_from_iter(map.into_values());
189 Binder::bind_with_vars(inner, bound_vars)
190 }
191}