]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | //! Freshening is the process of replacing unknown variables with fresh types. The idea is that |
2 | //! the type, after freshening, contains no inference variables but instead contains either a | |
3 | //! value for each variable or fresh "arbitrary" types wherever a variable would have been. | |
4 | //! | |
5 | //! Freshening is used primarily to get a good type for inserting into a cache. The result | |
6 | //! summarizes what the type inferencer knows "so far". The primary place it is used right now is | |
7 | //! in the trait matching algorithm, which needs to be able to cache whether an `impl` self type | |
8 | //! matches some other type X -- *without* affecting `X`. That means if that if the type `X` is in | |
9 | //! fact an unbound type variable, we want the match to be regarded as ambiguous, because depending | |
10 | //! on what type that type variable is ultimately assigned, the match may or may not succeed. | |
11 | //! | |
3b2f2976 XL |
12 | //! To handle closures, freshened types also have to contain the signature and kind of any |
13 | //! closure in the local inference context, as otherwise the cache key might be invalidated. | |
14 | //! The way this is done is somewhat hacky - the closure signature is appended to the substs, | |
15 | //! as well as the closure kind "encoded" as a type. Also, special handling is needed when | |
16 | //! the closure signature contains a reference to the original closure. | |
17 | //! | |
1a4d82fc JJ |
18 | //! Note that you should be careful not to allow the output of freshening to leak to the user in |
19 | //! error messages or in any other form. Freshening is only really useful as an internal detail. | |
20 | //! | |
3b2f2976 XL |
21 | //! Because of the manipulation required to handle closures, doing arbitrary operations on |
22 | //! freshened types is not recommended. However, in addition to doing equality/hash | |
23 | //! comparisons (for caching), it is possible to do a `ty::_match` operation between | |
24 | //! 2 freshened types - this works even with the closure encoding. | |
25 | //! | |
26 | //! __An important detail concerning regions.__ The freshener also replaces *all* free regions with | |
3157f602 | 27 | //! 'erased. The reason behind this is that, in general, we do not take region relationships into |
1a4d82fc JJ |
28 | //! account when making type-overloaded decisions. This is important because of the design of the |
29 | //! region inferencer, which is not based on unification but rather on accumulating and then | |
30 | //! solving a set of constraints. In contrast, the type inferencer assigns a value to each type | |
31 | //! variable only once, and it does so as soon as it can, so it is reasonable to ask what the type | |
32 | //! inferencer knows "so far". | |
33 | ||
9fa01778 XL |
34 | use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; |
35 | use crate::ty::fold::TypeFolder; | |
36 | use crate::util::nodemap::FxHashMap; | |
3b2f2976 | 37 | |
9e0c209e | 38 | use std::collections::hash_map::Entry; |
1a4d82fc JJ |
39 | |
40 | use super::InferCtxt; | |
d9579d0f | 41 | use super::unify_key::ToType; |
1a4d82fc | 42 | |
dc9dc135 XL |
43 | pub struct TypeFreshener<'a, 'tcx> { |
44 | infcx: &'a InferCtxt<'a, 'tcx>, | |
48663c56 XL |
45 | ty_freshen_count: u32, |
46 | const_freshen_count: u32, | |
47 | ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>, | |
48 | const_freshen_map: FxHashMap<ty::InferConst<'tcx>, &'tcx ty::Const<'tcx>>, | |
1a4d82fc JJ |
49 | } |
50 | ||
dc9dc135 XL |
51 | impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { |
52 | pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> TypeFreshener<'a, 'tcx> { | |
1a4d82fc | 53 | TypeFreshener { |
041b39d2 | 54 | infcx, |
48663c56 XL |
55 | ty_freshen_count: 0, |
56 | const_freshen_count: 0, | |
57 | ty_freshen_map: Default::default(), | |
58 | const_freshen_map: Default::default(), | |
1a4d82fc JJ |
59 | } |
60 | } | |
61 | ||
48663c56 XL |
62 | fn freshen_ty<F>( |
63 | &mut self, | |
64 | opt_ty: Option<Ty<'tcx>>, | |
65 | key: ty::InferTy, | |
66 | freshener: F, | |
67 | ) -> Ty<'tcx> | |
68 | where | |
1a4d82fc JJ |
69 | F: FnOnce(u32) -> ty::InferTy, |
70 | { | |
c30ab7b3 SL |
71 | if let Some(ty) = opt_ty { |
72 | return ty.fold_with(self); | |
1a4d82fc JJ |
73 | } |
74 | ||
48663c56 | 75 | match self.ty_freshen_map.entry(key) { |
1a4d82fc JJ |
76 | Entry::Occupied(entry) => *entry.get(), |
77 | Entry::Vacant(entry) => { | |
48663c56 XL |
78 | let index = self.ty_freshen_count; |
79 | self.ty_freshen_count += 1; | |
80 | let t = self.infcx.tcx.mk_ty_infer(freshener(index)); | |
1a4d82fc JJ |
81 | entry.insert(t); |
82 | t | |
83 | } | |
84 | } | |
85 | } | |
48663c56 XL |
86 | |
87 | fn freshen_const<F>( | |
88 | &mut self, | |
89 | opt_ct: Option<&'tcx ty::Const<'tcx>>, | |
90 | key: ty::InferConst<'tcx>, | |
91 | freshener: F, | |
92 | ty: Ty<'tcx>, | |
93 | ) -> &'tcx ty::Const<'tcx> | |
94 | where | |
95 | F: FnOnce(u32) -> ty::InferConst<'tcx>, | |
96 | { | |
97 | if let Some(ct) = opt_ct { | |
98 | return ct.fold_with(self); | |
99 | } | |
100 | ||
101 | match self.const_freshen_map.entry(key) { | |
102 | Entry::Occupied(entry) => *entry.get(), | |
103 | Entry::Vacant(entry) => { | |
104 | let index = self.const_freshen_count; | |
105 | self.const_freshen_count += 1; | |
106 | let ct = self.infcx.tcx.mk_const_infer(freshener(index), ty); | |
107 | entry.insert(ct); | |
108 | ct | |
109 | } | |
110 | } | |
111 | } | |
1a4d82fc JJ |
112 | } |
113 | ||
dc9dc135 XL |
114 | impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { |
115 | fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { | |
1a4d82fc JJ |
116 | self.infcx.tcx |
117 | } | |
118 | ||
7cac9316 | 119 | fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { |
9e0c209e | 120 | match *r { |
1a4d82fc JJ |
121 | ty::ReLateBound(..) => { |
122 | // leave bound regions alone | |
123 | r | |
124 | } | |
125 | ||
126 | ty::ReStatic | | |
7cac9316 | 127 | ty::ReEarlyBound(..) | |
1a4d82fc JJ |
128 | ty::ReFree(_) | |
129 | ty::ReScope(_) | | |
e9174d1e | 130 | ty::ReVar(_) | |
0bf4aa26 | 131 | ty::RePlaceholder(..) | |
3157f602 XL |
132 | ty::ReEmpty | |
133 | ty::ReErased => { | |
134 | // replace all free regions with 'erased | |
48663c56 | 135 | self.tcx().lifetimes.re_erased |
1a4d82fc | 136 | } |
ff7c6d11 XL |
137 | |
138 | ty::ReClosureBound(..) => { | |
139 | bug!( | |
0531ce1d | 140 | "encountered unexpected region: {:?}", |
ff7c6d11 XL |
141 | r, |
142 | ); | |
143 | } | |
1a4d82fc JJ |
144 | } |
145 | } | |
146 | ||
147 | fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { | |
3b2f2976 XL |
148 | if !t.needs_infer() && !t.has_erasable_regions() && |
149 | !(t.has_closure_types() && self.infcx.in_progress_tables.is_some()) { | |
62682a34 SL |
150 | return t; |
151 | } | |
152 | ||
c34b1796 AL |
153 | let tcx = self.infcx.tcx; |
154 | ||
e74abb32 | 155 | match t.kind { |
b7449926 | 156 | ty::Infer(ty::TyVar(v)) => { |
0531ce1d | 157 | let opt_ty = self.infcx.type_variables.borrow_mut().probe(v).known(); |
48663c56 | 158 | self.freshen_ty( |
54a0048b | 159 | opt_ty, |
c34b1796 AL |
160 | ty::TyVar(v), |
161 | ty::FreshTy) | |
1a4d82fc JJ |
162 | } |
163 | ||
b7449926 | 164 | ty::Infer(ty::IntVar(v)) => { |
48663c56 | 165 | self.freshen_ty( |
c34b1796 | 166 | self.infcx.int_unification_table.borrow_mut() |
0531ce1d | 167 | .probe_value(v) |
c34b1796 AL |
168 | .map(|v| v.to_type(tcx)), |
169 | ty::IntVar(v), | |
170 | ty::FreshIntTy) | |
1a4d82fc JJ |
171 | } |
172 | ||
b7449926 | 173 | ty::Infer(ty::FloatVar(v)) => { |
48663c56 | 174 | self.freshen_ty( |
c34b1796 | 175 | self.infcx.float_unification_table.borrow_mut() |
0531ce1d | 176 | .probe_value(v) |
c34b1796 AL |
177 | .map(|v| v.to_type(tcx)), |
178 | ty::FloatVar(v), | |
d9579d0f | 179 | ty::FreshFloatTy) |
1a4d82fc JJ |
180 | } |
181 | ||
48663c56 XL |
182 | ty::Infer(ty::FreshTy(ct)) | |
183 | ty::Infer(ty::FreshIntTy(ct)) | | |
184 | ty::Infer(ty::FreshFloatTy(ct)) => { | |
185 | if ct >= self.ty_freshen_count { | |
54a0048b SL |
186 | bug!("Encountered a freshend type with id {} \ |
187 | but our counter is only at {}", | |
48663c56 XL |
188 | ct, |
189 | self.ty_freshen_count); | |
1a4d82fc JJ |
190 | } |
191 | t | |
192 | } | |
193 | ||
b7449926 XL |
194 | ty::Generator(..) | |
195 | ty::Bool | | |
196 | ty::Char | | |
197 | ty::Int(..) | | |
198 | ty::Uint(..) | | |
199 | ty::Float(..) | | |
200 | ty::Adt(..) | | |
201 | ty::Str | | |
202 | ty::Error | | |
203 | ty::Array(..) | | |
204 | ty::Slice(..) | | |
205 | ty::RawPtr(..) | | |
206 | ty::Ref(..) | | |
207 | ty::FnDef(..) | | |
208 | ty::FnPtr(_) | | |
209 | ty::Dynamic(..) | | |
210 | ty::Never | | |
211 | ty::Tuple(..) | | |
212 | ty::Projection(..) | | |
0bf4aa26 | 213 | ty::UnnormalizedProjection(..) | |
b7449926 XL |
214 | ty::Foreign(..) | |
215 | ty::Param(..) | | |
216 | ty::Closure(..) | | |
217 | ty::GeneratorWitness(..) | | |
218 | ty::Opaque(..) => { | |
9cc50fc6 | 219 | t.super_fold_with(self) |
1a4d82fc | 220 | } |
a1dfa0c6 XL |
221 | |
222 | ty::Placeholder(..) | | |
223 | ty::Bound(..) => bug!("unexpected type {:?}", t), | |
1a4d82fc JJ |
224 | } |
225 | } | |
48663c56 XL |
226 | |
227 | fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { | |
228 | match ct.val { | |
60c5eb7d | 229 | ty::ConstKind::Infer(ty::InferConst::Var(v)) => { |
48663c56 XL |
230 | let opt_ct = self.infcx.const_unification_table |
231 | .borrow_mut() | |
232 | .probe_value(v) | |
233 | .val | |
234 | .known(); | |
235 | return self.freshen_const( | |
236 | opt_ct, | |
237 | ty::InferConst::Var(v), | |
238 | ty::InferConst::Fresh, | |
239 | ct.ty, | |
240 | ); | |
241 | } | |
60c5eb7d | 242 | ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => { |
48663c56 XL |
243 | if i >= self.const_freshen_count { |
244 | bug!( | |
245 | "Encountered a freshend const with id {} \ | |
246 | but our counter is only at {}", | |
247 | i, | |
248 | self.const_freshen_count, | |
249 | ); | |
250 | } | |
251 | return ct; | |
252 | } | |
253 | ||
60c5eb7d XL |
254 | ty::ConstKind::Bound(..) | |
255 | ty::ConstKind::Placeholder(_) => { | |
48663c56 XL |
256 | bug!("unexpected const {:?}", ct) |
257 | } | |
258 | ||
60c5eb7d XL |
259 | ty::ConstKind::Param(_) | |
260 | ty::ConstKind::Value(_) | | |
261 | ty::ConstKind::Unevaluated(..) => {} | |
48663c56 XL |
262 | } |
263 | ||
264 | ct.super_fold_with(self) | |
265 | } | |
1a4d82fc | 266 | } |