@@ -298,6 +298,51 @@ impl LoanPath {
298
298
LpExtend ( ref base, _, _) => base. kill_scope ( tcx) ,
299
299
}
300
300
}
301
+
302
+ fn has_fork ( & self , other : & LoanPath ) -> bool {
303
+ match ( self , other) {
304
+ ( & LpExtend ( ref base, _, LpInterior ( id) ) , & LpExtend ( ref base2, _, LpInterior ( id2) ) ) =>
305
+ if id == id2 {
306
+ base. has_fork ( & * * base2)
307
+ } else {
308
+ true
309
+ } ,
310
+ ( & LpExtend ( ref base, _, LpDeref ( _) ) , _) => base. has_fork ( other) ,
311
+ ( _, & LpExtend ( ref base, _, LpDeref ( _) ) ) => self . has_fork ( & * * base) ,
312
+ _ => false ,
313
+ }
314
+ }
315
+
316
+ fn depth ( & self ) -> uint {
317
+ match * self {
318
+ LpExtend ( ref base, _, LpDeref ( _) ) => base. depth ( ) ,
319
+ LpExtend ( ref base, _, LpInterior ( _) ) => base. depth ( ) + 1 ,
320
+ _ => 0 ,
321
+ }
322
+ }
323
+
324
+ fn common ( & self , other : & LoanPath ) -> Option < LoanPath > {
325
+ match ( self , other) {
326
+ ( & LpExtend ( ref base, a, LpInterior ( id) ) , & LpExtend ( ref base2, _, LpInterior ( id2) ) ) =>
327
+ if id == id2 {
328
+ base. common ( & * * base2) . map ( |x| {
329
+ let xd = x. depth ( ) ;
330
+ if base. depth ( ) == xd && base2. depth ( ) == xd {
331
+ LpExtend ( Rc :: new ( x) , a, LpInterior ( id) )
332
+ } else {
333
+ x
334
+ }
335
+ } )
336
+ } else {
337
+ base. common ( & * * base2)
338
+ } ,
339
+ ( & LpExtend ( ref base, _, LpDeref ( _) ) , _) => base. common ( other) ,
340
+ ( _, & LpExtend ( ref other, _, LpDeref ( _) ) ) => self . common ( & * * other) ,
341
+ ( & LpVar ( id) , & LpVar ( id2) ) => if id == id2 { Some ( LpVar ( id) ) } else { None } ,
342
+ ( & LpUpvar ( id) , & LpUpvar ( id2) ) => if id == id2 { Some ( LpUpvar ( id) ) } else { None } ,
343
+ _ => None ,
344
+ }
345
+ }
301
346
}
302
347
303
348
pub fn opt_loan_path ( cmt : & mc:: cmt ) -> Option < Rc < LoanPath > > {
@@ -416,24 +461,58 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
416
461
MovedInCapture => "capture" ,
417
462
} ;
418
463
419
- match the_move. kind {
464
+ let ( ol , moved_lp_msg ) = match the_move. kind {
420
465
move_data:: Declared => {
421
466
self . tcx . sess . span_err (
422
467
use_span,
423
468
format ! ( "{} of possibly uninitialized variable: `{}`" ,
424
469
verb,
425
470
self . loan_path_to_string( lp) ) . as_slice ( ) ) ;
471
+ ( self . loan_path_to_string ( moved_lp) ,
472
+ String :: new ( ) )
426
473
}
427
474
_ => {
428
- 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 { "" } ;
429
507
self . tcx . sess . span_err (
430
508
use_span,
431
509
format ! ( "{} of {}moved value: `{}`" ,
432
510
verb,
433
- partially,
434
- self . loan_path_to_string( lp) ) . as_slice ( ) ) ;
511
+ msg,
512
+ nl) . as_slice ( ) ) ;
513
+ ( ol, moved_lp_msg)
435
514
}
436
- }
515
+ } ;
437
516
438
517
match the_move. kind {
439
518
move_data:: Declared => { }
@@ -456,19 +535,21 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
456
535
"moved by default (use `copy` to override)" ) ;
457
536
self . tcx . sess . span_note (
458
537
expr_span,
459
- format ! ( "`{}` moved here because it has type `{}`, which is {}" ,
460
- self . loan_path_to_string( moved_lp) ,
538
+ format ! ( "`{}` moved here{} because it has type `{}`, which is {}" ,
539
+ ol,
540
+ moved_lp_msg,
461
541
expr_ty. user_string( self . tcx) ,
462
542
suggestion) . as_slice ( ) ) ;
463
543
}
464
544
465
545
move_data:: MovePat => {
466
546
let pat_ty = ty:: node_id_to_type ( self . tcx , the_move. id ) ;
467
547
self . tcx . sess . span_note ( self . tcx . map . span ( the_move. id ) ,
468
- format ! ( "`{}` moved here because it has type `{}`, \
548
+ format ! ( "`{}` moved here{} because it has type `{}`, \
469
549
which is moved by default (use `ref` to \
470
550
override)",
471
- self . loan_path_to_string( moved_lp) ,
551
+ ol,
552
+ moved_lp_msg,
472
553
pat_ty. user_string( self . tcx) ) . as_slice ( ) ) ;
473
554
}
474
555
@@ -491,9 +572,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
491
572
capture that instead to override)") ;
492
573
self . tcx . sess . span_note (
493
574
expr_span,
494
- format ! ( "`{}` moved into closure environment here because it \
575
+ format ! ( "`{}` moved into closure environment here{} because it \
495
576
has type `{}`, which is {}",
496
- self . loan_path_to_string( moved_lp) ,
577
+ ol,
578
+ moved_lp_msg,
497
579
expr_ty. user_string( self . tcx) ,
498
580
suggestion) . as_slice ( ) ) ;
499
581
}
@@ -602,6 +684,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
602
684
span : Span ,
603
685
kind : AliasableViolationKind ,
604
686
cause : mc:: AliasableReason ) {
687
+ let mut is_closure = false ;
605
688
let prefix = match kind {
606
689
MutabilityViolation => {
607
690
"cannot assign to data"
@@ -625,6 +708,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
625
708
}
626
709
627
710
BorrowViolation ( euv:: ClosureInvocation ) => {
711
+ is_closure = true ;
628
712
"closure invocation"
629
713
}
630
714
@@ -649,14 +733,20 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
649
733
mc:: AliasableManaged => {
650
734
self . tcx . sess . span_err (
651
735
span,
652
- format ! ( "{} in a `@ ` pointer" , prefix) . as_slice ( ) ) ;
736
+ format ! ( "{} in a `Gc ` pointer" , prefix) . as_slice ( ) ) ;
653
737
}
654
738
mc:: AliasableBorrowed => {
655
739
self . tcx . sess . span_err (
656
740
span,
657
741
format ! ( "{} in a `&` reference" , prefix) . as_slice ( ) ) ;
658
742
}
659
743
}
744
+
745
+ if is_closure {
746
+ self . tcx . sess . span_note (
747
+ span,
748
+ "closures behind references must be called via `&mut`" ) ;
749
+ }
660
750
}
661
751
662
752
pub fn note_and_explain_bckerr ( & self , err : BckError ) {
0 commit comments