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
32
43
33
44
use ty:: { self , Ty , TyCtxt , TypeFoldable } ;
34
45
use ty:: fold:: TypeFolder ;
46
+ use ty:: subst:: Substs ;
35
47
use util:: nodemap:: FxHashMap ;
48
+ use hir:: def_id:: DefId ;
49
+
36
50
use std:: collections:: hash_map:: Entry ;
37
51
38
52
use super :: InferCtxt ;
@@ -42,6 +56,7 @@ pub struct TypeFreshener<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
42
56
infcx : & ' a InferCtxt < ' a , ' gcx , ' tcx > ,
43
57
freshen_count : u32 ,
44
58
freshen_map : FxHashMap < ty:: InferTy , Ty < ' tcx > > ,
59
+ closure_set : Vec < DefId > ,
45
60
}
46
61
47
62
impl < ' a , ' gcx , ' tcx > TypeFreshener < ' a , ' gcx , ' tcx > {
@@ -51,6 +66,7 @@ impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
51
66
infcx,
52
67
freshen_count : 0 ,
53
68
freshen_map : FxHashMap ( ) ,
69
+ closure_set : vec ! [ ] ,
54
70
}
55
71
}
56
72
@@ -76,6 +92,88 @@ impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
76
92
}
77
93
}
78
94
}
95
+
96
+ fn next_fresh < F > ( & mut self ,
97
+ freshener : F )
98
+ -> Ty < ' tcx >
99
+ where F : FnOnce ( u32 ) -> ty:: InferTy ,
100
+ {
101
+ let index = self . freshen_count ;
102
+ self . freshen_count += 1 ;
103
+ self . infcx . tcx . mk_infer ( freshener ( index) )
104
+ }
105
+
106
+ fn freshen_closure_like < M , C > ( & mut self ,
107
+ def_id : DefId ,
108
+ substs : ty:: ClosureSubsts < ' tcx > ,
109
+ t : Ty < ' tcx > ,
110
+ markers : M ,
111
+ combine : C )
112
+ -> Ty < ' tcx >
113
+ where M : FnOnce ( & mut Self ) -> ( Ty < ' tcx > , Ty < ' tcx > ) ,
114
+ C : FnOnce ( & ' tcx Substs < ' tcx > ) -> Ty < ' tcx >
115
+ {
116
+ let tcx = self . infcx . tcx ;
117
+
118
+ let closure_in_progress = self . infcx . in_progress_tables . map_or ( false , |tables| {
119
+ tcx. hir . as_local_node_id ( def_id) . map_or ( false , |closure_id| {
120
+ tables. borrow ( ) . local_id_root ==
121
+ Some ( DefId :: local ( tcx. hir . node_to_hir_id ( closure_id) . owner ) )
122
+ } )
123
+ } ) ;
124
+
125
+ if !closure_in_progress {
126
+ // If this closure belongs to another infcx, its kind etc. were
127
+ // fully inferred and its signature/kind are exactly what's listed
128
+ // in its infcx. So we don't need to add the markers for them.
129
+ return t. super_fold_with ( self ) ;
130
+ }
131
+
132
+ // We are encoding a closure in progress. Because we want our freshening
133
+ // key to contain all inference information needed to make sense of our
134
+ // value, we need to encode the closure signature and kind. The way
135
+ // we do that is to add them as 2 variables to the closure substs,
136
+ // basically because it's there (and nobody cares about adding extra stuff
137
+ // to substs).
138
+ //
139
+ // This means the "freshened" closure substs ends up looking like
140
+ // fresh_substs = [PARENT_SUBSTS* ; UPVARS* ; SIG_MARKER ; KIND_MARKER]
141
+ let ( marker_1, marker_2) = if self . closure_set . contains ( & def_id) {
142
+ // We found the closure def-id within its own signature. Just
143
+ // leave a new freshened type - any matching operations would
144
+ // have found and compared the exterior closure already to
145
+ // get here.
146
+ //
147
+ // In that case, we already know what the signature would
148
+ // be - the parent closure on the stack already contains a
149
+ // "copy" of the signature, so there is no reason to encode
150
+ // it again for injectivity. Just use a fresh type variable
151
+ // to make everything comparable.
152
+ //
153
+ // For example (closure kinds omitted for clarity)
154
+ // t=[closure FOO sig=[closure BAR sig=[closure FOO ..]]]
155
+ // Would get encoded to
156
+ // t=[closure FOO sig=[closure BAR sig=[closure FOO sig=$0]]]
157
+ //
158
+ // and we can decode by having
159
+ // $0=[closure BAR {sig doesn't exist in decode}]
160
+ // and get
161
+ // t=[closure FOO]
162
+ // sig[FOO] = [closure BAR]
163
+ // sig[BAR] = [closure FOO]
164
+ ( self . next_fresh ( ty:: FreshTy ) , self . next_fresh ( ty:: FreshTy ) )
165
+ } else {
166
+ self . closure_set . push ( def_id) ;
167
+ let markers = markers ( self ) ;
168
+ self . closure_set . pop ( ) ;
169
+ markers
170
+ } ;
171
+
172
+ combine ( tcx. mk_substs (
173
+ substs. substs . iter ( ) . map ( |k| k. fold_with ( self ) ) . chain (
174
+ [ marker_1, marker_2] . iter ( ) . cloned ( ) . map ( From :: from)
175
+ ) ) )
176
+ }
79
177
}
80
178
81
179
impl < ' a , ' gcx , ' tcx > TypeFolder < ' gcx , ' tcx > for TypeFreshener < ' a , ' gcx , ' tcx > {
@@ -105,7 +203,8 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
105
203
}
106
204
107
205
fn fold_ty ( & mut self , t : Ty < ' tcx > ) -> Ty < ' tcx > {
108
- if !t. needs_infer ( ) && !t. has_erasable_regions ( ) {
206
+ if !t. needs_infer ( ) && !t. has_erasable_regions ( ) &&
207
+ !( t. has_closure_types ( ) && self . infcx . in_progress_tables . is_some ( ) ) {
109
208
return t;
110
209
}
111
210
@@ -150,6 +249,51 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
150
249
t
151
250
}
152
251
252
+ ty:: TyClosure ( def_id, substs) => {
253
+ self . freshen_closure_like (
254
+ def_id, substs, t,
255
+ |this| {
256
+ // HACK: use a "random" integer type to mark the kind. Because
257
+ // different closure kinds shouldn't get unified during
258
+ // selection, the "subtyping" relationship (where any kind is
259
+ // better than no kind) shouldn't matter here, just that the
260
+ // types are different.
261
+ let closure_kind = this. infcx . closure_kind ( def_id) ;
262
+ let closure_kind_marker = match closure_kind {
263
+ None => tcx. types . i8 ,
264
+ Some ( ty:: ClosureKind :: Fn ) => tcx. types . i16 ,
265
+ Some ( ty:: ClosureKind :: FnMut ) => tcx. types . i32 ,
266
+ Some ( ty:: ClosureKind :: FnOnce ) => tcx. types . i64 ,
267
+ } ;
268
+
269
+ let closure_sig = this. infcx . fn_sig ( def_id) ;
270
+ ( tcx. mk_fn_ptr ( closure_sig. fold_with ( this) ) ,
271
+ closure_kind_marker)
272
+ } ,
273
+ |substs| tcx. mk_closure ( def_id, substs)
274
+ )
275
+ }
276
+
277
+ ty:: TyGenerator ( def_id, substs, interior) => {
278
+ self . freshen_closure_like (
279
+ def_id, substs, t,
280
+ |this| {
281
+ let gen_sig = this. infcx . generator_sig ( def_id) . unwrap ( ) ;
282
+ // FIXME: want to revise this strategy when generator
283
+ // signatures can actually contain LBRs.
284
+ let sig = this. tcx ( ) . no_late_bound_regions ( & gen_sig)
285
+ . unwrap_or_else ( || {
286
+ bug ! ( "late-bound regions in signature of {:?}" ,
287
+ def_id)
288
+ } ) ;
289
+ ( sig. yield_ty , sig. return_ty ) . fold_with ( this)
290
+ } ,
291
+ |substs| {
292
+ tcx. mk_generator ( def_id, ty:: ClosureSubsts { substs } , interior)
293
+ }
294
+ )
295
+ }
296
+
153
297
ty:: TyBool |
154
298
ty:: TyChar |
155
299
ty:: TyInt ( ..) |
@@ -165,8 +309,6 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
165
309
ty:: TyFnDef ( ..) |
166
310
ty:: TyFnPtr ( _) |
167
311
ty:: TyDynamic ( ..) |
168
- ty:: TyClosure ( ..) |
169
- ty:: TyGenerator ( ..) |
170
312
ty:: TyNever |
171
313
ty:: TyTuple ( ..) |
172
314
ty:: TyProjection ( ..) |
0 commit comments