@@ -42,7 +42,7 @@ use rustc_infer::infer::UpvarRegion;
42
42
use rustc_middle:: hir:: place:: { Place , PlaceBase , PlaceWithHirId , ProjectionKind } ;
43
43
use rustc_middle:: ty:: { self , Ty , TyCtxt , UpvarSubsts } ;
44
44
use rustc_span:: sym;
45
- use rustc_span:: { Span , Symbol } ;
45
+ use rustc_span:: { MultiSpan , Span , Symbol } ;
46
46
47
47
/// Describe the relationship between the paths of two places
48
48
/// eg:
@@ -135,7 +135,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
135
135
136
136
let upvar_id = ty:: UpvarId :: new ( var_hir_id, local_def_id) ;
137
137
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
+ } ;
139
143
140
144
capture_information. insert ( place, info) ;
141
145
}
@@ -308,8 +312,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
308
312
if let Some ( capture_kind) = upvar_capture_map. get ( & upvar_id) {
309
313
// upvar_capture_map only stores the UpvarCapture (CaptureKind),
310
314
// 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
+ } ;
313
320
determine_capture_info ( fake_capture_info, capture_info) . capture_kind
314
321
} else {
315
322
capture_info. capture_kind
@@ -359,20 +366,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
359
366
///
360
367
/// ```
361
368
/// {
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
+ /// },
366
389
/// ```
367
390
///
368
391
/// After the min capture analysis, we get:
369
392
/// ```
370
393
/// {
371
394
/// 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
+ /// },
373
400
/// ],
374
401
/// 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
+ /// },
376
407
/// ],
377
408
/// ```
378
409
fn compute_min_captures (
@@ -425,8 +456,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
425
456
// current place is ancestor of possible_descendant
426
457
PlaceAncestryRelation :: Ancestor => {
427
458
descendant_found = true ;
459
+ let backup_path_expr_id = updated_capture_info. path_expr_id ;
460
+
428
461
updated_capture_info =
429
462
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;
430
466
false
431
467
}
432
468
@@ -441,9 +477,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
441
477
// current place is descendant of possible_ancestor
442
478
PlaceAncestryRelation :: Descendant => {
443
479
ancestor_found = true ;
480
+ let backup_path_expr_id = possible_ancestor. info . path_expr_id ;
444
481
possible_ancestor. info =
445
482
determine_capture_info ( possible_ancestor. info , capture_info) ;
446
483
484
+ // we need to keep the ancestor's `path_expr_id`
485
+ possible_ancestor. info . path_expr_id = backup_path_expr_id;
486
+
447
487
// Only one ancestor of the current place will be in the list.
448
488
break ;
449
489
}
@@ -518,7 +558,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
518
558
let capture_str = construct_capture_info_string ( self . tcx , place, capture_info) ;
519
559
let output_str = format ! ( "Capturing {}" , capture_str) ;
520
560
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) ) ;
522
563
diag. span_note ( span, & output_str) ;
523
564
}
524
565
diag. emit ( ) ;
@@ -542,9 +583,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
542
583
construct_capture_info_string ( self . tcx , place, capture_info) ;
543
584
let output_str = format ! ( "Min Capture {}" , capture_str) ;
544
585
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
+ } ;
548
612
}
549
613
}
550
614
diag. emit ( ) ;
@@ -642,7 +706,8 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
642
706
) ;
643
707
644
708
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) ,
646
711
capture_kind : ty:: UpvarCapture :: ByValue ( Some ( usage_span) ) ,
647
712
} ;
648
713
@@ -762,7 +827,8 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
762
827
let new_upvar_borrow = ty:: UpvarBorrow { kind, region : curr_upvar_borrow. region } ;
763
828
764
829
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) ,
766
832
capture_kind : ty:: UpvarCapture :: ByRef ( new_upvar_borrow) ,
767
833
} ;
768
834
let updated_info = determine_capture_info ( curr_capture_info, capture_info) ;
@@ -824,7 +890,11 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
824
890
self . fcx . init_capture_kind ( self . capture_clause , upvar_id, self . closure_span ) ;
825
891
826
892
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
+ } ;
828
898
829
899
debug ! ( "Capturing new place {:?}, capture_info={:?}" , place_with_id, capture_info) ;
830
900
@@ -890,11 +960,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
890
960
}
891
961
}
892
962
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 {
898
964
let variable_name = match place. base {
899
965
PlaceBase :: Upvar ( upvar_id) => var_name ( tcx, upvar_id. var_path . hir_id ) . to_string ( ) ,
900
966
_ => bug ! ( "Capture_information should only contain upvars" ) ,
@@ -914,11 +980,42 @@ fn construct_capture_info_string(
914
980
projections_str. push_str ( proj. as_str ( ) ) ;
915
981
}
916
982
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
+
917
993
let capture_kind_str = match capture_info. capture_kind {
918
994
ty:: UpvarCapture :: ByValue ( _) => "ByValue" . into ( ) ,
919
995
ty:: UpvarCapture :: ByRef ( borrow) => format ! ( "{:?}" , borrow. kind) ,
920
996
} ;
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)
922
1019
}
923
1020
924
1021
fn 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 {
930
1027
/// (Note: CaptureInfo contains CaptureKind and an expression that led to capture it in that way)
931
1028
///
932
1029
/// 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.
934
1033
///
935
1034
/// If both the CaptureKind and Expression are considered to be equivalent,
936
1035
/// then `CaptureInfo` A is preferred. This can be useful in cases where we want to priortize
@@ -981,7 +1080,7 @@ fn determine_capture_info(
981
1080
} ;
982
1081
983
1082
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 ) {
985
1084
( Some ( _) , _) | ( None , None ) => capture_info_a,
986
1085
( None , Some ( _) ) => capture_info_b,
987
1086
}
0 commit comments