rustc_infer/infer/
freshen.rs
1use 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: Result<Ty<'tcx>, ty::InferTy>, mk_fresh: F) -> Ty<'tcx>
64 where
65 F: FnOnce(u32) -> Ty<'tcx>,
66 {
67 match input {
68 Ok(ty) => ty.fold_with(self),
69 Err(key) => match self.ty_freshen_map.entry(key) {
70 Entry::Occupied(entry) => *entry.get(),
71 Entry::Vacant(entry) => {
72 let index = self.ty_freshen_count;
73 self.ty_freshen_count += 1;
74 let t = mk_fresh(index);
75 entry.insert(t);
76 t
77 }
78 },
79 }
80 }
81
82 fn freshen_const<F>(
83 &mut self,
84 input: Result<ty::Const<'tcx>, ty::InferConst>,
85 freshener: F,
86 ) -> ty::Const<'tcx>
87 where
88 F: FnOnce(u32) -> ty::InferConst,
89 {
90 match input {
91 Ok(ct) => ct.fold_with(self),
92 Err(key) => match self.const_freshen_map.entry(key) {
93 Entry::Occupied(entry) => *entry.get(),
94 Entry::Vacant(entry) => {
95 let index = self.const_freshen_count;
96 self.const_freshen_count += 1;
97 let ct = ty::Const::new_infer(self.infcx.tcx, freshener(index));
98 entry.insert(ct);
99 ct
100 }
101 },
102 }
103 }
104}
105
106impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
107 fn cx(&self) -> TyCtxt<'tcx> {
108 self.infcx.tcx
109 }
110
111 fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
112 match *r {
113 ty::ReBound(..) => {
114 r
116 }
117
118 ty::ReEarlyParam(..)
119 | ty::ReLateParam(_)
120 | ty::ReVar(_)
121 | ty::RePlaceholder(..)
122 | ty::ReStatic
123 | ty::ReError(_)
124 | ty::ReErased => self.cx().lifetimes.re_erased,
125 }
126 }
127
128 #[inline]
129 fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
130 if !t.has_infer() && !t.has_erasable_regions() {
131 t
132 } else {
133 match *t.kind() {
134 ty::Infer(v) => self.fold_infer_ty(v).unwrap_or(t),
135
136 #[cfg(debug_assertions)]
139 ty::Placeholder(..) | ty::Bound(..) => bug!("unexpected type {:?}", t),
140
141 _ => t.super_fold_with(self),
142 }
143 }
144 }
145
146 fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
147 match ct.kind() {
148 ty::ConstKind::Infer(ty::InferConst::Var(v)) => {
149 let mut inner = self.infcx.inner.borrow_mut();
150 let input =
151 inner.const_unification_table().probe_value(v).known().ok_or_else(|| {
152 ty::InferConst::Var(inner.const_unification_table().find(v).vid)
153 });
154 drop(inner);
155 self.freshen_const(input, ty::InferConst::Fresh)
156 }
157 ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => {
158 if i >= self.const_freshen_count {
159 bug!(
160 "Encountered a freshend const with id {} \
161 but our counter is only at {}",
162 i,
163 self.const_freshen_count,
164 );
165 }
166 ct
167 }
168
169 ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
170 bug!("unexpected const {:?}", ct)
171 }
172
173 ty::ConstKind::Param(_)
174 | ty::ConstKind::Value(_)
175 | ty::ConstKind::Unevaluated(..)
176 | ty::ConstKind::Expr(..)
177 | ty::ConstKind::Error(_) => ct.super_fold_with(self),
178 }
179 }
180}
181
182impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
183 #[inline(never)]
185 fn fold_infer_ty(&mut self, v: ty::InferTy) -> Option<Ty<'tcx>> {
186 match v {
187 ty::TyVar(v) => {
188 let mut inner = self.infcx.inner.borrow_mut();
189 let input = inner
190 .type_variables()
191 .probe(v)
192 .known()
193 .ok_or_else(|| ty::TyVar(inner.type_variables().root_var(v)));
194 drop(inner);
195 Some(self.freshen_ty(input, |n| Ty::new_fresh(self.infcx.tcx, n)))
196 }
197
198 ty::IntVar(v) => {
199 let mut inner = self.infcx.inner.borrow_mut();
200 let value = inner.int_unification_table().probe_value(v);
201 let input = match value {
202 ty::IntVarValue::IntType(ty) => Ok(Ty::new_int(self.infcx.tcx, ty)),
203 ty::IntVarValue::UintType(ty) => Ok(Ty::new_uint(self.infcx.tcx, ty)),
204 ty::IntVarValue::Unknown => {
205 Err(ty::IntVar(inner.int_unification_table().find(v)))
206 }
207 };
208 drop(inner);
209 Some(self.freshen_ty(input, |n| Ty::new_fresh_int(self.infcx.tcx, n)))
210 }
211
212 ty::FloatVar(v) => {
213 let mut inner = self.infcx.inner.borrow_mut();
214 let value = inner.float_unification_table().probe_value(v);
215 let input = match value {
216 ty::FloatVarValue::Known(ty) => Ok(Ty::new_float(self.infcx.tcx, ty)),
217 ty::FloatVarValue::Unknown => {
218 Err(ty::FloatVar(inner.float_unification_table().find(v)))
219 }
220 };
221 drop(inner);
222 Some(self.freshen_ty(input, |n| Ty::new_fresh_float(self.infcx.tcx, n)))
223 }
224
225 ty::FreshTy(ct) | ty::FreshIntTy(ct) | ty::FreshFloatTy(ct) => {
226 if ct >= self.ty_freshen_count {
227 bug!(
228 "Encountered a freshend type with id {} \
229 but our counter is only at {}",
230 ct,
231 self.ty_freshen_count
232 );
233 }
234 None
235 }
236 }
237 }
238}