19
19
//! fact an unbound type variable, we want the match to be regarded as ambiguous, because depending
20
20
//! on what type that type variable is ultimately assigned, the match may or may not succeed.
21
21
//!
22
+ //! To handle closures, freshened types also have to contain the signature and kind of any
23
+ //! closure in the local inference context, as otherwise the cache key might be invalidated.
24
+ //! The way this is done is somewhat hacky - the closure signature is appended to the substs,
25
+ //! as well as the closure kind "encoded" as a type. Also, special handling is needed when
26
+ //! the closure signature contains a reference to the original closure.
27
+ //!
22
28
//! Note that you should be careful not to allow the output of freshening to leak to the user in
23
29
//! error messages or in any other form. Freshening is only really useful as an internal detail.
24
30
//!
25
- //! __An important detail concerning regions.__ The freshener also replaces *all* regions with
31
+ //! Because of the manipulation required to handle closures, doing arbitrary operations on
32
+ //! freshened types is not recommended. However, in addition to doing equality/hash
33
+ //! comparisons (for caching), it is possible to do a `ty::_match` operation between
34
+ //! 2 freshened types - this works even with the closure encoding.
35
+ //!
36
+ //! __An important detail concerning regions.__ The freshener also replaces *all* free regions with
26
37
//! 'erased. The reason behind this is that, in general, we do not take region relationships into
27
38
//! account when making type-overloaded decisions. This is important because of the design of the
28
39
//! region inferencer, which is not based on unification but rather on accumulating and then
33
44
use ty:: { self , Ty , TyCtxt , TypeFoldable } ;
34
45
use ty:: fold:: TypeFolder ;
35
46
use util:: nodemap:: FxHashMap ;
47
+ use hir:: def_id:: DefId ;
48
+
36
49
use std:: collections:: hash_map:: Entry ;
37
50
38
51
use super :: InferCtxt ;
@@ -42,6 +55,7 @@ pub struct TypeFreshener<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
42
55
infcx : & ' a InferCtxt < ' a , ' gcx , ' tcx > ,
43
56
freshen_count : u32 ,
44
57
freshen_map : FxHashMap < ty:: InferTy , Ty < ' tcx > > ,
58
+ closure_set : Vec < DefId > ,
45
59
}
46
60
47
61
impl < ' a , ' gcx , ' tcx > TypeFreshener < ' a , ' gcx , ' tcx > {
@@ -51,6 +65,7 @@ impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
51
65
infcx,
52
66
freshen_count : 0 ,
53
67
freshen_map : FxHashMap ( ) ,
68
+ closure_set : vec ! [ ] ,
54
69
}
55
70
}
56
71
@@ -76,6 +91,16 @@ impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
76
91
}
77
92
}
78
93
}
94
+
95
+ fn next_fresh < F > ( & mut self ,
96
+ freshener : F )
97
+ -> Ty < ' tcx >
98
+ where F : FnOnce ( u32 ) -> ty:: InferTy ,
99
+ {
100
+ let index = self . freshen_count ;
101
+ self . freshen_count += 1 ;
102
+ self . infcx . tcx . mk_infer ( freshener ( index) )
103
+ }
79
104
}
80
105
81
106
impl < ' a , ' gcx , ' tcx > TypeFolder < ' gcx , ' tcx > for TypeFreshener < ' a , ' gcx , ' tcx > {
@@ -105,7 +130,8 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
105
130
}
106
131
107
132
fn fold_ty ( & mut self , t : Ty < ' tcx > ) -> Ty < ' tcx > {
108
- if !t. needs_infer ( ) && !t. has_erasable_regions ( ) {
133
+ if !t. needs_infer ( ) && !t. has_erasable_regions ( ) &&
134
+ !( t. has_closure_types ( ) && self . infcx . in_progress_tables . is_some ( ) ) {
109
135
return t;
110
136
}
111
137
@@ -150,6 +176,82 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
150
176
t
151
177
}
152
178
179
+ ty:: TyClosure ( def_id, substs) => {
180
+ let closure_in_progress = self . infcx . in_progress_tables . map_or ( false , |tables| {
181
+ tcx. hir . as_local_node_id ( def_id) . map_or ( false , |closure_id| {
182
+ tables. borrow ( ) . local_id_root ==
183
+ Some ( DefId :: local ( tcx. hir . node_to_hir_id ( closure_id) . owner ) )
184
+ } )
185
+ } ) ;
186
+
187
+ if !closure_in_progress {
188
+ // If this closure belongs to another infcx, its kind etc. were
189
+ // fully inferred and its signature/kind are exactly what's listed
190
+ // in its infcx. So we don't need to add the markers for them.
191
+ return t. super_fold_with ( self ) ;
192
+ }
193
+
194
+ // We are encoding a closure in progress. Because we want our freshening
195
+ // key to contain all inference information needed to make sense of our
196
+ // value, we need to encode the closure signature and kind. The way
197
+ // we do that is to add them as 2 variables to the closure substs,
198
+ // basically because it's there (and nobody cares about adding extra stuff
199
+ // to substs).
200
+ //
201
+ // This means the "freshened" closure substs ends up looking like
202
+ // fresh_substs = [PARENT_SUBSTS* ; UPVARS* ; SIG_MARKER ; KIND_MARKER]
203
+
204
+ let closure_sig_marker = if self . closure_set . contains ( & def_id) {
205
+ // We found the closure def-id within its own signature. Just
206
+ // leave a new freshened type - any matching operations would
207
+ // have found and compared the exterior closure already to
208
+ // get here.
209
+ //
210
+ // In that case, we already know what the signature would
211
+ // be - the parent closure on the stack already contains a
212
+ // "copy" of the signature, so there is no reason to encode
213
+ // it again for injectivity. Just use a fresh type variable
214
+ // to make everything comparable.
215
+ //
216
+ // For example (closure kinds omitted for clarity)
217
+ // t=[closure FOO sig=[closure BAR sig=[closure FOO ..]]]
218
+ // Would get encoded to
219
+ // t=[closure FOO sig=[closure BAR sig=[closure FOO sig=$0]]]
220
+ //
221
+ // and we can decode by having
222
+ // $0=[closure BAR {sig doesn't exist in decode}]
223
+ // and get
224
+ // t=[closure FOO]
225
+ // sig[FOO] = [closure BAR]
226
+ // sig[BAR] = [closure FOO]
227
+ self . next_fresh ( ty:: FreshTy )
228
+ } else {
229
+ self . closure_set . push ( def_id) ;
230
+ let closure_sig = self . infcx . fn_sig ( def_id) ;
231
+ let closure_sig_marker = tcx. mk_fn_ptr ( closure_sig. fold_with ( self ) ) ;
232
+ self . closure_set . pop ( ) ;
233
+ closure_sig_marker
234
+ } ;
235
+
236
+ // HACK: use a "random" integer type to mark the kind. Because different
237
+ // closure kinds shouldn't get unified during selection, the "subtyping"
238
+ // relationship (where any kind is better than no kind) shouldn't
239
+ // matter here, just that the types are different.
240
+ let closure_kind = self . infcx . closure_kind ( def_id) ;
241
+ let closure_kind_marker = match closure_kind {
242
+ None => tcx. types . i8 ,
243
+ Some ( ty:: ClosureKind :: Fn ) => tcx. types . i16 ,
244
+ Some ( ty:: ClosureKind :: FnMut ) => tcx. types . i32 ,
245
+ Some ( ty:: ClosureKind :: FnOnce ) => tcx. types . i64 ,
246
+ } ;
247
+
248
+ let params = tcx. mk_substs (
249
+ substs. substs . iter ( ) . map ( |k| k. fold_with ( self ) ) . chain (
250
+ [ closure_sig_marker, closure_kind_marker] . iter ( ) . cloned ( ) . map ( From :: from)
251
+ ) ) ;
252
+ tcx. mk_closure ( def_id, params)
253
+ }
254
+
153
255
ty:: TyBool |
154
256
ty:: TyChar |
155
257
ty:: TyInt ( ..) |
@@ -165,7 +267,6 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
165
267
ty:: TyFnDef ( ..) |
166
268
ty:: TyFnPtr ( _) |
167
269
ty:: TyDynamic ( ..) |
168
- ty:: TyClosure ( ..) |
169
270
ty:: TyNever |
170
271
ty:: TyTuple ( ..) |
171
272
ty:: TyProjection ( ..) |
0 commit comments