@@ -461,24 +461,58 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
461461 MovedInCapture => "capture" ,
462462 } ;
463463
464- match the_move. kind {
464+ let ( ol , moved_lp_msg ) = match the_move. kind {
465465 move_data:: Declared => {
466466 self . tcx . sess . span_err (
467467 use_span,
468468 format ! ( "{} of possibly uninitialized variable: `{}`" ,
469469 verb,
470470 self . loan_path_to_string( lp) ) . as_slice ( ) ) ;
471+ ( self . loan_path_to_string ( moved_lp) ,
472+ String :: new ( ) )
471473 }
472474 _ => {
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 { "" } ;
474507 self . tcx . sess . span_err (
475508 use_span,
476509 format ! ( "{} of {}moved value: `{}`" ,
477510 verb,
478- partially,
479- self . loan_path_to_string( lp) ) . as_slice ( ) ) ;
511+ msg,
512+ nl) . as_slice ( ) ) ;
513+ ( ol, moved_lp_msg)
480514 }
481- }
515+ } ;
482516
483517 match the_move. kind {
484518 move_data:: Declared => { }
@@ -501,19 +535,21 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
501535 "moved by default (use `copy` to override)" ) ;
502536 self . tcx . sess . span_note (
503537 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,
506541 expr_ty. user_string( self . tcx) ,
507542 suggestion) . as_slice ( ) ) ;
508543 }
509544
510545 move_data:: MovePat => {
511546 let pat_ty = ty:: node_id_to_type ( self . tcx , the_move. id ) ;
512547 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 `{}`, \
514549 which is moved by default (use `ref` to \
515550 override)",
516- self . loan_path_to_string( moved_lp) ,
551+ ol,
552+ moved_lp_msg,
517553 pat_ty. user_string( self . tcx) ) . as_slice ( ) ) ;
518554 }
519555
@@ -536,9 +572,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
536572 capture that instead to override)") ;
537573 self . tcx . sess . span_note (
538574 expr_span,
539- format ! ( "`{}` moved into closure environment here because it \
575+ format ! ( "`{}` moved into closure environment here{} because it \
540576 has type `{}`, which is {}",
541- self . loan_path_to_string( moved_lp) ,
577+ ol,
578+ moved_lp_msg,
542579 expr_ty. user_string( self . tcx) ,
543580 suggestion) . as_slice ( ) ) ;
544581 }
0 commit comments