@@ -461,24 +461,58 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
461
461
MovedInCapture => "capture" ,
462
462
} ;
463
463
464
- match the_move. kind {
464
+ let ( ol , moved_lp_msg ) = match the_move. kind {
465
465
move_data:: Declared => {
466
466
self . tcx . sess . span_err (
467
467
use_span,
468
468
format ! ( "{} of possibly uninitialized variable: `{}`" ,
469
469
verb,
470
470
self . loan_path_to_string( lp) ) . as_slice ( ) ) ;
471
+ ( self . loan_path_to_string ( moved_lp) ,
472
+ String :: new ( ) )
471
473
}
472
474
_ => {
473
- let partially = if lp == moved_lp { "" } else { "partially " } ;
475
+ // If moved_lp is something like `x.a`, and lp is something like `x.b`, we would
476
+ // normally generate a rather confusing message:
477
+ //
478
+ // error: use of moved value: `x.b`
479
+ // note: `x.a` moved here...
480
+ //
481
+ // What we want to do instead is get the 'common ancestor' of the two moves and
482
+ // use that for most of the message instead, giving is something like this:
483
+ //
484
+ // error: use of moved value: `x`
485
+ // note: `x` moved here (through moving `x.a`)...
486
+
487
+ let common = moved_lp. common ( lp) ;
488
+ let has_common = common. is_some ( ) ;
489
+ let has_fork = moved_lp. has_fork ( lp) ;
490
+ let ( nl, ol, moved_lp_msg) =
491
+ if has_fork && has_common {
492
+ let nl = self . loan_path_to_string ( & common. unwrap ( ) ) ;
493
+ let ol = nl. clone ( ) ;
494
+ let moved_lp_msg = format ! ( " (through moving `{}`)" ,
495
+ self . loan_path_to_string( moved_lp) ) ;
496
+ ( nl, ol, moved_lp_msg)
497
+ } else {
498
+ ( self . loan_path_to_string ( lp) ,
499
+ self . loan_path_to_string ( moved_lp) ,
500
+ String :: new ( ) )
501
+ } ;
502
+
503
+ let partial = moved_lp. depth ( ) > lp. depth ( ) ;
504
+ let msg = if !has_fork && partial { "partially " }
505
+ else if has_fork && !has_common { "collaterally " }
506
+ else { "" } ;
474
507
self . tcx . sess . span_err (
475
508
use_span,
476
509
format ! ( "{} of {}moved value: `{}`" ,
477
510
verb,
478
- partially,
479
- self . loan_path_to_string( lp) ) . as_slice ( ) ) ;
511
+ msg,
512
+ nl) . as_slice ( ) ) ;
513
+ ( ol, moved_lp_msg)
480
514
}
481
- }
515
+ } ;
482
516
483
517
match the_move. kind {
484
518
move_data:: Declared => { }
@@ -501,19 +535,21 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
501
535
"moved by default (use `copy` to override)" ) ;
502
536
self . tcx . sess . span_note (
503
537
expr_span,
504
- format ! ( "`{}` moved here because it has type `{}`, which is {}" ,
505
- self . loan_path_to_string( moved_lp) ,
538
+ format ! ( "`{}` moved here{} because it has type `{}`, which is {}" ,
539
+ ol,
540
+ moved_lp_msg,
506
541
expr_ty. user_string( self . tcx) ,
507
542
suggestion) . as_slice ( ) ) ;
508
543
}
509
544
510
545
move_data:: MovePat => {
511
546
let pat_ty = ty:: node_id_to_type ( self . tcx , the_move. id ) ;
512
547
self . tcx . sess . span_note ( self . tcx . map . span ( the_move. id ) ,
513
- format ! ( "`{}` moved here because it has type `{}`, \
548
+ format ! ( "`{}` moved here{} because it has type `{}`, \
514
549
which is moved by default (use `ref` to \
515
550
override)",
516
- self . loan_path_to_string( moved_lp) ,
551
+ ol,
552
+ moved_lp_msg,
517
553
pat_ty. user_string( self . tcx) ) . as_slice ( ) ) ;
518
554
}
519
555
@@ -536,9 +572,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
536
572
capture that instead to override)") ;
537
573
self . tcx . sess . span_note (
538
574
expr_span,
539
- format ! ( "`{}` moved into closure environment here because it \
575
+ format ! ( "`{}` moved into closure environment here{} because it \
540
576
has type `{}`, which is {}",
541
- self . loan_path_to_string( moved_lp) ,
577
+ ol,
578
+ moved_lp_msg,
542
579
expr_ty. user_string( self . tcx) ,
543
580
suggestion) . as_slice ( ) ) ;
544
581
}
0 commit comments