about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-08-27 23:44:44 +0200
committerMazdak Farrokhzad <twingoow@gmail.com>2019-08-27 23:44:44 +0200
commit42e895d4d99ec7724f3efd632f52170f3f99a5aa (patch)
treeee1a9de1892767097e8a7ce767191648c78ef3a5
parentdbbe3363c94b120d1eba9cba01dadddd862716b8 (diff)
downloadrust-42e895d4d99ec7724f3efd632f52170f3f99a5aa.tar.gz
rust-42e895d4d99ec7724f3efd632f52170f3f99a5aa.zip
Improve 'mut ' diagnostic.
-rw-r--r--src/libsyntax/parse/parser/pat.rs54
-rw-r--r--src/test/ui/parser/issue-32501.rs2
-rw-r--r--src/test/ui/parser/issue-32501.stderr6
-rw-r--r--src/test/ui/parser/mut-patterns.rs3
-rw-r--r--src/test/ui/parser/mut-patterns.stderr46
-rw-r--r--src/test/ui/self/self_type_keyword.rs2
-rw-r--r--src/test/ui/self/self_type_keyword.stderr6
7 files changed, 82 insertions, 37 deletions
diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs
index 08934e85330..1ffb112a5e8 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<Pat>) {
-                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<Pat>) -> bool {
+        struct AddMut(bool);
+        impl MutVisitor for AddMut {
+            fn visit_pat(&mut self, pat: &mut P<Pat>) {
+                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 695baf81872..500242030c6 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 f5d3300cf9c..d53302449a8 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 0c78ca726e0..d46186a0fea 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 a1293129e2e..18ffaa52558 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 d479905932b..844f13c2f89 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 fdae06ccdd9..bb631194bf3 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