]> git.proxmox.com Git - rustc.git/blame - src/librustc/infer/freshen.rs
New upstream version 1.41.1+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
9fa01778
XL
34use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
35use crate::ty::fold::TypeFolder;
36use crate::util::nodemap::FxHashMap;
3b2f2976 37
9e0c209e 38use std::collections::hash_map::Entry;
1a4d82fc
JJ
39
40use super::InferCtxt;
d9579d0f 41use super::unify_key::ToType;
1a4d82fc 42
dc9dc135
XL
43pub 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
51impl<'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
114impl<'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}