1919//! fact an unbound type variable, we want the match to be regarded as ambiguous, because depending
2020//! on what type that type variable is ultimately assigned, the match may or may not succeed.
2121//!
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+ //!
2228//! Note that you should be careful not to allow the output of freshening to leak to the user in
2329//! error messages or in any other form. Freshening is only really useful as an internal detail.
2430//!
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
2637//! 'erased. The reason behind this is that, in general, we do not take region relationships into
2738//! account when making type-overloaded decisions. This is important because of the design of the
2839//! region inferencer, which is not based on unification but rather on accumulating and then
3344use ty:: { self , Ty , TyCtxt , TypeFoldable } ;
3445use ty:: fold:: TypeFolder ;
3546use util:: nodemap:: FxHashMap ;
47+ use hir:: def_id:: DefId ;
48+
3649use std:: collections:: hash_map:: Entry ;
3750
3851use super :: InferCtxt ;
@@ -42,6 +55,7 @@ pub struct TypeFreshener<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
4255 infcx : & ' a InferCtxt < ' a , ' gcx , ' tcx > ,
4356 freshen_count : u32 ,
4457 freshen_map : FxHashMap < ty:: InferTy , Ty < ' tcx > > ,
58+ closure_set : Vec < DefId > ,
4559}
4660
4761impl < ' a , ' gcx , ' tcx > TypeFreshener < ' a , ' gcx , ' tcx > {
@@ -51,6 +65,7 @@ impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
5165 infcx,
5266 freshen_count : 0 ,
5367 freshen_map : FxHashMap ( ) ,
68+ closure_set : vec ! [ ] ,
5469 }
5570 }
5671
@@ -76,6 +91,16 @@ impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
7691 }
7792 }
7893 }
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+ }
79104}
80105
81106impl < ' 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> {
105130 }
106131
107132 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 ( ) ) {
109135 return t;
110136 }
111137
@@ -150,6 +176,82 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
150176 t
151177 }
152178
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+
153255 ty:: TyBool |
154256 ty:: TyChar |
155257 ty:: TyInt ( ..) |
@@ -165,7 +267,6 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
165267 ty:: TyFnDef ( ..) |
166268 ty:: TyFnPtr ( _) |
167269 ty:: TyDynamic ( ..) |
168- ty:: TyClosure ( ..) |
169270 ty:: TyNever |
170271 ty:: TyTuple ( ..) |
171272 ty:: TyProjection ( ..) |
0 commit comments