Skip to content

Commit 42e895d

Browse files
committed
Improve 'mut ' diagnostic.
1 parent dbbe336 commit 42e895d

File tree

7 files changed

+82
-37
lines changed

7 files changed

+82
-37
lines changed

src/libsyntax/parse/parser/pat.rs

+34-20
Original file line numberDiff line numberDiff line change
@@ -405,22 +405,13 @@ impl<'a> Parser<'a> {
405405
let mut pat = self.parse_pat(Some("identifier"))?;
406406

407407
// Add `mut` to any binding in the parsed pattern.
408-
struct AddMut;
409-
impl MutVisitor for AddMut {
410-
fn visit_pat(&mut self, pat: &mut P<Pat>) {
411-
if let PatKind::Ident(BindingMode::ByValue(ref mut m), ..) = pat.node {
412-
*m = Mutability::Mutable;
413-
}
414-
noop_visit_pat(pat, self);
415-
}
416-
}
417-
AddMut.visit_pat(&mut pat);
408+
let changed_any_binding = Self::make_all_value_bindings_mutable(&mut pat);
418409

419410
// Unwrap; If we don't have `mut $ident`, error.
420411
let pat = pat.into_inner();
421412
match &pat.node {
422413
PatKind::Ident(..) => {}
423-
_ => self.ban_mut_general_pat(mut_span, &pat),
414+
_ => self.ban_mut_general_pat(mut_span, &pat, changed_any_binding),
424415
}
425416

426417
Ok(pat.node)
@@ -442,17 +433,40 @@ impl<'a> Parser<'a> {
442433
self.parse_pat_ident(BindingMode::ByRef(Mutability::Mutable))
443434
}
444435

436+
/// Turn all by-value immutable bindings in a pattern into mutable bindings.
437+
/// Returns `true` if any change was made.
438+
fn make_all_value_bindings_mutable(pat: &mut P<Pat>) -> bool {
439+
struct AddMut(bool);
440+
impl MutVisitor for AddMut {
441+
fn visit_pat(&mut self, pat: &mut P<Pat>) {
442+
if let PatKind::Ident(BindingMode::ByValue(ref mut m @ Mutability::Immutable), ..)
443+
= pat.node
444+
{
445+
*m = Mutability::Mutable;
446+
self.0 = true;
447+
}
448+
noop_visit_pat(pat, self);
449+
}
450+
}
451+
452+
let mut add_mut = AddMut(false);
453+
add_mut.visit_pat(pat);
454+
add_mut.0
455+
}
456+
445457
/// Error on `mut $pat` where `$pat` is not an ident.
446-
fn ban_mut_general_pat(&self, lo: Span, pat: &Pat) {
458+
fn ban_mut_general_pat(&self, lo: Span, pat: &Pat, changed_any_binding: bool) {
447459
let span = lo.to(pat.span);
448-
self.struct_span_err(span, "`mut` must be attached to each individual binding")
449-
.span_suggestion(
450-
span,
451-
"add `mut` to each binding",
452-
pprust::pat_to_string(&pat),
453-
Applicability::MachineApplicable,
454-
)
455-
.emit();
460+
let fix = pprust::pat_to_string(&pat);
461+
let (problem, suggestion) = if changed_any_binding {
462+
("`mut` must be attached to each individual binding", "add `mut` to each binding")
463+
} else {
464+
("`mut` must be followed by a named binding", "remove the `mut` prefix")
465+
};
466+
self.struct_span_err(span, problem)
467+
.span_suggestion(span, suggestion, fix, Applicability::MachineApplicable)
468+
.note("`mut` may be followed by `variable` and `variable @ pattern`")
469+
.emit()
456470
}
457471

458472
/// Eat any extraneous `mut`s and error + recover if we ate any.

src/test/ui/parser/issue-32501.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ fn main() {
55
let mut b = 0;
66
let mut _b = 0;
77
let mut _ = 0;
8-
//~^ ERROR `mut` must be attached to each individual binding
8+
//~^ ERROR `mut` must be followed by a named binding
99
}

src/test/ui/parser/issue-32501.stderr

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
error: `mut` must be attached to each individual binding
1+
error: `mut` must be followed by a named binding
22
--> $DIR/issue-32501.rs:7:9
33
|
44
LL | let mut _ = 0;
5-
| ^^^^^ help: add `mut` to each binding: `_`
5+
| ^^^^^ help: remove the `mut` prefix: `_`
6+
|
7+
= note: `mut` may be followed by `variable` and `variable @ pattern`
68

79
error: aborting due to previous error
810

src/test/ui/parser/mut-patterns.rs

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
#![allow(warnings)]
77

88
pub fn main() {
9+
let mut _ = 0; //~ ERROR `mut` must be followed by a named binding
10+
let mut (_, _) = (0, 0); //~ ERROR `mut` must be followed by a named binding
11+
912
let mut mut x = 0;
1013
//~^ ERROR `mut` on a binding may not be repeated
1114
//~| remove the additional `mut`s
+35-11
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,49 @@
1+
error: `mut` must be followed by a named binding
2+
--> $DIR/mut-patterns.rs:9:9
3+
|
4+
LL | let mut _ = 0;
5+
| ^^^^^ help: remove the `mut` prefix: `_`
6+
|
7+
= note: `mut` may be followed by `variable` and `variable @ pattern`
8+
9+
error: `mut` must be followed by a named binding
10+
--> $DIR/mut-patterns.rs:10:9
11+
|
12+
LL | let mut (_, _) = (0, 0);
13+
| ^^^^^^^^^^ help: remove the `mut` prefix: `(_, _)`
14+
|
15+
= note: `mut` may be followed by `variable` and `variable @ pattern`
16+
117
error: `mut` on a binding may not be repeated
2-
--> $DIR/mut-patterns.rs:9:13
18+
--> $DIR/mut-patterns.rs:12:13
319
|
420
LL | let mut mut x = 0;
521
| ^^^ help: remove the additional `mut`s
622

723
error: `mut` must be attached to each individual binding
8-
--> $DIR/mut-patterns.rs:14:9
24+
--> $DIR/mut-patterns.rs:17:9
925
|
1026
LL | let mut Foo { x: x } = Foo { x: 3 };
1127
| ^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { x: mut x }`
28+
|
29+
= note: `mut` may be followed by `variable` and `variable @ pattern`
1230

1331
error: `mut` must be attached to each individual binding
14-
--> $DIR/mut-patterns.rs:18:9
32+
--> $DIR/mut-patterns.rs:21:9
1533
|
1634
LL | let mut Foo { x } = Foo { x: 3 };
1735
| ^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { mut x }`
36+
|
37+
= note: `mut` may be followed by `variable` and `variable @ pattern`
1838

1939
error: `mut` on a binding may not be repeated
20-
--> $DIR/mut-patterns.rs:23:13
40+
--> $DIR/mut-patterns.rs:26:13
2141
|
2242
LL | let mut mut yield(become, await) = r#yield(0, 0);
2343
| ^^^ help: remove the additional `mut`s
2444

2545
error: expected identifier, found reserved keyword `yield`
26-
--> $DIR/mut-patterns.rs:23:17
46+
--> $DIR/mut-patterns.rs:26:17
2747
|
2848
LL | let mut mut yield(become, await) = r#yield(0, 0);
2949
| ^^^^^ expected identifier, found reserved keyword
@@ -33,7 +53,7 @@ LL | let mut mut r#yield(become, await) = r#yield(0, 0);
3353
| ^^^^^^^
3454

3555
error: expected identifier, found reserved keyword `become`
36-
--> $DIR/mut-patterns.rs:23:23
56+
--> $DIR/mut-patterns.rs:26:23
3757
|
3858
LL | let mut mut yield(become, await) = r#yield(0, 0);
3959
| ^^^^^^ expected identifier, found reserved keyword
@@ -43,7 +63,7 @@ LL | let mut mut yield(r#become, await) = r#yield(0, 0);
4363
| ^^^^^^^^
4464

4565
error: expected identifier, found reserved keyword `await`
46-
--> $DIR/mut-patterns.rs:23:31
66+
--> $DIR/mut-patterns.rs:26:31
4767
|
4868
LL | let mut mut yield(become, await) = r#yield(0, 0);
4969
| ^^^^^ expected identifier, found reserved keyword
@@ -53,25 +73,29 @@ LL | let mut mut yield(become, r#await) = r#yield(0, 0);
5373
| ^^^^^^^
5474

5575
error: `mut` must be attached to each individual binding
56-
--> $DIR/mut-patterns.rs:23:9
76+
--> $DIR/mut-patterns.rs:26:9
5777
|
5878
LL | let mut mut yield(become, await) = r#yield(0, 0);
5979
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `r#yield(mut r#become, mut r#await)`
80+
|
81+
= note: `mut` may be followed by `variable` and `variable @ pattern`
6082

6183
error: `mut` must be attached to each individual binding
62-
--> $DIR/mut-patterns.rs:32:9
84+
--> $DIR/mut-patterns.rs:35:9
6385
|
6486
LL | let mut W(mut a, W(b, W(ref c, W(d, B { box f }))))
6587
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `W(mut a, W(mut b, W(ref c, W(mut d, B { box mut f }))))`
88+
|
89+
= note: `mut` may be followed by `variable` and `variable @ pattern`
6690

6791
error: expected identifier, found `x`
68-
--> $DIR/mut-patterns.rs:39:21
92+
--> $DIR/mut-patterns.rs:42:21
6993
|
7094
LL | let mut $p = 0;
7195
| ^^ expected identifier
7296
...
7397
LL | foo!(x);
7498
| -------- in this macro invocation
7599

76-
error: aborting due to 10 previous errors
100+
error: aborting due to 12 previous errors
77101

src/test/ui/self/self_type_keyword.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub fn main() {
1414
ref Self => (),
1515
//~^ ERROR expected identifier, found keyword `Self`
1616
mut Self => (),
17-
//~^ ERROR `mut` must be attached to each individual binding
17+
//~^ ERROR `mut` must be followed by a named binding
1818
//~| ERROR cannot find unit struct/variant or constant `Self`
1919
ref mut Self => (),
2020
//~^ ERROR expected identifier, found keyword `Self`

src/test/ui/self/self_type_keyword.stderr

+4-2
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ error: expected identifier, found keyword `Self`
1010
LL | ref Self => (),
1111
| ^^^^ expected identifier, found keyword
1212

13-
error: `mut` must be attached to each individual binding
13+
error: `mut` must be followed by a named binding
1414
--> $DIR/self_type_keyword.rs:16:9
1515
|
1616
LL | mut Self => (),
17-
| ^^^^^^^^ help: add `mut` to each binding: `Self`
17+
| ^^^^^^^^ help: remove the `mut` prefix: `Self`
18+
|
19+
= note: `mut` may be followed by `variable` and `variable @ pattern`
1820

1921
error: expected identifier, found keyword `Self`
2022
--> $DIR/self_type_keyword.rs:19:17

0 commit comments

Comments
 (0)