about summary refs log tree commit diff
path: root/compiler/rustc_parse/src/parser
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 /compiler/rustc_parse/src/parser
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.
Diffstat (limited to 'compiler/rustc_parse/src/parser')
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs34
1 files changed, 33 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) {