@@ -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
}
@@ -298,8 +302,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
298
302
if let Some ( capture_kind) = upvar_capture_map. get ( & upvar_id) {
299
303
// upvar_capture_map only stores the UpvarCapture (CaptureKind),
300
304
// 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
+ } ;
303
310
determine_capture_info ( fake_capture_info, capture_info) . capture_kind
304
311
} else {
305
312
capture_info. capture_kind
@@ -349,20 +356,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
349
356
///
350
357
/// ```
351
358
/// {
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
+ /// },
356
379
/// ```
357
380
///
358
381
/// After the min capture analysis, we get:
359
382
/// ```
360
383
/// {
361
384
/// 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
+ /// },
363
390
/// ],
364
391
/// 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
+ /// },
366
397
/// ],
367
398
/// ```
368
399
fn compute_min_captures (
@@ -415,8 +446,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
415
446
// current place is ancestor of possible_descendant
416
447
PlaceAncestryRelation :: Ancestor => {
417
448
descendant_found = true ;
449
+ let backup_path_expr_id = updated_capture_info. path_expr_id ;
450
+
418
451
updated_capture_info =
419
452
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;
420
456
false
421
457
}
422
458
@@ -431,9 +467,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
431
467
// current place is descendant of possible_ancestor
432
468
PlaceAncestryRelation :: Descendant => {
433
469
ancestor_found = true ;
470
+ let backup_path_expr_id = possible_ancestor. info . path_expr_id ;
434
471
possible_ancestor. info =
435
472
determine_capture_info ( possible_ancestor. info , capture_info) ;
436
473
474
+ // we need to keep the ancestor's `path_expr_id`
475
+ possible_ancestor. info . path_expr_id = backup_path_expr_id;
476
+
437
477
// Only one ancestor of the current place will be in the list.
438
478
break ;
439
479
}
@@ -508,7 +548,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
508
548
let capture_str = construct_capture_info_string ( self . tcx , place, capture_info) ;
509
549
let output_str = format ! ( "Capturing {}" , capture_str) ;
510
550
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) ) ;
512
553
diag. span_note ( span, & output_str) ;
513
554
}
514
555
diag. emit ( ) ;
@@ -532,9 +573,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
532
573
construct_capture_info_string ( self . tcx , place, capture_info) ;
533
574
let output_str = format ! ( "Min Capture {}" , capture_str) ;
534
575
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
+ } ;
538
602
}
539
603
}
540
604
diag. emit ( ) ;
@@ -632,7 +696,8 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
632
696
) ;
633
697
634
698
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) ,
636
701
capture_kind : ty:: UpvarCapture :: ByValue ( Some ( usage_span) ) ,
637
702
} ;
638
703
@@ -752,7 +817,8 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
752
817
let new_upvar_borrow = ty:: UpvarBorrow { kind, region : curr_upvar_borrow. region } ;
753
818
754
819
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) ,
756
822
capture_kind : ty:: UpvarCapture :: ByRef ( new_upvar_borrow) ,
757
823
} ;
758
824
let updated_info = determine_capture_info ( curr_capture_info, capture_info) ;
@@ -814,7 +880,11 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
814
880
self . fcx . init_capture_kind ( self . capture_clause , upvar_id, self . closure_span ) ;
815
881
816
882
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
+ } ;
818
888
819
889
debug ! ( "Capturing new place {:?}, capture_info={:?}" , place_with_id, capture_info) ;
820
890
@@ -880,11 +950,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
880
950
}
881
951
}
882
952
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 {
888
954
let variable_name = match place. base {
889
955
PlaceBase :: Upvar ( upvar_id) => var_name ( tcx, upvar_id. var_path . hir_id ) . to_string ( ) ,
890
956
_ => bug ! ( "Capture_information should only contain upvars" ) ,
@@ -904,11 +970,42 @@ fn construct_capture_info_string(
904
970
projections_str. push_str ( proj. as_str ( ) ) ;
905
971
}
906
972
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
+
907
983
let capture_kind_str = match capture_info. capture_kind {
908
984
ty:: UpvarCapture :: ByValue ( _) => "ByValue" . into ( ) ,
909
985
ty:: UpvarCapture :: ByRef ( borrow) => format ! ( "{:?}" , borrow. kind) ,
910
986
} ;
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)
912
1009
}
913
1010
914
1011
fn 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 {
920
1017
/// (Note: CaptureInfo contains CaptureKind and an expression that led to capture it in that way)
921
1018
///
922
1019
/// 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.
924
1023
///
925
1024
/// If both the CaptureKind and Expression are considered to be equivalent,
926
1025
/// then `CaptureInfo` A is preferred. This can be useful in cases where we want to priortize
@@ -971,7 +1070,7 @@ fn determine_capture_info(
971
1070
} ;
972
1071
973
1072
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 ) {
975
1074
( Some ( _) , _) | ( None , None ) => capture_info_a,
976
1075
( None , Some ( _) ) => capture_info_b,
977
1076
}
0 commit comments