]> git.proxmox.com Git - rustc.git/blame - src/librustc/infer/freshen.rs
New upstream version 1.40.0+dfsg1
[rustc.git] / src / librustc / infer / freshen.rs
CommitLineData
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
48663c56 34use crate::mir::interpret::ConstValue;
9fa01778
XL
35use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
36use crate::ty::fold::TypeFolder;
37use crate::util::nodemap::FxHashMap;
3b2f2976 38
9e0c209e 39use std::collections::hash_map::Entry;
1a4d82fc
JJ
40
41use super::InferCtxt;
d9579d0f 42use super::unify_key::ToType;
1a4d82fc 43
dc9dc135
XL
44pub struct TypeFreshener<'a, 'tcx> {
45 infcx: &'a InferCtxt<'a, 'tcx>,
48663c56
XL
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<'tcx>, &'tcx ty::Const<'tcx>>,
1a4d82fc
JJ
50}
51
dc9dc135
XL
52impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
53 pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> TypeFreshener<'a, 'tcx> {
1a4d82fc 54 TypeFreshener {
041b39d2 55 infcx,
48663c56
XL
56 ty_freshen_count: 0,
57 const_freshen_count: 0,
58 ty_freshen_map: Default::default(),
59 const_freshen_map: Default::default(),
1a4d82fc
JJ
60 }
61 }
62
48663c56
XL
63 fn freshen_ty<F>(
64 &mut self,
65 opt_ty: Option<Ty<'tcx>>,
66 key: ty::InferTy,
67 freshener: F,
68 ) -> Ty<'tcx>
69 where
1a4d82fc
JJ
70 F: FnOnce(u32) -> ty::InferTy,
71 {
c30ab7b3
SL
72 if let Some(ty) = opt_ty {
73 return ty.fold_with(self);
1a4d82fc
JJ
74 }
75
48663c56 76 match self.ty_freshen_map.entry(key) {
1a4d82fc
JJ
77 Entry::Occupied(entry) => *entry.get(),
78 Entry::Vacant(entry) => {
48663c56
XL
79 let index = self.ty_freshen_count;
80 self.ty_freshen_count += 1;
81 let t = self.infcx.tcx.mk_ty_infer(freshener(index));
1a4d82fc
JJ
82 entry.insert(t);
83 t
84 }
85 }
86 }
48663c56
XL
87
88 fn freshen_const<F>(
89 &mut self,
90 opt_ct: Option<&'tcx ty::Const<'tcx>>,
91 key: ty::InferConst<'tcx>,
92 freshener: F,
93 ty: Ty<'tcx>,
94 ) -> &'tcx ty::Const<'tcx>
95 where
96 F: FnOnce(u32) -> ty::InferConst<'tcx>,
97 {
98 if let Some(ct) = opt_ct {
99 return ct.fold_with(self);
100 }
101
102 match self.const_freshen_map.entry(key) {
103 Entry::Occupied(entry) => *entry.get(),
104 Entry::Vacant(entry) => {
105 let index = self.const_freshen_count;
106 self.const_freshen_count += 1;
107 let ct = self.infcx.tcx.mk_const_infer(freshener(index), ty);
108 entry.insert(ct);
109 ct
110 }
111 }
112 }
1a4d82fc
JJ
113}
114
dc9dc135
XL
115impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
116 fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
1a4d82fc
JJ
117 self.infcx.tcx
118 }
119
7cac9316 120 fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
9e0c209e 121 match *r {
1a4d82fc
JJ
122 ty::ReLateBound(..) => {
123 // leave bound regions alone
124 r
125 }
126
127 ty::ReStatic |
7cac9316 128 ty::ReEarlyBound(..) |
1a4d82fc
JJ
129 ty::ReFree(_) |
130 ty::ReScope(_) |
e9174d1e 131 ty::ReVar(_) |
0bf4aa26 132 ty::RePlaceholder(..) |
3157f602
XL
133 ty::ReEmpty |
134 ty::ReErased => {
135 // replace all free regions with 'erased
48663c56 136 self.tcx().lifetimes.re_erased
1a4d82fc 137 }
ff7c6d11
XL
138
139 ty::ReClosureBound(..) => {
140 bug!(
0531ce1d 141 "encountered unexpected region: {:?}",
ff7c6d11
XL
142 r,
143 );
144 }
1a4d82fc
JJ
145 }
146 }
147
148 fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
3b2f2976
XL
149 if !t.needs_infer() && !t.has_erasable_regions() &&
150 !(t.has_closure_types() && self.infcx.in_progress_tables.is_some()) {
62682a34
SL
151 return t;
152 }
153
c34b1796
AL
154 let tcx = self.infcx.tcx;
155
e74abb32 156 match t.kind {
b7449926 157 ty::Infer(ty::TyVar(v)) => {
0531ce1d 158 let opt_ty = self.infcx.type_variables.borrow_mut().probe(v).known();
48663c56 159 self.freshen_ty(
54a0048b 160 opt_ty,
c34b1796
AL
161 ty::TyVar(v),
162 ty::FreshTy)
1a4d82fc
JJ
163 }
164
b7449926 165 ty::Infer(ty::IntVar(v)) => {
48663c56 166 self.freshen_ty(
c34b1796 167 self.infcx.int_unification_table.borrow_mut()
0531ce1d 168 .probe_value(v)
c34b1796
AL
169 .map(|v| v.to_type(tcx)),
170 ty::IntVar(v),
171 ty::FreshIntTy)
1a4d82fc
JJ
172 }
173
b7449926 174 ty::Infer(ty::FloatVar(v)) => {
48663c56 175 self.freshen_ty(
c34b1796 176 self.infcx.float_unification_table.borrow_mut()
0531ce1d 177 .probe_value(v)
c34b1796
AL
178 .map(|v| v.to_type(tcx)),
179 ty::FloatVar(v),
d9579d0f 180 ty::FreshFloatTy)
1a4d82fc
JJ
181 }
182
48663c56
XL
183 ty::Infer(ty::FreshTy(ct)) |
184 ty::Infer(ty::FreshIntTy(ct)) |
185 ty::Infer(ty::FreshFloatTy(ct)) => {
186 if ct >= self.ty_freshen_count {
54a0048b
SL
187 bug!("Encountered a freshend type with id {} \
188 but our counter is only at {}",
48663c56
XL
189 ct,
190 self.ty_freshen_count);
1a4d82fc
JJ
191 }
192 t
193 }
194
b7449926
XL
195 ty::Generator(..) |
196 ty::Bool |
197 ty::Char |
198 ty::Int(..) |
199 ty::Uint(..) |
200 ty::Float(..) |
201 ty::Adt(..) |
202 ty::Str |
203 ty::Error |
204 ty::Array(..) |
205 ty::Slice(..) |
206 ty::RawPtr(..) |
207 ty::Ref(..) |
208 ty::FnDef(..) |
209 ty::FnPtr(_) |
210 ty::Dynamic(..) |
211 ty::Never |
212 ty::Tuple(..) |
213 ty::Projection(..) |
0bf4aa26 214 ty::UnnormalizedProjection(..) |
b7449926
XL
215 ty::Foreign(..) |
216 ty::Param(..) |
217 ty::Closure(..) |
218 ty::GeneratorWitness(..) |
219 ty::Opaque(..) => {
9cc50fc6 220 t.super_fold_with(self)
1a4d82fc 221 }
a1dfa0c6
XL
222
223 ty::Placeholder(..) |
224 ty::Bound(..) => bug!("unexpected type {:?}", t),
1a4d82fc
JJ
225 }
226 }
48663c56
XL
227
228 fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
229 match ct.val {
230 ConstValue::Infer(ty::InferConst::Var(v)) => {
231 let opt_ct = self.infcx.const_unification_table
232 .borrow_mut()
233 .probe_value(v)
234 .val
235 .known();
236 return self.freshen_const(
237 opt_ct,
238 ty::InferConst::Var(v),
239 ty::InferConst::Fresh,
240 ct.ty,
241 );
242 }
243 ConstValue::Infer(ty::InferConst::Fresh(i)) => {
244 if i >= self.const_freshen_count {
245 bug!(
246 "Encountered a freshend const with id {} \
247 but our counter is only at {}",
248 i,
249 self.const_freshen_count,
250 );
251 }
252 return ct;
253 }
254
e74abb32 255 ConstValue::Bound(..) |
48663c56
XL
256 ConstValue::Placeholder(_) => {
257 bug!("unexpected const {:?}", ct)
258 }
259
260 ConstValue::Param(_) |
261 ConstValue::Scalar(_) |
dc9dc135
XL
262 ConstValue::Slice { .. } |
263 ConstValue::ByRef { .. } |
48663c56
XL
264 ConstValue::Unevaluated(..) => {}
265 }
266
267 ct.super_fold_with(self)
268 }
1a4d82fc 269}