@@ -45,16 +45,14 @@ use super::FnCtxt;
45
45
use middle:: expr_use_visitor as euv;
46
46
use middle:: mem_categorization as mc;
47
47
use middle:: mem_categorization:: Categorization ;
48
+ use rustc:: hir:: def_id:: DefId ;
48
49
use rustc:: ty:: { self , Ty , TyCtxt } ;
49
50
use rustc:: infer:: UpvarRegion ;
50
51
use syntax:: ast;
51
52
use syntax_pos:: Span ;
52
53
use rustc:: hir;
53
54
use rustc:: hir:: def_id:: DefIndex ;
54
55
use rustc:: hir:: intravisit:: { self , NestedVisitorMap , Visitor } ;
55
- use rustc:: util:: nodemap:: FxHashMap ;
56
-
57
- use std:: collections:: hash_map:: Entry ;
58
56
59
57
impl < ' a , ' gcx , ' tcx > FnCtxt < ' a , ' gcx , ' tcx > {
60
58
pub fn closure_analyze ( & self , body : & ' gcx hir:: Body ) {
@@ -98,7 +96,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
98
96
span : Span ,
99
97
body : & hir:: Body ,
100
98
capture_clause : hir:: CaptureClause ,
101
- gen : bool ,
99
+ is_generator : bool ,
102
100
) {
103
101
/*!
104
102
* Analysis starting point.
@@ -110,24 +108,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
110
108
body. id( )
111
109
) ;
112
110
113
- let infer_kind = if gen {
114
- false
115
- } else {
116
- match self . tables
117
- . borrow_mut ( )
118
- . closure_kinds_mut ( )
119
- . entry ( closure_hir_id)
120
- {
121
- Entry :: Occupied ( _) => false ,
122
- Entry :: Vacant ( entry) => {
123
- debug ! ( "check_closure: adding closure {:?} as Fn" , closure_node_id) ;
124
- entry. insert ( ( ty:: ClosureKind :: Fn , None ) ) ;
125
- true
126
- }
111
+ // Extract the type of the closure.
112
+ let ( closure_def_id, closure_substs) = match self . node_ty ( closure_hir_id) . sty {
113
+ ty:: TyClosure ( def_id, substs) | ty:: TyGenerator ( def_id, substs, _) => ( def_id, substs) ,
114
+ ref t => {
115
+ span_bug ! (
116
+ span,
117
+ "type of closure expr {:?} is not a closure {:?}" ,
118
+ closure_node_id,
119
+ t
120
+ ) ;
127
121
}
128
122
} ;
129
123
130
- let closure_def_id = self . tcx . hir . local_def_id ( closure_node_id) ;
124
+ let infer_kind = if is_generator {
125
+ false
126
+ } else {
127
+ self . closure_kind ( closure_def_id, closure_substs) . is_none ( )
128
+ } ;
131
129
132
130
self . tcx
133
131
. with_freevars ( closure_node_id, |freevars| for freevar in freevars {
@@ -156,24 +154,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
156
154
. insert ( upvar_id, capture_kind) ;
157
155
} ) ;
158
156
159
- // Extract the type of the closure.
160
- let ( def_id, closure_substs) = match self . node_ty ( closure_hir_id) . sty {
161
- ty:: TyClosure ( def_id, substs) | ty:: TyGenerator ( def_id, substs, _) => ( def_id, substs) ,
162
- ref t => {
163
- span_bug ! (
164
- span,
165
- "type of closure expr {:?} is not a closure {:?}" ,
166
- closure_node_id,
167
- t
168
- ) ;
169
- }
170
- } ;
171
-
172
157
let body_owner_def_id = self . tcx . hir . body_owner_def_id ( body. id ( ) ) ;
173
158
let region_scope_tree = & self . tcx . region_scope_tree ( body_owner_def_id) ;
174
159
let mut delegate = InferBorrowKind {
175
160
fcx : self ,
176
- adjust_closure_kinds : FxHashMap ( ) ,
161
+ closure_def_id : closure_def_id,
162
+ current_closure_kind : ty:: ClosureKind :: LATTICE_BOTTOM ,
163
+ current_origin : None ,
177
164
adjust_upvar_captures : ty:: UpvarCaptureMap :: default ( ) ,
178
165
} ;
179
166
euv:: ExprUseVisitor :: with_infer (
@@ -184,22 +171,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
184
171
& self . tables . borrow ( ) ,
185
172
) . consume_body ( body) ;
186
173
187
- // Write the adjusted values back into the main tables.
188
174
if infer_kind {
189
- let opt_adjusted = delegate. adjust_closure_kinds . remove ( & closure_def_id. index ) ;
190
- let closure_kind_ty = closure_substs. closure_kind_ty ( def_id, self . tcx ) ;
191
- if let Some ( ( kind, origin) ) = opt_adjusted {
175
+ // Unify the (as yet unbound) type variable in the closure
176
+ // substs with the kind we inferred.
177
+ let inferred_kind = delegate. current_closure_kind ;
178
+ let closure_kind_ty = closure_substs. closure_kind_ty ( closure_def_id, self . tcx ) ;
179
+ self . demand_eqtype ( span, inferred_kind. to_ty ( self . tcx ) , closure_kind_ty) ;
180
+
181
+ // If we have an origin, store it.
182
+ if let Some ( origin) = delegate. current_origin {
192
183
self . tables
193
184
. borrow_mut ( )
194
- . closure_kinds_mut ( )
195
- . insert ( closure_hir_id, ( kind, origin) ) ;
196
-
197
- self . demand_eqtype ( span, kind. to_ty ( self . tcx ) , closure_kind_ty) ;
198
- } else {
199
- // If there are only reads, or no upvars, then the
200
- // default of `Fn` will never *have* to be adjusted, so there will be
201
- // no entry in the map.
202
- self . demand_eqtype ( span, ty:: ClosureKind :: Fn . to_ty ( self . tcx ) , closure_kind_ty) ;
185
+ . closure_kind_origins_mut ( )
186
+ . insert ( closure_hir_id, origin) ;
203
187
}
204
188
}
205
189
@@ -229,19 +213,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
229
213
final_upvar_tys
230
214
) ;
231
215
for ( upvar_ty, final_upvar_ty) in closure_substs
232
- . upvar_tys ( def_id , self . tcx )
216
+ . upvar_tys ( closure_def_id , self . tcx )
233
217
. zip ( final_upvar_tys)
234
218
{
235
219
self . demand_eqtype ( span, final_upvar_ty, upvar_ty) ;
236
220
}
237
221
238
222
// If we are also inferred the closure kind here,
239
223
// process any deferred resolutions.
240
- if infer_kind {
241
- let deferred_call_resolutions = self . remove_deferred_call_resolutions ( closure_def_id) ;
242
- for deferred_call_resolution in deferred_call_resolutions {
243
- deferred_call_resolution. resolve ( self ) ;
244
- }
224
+ let deferred_call_resolutions = self . remove_deferred_call_resolutions ( closure_def_id) ;
225
+ for deferred_call_resolution in deferred_call_resolutions {
226
+ deferred_call_resolution. resolve ( self ) ;
245
227
}
246
228
}
247
229
@@ -293,7 +275,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
293
275
294
276
struct InferBorrowKind < ' a , ' gcx : ' a + ' tcx , ' tcx : ' a > {
295
277
fcx : & ' a FnCtxt < ' a , ' gcx , ' tcx > ,
296
- adjust_closure_kinds : FxHashMap < DefIndex , ( ty:: ClosureKind , Option < ( Span , ast:: Name ) > ) > ,
278
+
279
+ // The def-id of the closure whose kind and upvar accesses are being inferred.
280
+ closure_def_id : DefId ,
281
+
282
+ // The kind that we have inferred that the current closure
283
+ // requires. Note that we *always* infer a minimal kind, even if
284
+ // we don't always *use* that in the final result (i.e., sometimes
285
+ // we've taken the closure kind from the expectations instead, and
286
+ // for generators we don't even implement the closure traits
287
+ // really).
288
+ current_closure_kind : ty:: ClosureKind ,
289
+
290
+ // If we modified `current_closure_kind`, this field contains a `Some()` with the
291
+ // variable access that caused us to do so.
292
+ current_origin : Option < ( Span , ast:: Name ) > ,
293
+
294
+ // For each upvar that we access, we track the minimal kind of
295
+ // access we need (ref, ref mut, move, etc).
297
296
adjust_upvar_captures : ty:: UpvarCaptureMap < ' tcx > ,
298
297
}
299
298
@@ -533,42 +532,36 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
533
532
var_name
534
533
) ;
535
534
536
- let closure_kind = self . adjust_closure_kinds
537
- . get ( & closure_id)
538
- . cloned ( )
539
- . or_else ( || {
540
- let closure_id = self . fcx . tcx . hir . def_index_to_hir_id ( closure_id) ;
541
- self . fcx
542
- . tables
543
- . borrow ( )
544
- . closure_kinds ( )
545
- . get ( closure_id)
546
- . cloned ( )
547
- } ) ;
535
+ // Is this the closure whose kind is currently being inferred?
536
+ if DefId :: local ( closure_id) != self . closure_def_id {
537
+ debug ! ( "adjust_closure_kind: not current closure" ) ;
538
+ return ;
539
+ }
548
540
549
- if let Some ( ( existing_kind, _) ) = closure_kind {
550
- debug ! (
551
- "adjust_closure_kind: closure_id={:?}, existing_kind={:?}, new_kind={:?}" ,
552
- closure_id,
553
- existing_kind,
554
- new_kind
555
- ) ;
556
-
557
- match ( existing_kind, new_kind) {
558
- ( ty:: ClosureKind :: Fn , ty:: ClosureKind :: Fn ) |
559
- ( ty:: ClosureKind :: FnMut , ty:: ClosureKind :: Fn ) |
560
- ( ty:: ClosureKind :: FnMut , ty:: ClosureKind :: FnMut ) |
561
- ( ty:: ClosureKind :: FnOnce , _) => {
562
- // no change needed
563
- }
541
+ // closures start out as `Fn`.
542
+ let existing_kind = self . current_closure_kind ;
564
543
565
- ( ty:: ClosureKind :: Fn , ty:: ClosureKind :: FnMut ) |
566
- ( ty:: ClosureKind :: Fn , ty:: ClosureKind :: FnOnce ) |
567
- ( ty:: ClosureKind :: FnMut , ty:: ClosureKind :: FnOnce ) => {
568
- // new kind is stronger than the old kind
569
- self . adjust_closure_kinds
570
- . insert ( closure_id, ( new_kind, Some ( ( upvar_span, var_name) ) ) ) ;
571
- }
544
+ debug ! (
545
+ "adjust_closure_kind: closure_id={:?}, existing_kind={:?}, new_kind={:?}" ,
546
+ closure_id,
547
+ existing_kind,
548
+ new_kind
549
+ ) ;
550
+
551
+ match ( existing_kind, new_kind) {
552
+ ( ty:: ClosureKind :: Fn , ty:: ClosureKind :: Fn ) |
553
+ ( ty:: ClosureKind :: FnMut , ty:: ClosureKind :: Fn ) |
554
+ ( ty:: ClosureKind :: FnMut , ty:: ClosureKind :: FnMut ) |
555
+ ( ty:: ClosureKind :: FnOnce , _) => {
556
+ // no change needed
557
+ }
558
+
559
+ ( ty:: ClosureKind :: Fn , ty:: ClosureKind :: FnMut ) |
560
+ ( ty:: ClosureKind :: Fn , ty:: ClosureKind :: FnOnce ) |
561
+ ( ty:: ClosureKind :: FnMut , ty:: ClosureKind :: FnOnce ) => {
562
+ // new kind is stronger than the old kind
563
+ self . current_closure_kind = new_kind;
564
+ self . current_origin = Some ( ( upvar_span, var_name) ) ;
572
565
}
573
566
}
574
567
}
0 commit comments