1use core::panic;
2
3use rustc_type_ir::data_structures::IndexMap;
4use rustc_type_ir::inherent::*;
5use rustc_type_ir::{
6 self as ty, InferCtxtLike, Interner, PlaceholderConst, PlaceholderRegion, PlaceholderType,
7 TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
8};
9
10pub struct BoundVarReplacer<'a, Infcx, I = <Infcx as InferCtxtLike>::Interner>
11where
12 Infcx: InferCtxtLike<Interner = I>,
13 I: Interner,
14{
15 infcx: &'a Infcx,
16 mapped_regions: IndexMap<ty::PlaceholderRegion<I>, ty::BoundRegion<I>>,
20 mapped_types: IndexMap<ty::PlaceholderType<I>, ty::BoundTy<I>>,
21 mapped_consts: IndexMap<ty::PlaceholderConst<I>, ty::BoundConst<I>>,
22 current_index: ty::DebruijnIndex,
25 universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
28}
29
30impl<'a, Infcx, I> BoundVarReplacer<'a, Infcx, I>
31where
32 Infcx: InferCtxtLike<Interner = I>,
33 I: Interner,
34{
35 pub fn replace_bound_vars<T: TypeFoldable<I>>(
40 infcx: &'a Infcx,
41 universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
42 value: T,
43 ) -> (
44 T,
45 IndexMap<ty::PlaceholderRegion<I>, ty::BoundRegion<I>>,
46 IndexMap<ty::PlaceholderType<I>, ty::BoundTy<I>>,
47 IndexMap<ty::PlaceholderConst<I>, ty::BoundConst<I>>,
48 ) {
49 let mut replacer = BoundVarReplacer {
50 infcx,
51 mapped_regions: Default::default(),
52 mapped_types: Default::default(),
53 mapped_consts: Default::default(),
54 current_index: ty::INNERMOST,
55 universe_indices,
56 };
57
58 let value = value.fold_with(&mut replacer);
59
60 (value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts)
61 }
62
63 fn universe_for(&mut self, debruijn: ty::DebruijnIndex) -> ty::UniverseIndex {
64 let infcx = self.infcx;
65 let index =
66 self.universe_indices.len() + self.current_index.as_usize() - debruijn.as_usize() - 1;
67 let universe = self.universe_indices[index].unwrap_or_else(|| {
68 for i in self.universe_indices.iter_mut().take(index + 1) {
69 *i = i.or_else(|| Some(infcx.create_next_universe()))
70 }
71 self.universe_indices[index].unwrap()
72 });
73 universe
74 }
75}
76
77impl<Infcx, I> TypeFolder<I> for BoundVarReplacer<'_, Infcx, I>
78where
79 Infcx: InferCtxtLike<Interner = I>,
80 I: Interner,
81{
82 fn cx(&self) -> I {
83 self.infcx.cx()
84 }
85
86 fn fold_binder<T: TypeFoldable<I>>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> {
87 self.current_index.shift_in(1);
88 let t = t.super_fold_with(self);
89 self.current_index.shift_out(1);
90 t
91 }
92
93 fn fold_region(&mut self, r: I::Region) -> I::Region {
94 match r.kind() {
95 ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _)
96 if debruijn.as_usize()
97 >= self.current_index.as_usize() + self.universe_indices.len() =>
98 {
99 {
::core::panicking::panic_fmt(format_args!("Bound vars {1:#?} outside of `self.universe_indices`: {0:#?}",
self.universe_indices, r));
};panic!(
100 "Bound vars {r:#?} outside of `self.universe_indices`: {:#?}",
101 self.universe_indices
102 );
103 }
104 ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br)
105 if debruijn >= self.current_index =>
106 {
107 let universe = self.universe_for(debruijn);
108 let p = PlaceholderRegion::new(universe, br);
109 self.mapped_regions.insert(p, br);
110 Region::new_placeholder(self.cx(), p)
111 }
112 _ => r,
113 }
114 }
115
116 fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
117 match t.kind() {
118 ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), _)
119 if debruijn.as_usize() + 1
120 > self.current_index.as_usize() + self.universe_indices.len() =>
121 {
122 {
::core::panicking::panic_fmt(format_args!("Bound vars {1:#?} outside of `self.universe_indices`: {0:#?}",
self.universe_indices, t));
};panic!(
123 "Bound vars {t:#?} outside of `self.universe_indices`: {:#?}",
124 self.universe_indices
125 );
126 }
127 ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_ty)
128 if debruijn >= self.current_index =>
129 {
130 let universe = self.universe_for(debruijn);
131 let p = PlaceholderType::new(universe, bound_ty);
132 self.mapped_types.insert(p, bound_ty);
133 Ty::new_placeholder(self.cx(), p)
134 }
135 _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self),
136 _ => t,
137 }
138 }
139
140 fn fold_const(&mut self, ct: I::Const) -> I::Const {
141 match ct.kind() {
142 ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), _)
143 if debruijn.as_usize() + 1
144 > self.current_index.as_usize() + self.universe_indices.len() =>
145 {
146 {
::core::panicking::panic_fmt(format_args!("Bound vars {1:#?} outside of `self.universe_indices`: {0:#?}",
self.universe_indices, ct));
};panic!(
147 "Bound vars {ct:#?} outside of `self.universe_indices`: {:#?}",
148 self.universe_indices
149 );
150 }
151 ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_const)
152 if debruijn >= self.current_index =>
153 {
154 let universe = self.universe_for(debruijn);
155 let p = PlaceholderConst::new(universe, bound_const);
156 self.mapped_consts.insert(p, bound_const);
157 Const::new_placeholder(self.cx(), p)
158 }
159 _ => ct.super_fold_with(self),
160 }
161 }
162
163 fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
164 if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
165 }
166}