Skip to content

Commit

Permalink
Auto merge of rust-lang#117289 - estebank:issue-72298, r=cjgillot
Browse files Browse the repository at this point in the history
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 rust-lang#72298.
  • Loading branch information
bors committed Nov 1, 2023
2 parents 7fc6365 + b589f47 commit e8db74b
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 1 deletion.
34 changes: 33 additions & 1 deletion compiler/rustc_parse/src/parser/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down
18 changes: 18 additions & 0 deletions tests/ui/pattern/incorrect-placement-of-pattern-modifiers.fixed
Original file line number Diff line number Diff line change
@@ -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
}
18 changes: 18 additions & 0 deletions tests/ui/pattern/incorrect-placement-of-pattern-modifiers.rs
Original file line number Diff line number Diff line change
@@ -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
}
58 changes: 58 additions & 0 deletions tests/ui/pattern/incorrect-placement-of-pattern-modifiers.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit e8db74b

Please sign in to comment.