From 0b1e08cb557768f168266c7bbcdcb93fcf372a66 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 17 Feb 2020 16:03:07 +0100 Subject: [PATCH] parse: recover `mut (x @ y)` as `(mut x @ mut y)`. --- src/librustc_parse/parser/pat.rs | 29 +++++++++++-------------- src/test/ui/parser/mut-patterns.rs | 2 ++ src/test/ui/parser/mut-patterns.stderr | 30 ++++++++++++++++---------- 3 files changed, 34 insertions(+), 27 deletions(-) diff --git a/src/librustc_parse/parser/pat.rs b/src/librustc_parse/parser/pat.rs index ec6d4db610285..520d325f16b61 100644 --- a/src/librustc_parse/parser/pat.rs +++ b/src/librustc_parse/parser/pat.rs @@ -503,17 +503,18 @@ impl<'a> Parser<'a> { // Parse the pattern we hope to be an identifier. let mut pat = self.parse_pat(Some("identifier"))?; - // Add `mut` to any binding in the parsed pattern. - 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.kind { - PatKind::Ident(..) => {} - _ => self.ban_mut_general_pat(mut_span, &pat, changed_any_binding), + // If we don't have `mut $ident (@ pat)?`, error. + if let PatKind::Ident(BindingMode::ByValue(m @ Mutability::Not), ..) = &mut pat.kind { + // Don't recurse into the subpattern. + // `mut` on the outer binding doesn't affect the inner bindings. + *m = Mutability::Mut; + } else { + // Add `mut` to any binding in the parsed pattern. + let changed_any_binding = Self::make_all_value_bindings_mutable(&mut pat); + self.ban_mut_general_pat(mut_span, &pat, changed_any_binding); } - Ok(pat.kind) + Ok(pat.into_inner().kind) } /// Recover on `mut ref? ident @ pat` and suggest @@ -542,14 +543,10 @@ impl<'a> Parser<'a> { } fn visit_pat(&mut self, pat: &mut P) { - if let PatKind::Ident(ref mut bm, ..) = pat.kind { - if let BindingMode::ByValue(ref mut m @ Mutability::Not) = bm { - *m = Mutability::Mut; - } + if let PatKind::Ident(BindingMode::ByValue(m @ Mutability::Not), ..) = &mut pat.kind + { self.0 = true; - // Don't recurse into the subpattern, mut on the outer - // binding doesn't affect the inner bindings. - return; + *m = Mutability::Mut; } noop_visit_pat(pat, self); } diff --git a/src/test/ui/parser/mut-patterns.rs b/src/test/ui/parser/mut-patterns.rs index 66fd5893af5ee..8b83d6ab2f8c8 100644 --- a/src/test/ui/parser/mut-patterns.rs +++ b/src/test/ui/parser/mut-patterns.rs @@ -9,6 +9,8 @@ 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 (x @ y) = 0; //~ ERROR `mut` must be attached to each individual 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 5f4c349d7d659..9a6af7394bf4a 100644 --- a/src/test/ui/parser/mut-patterns.stderr +++ b/src/test/ui/parser/mut-patterns.stderr @@ -14,14 +14,22 @@ LL | let mut (_, _) = (0, 0); | = note: `mut` may be followed by `variable` and `variable @ pattern` +error: `mut` must be attached to each individual binding + --> $DIR/mut-patterns.rs:12:9 + | +LL | let mut (x @ y) = 0; + | ^^^^^^^^^^^ help: add `mut` to each binding: `(mut x @ mut y)` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` + error: `mut` on a binding may not be repeated - --> $DIR/mut-patterns.rs:12:13 + --> $DIR/mut-patterns.rs:14: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:17:9 + --> $DIR/mut-patterns.rs:19:9 | LL | let mut Foo { x: x } = Foo { x: 3 }; | ^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { x: mut x }` @@ -29,7 +37,7 @@ LL | let mut Foo { x: x } = Foo { x: 3 }; = note: `mut` may be followed by `variable` and `variable @ pattern` error: `mut` must be attached to each individual binding - --> $DIR/mut-patterns.rs:21:9 + --> $DIR/mut-patterns.rs:23:9 | LL | let mut Foo { x } = Foo { x: 3 }; | ^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { mut x }` @@ -37,13 +45,13 @@ LL | let mut Foo { x } = Foo { x: 3 }; = note: `mut` may be followed by `variable` and `variable @ pattern` error: `mut` on a binding may not be repeated - --> $DIR/mut-patterns.rs:26:13 + --> $DIR/mut-patterns.rs:28: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:26:17 + --> $DIR/mut-patterns.rs:28:17 | LL | let mut mut yield(become, await) = r#yield(0, 0); | ^^^^^ expected identifier, found reserved keyword @@ -54,7 +62,7 @@ LL | let mut mut r#yield(become, await) = r#yield(0, 0); | ^^^^^^^ error: expected identifier, found reserved keyword `become` - --> $DIR/mut-patterns.rs:26:23 + --> $DIR/mut-patterns.rs:28:23 | LL | let mut mut yield(become, await) = r#yield(0, 0); | ^^^^^^ expected identifier, found reserved keyword @@ -65,7 +73,7 @@ LL | let mut mut yield(r#become, await) = r#yield(0, 0); | ^^^^^^^^ error: expected identifier, found keyword `await` - --> $DIR/mut-patterns.rs:26:31 + --> $DIR/mut-patterns.rs:28:31 | LL | let mut mut yield(become, await) = r#yield(0, 0); | ^^^^^ expected identifier, found keyword @@ -76,7 +84,7 @@ 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:26:9 + --> $DIR/mut-patterns.rs:28: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)` @@ -84,7 +92,7 @@ LL | let mut mut yield(become, await) = r#yield(0, 0); = note: `mut` may be followed by `variable` and `variable @ pattern` error: `mut` must be attached to each individual binding - --> $DIR/mut-patterns.rs:35:9 + --> $DIR/mut-patterns.rs:37: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 }))))` @@ -92,7 +100,7 @@ LL | let mut W(mut a, W(b, W(ref c, W(d, B { box f })))) = note: `mut` may be followed by `variable` and `variable @ pattern` error: expected identifier, found `x` - --> $DIR/mut-patterns.rs:42:21 + --> $DIR/mut-patterns.rs:44:21 | LL | let mut $p = 0; | ^^ expected identifier @@ -102,5 +110,5 @@ LL | foo!(x); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 12 previous errors +error: aborting due to 13 previous errors