@@ -400,50 +400,82 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
400400 for restr_path in loan1. restricted_paths . iter ( ) {
401401 if * restr_path != loan2_base_path { continue ; }
402402
403- let old_pronoun = if new_loan. loan_path == old_loan. loan_path {
403+ // If new_loan is something like `x.a`, and old_loan is something like `x.b`, we would
404+ // normally generate a rather confusing message (in this case, for multiple mutable
405+ // borrows):
406+ //
407+ // error: cannot borrow `x.b` as mutable more than once at a time
408+ // note: previous borrow of `x.a` occurs here; the mutable borrow prevents
409+ // subsequent moves, borrows, or modification of `x.a` until the borrow ends
410+ //
411+ // What we want to do instead is get the 'common ancestor' of the two borrow paths and
412+ // use that for most of the message instead, giving is something like this:
413+ //
414+ // error: cannot borrow `x` as mutable more than once at a time
415+ // note: previous borrow of `x` occurs here (through borrowing `x.a`); the mutable
416+ // borrow prevents subsequent moves, borrows, or modification of `x` until the
417+ // borrow ends
418+
419+ let common = new_loan. loan_path . common ( & * old_loan. loan_path ) ;
420+ let ( nl, ol, new_loan_msg, old_loan_msg) =
421+ if new_loan. loan_path . has_fork ( & * old_loan. loan_path ) && common. is_some ( ) {
422+ let nl = self . bccx . loan_path_to_string ( & common. unwrap ( ) ) ;
423+ let ol = nl. clone ( ) ;
424+ let new_loan_msg = format ! ( " (here through borrowing `{}`)" ,
425+ self . bccx. loan_path_to_string(
426+ & * new_loan. loan_path) ) ;
427+ let old_loan_msg = format ! ( " (through borrowing `{}`)" ,
428+ self . bccx. loan_path_to_string(
429+ & * old_loan. loan_path) ) ;
430+ ( nl, ol, new_loan_msg, old_loan_msg)
431+ } else {
432+ ( self . bccx . loan_path_to_string ( & * new_loan. loan_path ) ,
433+ self . bccx . loan_path_to_string ( & * old_loan. loan_path ) ,
434+ String :: new ( ) , String :: new ( ) )
435+ } ;
436+
437+ let ol_pronoun = if new_loan. loan_path == old_loan. loan_path {
404438 "it" . to_string ( )
405439 } else {
406- format ! ( "`{}`" ,
407- self . bccx. loan_path_to_string( & * old_loan. loan_path) )
440+ format ! ( "`{}`" , ol)
408441 } ;
409442
410443 match ( new_loan. kind , old_loan. kind ) {
411444 ( ty:: MutBorrow , ty:: MutBorrow ) => {
412445 self . bccx . span_err (
413446 new_loan. span ,
414- format ! ( "cannot borrow `{}` as mutable \
447+ format ! ( "cannot borrow `{}`{} as mutable \
415448 more than once at a time",
416- self . bccx. loan_path_to_string(
417- & * new_loan. loan_path) ) . as_slice ( ) ) ;
449+ nl, new_loan_msg) . as_slice ( ) )
418450 }
419451
420452 ( ty:: UniqueImmBorrow , _) => {
421453 self . bccx . span_err (
422454 new_loan. span ,
423455 format ! ( "closure requires unique access to `{}` \
424- but {} is already borrowed",
425- self . bccx. loan_path_to_string( & * new_loan. loan_path) ,
426- old_pronoun) . as_slice ( ) ) ;
456+ but {} is already borrowed{}",
457+ nl, ol_pronoun, old_loan_msg) . as_slice ( ) ) ;
427458 }
428459
429460 ( _, ty:: UniqueImmBorrow ) => {
430461 self . bccx . span_err (
431462 new_loan. span ,
432- format ! ( "cannot borrow `{}` as {} because \
463+ format ! ( "cannot borrow `{}`{} as {} because \
433464 previous closure requires unique access",
434- self . bccx. loan_path_to_string( & * new_loan. loan_path) ,
435- new_loan. kind. to_user_str( ) ) . as_slice ( ) ) ;
465+ nl, new_loan_msg, new_loan. kind. to_user_str( ) ) . as_slice ( ) ) ;
436466 }
437467
438468 ( _, _) => {
439469 self . bccx . span_err (
440470 new_loan. span ,
441- format ! ( "cannot borrow `{}` as {} because \
442- {} is also borrowed as {}",
443- self . bccx. loan_path_to_string( & * new_loan. loan_path) ,
471+ format ! ( "cannot borrow `{}`{} as {} because \
472+ {} is also borrowed as {}{}",
473+ nl,
474+ new_loan_msg,
444475 new_loan. kind. to_user_str( ) ,
445- old_pronoun,
446- old_loan. kind. to_user_str( ) ) . as_slice ( ) ) ;
476+ ol_pronoun,
477+ old_loan. kind. to_user_str( ) ,
478+ old_loan_msg) . as_slice ( ) ) ;
447479 }
448480 }
449481
@@ -452,8 +484,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
452484 self . bccx . span_note (
453485 span,
454486 format ! ( "borrow occurs due to use of `{}` in closure" ,
455- self . bccx. loan_path_to_string(
456- & * new_loan. loan_path) ) . as_slice ( ) ) ;
487+ nl) . as_slice ( ) ) ;
457488 }
458489 _ => { }
459490 }
@@ -463,30 +494,29 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
463494 format ! ( "the mutable borrow prevents subsequent \
464495 moves, borrows, or modification of `{0}` \
465496 until the borrow ends",
466- self . bccx. loan_path_to_string(
467- & * old_loan. loan_path) )
497+ ol)
468498 }
469499
470500 ty:: ImmBorrow => {
471501 format ! ( "the immutable borrow prevents subsequent \
472502 moves or mutable borrows of `{0}` \
473503 until the borrow ends",
474- self . bccx . loan_path_to_string ( & * old_loan . loan_path ) )
504+ ol )
475505 }
476506
477507 ty:: UniqueImmBorrow => {
478508 format ! ( "the unique capture prevents subsequent \
479509 moves or borrows of `{0}` \
480510 until the borrow ends",
481- self . bccx . loan_path_to_string ( & * old_loan . loan_path ) )
511+ ol )
482512 }
483513 } ;
484514
485515 let borrow_summary = match old_loan. cause {
486516 euv:: ClosureCapture ( _) => {
487- format ! ( "previous borrow of `{}` occurs here due to \
517+ format ! ( "previous borrow of `{}` occurs here{} due to \
488518 use in closure",
489- self . bccx . loan_path_to_string ( & * old_loan . loan_path ) )
519+ ol , old_loan_msg )
490520 }
491521
492522 euv:: OverloadedOperator ( ..) |
@@ -496,8 +526,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
496526 euv:: ForLoop ( ..) |
497527 euv:: RefBinding ( ..) |
498528 euv:: MatchDiscriminant ( ..) => {
499- format ! ( "previous borrow of `{}` occurs here" ,
500- self . bccx . loan_path_to_string ( & * old_loan . loan_path ) )
529+ format ! ( "previous borrow of `{}` occurs here{} " ,
530+ ol , old_loan_msg )
501531 }
502532 } ;
503533
0 commit comments