diff options
| author | bors <bors@rust-lang.org> | 2023-11-01 18:39:01 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-11-01 18:39:01 +0000 |
| commit | b0a07595b5ca544c499775db0987a673a96dc074 (patch) | |
| tree | 914912b8e0b5967dca38f1e7c2400fff2c0d8f70 | |
| parent | f3457dbf84cd86d284454d12705861398ece76c3 (diff) | |
| parent | b589f474410829046f2f37ff31bd7035b87251fa (diff) | |
| download | rust-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.
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`. |
