@@ -42,7 +42,7 @@ use rustc_infer::infer::UpvarRegion;
4242use rustc_middle:: hir:: place:: { Place , PlaceBase , PlaceWithHirId , ProjectionKind } ;
4343use rustc_middle:: ty:: { self , Ty , TyCtxt , UpvarSubsts } ;
4444use rustc_span:: sym;
45- use rustc_span:: { Span , Symbol } ;
45+ use rustc_span:: { MultiSpan , Span , Symbol } ;
4646
4747/// Describe the relationship between the paths of two places
4848/// eg:
@@ -135,7 +135,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
135135
136136 let upvar_id = ty:: UpvarId :: new ( var_hir_id, local_def_id) ;
137137 let capture_kind = self . init_capture_kind ( capture_clause, upvar_id, span) ;
138- let info = ty:: CaptureInfo { expr_id : None , capture_kind } ;
138+ let info = ty:: CaptureInfo {
139+ capture_kind_expr_id : None ,
140+ path_expr_id : None ,
141+ capture_kind,
142+ } ;
139143
140144 capture_information. insert ( place, info) ;
141145 }
@@ -308,8 +312,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
308312 if let Some ( capture_kind) = upvar_capture_map. get ( & upvar_id) {
309313 // upvar_capture_map only stores the UpvarCapture (CaptureKind),
310314 // so we create a fake capture info with no expression.
311- let fake_capture_info =
312- ty:: CaptureInfo { expr_id : None , capture_kind : * capture_kind } ;
315+ let fake_capture_info = ty:: CaptureInfo {
316+ capture_kind_expr_id : None ,
317+ path_expr_id : None ,
318+ capture_kind : * capture_kind,
319+ } ;
313320 determine_capture_info ( fake_capture_info, capture_info) . capture_kind
314321 } else {
315322 capture_info. capture_kind
@@ -359,20 +366,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
359366 ///
360367 /// ```
361368 /// {
362- /// Place(base: hir_id_s, projections: [], ....) -> (hir_id_L5, ByValue),
363- /// Place(base: hir_id_p, projections: [Field(0, 0)], ...) -> (hir_id_L2, ByRef(MutBorrow))
364- /// Place(base: hir_id_p, projections: [Field(1, 0)], ...) -> (hir_id_L3, ByRef(ImmutBorrow))
365- /// Place(base: hir_id_p, projections: [], ...) -> (hir_id_L4, ByRef(ImmutBorrow))
369+ /// Place(base: hir_id_s, projections: [], ....) -> {
370+ /// capture_kind_expr: hir_id_L5,
371+ /// path_expr_id: hir_id_L5,
372+ /// capture_kind: ByValue
373+ /// },
374+ /// Place(base: hir_id_p, projections: [Field(0, 0)], ...) -> {
375+ /// capture_kind_expr: hir_id_L2,
376+ /// path_expr_id: hir_id_L2,
377+ /// capture_kind: ByValue
378+ /// },
379+ /// Place(base: hir_id_p, projections: [Field(1, 0)], ...) -> {
380+ /// capture_kind_expr: hir_id_L3,
381+ /// path_expr_id: hir_id_L3,
382+ /// capture_kind: ByValue
383+ /// },
384+ /// Place(base: hir_id_p, projections: [], ...) -> {
385+ /// capture_kind_expr: hir_id_L4,
386+ /// path_expr_id: hir_id_L4,
387+ /// capture_kind: ByValue
388+ /// },
366389 /// ```
367390 ///
368391 /// After the min capture analysis, we get:
369392 /// ```
370393 /// {
371394 /// hir_id_s -> [
372- /// Place(base: hir_id_s, projections: [], ....) -> (hir_id_L4, ByValue)
395+ /// Place(base: hir_id_s, projections: [], ....) -> {
396+ /// capture_kind_expr: hir_id_L5,
397+ /// path_expr_id: hir_id_L5,
398+ /// capture_kind: ByValue
399+ /// },
373400 /// ],
374401 /// hir_id_p -> [
375- /// Place(base: hir_id_p, projections: [], ...) -> (hir_id_L2, ByRef(MutBorrow)),
402+ /// Place(base: hir_id_p, projections: [], ...) -> {
403+ /// capture_kind_expr: hir_id_L2,
404+ /// path_expr_id: hir_id_L4,
405+ /// capture_kind: ByValue
406+ /// },
376407 /// ],
377408 /// ```
378409 fn compute_min_captures (
@@ -425,8 +456,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
425456 // current place is ancestor of possible_descendant
426457 PlaceAncestryRelation :: Ancestor => {
427458 descendant_found = true ;
459+ let backup_path_expr_id = updated_capture_info. path_expr_id ;
460+
428461 updated_capture_info =
429462 determine_capture_info ( updated_capture_info, possible_descendant. info ) ;
463+
464+ // we need to keep the ancestor's `path_expr_id`
465+ updated_capture_info. path_expr_id = backup_path_expr_id;
430466 false
431467 }
432468
@@ -441,9 +477,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
441477 // current place is descendant of possible_ancestor
442478 PlaceAncestryRelation :: Descendant => {
443479 ancestor_found = true ;
480+ let backup_path_expr_id = possible_ancestor. info . path_expr_id ;
444481 possible_ancestor. info =
445482 determine_capture_info ( possible_ancestor. info , capture_info) ;
446483
484+ // we need to keep the ancestor's `path_expr_id`
485+ possible_ancestor. info . path_expr_id = backup_path_expr_id;
486+
447487 // Only one ancestor of the current place will be in the list.
448488 break ;
449489 }
@@ -518,7 +558,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
518558 let capture_str = construct_capture_info_string ( self . tcx , place, capture_info) ;
519559 let output_str = format ! ( "Capturing {}" , capture_str) ;
520560
521- let span = capture_info. expr_id . map_or ( closure_span, |e| self . tcx . hir ( ) . span ( e) ) ;
561+ let span =
562+ capture_info. path_expr_id . map_or ( closure_span, |e| self . tcx . hir ( ) . span ( e) ) ;
522563 diag. span_note ( span, & output_str) ;
523564 }
524565 diag. emit ( ) ;
@@ -542,9 +583,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
542583 construct_capture_info_string ( self . tcx , place, capture_info) ;
543584 let output_str = format ! ( "Min Capture {}" , capture_str) ;
544585
545- let span =
546- capture_info. expr_id . map_or ( closure_span, |e| self . tcx . hir ( ) . span ( e) ) ;
547- diag. span_note ( span, & output_str) ;
586+ if capture. info . path_expr_id != capture. info . capture_kind_expr_id {
587+ let path_span = capture_info
588+ . path_expr_id
589+ . map_or ( closure_span, |e| self . tcx . hir ( ) . span ( e) ) ;
590+ let capture_kind_span = capture_info
591+ . capture_kind_expr_id
592+ . map_or ( closure_span, |e| self . tcx . hir ( ) . span ( e) ) ;
593+
594+ let mut multi_span: MultiSpan =
595+ MultiSpan :: from_spans ( vec ! [ path_span, capture_kind_span] ) ;
596+
597+ let capture_kind_label =
598+ construct_capture_kind_reason_string ( self . tcx , place, capture_info) ;
599+ let path_label = construct_path_string ( self . tcx , place) ;
600+
601+ multi_span. push_span_label ( path_span, path_label) ;
602+ multi_span. push_span_label ( capture_kind_span, capture_kind_label) ;
603+
604+ diag. span_note ( multi_span, & output_str) ;
605+ } else {
606+ let span = capture_info
607+ . path_expr_id
608+ . map_or ( closure_span, |e| self . tcx . hir ( ) . span ( e) ) ;
609+
610+ diag. span_note ( span, & output_str) ;
611+ } ;
548612 }
549613 }
550614 diag. emit ( ) ;
@@ -642,7 +706,8 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
642706 ) ;
643707
644708 let capture_info = ty:: CaptureInfo {
645- expr_id : Some ( diag_expr_id) ,
709+ capture_kind_expr_id : Some ( diag_expr_id) ,
710+ path_expr_id : Some ( diag_expr_id) ,
646711 capture_kind : ty:: UpvarCapture :: ByValue ( Some ( usage_span) ) ,
647712 } ;
648713
@@ -762,7 +827,8 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
762827 let new_upvar_borrow = ty:: UpvarBorrow { kind, region : curr_upvar_borrow. region } ;
763828
764829 let capture_info = ty:: CaptureInfo {
765- expr_id : Some ( diag_expr_id) ,
830+ capture_kind_expr_id : Some ( diag_expr_id) ,
831+ path_expr_id : Some ( diag_expr_id) ,
766832 capture_kind : ty:: UpvarCapture :: ByRef ( new_upvar_borrow) ,
767833 } ;
768834 let updated_info = determine_capture_info ( curr_capture_info, capture_info) ;
@@ -824,7 +890,11 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
824890 self . fcx . init_capture_kind ( self . capture_clause , upvar_id, self . closure_span ) ;
825891
826892 let expr_id = Some ( diag_expr_id) ;
827- let capture_info = ty:: CaptureInfo { expr_id, capture_kind } ;
893+ let capture_info = ty:: CaptureInfo {
894+ capture_kind_expr_id : expr_id,
895+ path_expr_id : expr_id,
896+ capture_kind,
897+ } ;
828898
829899 debug ! ( "Capturing new place {:?}, capture_info={:?}" , place_with_id, capture_info) ;
830900
@@ -890,11 +960,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
890960 }
891961}
892962
893- fn construct_capture_info_string (
894- tcx : TyCtxt < ' _ > ,
895- place : & Place < ' tcx > ,
896- capture_info : & ty:: CaptureInfo < ' tcx > ,
897- ) -> String {
963+ fn construct_place_string ( tcx : TyCtxt < ' _ > , place : & Place < ' tcx > ) -> String {
898964 let variable_name = match place. base {
899965 PlaceBase :: Upvar ( upvar_id) => var_name ( tcx, upvar_id. var_path . hir_id ) . to_string ( ) ,
900966 _ => bug ! ( "Capture_information should only contain upvars" ) ,
@@ -914,11 +980,42 @@ fn construct_capture_info_string(
914980 projections_str. push_str ( proj. as_str ( ) ) ;
915981 }
916982
983+ format ! ( "{}[{}]" , variable_name, projections_str)
984+ }
985+
986+ fn construct_capture_kind_reason_string (
987+ tcx : TyCtxt < ' _ > ,
988+ place : & Place < ' tcx > ,
989+ capture_info : & ty:: CaptureInfo < ' tcx > ,
990+ ) -> String {
991+ let place_str = construct_place_string ( tcx, & place) ;
992+
917993 let capture_kind_str = match capture_info. capture_kind {
918994 ty:: UpvarCapture :: ByValue ( _) => "ByValue" . into ( ) ,
919995 ty:: UpvarCapture :: ByRef ( borrow) => format ! ( "{:?}" , borrow. kind) ,
920996 } ;
921- format ! ( "{}[{}] -> {}" , variable_name, projections_str, capture_kind_str)
997+
998+ format ! ( "{} captured as {} here" , place_str, capture_kind_str)
999+ }
1000+
1001+ fn construct_path_string ( tcx : TyCtxt < ' _ > , place : & Place < ' tcx > ) -> String {
1002+ let place_str = construct_place_string ( tcx, & place) ;
1003+
1004+ format ! ( "{} used here" , place_str)
1005+ }
1006+
1007+ fn construct_capture_info_string (
1008+ tcx : TyCtxt < ' _ > ,
1009+ place : & Place < ' tcx > ,
1010+ capture_info : & ty:: CaptureInfo < ' tcx > ,
1011+ ) -> String {
1012+ let place_str = construct_place_string ( tcx, & place) ;
1013+
1014+ let capture_kind_str = match capture_info. capture_kind {
1015+ ty:: UpvarCapture :: ByValue ( _) => "ByValue" . into ( ) ,
1016+ ty:: UpvarCapture :: ByRef ( borrow) => format ! ( "{:?}" , borrow. kind) ,
1017+ } ;
1018+ format ! ( "{} -> {}" , place_str, capture_kind_str)
9221019}
9231020
9241021fn var_name ( tcx : TyCtxt < ' _ > , var_hir_id : hir:: HirId ) -> Symbol {
@@ -930,7 +1027,9 @@ fn var_name(tcx: TyCtxt<'_>, var_hir_id: hir::HirId) -> Symbol {
9301027/// (Note: CaptureInfo contains CaptureKind and an expression that led to capture it in that way)
9311028///
9321029/// If both `CaptureKind`s are considered equivalent, then the CaptureInfo is selected based
933- /// on the `CaptureInfo` containing an associated expression id.
1030+ /// on the `CaptureInfo` containing an associated `capture_kind_expr_id`.
1031+ ///
1032+ /// It is the caller's duty to figure out which path_expr_id to use.
9341033///
9351034/// If both the CaptureKind and Expression are considered to be equivalent,
9361035/// then `CaptureInfo` A is preferred. This can be useful in cases where we want to priortize
@@ -981,7 +1080,7 @@ fn determine_capture_info(
9811080 } ;
9821081
9831082 if eq_capture_kind {
984- match ( capture_info_a. expr_id , capture_info_b. expr_id ) {
1083+ match ( capture_info_a. capture_kind_expr_id , capture_info_b. capture_kind_expr_id ) {
9851084 ( Some ( _) , _) | ( None , None ) => capture_info_a,
9861085 ( None , Some ( _) ) => capture_info_b,
9871086 }
0 commit comments