about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-11-01 18:39:01 +0000
committerbors <bors@rust-lang.org>2023-11-01 18:39:01 +0000
commitb0a07595b5ca544c499775db0987a673a96dc074 (patch)
tree914912b8e0b5967dca38f1e7c2400fff2c0d8f70
parentf3457dbf84cd86d284454d12705861398ece76c3 (diff)
parentb589f474410829046f2f37ff31bd7035b87251fa (diff)
downloadrust-b0a07595b5ca544c499775db0987a673a96dc074.tar.gz
rust-b0a07595b5ca544c499775db0987a673a96dc074.zip
Auto merge of #117289 - estebank:issue-72298, r=cjgillot
Account for `ref` and `mut` in the wrong place for pattern ident renaming

If the user writes `S { ref field: name }` instead of `S { field: ref name }`, we suggest the correct code.

Fix #72298.
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs34
-rw-r--r--tests/ui/pattern/incorrect-placement-of-pattern-modifiers.fixed18
-rw-r--r--tests/ui/pattern/incorrect-placement-of-pattern-modifiers.rs18
-rw-r--r--tests/ui/pattern/incorrect-placement-of-pattern-modifiers.stderr58
4 files changed, 127 insertions, 1 deletions
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 3e4e9278910..3378e4d46b7 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -967,11 +967,12 @@ impl<'a> Parser<'a> {
 
             // check that a comma comes after every field
             if !ate_comma {
-                let err = ExpectedCommaAfterPatternField { span: self.token.span }
+                let mut err = ExpectedCommaAfterPatternField { span: self.token.span }
                     .into_diagnostic(&self.sess.span_diagnostic);
                 if let Some(mut delayed) = delayed_err {
                     delayed.emit();
                 }
+                self.recover_misplaced_pattern_modifiers(&fields, &mut err);
                 return Err(err);
             }
             ate_comma = false;
@@ -1109,6 +1110,37 @@ impl<'a> Parser<'a> {
         Ok((fields, etc))
     }
 
+    /// If the user writes `S { ref field: name }` instead of `S { field: ref name }`, we suggest
+    /// the correct code.
+    fn recover_misplaced_pattern_modifiers(
+        &self,
+        fields: &ThinVec<PatField>,
+        err: &mut DiagnosticBuilder<'a, ErrorGuaranteed>,
+    ) {
+        if let Some(last) = fields.iter().last()
+            && last.is_shorthand
+            && let PatKind::Ident(binding, ident, None) = last.pat.kind
+            && binding != BindingAnnotation::NONE
+            && self.token == token::Colon
+            // We found `ref mut? ident:`, try to parse a `name,` or `name }`.
+            && let Some(name_span) = self.look_ahead(1, |t| t.is_ident().then(|| t.span))
+            && self.look_ahead(2, |t| {
+                t == &token::Comma || t == &token::CloseDelim(Delimiter::Brace)
+            })
+        {
+            let span = last.pat.span.with_hi(ident.span.lo());
+            // We have `S { ref field: name }` instead of `S { field: ref name }`
+            err.multipart_suggestion(
+                "the pattern modifiers belong after the `:`",
+                vec![
+                    (span, String::new()),
+                    (name_span.shrink_to_lo(), binding.prefix_str().to_string()),
+                ],
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
     /// Recover on `...` or `_` as if it were `..` to avoid further errors.
     /// See issue #46718.
     fn recover_bad_dot_dot(&self) {
diff --git a/tests/ui/pattern/incorrect-placement-of-pattern-modifiers.fixed b/tests/ui/pattern/incorrect-placement-of-pattern-modifiers.fixed
new file mode 100644
index 00000000000..cf6c2a24fdf
--- /dev/null
+++ b/tests/ui/pattern/incorrect-placement-of-pattern-modifiers.fixed
@@ -0,0 +1,18 @@
+// run-rustfix
+struct S {
+    field_name: (),
+}
+
+fn main() {
+    match (S {field_name: ()}) {
+        S {field_name: ref _foo} => {} //~ ERROR expected `,`
+    }
+    match (S {field_name: ()}) {
+        S {field_name: mut _foo} => {} //~ ERROR expected `,`
+    }
+    match (S {field_name: ()}) {
+        S {field_name: ref mut _foo} => {} //~ ERROR expected `,`
+    }
+    // Verify that we recover enough to run typeck.
+    let _: usize = 3usize; //~ ERROR mismatched types
+}
diff --git a/tests/ui/pattern/incorrect-placement-of-pattern-modifiers.rs b/tests/ui/pattern/incorrect-placement-of-pattern-modifiers.rs
new file mode 100644
index 00000000000..98772c1188e
--- /dev/null
+++ b/tests/ui/pattern/incorrect-placement-of-pattern-modifiers.rs
@@ -0,0 +1,18 @@
+// run-rustfix
+struct S {
+    field_name: (),
+}
+
+fn main() {
+    match (S {field_name: ()}) {
+        S {ref field_name: _foo} => {} //~ ERROR expected `,`
+    }
+    match (S {field_name: ()}) {
+        S {mut field_name: _foo} => {} //~ ERROR expected `,`
+    }
+    match (S {field_name: ()}) {
+        S {ref mut field_name: _foo} => {} //~ ERROR expected `,`
+    }
+    // Verify that we recover enough to run typeck.
+    let _: usize = 3u8; //~ ERROR mismatched types
+}
diff --git a/tests/ui/pattern/incorrect-placement-of-pattern-modifiers.stderr b/tests/ui/pattern/incorrect-placement-of-pattern-modifiers.stderr
new file mode 100644
index 00000000000..e80789253c0
--- /dev/null
+++ b/tests/ui/pattern/incorrect-placement-of-pattern-modifiers.stderr
@@ -0,0 +1,58 @@
+error: expected `,`
+  --> $DIR/incorrect-placement-of-pattern-modifiers.rs:8:26
+   |
+LL |         S {ref field_name: _foo} => {}
+   |         -                ^
+   |         |
+   |         while parsing the fields for this pattern
+   |
+help: the pattern modifiers belong after the `:`
+   |
+LL -         S {ref field_name: _foo} => {}
+LL +         S {field_name: ref _foo} => {}
+   |
+
+error: expected `,`
+  --> $DIR/incorrect-placement-of-pattern-modifiers.rs:11:26
+   |
+LL |         S {mut field_name: _foo} => {}
+   |         -                ^
+   |         |
+   |         while parsing the fields for this pattern
+   |
+help: the pattern modifiers belong after the `:`
+   |
+LL -         S {mut field_name: _foo} => {}
+LL +         S {field_name: mut _foo} => {}
+   |
+
+error: expected `,`
+  --> $DIR/incorrect-placement-of-pattern-modifiers.rs:14:30
+   |
+LL |         S {ref mut field_name: _foo} => {}
+   |         -                    ^
+   |         |
+   |         while parsing the fields for this pattern
+   |
+help: the pattern modifiers belong after the `:`
+   |
+LL -         S {ref mut field_name: _foo} => {}
+LL +         S {field_name: ref mut _foo} => {}
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/incorrect-placement-of-pattern-modifiers.rs:17:20
+   |
+LL |     let _: usize = 3u8;
+   |            -----   ^^^ expected `usize`, found `u8`
+   |            |
+   |            expected due to this
+   |
+help: change the type of the numeric literal from `u8` to `usize`
+   |
+LL |     let _: usize = 3usize;
+   |                     ~~~~~
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.