@@ -46,9 +46,9 @@ use rustc_span::{Span, Symbol};
46
46
47
47
/// Describe the relationship between the paths of two places
48
48
/// eg:
49
- /// - foo is ancestor of foo.bar.baz
50
- /// - foo.bar.baz is an descendant of foo.bar,
51
- /// - foo.bar and foo.baz are divergent
49
+ /// - ` foo` is ancestor of ` foo.bar.baz`
50
+ /// - ` foo.bar.baz` is an descendant of ` foo.bar`
51
+ /// - ` foo.bar` and ` foo.baz` are divergent
52
52
enum PlaceAncestryRelation {
53
53
Ancestor ,
54
54
Descendant ,
@@ -124,7 +124,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
124
124
125
125
let local_def_id = closure_def_id. expect_local ( ) ;
126
126
127
- let mut capture_information = FxIndexMap :: < Place < ' tcx > , ty:: CaptureInfo < ' tcx > > :: default ( ) ;
127
+ let mut capture_information: FxIndexMap < Place < ' tcx > , ty:: CaptureInfo < ' tcx > > =
128
+ Default :: default ( ) ;
128
129
if !self . tcx . features ( ) . capture_disjoint_fields {
129
130
if let Some ( upvars) = self . tcx . upvars_mentioned ( closure_def_id) {
130
131
for ( & var_hir_id, _) in upvars. iter ( ) {
@@ -186,7 +187,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
186
187
self . compute_min_captures ( closure_def_id, delegate) ;
187
188
self . log_closure_min_capture_info ( closure_def_id, span) ;
188
189
189
- self . set_closure_captures ( closure_def_id) ;
190
+ self . min_captures_to_closure_captures_bridge ( closure_def_id) ;
190
191
191
192
// Now that we've analyzed the closure, we know how each
192
193
// variable is borrowed, and we know what traits the closure
@@ -274,8 +275,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
274
275
///
275
276
/// 2. upvar_capture_map
276
277
/// UpvarId(foo,c) -> MutBorrow, UpvarId(bar, c) -> ByValue
277
-
278
- fn set_closure_captures ( & self , closure_def_id : DefId ) {
278
+ fn min_captures_to_closure_captures_bridge ( & self , closure_def_id : DefId ) {
279
279
let mut closure_captures: FxIndexMap < hir:: HirId , ty:: UpvarId > = Default :: default ( ) ;
280
280
let mut upvar_capture_map = ty:: UpvarCaptureMap :: default ( ) ;
281
281
@@ -304,8 +304,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
304
304
// so we create a fake capture info with no expression.
305
305
let fake_capture_info =
306
306
ty:: CaptureInfo { expr_id : None , capture_kind : capture_kind. clone ( ) } ;
307
- self . determine_capture_info ( fake_capture_info, capture_info. clone ( ) )
308
- . capture_kind
307
+ determine_capture_info ( fake_capture_info, capture_info) . capture_kind
309
308
} else {
310
309
capture_info. capture_kind
311
310
} ;
@@ -329,7 +328,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
329
328
}
330
329
}
331
330
332
- /// Analyses the information collected by InferBorrowKind to compute the min number of
331
+ /// Analyzes the information collected by ` InferBorrowKind` to compute the min number of
333
332
/// Places (and corresponding capture kind) that we need to keep track of to support all
334
333
/// the required captured paths.
335
334
///
@@ -420,8 +419,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
420
419
// current place is ancestor of possible_descendant
421
420
PlaceAncestryRelation :: Ancestor => {
422
421
descendant_found = true ;
423
- updated_capture_info = self
424
- . determine_capture_info ( updated_capture_info, possible_descendant. info ) ;
422
+ updated_capture_info =
423
+ determine_capture_info ( updated_capture_info, possible_descendant. info ) ;
425
424
false
426
425
}
427
426
@@ -437,7 +436,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
437
436
PlaceAncestryRelation :: Descendant => {
438
437
ancestor_found = true ;
439
438
possible_ancestor. info =
440
- self . determine_capture_info ( possible_ancestor. info , capture_info) ;
439
+ determine_capture_info ( possible_ancestor. info , capture_info) ;
441
440
442
441
// Only one ancestor of the current place will be in the list.
443
442
break ;
@@ -500,60 +499,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
500
499
self . tcx . has_attr ( closure_def_id, sym:: rustc_capture_analysis)
501
500
}
502
501
503
- /// Helper function to determine if we need to escalate CaptureKind from
504
- /// CaptureInfo A to B and returns the escalated CaptureInfo.
505
- /// (Note: CaptureInfo contains CaptureKind and an expression that led to capture it in that way)
506
- ///
507
- /// If both `CaptureKind`s are considered equivalent, then the CaptureInfo is selected based
508
- /// on the `CaptureInfo` containing an associated expression id.
509
- ///
510
- /// If both the CaptureKind and Expression are considered to be equivalent,
511
- /// then `CaptureInfo` A is preferred.
512
- fn determine_capture_info (
513
- & self ,
514
- capture_info_a : ty:: CaptureInfo < ' tcx > ,
515
- capture_info_b : ty:: CaptureInfo < ' tcx > ,
516
- ) -> ty:: CaptureInfo < ' tcx > {
517
- // If the capture kind is equivalent then, we don't need to escalate and can compare the
518
- // expressions.
519
- let eq_capture_kind = match ( capture_info_a. capture_kind , capture_info_b. capture_kind ) {
520
- ( ty:: UpvarCapture :: ByValue ( _) , ty:: UpvarCapture :: ByValue ( _) ) => true ,
521
- ( ty:: UpvarCapture :: ByRef ( ref_a) , ty:: UpvarCapture :: ByRef ( ref_b) ) => {
522
- ref_a. kind == ref_b. kind
523
- }
524
- _ => false ,
525
- } ;
526
-
527
- if eq_capture_kind {
528
- match ( capture_info_a. expr_id , capture_info_b. expr_id ) {
529
- ( Some ( _) , _) | ( None , None ) => capture_info_a,
530
- ( None , Some ( _) ) => capture_info_b,
531
- }
532
- } else {
533
- match ( capture_info_a. capture_kind , capture_info_b. capture_kind ) {
534
- ( ty:: UpvarCapture :: ByValue ( _) , _) => capture_info_a,
535
- ( _, ty:: UpvarCapture :: ByValue ( _) ) => capture_info_b,
536
- ( ty:: UpvarCapture :: ByRef ( ref_a) , ty:: UpvarCapture :: ByRef ( ref_b) ) => {
537
- match ( ref_a. kind , ref_b. kind ) {
538
- // Take LHS:
539
- ( ty:: UniqueImmBorrow | ty:: MutBorrow , ty:: ImmBorrow )
540
- | ( ty:: MutBorrow , ty:: UniqueImmBorrow ) => capture_info_a,
541
-
542
- // Take RHS:
543
- ( ty:: ImmBorrow , ty:: UniqueImmBorrow | ty:: MutBorrow )
544
- | ( ty:: UniqueImmBorrow , ty:: MutBorrow ) => capture_info_b,
545
-
546
- ( ty:: ImmBorrow , ty:: ImmBorrow )
547
- | ( ty:: UniqueImmBorrow , ty:: UniqueImmBorrow )
548
- | ( ty:: MutBorrow , ty:: MutBorrow ) => {
549
- bug ! ( "Expected unequal capture kinds" ) ;
550
- }
551
- }
552
- }
553
- }
554
- }
555
- }
556
-
557
502
fn log_closure_capture_info (
558
503
& self ,
559
504
closure_def_id : rustc_hir:: def_id:: DefId ,
@@ -617,8 +562,9 @@ struct InferBorrowKind<'a, 'tcx> {
617
562
// variable access that caused us to do so.
618
563
current_origin : Option < ( Span , Symbol ) > ,
619
564
620
- /// For each Place that we access , we track the minimal kind of
565
+ /// For each Place that is captured by the closure , we track the minimal kind of
621
566
/// access we need (ref, ref mut, move, etc) and the expression that resulted in such access.
567
+ ///
622
568
/// Consider closure where s.str1 is captured via an ImmutableBorrow and
623
569
/// s.str2 via a MutableBorrow
624
570
///
@@ -686,7 +632,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
686
632
} ;
687
633
688
634
let curr_info = self . capture_information [ & place_with_id. place ] ;
689
- let updated_info = self . fcx . determine_capture_info ( curr_info, capture_info) ;
635
+ let updated_info = determine_capture_info ( curr_info, capture_info) ;
690
636
691
637
self . capture_information [ & place_with_id. place ] = updated_info;
692
638
}
@@ -804,7 +750,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
804
750
expr_id : Some ( diag_expr_id) ,
805
751
capture_kind : ty:: UpvarCapture :: ByRef ( new_upvar_borrow) ,
806
752
} ;
807
- let updated_info = self . fcx . determine_capture_info ( curr_capture_info, capture_info) ;
753
+ let updated_info = determine_capture_info ( curr_capture_info, capture_info) ;
808
754
self . capture_information [ & place_with_id. place ] = updated_info;
809
755
} ;
810
756
}
@@ -859,14 +805,14 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
859
805
if let PlaceBase :: Upvar ( upvar_id) = place_with_id. place . base {
860
806
assert_eq ! ( self . closure_def_id. expect_local( ) , upvar_id. closure_expr_id) ;
861
807
862
- debug ! ( "Capturing new place {:?}" , place_with_id) ;
863
-
864
808
let capture_kind =
865
809
self . fcx . init_capture_kind ( self . capture_clause , upvar_id, self . closure_span ) ;
866
810
867
811
let expr_id = Some ( diag_expr_id) ;
868
812
let capture_info = ty:: CaptureInfo { expr_id, capture_kind } ;
869
813
814
+ debug ! ( "Capturing new place {:?}, capture_info={:?}" , place_with_id, capture_info) ;
815
+
870
816
self . capture_information . insert ( place_with_id. place . clone ( ) , capture_info) ;
871
817
} else {
872
818
debug ! ( "Not upvar: {:?}" , place_with_id) ;
@@ -964,6 +910,92 @@ fn var_name(tcx: TyCtxt<'_>, var_hir_id: hir::HirId) -> Symbol {
964
910
tcx. hir ( ) . name ( var_hir_id)
965
911
}
966
912
913
+ /// Helper function to determine if we need to escalate CaptureKind from
914
+ /// CaptureInfo A to B and returns the escalated CaptureInfo.
915
+ /// (Note: CaptureInfo contains CaptureKind and an expression that led to capture it in that way)
916
+ ///
917
+ /// If both `CaptureKind`s are considered equivalent, then the CaptureInfo is selected based
918
+ /// on the `CaptureInfo` containing an associated expression id.
919
+ ///
920
+ /// If both the CaptureKind and Expression are considered to be equivalent,
921
+ /// then `CaptureInfo` A is preferred. This can be useful in cases where we want to priortize
922
+ /// expressions reported back to the user as part of diagnostics based on which appears earlier
923
+ /// in the closure. This can be acheived simply by calling
924
+ /// `determine_capture_info(existing_info, current_info)`. This works out because the
925
+ /// expressions that occur earlier in the closure body than the current expression are processed before.
926
+ /// Consider the following example
927
+ /// ```rust
928
+ /// let mut p: Point { x: 10, y: 10 };
929
+ ///
930
+ /// let c = || {
931
+ /// p.x += 10;
932
+ /// // ^ E1 ^
933
+ /// // ...
934
+ /// // More code
935
+ /// // ...
936
+ /// p.x += 10; // E2
937
+ /// // ^ E2 ^
938
+ /// }
939
+ /// ```
940
+ /// `CaptureKind` associated with both `E1` and `E2` will be ByRef(MutBorrow),
941
+ /// and both have an expression associated, however for diagnostics we prfer reporting
942
+ /// `E1` since it appears earlier in the closure body. When `E2` is being processed we
943
+ /// would've already handled `E1`, and have an existing capture_information for it.
944
+ /// Calling `determine_capture_info(existing_info_e1, current_info_e2)` will return
945
+ /// `existing_info_e1` in this case, allowing us to point to `E1` in case of diagnostics.
946
+ fn determine_capture_info (
947
+ capture_info_a : ty:: CaptureInfo < ' tcx > ,
948
+ capture_info_b : ty:: CaptureInfo < ' tcx > ,
949
+ ) -> ty:: CaptureInfo < ' tcx > {
950
+ // If the capture kind is equivalent then, we don't need to escalate and can compare the
951
+ // expressions.
952
+ let eq_capture_kind = match ( capture_info_a. capture_kind , capture_info_b. capture_kind ) {
953
+ ( ty:: UpvarCapture :: ByValue ( _) , ty:: UpvarCapture :: ByValue ( _) ) => {
954
+ // We don't need to worry about the spans being ignored here.
955
+ //
956
+ // The expr_id in capture_info corresponds to the span that is stored within
957
+ // ByValue(span) and therefore it gets handled with priortizing based on
958
+ // expressions below.
959
+ true
960
+ }
961
+ ( ty:: UpvarCapture :: ByRef ( ref_a) , ty:: UpvarCapture :: ByRef ( ref_b) ) => {
962
+ ref_a. kind == ref_b. kind
963
+ }
964
+ ( ty:: UpvarCapture :: ByValue ( _) , _) | ( ty:: UpvarCapture :: ByRef ( _) , _) => false ,
965
+ } ;
966
+
967
+ if eq_capture_kind {
968
+ match ( capture_info_a. expr_id , capture_info_b. expr_id ) {
969
+ ( Some ( _) , _) | ( None , None ) => capture_info_a,
970
+ ( None , Some ( _) ) => capture_info_b,
971
+ }
972
+ } else {
973
+ // We select the CaptureKind which ranks higher based the following priority order:
974
+ // ByValue > MutBorrow > UniqueImmBorrow > ImmBorrow
975
+ match ( capture_info_a. capture_kind , capture_info_b. capture_kind ) {
976
+ ( ty:: UpvarCapture :: ByValue ( _) , _) => capture_info_a,
977
+ ( _, ty:: UpvarCapture :: ByValue ( _) ) => capture_info_b,
978
+ ( ty:: UpvarCapture :: ByRef ( ref_a) , ty:: UpvarCapture :: ByRef ( ref_b) ) => {
979
+ match ( ref_a. kind , ref_b. kind ) {
980
+ // Take LHS:
981
+ ( ty:: UniqueImmBorrow | ty:: MutBorrow , ty:: ImmBorrow )
982
+ | ( ty:: MutBorrow , ty:: UniqueImmBorrow ) => capture_info_a,
983
+
984
+ // Take RHS:
985
+ ( ty:: ImmBorrow , ty:: UniqueImmBorrow | ty:: MutBorrow )
986
+ | ( ty:: UniqueImmBorrow , ty:: MutBorrow ) => capture_info_b,
987
+
988
+ ( ty:: ImmBorrow , ty:: ImmBorrow )
989
+ | ( ty:: UniqueImmBorrow , ty:: UniqueImmBorrow )
990
+ | ( ty:: MutBorrow , ty:: MutBorrow ) => {
991
+ bug ! ( "Expected unequal capture kinds" ) ;
992
+ }
993
+ }
994
+ }
995
+ }
996
+ }
997
+ }
998
+
967
999
/// Determines the Ancestry relationship of Place A relative to Place B
968
1000
///
969
1001
/// `PlaceAncestryRelation::Ancestor` implies Place A is ancestor of Place B
0 commit comments