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
3243
3344use ty:: { self , Ty , TyCtxt , TypeFoldable } ;
3445use ty:: fold:: TypeFolder ;
46+ use ty:: subst:: Substs ;
3547use util:: nodemap:: FxHashMap ;
48+ use hir:: def_id:: DefId ;
49+
3650use std:: collections:: hash_map:: Entry ;
3751
3852use super :: InferCtxt ;
@@ -42,6 +56,7 @@ pub struct TypeFreshener<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
4256 infcx : & ' a InferCtxt < ' a , ' gcx , ' tcx > ,
4357 freshen_count : u32 ,
4458 freshen_map : FxHashMap < ty:: InferTy , Ty < ' tcx > > ,
59+ closure_set : Vec < DefId > ,
4560}
4661
4762impl < ' a , ' gcx , ' tcx > TypeFreshener < ' a , ' gcx , ' tcx > {
@@ -51,6 +66,7 @@ impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
5166 infcx,
5267 freshen_count : 0 ,
5368 freshen_map : FxHashMap ( ) ,
69+ closure_set : vec ! [ ] ,
5470 }
5571 }
5672
@@ -76,6 +92,88 @@ impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
7692 }
7793 }
7894 }
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+ }
79177}
80178
81179impl < ' 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> {
105203 }
106204
107205 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 ( ) ) {
109208 return t;
110209 }
111210
@@ -150,6 +249,51 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
150249 t
151250 }
152251
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+
153297 ty:: TyBool |
154298 ty:: TyChar |
155299 ty:: TyInt ( ..) |
@@ -165,8 +309,6 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
165309 ty:: TyFnDef ( ..) |
166310 ty:: TyFnPtr ( _) |
167311 ty:: TyDynamic ( ..) |
168- ty:: TyClosure ( ..) |
169- ty:: TyGenerator ( ..) |
170312 ty:: TyNever |
171313 ty:: TyTuple ( ..) |
172314 ty:: TyProjection ( ..) |
0 commit comments