@@ -46,9 +46,9 @@ use rustc_span::{Span, Symbol};
4646
4747/// Describe the relationship between the paths of two places
4848/// 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
5252enum PlaceAncestryRelation {
5353 Ancestor ,
5454 Descendant ,
@@ -124,7 +124,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
124124
125125 let local_def_id = closure_def_id. expect_local ( ) ;
126126
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 ( ) ;
128129 if !self . tcx . features ( ) . capture_disjoint_fields {
129130 if let Some ( upvars) = self . tcx . upvars_mentioned ( closure_def_id) {
130131 for ( & var_hir_id, _) in upvars. iter ( ) {
@@ -186,7 +187,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
186187 self . compute_min_captures ( closure_def_id, delegate) ;
187188 self . log_closure_min_capture_info ( closure_def_id, span) ;
188189
189- self . set_closure_captures ( closure_def_id) ;
190+ self . min_captures_to_closure_captures_bridge ( closure_def_id) ;
190191
191192 // Now that we've analyzed the closure, we know how each
192193 // variable is borrowed, and we know what traits the closure
@@ -274,8 +275,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
274275 ///
275276 /// 2. upvar_capture_map
276277 /// 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 ) {
279279 let mut closure_captures: FxIndexMap < hir:: HirId , ty:: UpvarId > = Default :: default ( ) ;
280280 let mut upvar_capture_map = ty:: UpvarCaptureMap :: default ( ) ;
281281
@@ -304,8 +304,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
304304 // so we create a fake capture info with no expression.
305305 let fake_capture_info =
306306 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
309308 } else {
310309 capture_info. capture_kind
311310 } ;
@@ -329,7 +328,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
329328 }
330329 }
331330
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
333332 /// Places (and corresponding capture kind) that we need to keep track of to support all
334333 /// the required captured paths.
335334 ///
@@ -420,8 +419,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
420419 // current place is ancestor of possible_descendant
421420 PlaceAncestryRelation :: Ancestor => {
422421 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 ) ;
425424 false
426425 }
427426
@@ -437,7 +436,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
437436 PlaceAncestryRelation :: Descendant => {
438437 ancestor_found = true ;
439438 possible_ancestor. info =
440- self . determine_capture_info ( possible_ancestor. info , capture_info) ;
439+ determine_capture_info ( possible_ancestor. info , capture_info) ;
441440
442441 // Only one ancestor of the current place will be in the list.
443442 break ;
@@ -500,60 +499,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
500499 self . tcx . has_attr ( closure_def_id, sym:: rustc_capture_analysis)
501500 }
502501
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-
557502 fn log_closure_capture_info (
558503 & self ,
559504 closure_def_id : rustc_hir:: def_id:: DefId ,
@@ -617,8 +562,9 @@ struct InferBorrowKind<'a, 'tcx> {
617562 // variable access that caused us to do so.
618563 current_origin : Option < ( Span , Symbol ) > ,
619564
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
621566 /// access we need (ref, ref mut, move, etc) and the expression that resulted in such access.
567+ ///
622568 /// Consider closure where s.str1 is captured via an ImmutableBorrow and
623569 /// s.str2 via a MutableBorrow
624570 ///
@@ -686,7 +632,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
686632 } ;
687633
688634 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) ;
690636
691637 self . capture_information [ & place_with_id. place ] = updated_info;
692638 }
@@ -804,7 +750,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
804750 expr_id : Some ( diag_expr_id) ,
805751 capture_kind : ty:: UpvarCapture :: ByRef ( new_upvar_borrow) ,
806752 } ;
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) ;
808754 self . capture_information [ & place_with_id. place ] = updated_info;
809755 } ;
810756 }
@@ -859,14 +805,14 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
859805 if let PlaceBase :: Upvar ( upvar_id) = place_with_id. place . base {
860806 assert_eq ! ( self . closure_def_id. expect_local( ) , upvar_id. closure_expr_id) ;
861807
862- debug ! ( "Capturing new place {:?}" , place_with_id) ;
863-
864808 let capture_kind =
865809 self . fcx . init_capture_kind ( self . capture_clause , upvar_id, self . closure_span ) ;
866810
867811 let expr_id = Some ( diag_expr_id) ;
868812 let capture_info = ty:: CaptureInfo { expr_id, capture_kind } ;
869813
814+ debug ! ( "Capturing new place {:?}, capture_info={:?}" , place_with_id, capture_info) ;
815+
870816 self . capture_information . insert ( place_with_id. place . clone ( ) , capture_info) ;
871817 } else {
872818 debug ! ( "Not upvar: {:?}" , place_with_id) ;
@@ -964,6 +910,92 @@ fn var_name(tcx: TyCtxt<'_>, var_hir_id: hir::HirId) -> Symbol {
964910 tcx. hir ( ) . name ( var_hir_id)
965911}
966912
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+
967999/// Determines the Ancestry relationship of Place A relative to Place B
9681000///
9691001/// `PlaceAncestryRelation::Ancestor` implies Place A is ancestor of Place B
0 commit comments