diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 08934e8533049..1ffb112a5e87e 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -405,22 +405,13 @@ impl<'a> Parser<'a> { let mut pat = self.parse_pat(Some("identifier"))?; // Add `mut` to any binding in the parsed pattern. - struct AddMut; - impl MutVisitor for AddMut { - fn visit_pat(&mut self, pat: &mut P) { - if let PatKind::Ident(BindingMode::ByValue(ref mut m), ..) = pat.node { - *m = Mutability::Mutable; - } - noop_visit_pat(pat, self); - } - } - AddMut.visit_pat(&mut pat); + let changed_any_binding = Self::make_all_value_bindings_mutable(&mut pat); // Unwrap; If we don't have `mut $ident`, error. let pat = pat.into_inner(); match &pat.node { PatKind::Ident(..) => {} - _ => self.ban_mut_general_pat(mut_span, &pat), + _ => self.ban_mut_general_pat(mut_span, &pat, changed_any_binding), } Ok(pat.node) @@ -442,17 +433,40 @@ impl<'a> Parser<'a> { self.parse_pat_ident(BindingMode::ByRef(Mutability::Mutable)) } + /// Turn all by-value immutable bindings in a pattern into mutable bindings. + /// Returns `true` if any change was made. + fn make_all_value_bindings_mutable(pat: &mut P) -> bool { + struct AddMut(bool); + impl MutVisitor for AddMut { + fn visit_pat(&mut self, pat: &mut P) { + if let PatKind::Ident(BindingMode::ByValue(ref mut m @ Mutability::Immutable), ..) + = pat.node + { + *m = Mutability::Mutable; + self.0 = true; + } + noop_visit_pat(pat, self); + } + } + + let mut add_mut = AddMut(false); + add_mut.visit_pat(pat); + add_mut.0 + } + /// Error on `mut $pat` where `$pat` is not an ident. - fn ban_mut_general_pat(&self, lo: Span, pat: &Pat) { + fn ban_mut_general_pat(&self, lo: Span, pat: &Pat, changed_any_binding: bool) { let span = lo.to(pat.span); - self.struct_span_err(span, "`mut` must be attached to each individual binding") - .span_suggestion( - span, - "add `mut` to each binding", - pprust::pat_to_string(&pat), - Applicability::MachineApplicable, - ) - .emit(); + let fix = pprust::pat_to_string(&pat); + let (problem, suggestion) = if changed_any_binding { + ("`mut` must be attached to each individual binding", "add `mut` to each binding") + } else { + ("`mut` must be followed by a named binding", "remove the `mut` prefix") + }; + self.struct_span_err(span, problem) + .span_suggestion(span, suggestion, fix, Applicability::MachineApplicable) + .note("`mut` may be followed by `variable` and `variable @ pattern`") + .emit() } /// Eat any extraneous `mut`s and error + recover if we ate any. diff --git a/src/test/ui/parser/issue-32501.rs b/src/test/ui/parser/issue-32501.rs index 695baf8187276..500242030c655 100644 --- a/src/test/ui/parser/issue-32501.rs +++ b/src/test/ui/parser/issue-32501.rs @@ -5,5 +5,5 @@ fn main() { let mut b = 0; let mut _b = 0; let mut _ = 0; - //~^ ERROR `mut` must be attached to each individual binding + //~^ ERROR `mut` must be followed by a named binding } diff --git a/src/test/ui/parser/issue-32501.stderr b/src/test/ui/parser/issue-32501.stderr index f5d3300cf9c56..d53302449a806 100644 --- a/src/test/ui/parser/issue-32501.stderr +++ b/src/test/ui/parser/issue-32501.stderr @@ -1,8 +1,10 @@ -error: `mut` must be attached to each individual binding +error: `mut` must be followed by a named binding --> $DIR/issue-32501.rs:7:9 | LL | let mut _ = 0; - | ^^^^^ help: add `mut` to each binding: `_` + | ^^^^^ help: remove the `mut` prefix: `_` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` error: aborting due to previous error diff --git a/src/test/ui/parser/mut-patterns.rs b/src/test/ui/parser/mut-patterns.rs index 0c78ca726e003..d46186a0fea0e 100644 --- a/src/test/ui/parser/mut-patterns.rs +++ b/src/test/ui/parser/mut-patterns.rs @@ -6,6 +6,9 @@ #![allow(warnings)] pub fn main() { + let mut _ = 0; //~ ERROR `mut` must be followed by a named binding + let mut (_, _) = (0, 0); //~ ERROR `mut` must be followed by a named binding + let mut mut x = 0; //~^ ERROR `mut` on a binding may not be repeated //~| remove the additional `mut`s diff --git a/src/test/ui/parser/mut-patterns.stderr b/src/test/ui/parser/mut-patterns.stderr index a1293129e2eaf..18ffaa5255870 100644 --- a/src/test/ui/parser/mut-patterns.stderr +++ b/src/test/ui/parser/mut-patterns.stderr @@ -1,29 +1,49 @@ +error: `mut` must be followed by a named binding + --> $DIR/mut-patterns.rs:9:9 + | +LL | let mut _ = 0; + | ^^^^^ help: remove the `mut` prefix: `_` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` + +error: `mut` must be followed by a named binding + --> $DIR/mut-patterns.rs:10:9 + | +LL | let mut (_, _) = (0, 0); + | ^^^^^^^^^^ help: remove the `mut` prefix: `(_, _)` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` + error: `mut` on a binding may not be repeated - --> $DIR/mut-patterns.rs:9:13 + --> $DIR/mut-patterns.rs:12:13 | LL | let mut mut x = 0; | ^^^ help: remove the additional `mut`s error: `mut` must be attached to each individual binding - --> $DIR/mut-patterns.rs:14:9 + --> $DIR/mut-patterns.rs:17:9 | LL | let mut Foo { x: x } = Foo { x: 3 }; | ^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { x: mut x }` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` error: `mut` must be attached to each individual binding - --> $DIR/mut-patterns.rs:18:9 + --> $DIR/mut-patterns.rs:21:9 | LL | let mut Foo { x } = Foo { x: 3 }; | ^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { mut x }` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` error: `mut` on a binding may not be repeated - --> $DIR/mut-patterns.rs:23:13 + --> $DIR/mut-patterns.rs:26:13 | LL | let mut mut yield(become, await) = r#yield(0, 0); | ^^^ help: remove the additional `mut`s error: expected identifier, found reserved keyword `yield` - --> $DIR/mut-patterns.rs:23:17 + --> $DIR/mut-patterns.rs:26:17 | LL | let mut mut yield(become, await) = r#yield(0, 0); | ^^^^^ expected identifier, found reserved keyword @@ -33,7 +53,7 @@ LL | let mut mut r#yield(become, await) = r#yield(0, 0); | ^^^^^^^ error: expected identifier, found reserved keyword `become` - --> $DIR/mut-patterns.rs:23:23 + --> $DIR/mut-patterns.rs:26:23 | LL | let mut mut yield(become, await) = r#yield(0, 0); | ^^^^^^ expected identifier, found reserved keyword @@ -43,7 +63,7 @@ LL | let mut mut yield(r#become, await) = r#yield(0, 0); | ^^^^^^^^ error: expected identifier, found reserved keyword `await` - --> $DIR/mut-patterns.rs:23:31 + --> $DIR/mut-patterns.rs:26:31 | LL | let mut mut yield(become, await) = r#yield(0, 0); | ^^^^^ expected identifier, found reserved keyword @@ -53,19 +73,23 @@ LL | let mut mut yield(become, r#await) = r#yield(0, 0); | ^^^^^^^ error: `mut` must be attached to each individual binding - --> $DIR/mut-patterns.rs:23:9 + --> $DIR/mut-patterns.rs:26:9 | LL | let mut mut yield(become, await) = r#yield(0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `r#yield(mut r#become, mut r#await)` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` error: `mut` must be attached to each individual binding - --> $DIR/mut-patterns.rs:32:9 + --> $DIR/mut-patterns.rs:35:9 | LL | let mut W(mut a, W(b, W(ref c, W(d, B { box f })))) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `W(mut a, W(mut b, W(ref c, W(mut d, B { box mut f }))))` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` error: expected identifier, found `x` - --> $DIR/mut-patterns.rs:39:21 + --> $DIR/mut-patterns.rs:42:21 | LL | let mut $p = 0; | ^^ expected identifier @@ -73,5 +97,5 @@ LL | let mut $p = 0; LL | foo!(x); | -------- in this macro invocation -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors diff --git a/src/test/ui/self/self_type_keyword.rs b/src/test/ui/self/self_type_keyword.rs index d479905932be0..844f13c2f896a 100644 --- a/src/test/ui/self/self_type_keyword.rs +++ b/src/test/ui/self/self_type_keyword.rs @@ -14,7 +14,7 @@ pub fn main() { ref Self => (), //~^ ERROR expected identifier, found keyword `Self` mut Self => (), - //~^ ERROR `mut` must be attached to each individual binding + //~^ ERROR `mut` must be followed by a named binding //~| ERROR cannot find unit struct/variant or constant `Self` ref mut Self => (), //~^ ERROR expected identifier, found keyword `Self` diff --git a/src/test/ui/self/self_type_keyword.stderr b/src/test/ui/self/self_type_keyword.stderr index fdae06ccdd9f5..bb631194bf3df 100644 --- a/src/test/ui/self/self_type_keyword.stderr +++ b/src/test/ui/self/self_type_keyword.stderr @@ -10,11 +10,13 @@ error: expected identifier, found keyword `Self` LL | ref Self => (), | ^^^^ expected identifier, found keyword -error: `mut` must be attached to each individual binding +error: `mut` must be followed by a named binding --> $DIR/self_type_keyword.rs:16:9 | LL | mut Self => (), - | ^^^^^^^^ help: add `mut` to each binding: `Self` + | ^^^^^^^^ help: remove the `mut` prefix: `Self` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` error: expected identifier, found keyword `Self` --> $DIR/self_type_keyword.rs:19:17