|
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