|
10 | 10 |
|
11 | 11 | use borrow_check::WriteKind;
|
12 | 12 | use rustc::middle::region::ScopeTree;
|
13 |
| -use rustc::mir::{BorrowKind, Field, Local, LocalKind, Location, Operand}; |
14 |
| -use rustc::mir::{Place, ProjectionElem, Rvalue, Statement, StatementKind}; |
| 13 | +use rustc::mir::{BindingForm, BorrowKind, ClearCrossCrate, Field, Local}; |
| 14 | +use rustc::mir::{LocalDecl, LocalKind, Location, Operand, Place}; |
| 15 | +use rustc::mir::{ProjectionElem, Rvalue, Statement, StatementKind}; |
| 16 | +use rustc::mir::VarBindingForm; |
15 | 17 | use rustc::ty::{self, RegionKind};
|
16 | 18 | use rustc_data_structures::indexed_vec::Idx;
|
17 | 19 | use rustc_data_structures::sync::Lrc;
|
@@ -622,42 +624,55 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
622 | 624 | assigned_span: Span,
|
623 | 625 | err_place: &Place<'tcx>,
|
624 | 626 | ) {
|
625 |
| - let is_arg = if let Place::Local(local) = place { |
626 |
| - if let LocalKind::Arg = self.mir.local_kind(*local) { |
627 |
| - true |
| 627 | + let (from_arg, local_decl) = if let Place::Local(local) = *err_place { |
| 628 | + if let LocalKind::Arg = self.mir.local_kind(local) { |
| 629 | + (true, Some(&self.mir.local_decls[local])) |
628 | 630 | } else {
|
629 |
| - false |
| 631 | + (false, Some(&self.mir.local_decls[local])) |
630 | 632 | }
|
631 | 633 | } else {
|
632 |
| - false |
| 634 | + (false, None) |
| 635 | + }; |
| 636 | + |
| 637 | + // If root local is initialized immediately (everything apart from let |
| 638 | + // PATTERN;) then make the error refer to that local, rather than the |
| 639 | + // place being assigned later. |
| 640 | + let (place_description, assigned_span) = match local_decl { |
| 641 | + Some(LocalDecl { is_user_variable: Some(ClearCrossCrate::Clear), .. }) |
| 642 | + | Some(LocalDecl { is_user_variable: Some(ClearCrossCrate::Set( |
| 643 | + BindingForm::Var(VarBindingForm { |
| 644 | + opt_match_place: None, .. |
| 645 | + }))), ..}) |
| 646 | + | Some(LocalDecl { is_user_variable: None, .. }) |
| 647 | + | None => (self.describe_place(place), assigned_span), |
| 648 | + Some(decl) => (self.describe_place(err_place), decl.source_info.span), |
633 | 649 | };
|
634 | 650 |
|
635 | 651 | let mut err = self.tcx.cannot_reassign_immutable(
|
636 | 652 | span,
|
637 |
| - &self.describe_place(place).unwrap_or("_".to_owned()), |
638 |
| - is_arg, |
| 653 | + place_description.as_ref().map(AsRef::as_ref).unwrap_or("_"), |
| 654 | + from_arg, |
639 | 655 | Origin::Mir,
|
640 | 656 | );
|
641 |
| - let msg = if is_arg { |
| 657 | + let msg = if from_arg { |
642 | 658 | "cannot assign to immutable argument"
|
643 | 659 | } else {
|
644 | 660 | "cannot assign twice to immutable variable"
|
645 | 661 | };
|
646 | 662 | if span != assigned_span {
|
647 |
| - if !is_arg { |
648 |
| - let value_msg = match self.describe_place(place) { |
| 663 | + if !from_arg { |
| 664 | + let value_msg = match place_description { |
649 | 665 | Some(name) => format!("`{}`", name),
|
650 | 666 | None => "value".to_owned(),
|
651 | 667 | };
|
652 | 668 | err.span_label(assigned_span, format!("first assignment to {}", value_msg));
|
653 | 669 | }
|
654 | 670 | }
|
655 |
| - if let Place::Local(local) = err_place { |
656 |
| - let local_decl = &self.mir.local_decls[*local]; |
657 |
| - if let Some(name) = local_decl.name { |
658 |
| - if local_decl.can_be_made_mutable() { |
| 671 | + if let Some(decl) = local_decl { |
| 672 | + if let Some(name) = decl.name { |
| 673 | + if decl.can_be_made_mutable() { |
659 | 674 | err.span_label(
|
660 |
| - local_decl.source_info.span, |
| 675 | + decl.source_info.span, |
661 | 676 | format!("consider changing this to `mut {}`", name),
|
662 | 677 | );
|
663 | 678 | }
|
|
0 commit comments