rustc_infer/infer/
freshen.rs1use std::collections::hash_map::Entry;
35
36use rustc_data_structures::fx::FxHashMap;
37use rustc_middle::bug;
38use rustc_middle::ty::{
39 self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
40};
41
42use super::InferCtxt;
43
44pub struct TypeFreshener<'a, 'tcx> {
45 infcx: &'a InferCtxt<'tcx>,
46 ty_freshen_count: u32,
47 const_freshen_count: u32,
48 ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
49 const_freshen_map: FxHashMap<ty::InferConst, ty::Const<'tcx>>,
50}
51
52impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
53 pub fn new(infcx: &'a InferCtxt<'tcx>) -> TypeFreshener<'a, 'tcx> {
54 TypeFreshener {
55 infcx,
56 ty_freshen_count: 0,
57 const_freshen_count: 0,
58 ty_freshen_map: Default::default(),
59 const_freshen_map: Default::default(),
60 }
61 }
62
63 fn freshen_ty<F>(&mut self, input: ty::InferTy, mk_fresh: F) -> Ty<'tcx>
64 where
65 F: FnOnce(u32) -> Ty<'tcx>,
66 {
67 match self.ty_freshen_map.entry(input) {
68 Entry::Occupied(entry) => *entry.get(),
69 Entry::Vacant(entry) => {
70 let index = self.ty_freshen_count;
71 self.ty_freshen_count += 1;
72 let t = mk_fresh(index);
73 entry.insert(t);
74 t
75 }
76 }
77 }
78
79 fn freshen_const<F>(&mut self, input: ty::InferConst, freshener: F) -> ty::Const<'tcx>
80 where
81 F: FnOnce(u32) -> ty::InferConst,
82 {
83 match self.const_freshen_map.entry(input) {
84 Entry::Occupied(entry) => *entry.get(),
85 Entry::Vacant(entry) => {
86 let index = self.const_freshen_count;
87 self.const_freshen_count += 1;
88 let ct = ty::Const::new_infer(self.infcx.tcx, freshener(index));
89 entry.insert(ct);
90 ct
91 }
92 }
93 }
94}
95
96impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
97 fn cx(&self) -> TyCtxt<'tcx> {
98 self.infcx.tcx
99 }
100
101 fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
102 match r.kind() {
103 ty::ReBound(..) => r,
105 ty::ReError(_) => r,
107
108 ty::ReEarlyParam(..)
109 | ty::ReLateParam(_)
110 | ty::ReVar(_)
111 | ty::RePlaceholder(..)
112 | ty::ReStatic
113 | ty::ReErased => self.cx().lifetimes.re_erased,
114 }
115 }
116
117 #[inline]
118 fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
119 if !t.has_infer() && !t.has_erasable_regions() {
120 t
121 } else {
122 match *t.kind() {
123 ty::Infer(v) => self.fold_infer_ty(v),
124
125 #[cfg(debug_assertions)]
128 ty::Placeholder(..) | ty::Bound(..) => bug!("unexpected type {:?}", t),
129
130 _ => t.super_fold_with(self),
131 }
132 }
133 }
134
135 fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
136 match ct.kind() {
137 ty::ConstKind::Infer(ty::InferConst::Var(v)) => {
138 let mut inner = self.infcx.inner.borrow_mut();
139 match inner.const_unification_table().probe_value(v).known() {
140 Some(const_) => {
141 drop(inner);
142 const_.fold_with(self)
143 }
144 None => {
145 let input =
146 ty::InferConst::Var(inner.const_unification_table().find(v).vid);
147 self.freshen_const(input, ty::InferConst::Fresh)
148 }
149 }
150 }
151 ty::ConstKind::Infer(ty::InferConst::Fresh(_)) => {
152 bug!("trying to freshen already-freshened const {ct:?}");
153 }
154
155 ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
156 bug!("unexpected const {ct:?}")
157 }
158
159 ty::ConstKind::Param(_)
160 | ty::ConstKind::Value(_)
161 | ty::ConstKind::Unevaluated(..)
162 | ty::ConstKind::Expr(..)
163 | ty::ConstKind::Error(_) => ct.super_fold_with(self),
164 }
165 }
166}
167
168impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
169 #[inline(never)]
171 fn fold_infer_ty(&mut self, ty: ty::InferTy) -> Ty<'tcx> {
172 match ty {
173 ty::TyVar(v) => {
174 let mut inner = self.infcx.inner.borrow_mut();
175 match inner.type_variables().probe(v).known() {
176 Some(ty) => {
177 drop(inner);
178 ty.fold_with(self)
179 }
180 None => {
181 let input = ty::TyVar(inner.type_variables().root_var(v));
182 self.freshen_ty(input, |n| Ty::new_fresh(self.infcx.tcx, n))
183 }
184 }
185 }
186
187 ty::IntVar(v) => {
188 let mut inner = self.infcx.inner.borrow_mut();
189 let value = inner.int_unification_table().probe_value(v);
190 match value {
191 ty::IntVarValue::IntType(ty) => Ty::new_int(self.infcx.tcx, ty),
192 ty::IntVarValue::UintType(ty) => Ty::new_uint(self.infcx.tcx, ty),
193 ty::IntVarValue::Unknown => {
194 let input = ty::IntVar(inner.int_unification_table().find(v));
195 self.freshen_ty(input, |n| Ty::new_fresh_int(self.infcx.tcx, n))
196 }
197 }
198 }
199
200 ty::FloatVar(v) => {
201 let mut inner = self.infcx.inner.borrow_mut();
202 let value = inner.float_unification_table().probe_value(v);
203 match value {
204 ty::FloatVarValue::Known(ty) => Ty::new_float(self.infcx.tcx, ty),
205 ty::FloatVarValue::Unknown => {
206 let input = ty::FloatVar(inner.float_unification_table().find(v));
207 self.freshen_ty(input, |n| Ty::new_fresh_float(self.infcx.tcx, n))
208 }
209 }
210 }
211
212 ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
213 bug!("trying to freshen already-freshened type {ty:?}");
214 }
215 }
216 }
217}