@@ -40,7 +40,7 @@ use rustc_hir::def_id::LocalDefId;
40
40
use rustc_hir:: intravisit:: { self , NestedVisitorMap , Visitor } ;
41
41
use rustc_infer:: infer:: UpvarRegion ;
42
42
use rustc_middle:: hir:: place:: { Place , PlaceBase , PlaceWithHirId , ProjectionKind } ;
43
- use rustc_middle:: ty:: { self , Ty , TyCtxt , UpvarSubsts } ;
43
+ use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeckResults , UpvarSubsts } ;
44
44
use rustc_span:: sym;
45
45
use rustc_span:: { MultiSpan , Span , Symbol } ;
46
46
@@ -55,6 +55,11 @@ enum PlaceAncestryRelation {
55
55
Divergent ,
56
56
}
57
57
58
+ /// Intermediate format to store a captured `Place` and associated `ty::CaptureInfo`
59
+ /// during capture analysis. Information in this map feeds into the minimum capture
60
+ /// analysis pass.
61
+ type InferredCaptureInformation < ' tcx > = FxIndexMap < Place < ' tcx > , ty:: CaptureInfo < ' tcx > > ;
62
+
58
63
impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
59
64
pub fn closure_analyze ( & self , body : & ' tcx hir:: Body < ' tcx > ) {
60
65
InferBorrowKindVisitor { fcx : self } . visit_body ( body) ;
@@ -124,28 +129,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
124
129
125
130
let local_def_id = closure_def_id. expect_local ( ) ;
126
131
127
- let mut capture_information: FxIndexMap < Place < ' tcx > , ty:: CaptureInfo < ' tcx > > =
128
- Default :: default ( ) ;
129
- if !self . tcx . features ( ) . capture_disjoint_fields {
130
- if let Some ( upvars) = self . tcx . upvars_mentioned ( closure_def_id) {
131
- for ( & var_hir_id, _) in upvars. iter ( ) {
132
- let place = self . place_for_root_variable ( local_def_id, var_hir_id) ;
133
-
134
- debug ! ( "seed place {:?}" , place) ;
135
-
136
- let upvar_id = ty:: UpvarId :: new ( var_hir_id, local_def_id) ;
137
- let capture_kind = self . init_capture_kind ( capture_clause, upvar_id, span) ;
138
- let info = ty:: CaptureInfo {
139
- capture_kind_expr_id : None ,
140
- path_expr_id : None ,
141
- capture_kind,
142
- } ;
143
-
144
- capture_information. insert ( place, info) ;
145
- }
146
- }
147
- }
148
-
149
132
let body_owner_def_id = self . tcx . hir ( ) . body_owner_def_id ( body. id ( ) ) ;
150
133
assert_eq ! ( body_owner_def_id. to_def_id( ) , closure_def_id) ;
151
134
let mut delegate = InferBorrowKind {
@@ -155,7 +138,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
155
138
capture_clause,
156
139
current_closure_kind : ty:: ClosureKind :: LATTICE_BOTTOM ,
157
140
current_origin : None ,
158
- capture_information,
141
+ capture_information : Default :: default ( ) ,
159
142
} ;
160
143
euv:: ExprUseVisitor :: new (
161
144
& mut delegate,
@@ -172,6 +155,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
172
155
) ;
173
156
self . log_capture_analysis_first_pass ( closure_def_id, & delegate. capture_information , span) ;
174
157
158
+ self . compute_min_captures ( closure_def_id, delegate. capture_information ) ;
159
+
160
+ // We now fake capture information for all variables that are mentioned within the closure
161
+ // We do this after handling migrations so that min_captures computes before
162
+ if !self . tcx . features ( ) . capture_disjoint_fields {
163
+ let mut capture_information: InferredCaptureInformation < ' tcx > = Default :: default ( ) ;
164
+
165
+ if let Some ( upvars) = self . tcx . upvars_mentioned ( closure_def_id) {
166
+ for var_hir_id in upvars. keys ( ) {
167
+ let place = self . place_for_root_variable ( local_def_id, * var_hir_id) ;
168
+
169
+ debug ! ( "seed place {:?}" , place) ;
170
+
171
+ let upvar_id = ty:: UpvarId :: new ( * var_hir_id, local_def_id) ;
172
+ let capture_kind = self . init_capture_kind ( capture_clause, upvar_id, span) ;
173
+ let fake_info = ty:: CaptureInfo {
174
+ capture_kind_expr_id : None ,
175
+ path_expr_id : None ,
176
+ capture_kind,
177
+ } ;
178
+
179
+ capture_information. insert ( place, fake_info) ;
180
+ }
181
+ }
182
+
183
+ // This will update the min captures based on this new fake information.
184
+ self . compute_min_captures ( closure_def_id, capture_information) ;
185
+ }
186
+
175
187
if let Some ( closure_substs) = infer_kind {
176
188
// Unify the (as yet unbound) type variable in the closure
177
189
// substs with the kind we inferred.
@@ -197,7 +209,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
197
209
}
198
210
}
199
211
200
- self . compute_min_captures ( closure_def_id, delegate) ;
201
212
self . log_closure_min_capture_info ( closure_def_id, span) ;
202
213
203
214
self . min_captures_to_closure_captures_bridge ( closure_def_id) ;
@@ -344,6 +355,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
344
355
/// Places (and corresponding capture kind) that we need to keep track of to support all
345
356
/// the required captured paths.
346
357
///
358
+ ///
359
+ /// Note: If this function is called multiple times for the same closure, it will update
360
+ /// the existing min_capture map that is stored in TypeckResults.
361
+ ///
347
362
/// Eg:
348
363
/// ```rust,no_run
349
364
/// struct Point { x: i32, y: i32 }
@@ -408,11 +423,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
408
423
fn compute_min_captures (
409
424
& self ,
410
425
closure_def_id : DefId ,
411
- inferred_info : InferBorrowKind < ' _ , ' tcx > ,
426
+ capture_information : InferredCaptureInformation < ' tcx > ,
412
427
) {
413
- let mut root_var_min_capture_list: ty:: RootVariableMinCaptureList < ' _ > = Default :: default ( ) ;
428
+ if capture_information. is_empty ( ) {
429
+ return ;
430
+ }
431
+
432
+ let mut typeck_results = self . typeck_results . borrow_mut ( ) ;
414
433
415
- for ( place, capture_info) in inferred_info. capture_information . into_iter ( ) {
434
+ let mut root_var_min_capture_list =
435
+ typeck_results. closure_min_captures . remove ( & closure_def_id) . unwrap_or_default ( ) ;
436
+
437
+ for ( place, capture_info) in capture_information. into_iter ( ) {
416
438
let var_hir_id = match place. base {
417
439
PlaceBase :: Upvar ( upvar_id) => upvar_id. var_path . hir_id ,
418
440
base => bug ! ( "Expected upvar, found={:?}" , base) ,
@@ -422,7 +444,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
422
444
423
445
let min_cap_list = match root_var_min_capture_list. get_mut ( & var_hir_id) {
424
446
None => {
425
- let mutability = self . determine_capture_mutability ( & place) ;
447
+ let mutability = self . determine_capture_mutability ( & typeck_results , & place) ;
426
448
let min_cap_list =
427
449
vec ! [ ty:: CapturedPlace { place, info: capture_info, mutability } ] ;
428
450
root_var_min_capture_list. insert ( var_hir_id, min_cap_list) ;
@@ -487,21 +509,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
487
509
488
510
// Only need to insert when we don't have an ancestor in the existing min capture list
489
511
if !ancestor_found {
490
- let mutability = self . determine_capture_mutability ( & place) ;
512
+ let mutability = self . determine_capture_mutability ( & typeck_results , & place) ;
491
513
let captured_place =
492
514
ty:: CapturedPlace { place, info : updated_capture_info, mutability } ;
493
515
min_cap_list. push ( captured_place) ;
494
516
}
495
517
}
496
518
497
519
debug ! ( "For closure={:?}, min_captures={:#?}" , closure_def_id, root_var_min_capture_list) ;
498
-
499
- if !root_var_min_capture_list. is_empty ( ) {
500
- self . typeck_results
501
- . borrow_mut ( )
502
- . closure_min_captures
503
- . insert ( closure_def_id, root_var_min_capture_list) ;
504
- }
520
+ typeck_results. closure_min_captures . insert ( closure_def_id, root_var_min_capture_list) ;
505
521
}
506
522
507
523
fn init_capture_kind (
@@ -613,18 +629,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
613
629
/// A captured place is mutable if
614
630
/// 1. Projections don't include a Deref of an immut-borrow, **and**
615
631
/// 2. PlaceBase is mut or projections include a Deref of a mut-borrow.
616
- fn determine_capture_mutability ( & self , place : & Place < ' tcx > ) -> hir:: Mutability {
632
+ fn determine_capture_mutability (
633
+ & self ,
634
+ typeck_results : & ' a TypeckResults < ' tcx > ,
635
+ place : & Place < ' tcx > ,
636
+ ) -> hir:: Mutability {
617
637
let var_hir_id = match place. base {
618
638
PlaceBase :: Upvar ( upvar_id) => upvar_id. var_path . hir_id ,
619
639
_ => unreachable ! ( ) ,
620
640
} ;
621
641
622
- let bm = * self
623
- . typeck_results
624
- . borrow ( )
625
- . pat_binding_modes ( )
626
- . get ( var_hir_id)
627
- . expect ( "missing binding mode" ) ;
642
+ let bm = * typeck_results. pat_binding_modes ( ) . get ( var_hir_id) . expect ( "missing binding mode" ) ;
628
643
629
644
let mut is_mutbl = match bm {
630
645
ty:: BindByValue ( mutability) => mutability,
@@ -698,9 +713,11 @@ struct InferBorrowKind<'a, 'tcx> {
698
713
///
699
714
/// For closure `fix_s`, (at a high level) the map contains
700
715
///
716
+ /// ```
701
717
/// Place { V1, [ProjectionKind::Field(Index=0, Variant=0)] } : CaptureKind { E1, ImmutableBorrow }
702
718
/// Place { V1, [ProjectionKind::Field(Index=1, Variant=0)] } : CaptureKind { E2, MutableBorrow }
703
- capture_information : FxIndexMap < Place < ' tcx > , ty:: CaptureInfo < ' tcx > > ,
719
+ /// ```
720
+ capture_information : InferredCaptureInformation < ' tcx > ,
704
721
}
705
722
706
723
impl < ' a , ' tcx > InferBorrowKind < ' a , ' tcx > {
0 commit comments