Skip to content

Commit a739c51

Browse files
committed
Auto merge of #51926 - matthewjasper:Initialization-span, r=nikomatsakis
[NLL] Use better span for initializing a variable twice Closes #51217 When assigning to a (projection from a) local immutable local which starts initialised (everything except `let PATTERN;`): * Point to the declaration of that local * Make the error message refer to the local, rather than the projection. r? @nikomatsakis
2 parents fb97bb5 + c613aa5 commit a739c51

File tree

4 files changed

+42
-28
lines changed

4 files changed

+42
-28
lines changed

src/librustc_mir/borrow_check/error_reporting.rs

+32-17
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010

1111
use borrow_check::WriteKind;
1212
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;
1517
use rustc::ty::{self, RegionKind};
1618
use rustc_data_structures::indexed_vec::Idx;
1719
use rustc_data_structures::sync::Lrc;
@@ -622,42 +624,55 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
622624
assigned_span: Span,
623625
err_place: &Place<'tcx>,
624626
) {
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]))
628630
} else {
629-
false
631+
(false, Some(&self.mir.local_decls[local]))
630632
}
631633
} 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),
633649
};
634650

635651
let mut err = self.tcx.cannot_reassign_immutable(
636652
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,
639655
Origin::Mir,
640656
);
641-
let msg = if is_arg {
657+
let msg = if from_arg {
642658
"cannot assign to immutable argument"
643659
} else {
644660
"cannot assign twice to immutable variable"
645661
};
646662
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 {
649665
Some(name) => format!("`{}`", name),
650666
None => "value".to_owned(),
651667
};
652668
err.span_label(assigned_span, format!("first assignment to {}", value_msg));
653669
}
654670
}
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() {
659674
err.span_label(
660-
local_decl.source_info.span,
675+
decl.source_info.span,
661676
format!("consider changing this to `mut {}`", name),
662677
);
663678
}

src/test/compile-fail/immut-function-arguments.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@
1313

1414
fn f(y: Box<isize>) {
1515
*y = 5; //[ast]~ ERROR cannot assign
16-
//[mir]~^ ERROR cannot assign twice
16+
//[mir]~^ ERROR cannot assign
1717
}
1818

1919
fn g() {
2020
let _frob = |q: Box<isize>| { *q = 2; }; //[ast]~ ERROR cannot assign
21-
//[mir]~^ ERROR cannot assign twice
21+
//[mir]~^ ERROR cannot assign
2222
}
2323

2424
fn main() {}

src/test/ui/command-line-diagnostics.nll.stderr

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ error[E0384]: cannot assign twice to immutable variable `x`
22
--> $DIR/command-line-diagnostics.rs:16:5
33
|
44
LL | let x = 42;
5-
| - -- first assignment to `x`
5+
| -
66
| |
7+
| first assignment to `x`
78
| consider changing this to `mut x`
89
LL | x = 43;
910
| ^^^^^^ cannot assign twice to immutable variable

src/test/ui/did_you_mean/issue-35937.nll.stderr

+6-8
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,24 @@ LL | let f = Foo { v: Vec::new() };
66
LL | f.v.push("cat".to_string()); //~ ERROR cannot borrow
77
| ^^^ cannot borrow as mutable
88

9-
error[E0384]: cannot assign twice to immutable variable `s.x`
9+
error[E0384]: cannot assign twice to immutable variable `s`
1010
--> $DIR/issue-35937.rs:26:5
1111
|
1212
LL | let s = S { x: 42 };
13-
| - ----------- first assignment to `s.x`
13+
| -
1414
| |
15+
| first assignment to `s`
1516
| consider changing this to `mut s`
1617
LL | s.x += 1; //~ ERROR cannot assign
1718
| ^^^^^^^^ cannot assign twice to immutable variable
1819

19-
error[E0384]: cannot assign twice to immutable variable `s.x`
20+
error[E0384]: cannot assign to immutable argument `s`
2021
--> $DIR/issue-35937.rs:30:5
2122
|
2223
LL | fn bar(s: S) {
23-
| -
24-
| |
25-
| first assignment to `s.x`
26-
| consider changing this to `mut s`
24+
| - consider changing this to `mut s`
2725
LL | s.x += 1; //~ ERROR cannot assign
28-
| ^^^^^^^^ cannot assign twice to immutable variable
26+
| ^^^^^^^^ cannot assign to immutable argument
2927

3028
error: aborting due to 3 previous errors
3129

0 commit comments

Comments
 (0)