@@ -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 }
@@ -298,8 +302,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
298302 if let Some ( capture_kind) = upvar_capture_map. get ( & upvar_id) {
299303 // upvar_capture_map only stores the UpvarCapture (CaptureKind),
300304 // so we create a fake capture info with no expression.
301- let fake_capture_info =
302- ty:: CaptureInfo { expr_id : None , capture_kind : * capture_kind } ;
305+ let fake_capture_info = ty:: CaptureInfo {
306+ capture_kind_expr_id : None ,
307+ path_expr_id : None ,
308+ capture_kind : * capture_kind,
309+ } ;
303310 determine_capture_info ( fake_capture_info, capture_info) . capture_kind
304311 } else {
305312 capture_info. capture_kind
@@ -349,20 +356,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
349356 ///
350357 /// ```
351358 /// {
352- /// Place(base: hir_id_s, projections: [], ....) -> (hir_id_L5, ByValue),
353- /// Place(base: hir_id_p, projections: [Field(0, 0)], ...) -> (hir_id_L2, ByRef(MutBorrow))
354- /// Place(base: hir_id_p, projections: [Field(1, 0)], ...) -> (hir_id_L3, ByRef(ImmutBorrow))
355- /// Place(base: hir_id_p, projections: [], ...) -> (hir_id_L4, ByRef(ImmutBorrow))
359+ /// Place(base: hir_id_s, projections: [], ....) -> {
360+ /// capture_kind_expr: hir_id_L5,
361+ /// path_expr_id: hir_id_L5,
362+ /// capture_kind: ByValue
363+ /// },
364+ /// Place(base: hir_id_p, projections: [Field(0, 0)], ...) -> {
365+ /// capture_kind_expr: hir_id_L2,
366+ /// path_expr_id: hir_id_L2,
367+ /// capture_kind: ByValue
368+ /// },
369+ /// Place(base: hir_id_p, projections: [Field(1, 0)], ...) -> {
370+ /// capture_kind_expr: hir_id_L3,
371+ /// path_expr_id: hir_id_L3,
372+ /// capture_kind: ByValue
373+ /// },
374+ /// Place(base: hir_id_p, projections: [], ...) -> {
375+ /// capture_kind_expr: hir_id_L4,
376+ /// path_expr_id: hir_id_L4,
377+ /// capture_kind: ByValue
378+ /// },
356379 /// ```
357380 ///
358381 /// After the min capture analysis, we get:
359382 /// ```
360383 /// {
361384 /// hir_id_s -> [
362- /// Place(base: hir_id_s, projections: [], ....) -> (hir_id_L4, ByValue)
385+ /// Place(base: hir_id_s, projections: [], ....) -> {
386+ /// capture_kind_expr: hir_id_L5,
387+ /// path_expr_id: hir_id_L5,
388+ /// capture_kind: ByValue
389+ /// },
363390 /// ],
364391 /// hir_id_p -> [
365- /// Place(base: hir_id_p, projections: [], ...) -> (hir_id_L2, ByRef(MutBorrow)),
392+ /// Place(base: hir_id_p, projections: [], ...) -> {
393+ /// capture_kind_expr: hir_id_L2,
394+ /// path_expr_id: hir_id_L4,
395+ /// capture_kind: ByValue
396+ /// },
366397 /// ],
367398 /// ```
368399 fn compute_min_captures (
@@ -415,8 +446,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
415446 // current place is ancestor of possible_descendant
416447 PlaceAncestryRelation :: Ancestor => {
417448 descendant_found = true ;
449+ let backup_path_expr_id = updated_capture_info. path_expr_id ;
450+
418451 updated_capture_info =
419452 determine_capture_info ( updated_capture_info, possible_descendant. info ) ;
453+
454+ // we need to keep the ancestor's `path_expr_id`
455+ updated_capture_info. path_expr_id = backup_path_expr_id;
420456 false
421457 }
422458
@@ -431,9 +467,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
431467 // current place is descendant of possible_ancestor
432468 PlaceAncestryRelation :: Descendant => {
433469 ancestor_found = true ;
470+ let backup_path_expr_id = possible_ancestor. info . path_expr_id ;
434471 possible_ancestor. info =
435472 determine_capture_info ( possible_ancestor. info , capture_info) ;
436473
474+ // we need to keep the ancestor's `path_expr_id`
475+ possible_ancestor. info . path_expr_id = backup_path_expr_id;
476+
437477 // Only one ancestor of the current place will be in the list.
438478 break ;
439479 }
@@ -508,7 +548,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
508548 let capture_str = construct_capture_info_string ( self . tcx , place, capture_info) ;
509549 let output_str = format ! ( "Capturing {}" , capture_str) ;
510550
511- let span = capture_info. expr_id . map_or ( closure_span, |e| self . tcx . hir ( ) . span ( e) ) ;
551+ let span =
552+ capture_info. path_expr_id . map_or ( closure_span, |e| self . tcx . hir ( ) . span ( e) ) ;
512553 diag. span_note ( span, & output_str) ;
513554 }
514555 diag. emit ( ) ;
@@ -532,9 +573,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
532573 construct_capture_info_string ( self . tcx , place, capture_info) ;
533574 let output_str = format ! ( "Min Capture {}" , capture_str) ;
534575
535- let span =
536- capture_info. expr_id . map_or ( closure_span, |e| self . tcx . hir ( ) . span ( e) ) ;
537- diag. span_note ( span, & output_str) ;
576+ if capture. info . path_expr_id != capture. info . capture_kind_expr_id {
577+ let path_span = capture_info
578+ . path_expr_id
579+ . map_or ( closure_span, |e| self . tcx . hir ( ) . span ( e) ) ;
580+ let capture_kind_span = capture_info
581+ . capture_kind_expr_id
582+ . map_or ( closure_span, |e| self . tcx . hir ( ) . span ( e) ) ;
583+
584+ let mut multi_span: MultiSpan =
585+ MultiSpan :: from_spans ( vec ! [ path_span, capture_kind_span] ) ;
586+
587+ let capture_kind_label =
588+ construct_capture_kind_reason_string ( self . tcx , place, capture_info) ;
589+ let path_label = construct_path_string ( self . tcx , place) ;
590+
591+ multi_span. push_span_label ( path_span, path_label) ;
592+ multi_span. push_span_label ( capture_kind_span, capture_kind_label) ;
593+
594+ diag. span_note ( multi_span, & output_str) ;
595+ } else {
596+ let span = capture_info
597+ . path_expr_id
598+ . map_or ( closure_span, |e| self . tcx . hir ( ) . span ( e) ) ;
599+
600+ diag. span_note ( span, & output_str) ;
601+ } ;
538602 }
539603 }
540604 diag. emit ( ) ;
@@ -632,7 +696,8 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
632696 ) ;
633697
634698 let capture_info = ty:: CaptureInfo {
635- expr_id : Some ( diag_expr_id) ,
699+ capture_kind_expr_id : Some ( diag_expr_id) ,
700+ path_expr_id : Some ( diag_expr_id) ,
636701 capture_kind : ty:: UpvarCapture :: ByValue ( Some ( usage_span) ) ,
637702 } ;
638703
@@ -752,7 +817,8 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
752817 let new_upvar_borrow = ty:: UpvarBorrow { kind, region : curr_upvar_borrow. region } ;
753818
754819 let capture_info = ty:: CaptureInfo {
755- expr_id : Some ( diag_expr_id) ,
820+ capture_kind_expr_id : Some ( diag_expr_id) ,
821+ path_expr_id : Some ( diag_expr_id) ,
756822 capture_kind : ty:: UpvarCapture :: ByRef ( new_upvar_borrow) ,
757823 } ;
758824 let updated_info = determine_capture_info ( curr_capture_info, capture_info) ;
@@ -814,7 +880,11 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
814880 self . fcx . init_capture_kind ( self . capture_clause , upvar_id, self . closure_span ) ;
815881
816882 let expr_id = Some ( diag_expr_id) ;
817- let capture_info = ty:: CaptureInfo { expr_id, capture_kind } ;
883+ let capture_info = ty:: CaptureInfo {
884+ capture_kind_expr_id : expr_id,
885+ path_expr_id : expr_id,
886+ capture_kind,
887+ } ;
818888
819889 debug ! ( "Capturing new place {:?}, capture_info={:?}" , place_with_id, capture_info) ;
820890
@@ -880,11 +950,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
880950 }
881951}
882952
883- fn construct_capture_info_string (
884- tcx : TyCtxt < ' _ > ,
885- place : & Place < ' tcx > ,
886- capture_info : & ty:: CaptureInfo < ' tcx > ,
887- ) -> String {
953+ fn construct_place_string ( tcx : TyCtxt < ' _ > , place : & Place < ' tcx > ) -> String {
888954 let variable_name = match place. base {
889955 PlaceBase :: Upvar ( upvar_id) => var_name ( tcx, upvar_id. var_path . hir_id ) . to_string ( ) ,
890956 _ => bug ! ( "Capture_information should only contain upvars" ) ,
@@ -904,11 +970,42 @@ fn construct_capture_info_string(
904970 projections_str. push_str ( proj. as_str ( ) ) ;
905971 }
906972
973+ format ! ( "{}[{}]" , variable_name, projections_str)
974+ }
975+
976+ fn construct_capture_kind_reason_string (
977+ tcx : TyCtxt < ' _ > ,
978+ place : & Place < ' tcx > ,
979+ capture_info : & ty:: CaptureInfo < ' tcx > ,
980+ ) -> String {
981+ let place_str = construct_place_string ( tcx, & place) ;
982+
907983 let capture_kind_str = match capture_info. capture_kind {
908984 ty:: UpvarCapture :: ByValue ( _) => "ByValue" . into ( ) ,
909985 ty:: UpvarCapture :: ByRef ( borrow) => format ! ( "{:?}" , borrow. kind) ,
910986 } ;
911- format ! ( "{}[{}] -> {}" , variable_name, projections_str, capture_kind_str)
987+
988+ format ! ( "{} captured as {} here" , place_str, capture_kind_str)
989+ }
990+
991+ fn construct_path_string ( tcx : TyCtxt < ' _ > , place : & Place < ' tcx > ) -> String {
992+ let place_str = construct_place_string ( tcx, & place) ;
993+
994+ format ! ( "{} used here" , place_str)
995+ }
996+
997+ fn construct_capture_info_string (
998+ tcx : TyCtxt < ' _ > ,
999+ place : & Place < ' tcx > ,
1000+ capture_info : & ty:: CaptureInfo < ' tcx > ,
1001+ ) -> String {
1002+ let place_str = construct_place_string ( tcx, & place) ;
1003+
1004+ let capture_kind_str = match capture_info. capture_kind {
1005+ ty:: UpvarCapture :: ByValue ( _) => "ByValue" . into ( ) ,
1006+ ty:: UpvarCapture :: ByRef ( borrow) => format ! ( "{:?}" , borrow. kind) ,
1007+ } ;
1008+ format ! ( "{} -> {}" , place_str, capture_kind_str)
9121009}
9131010
9141011fn var_name ( tcx : TyCtxt < ' _ > , var_hir_id : hir:: HirId ) -> Symbol {
@@ -920,7 +1017,9 @@ fn var_name(tcx: TyCtxt<'_>, var_hir_id: hir::HirId) -> Symbol {
9201017/// (Note: CaptureInfo contains CaptureKind and an expression that led to capture it in that way)
9211018///
9221019/// If both `CaptureKind`s are considered equivalent, then the CaptureInfo is selected based
923- /// on the `CaptureInfo` containing an associated expression id.
1020+ /// on the `CaptureInfo` containing an associated `capture_kind_expr_id`.
1021+ ///
1022+ /// It is the caller's duty to figure out which path_expr_id to use.
9241023///
9251024/// If both the CaptureKind and Expression are considered to be equivalent,
9261025/// then `CaptureInfo` A is preferred. This can be useful in cases where we want to priortize
@@ -971,7 +1070,7 @@ fn determine_capture_info(
9711070 } ;
9721071
9731072 if eq_capture_kind {
974- match ( capture_info_a. expr_id , capture_info_b. expr_id ) {
1073+ match ( capture_info_a. capture_kind_expr_id , capture_info_b. capture_kind_expr_id ) {
9751074 ( Some ( _) , _) | ( None , None ) => capture_info_a,
9761075 ( None , Some ( _) ) => capture_info_b,
9771076 }
0 commit comments