Skip to content

Commit

Permalink
Account for ref and mut in the wrong place for pattern ident rena…
Browse files Browse the repository at this point in the history
…ming

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

Fix #72298.
  • Loading branch information
estebank committed Oct 27, 2023
1 parent 6f65201 commit 505e128
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 1 deletion.
40 changes: 39 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,43 @@ 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
&& self.look_ahead(1, |t| t.is_ident())
&& self.look_ahead(2, |t| {
t == &token::Comma || t == &token::CloseDelim(Delimiter::Brace)
})
&& let span = last.pat.span.with_hi(ident.span.lo())
&& let Ok(snippet) = self.sess.source_map().span_to_snippet(span)
{
// 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()),
(
self.token
.span
.shrink_to_hi()
.with_hi(self.look_ahead(1, |t| t.span.lo())),
format!(" {snippet}"),
),
],
Applicability::MachineApplicable,
);
}
}

/// Recover on `...` or `_` as if it were `..` to avoid further errors.
/// See issue #46718.
fn recover_bad_dot_dot(&self) {
Expand Down
11 changes: 11 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,11 @@
// run-rustfix
struct S {
field_name: (),
}

fn main() {
match (S {field_name: ()}) {
S {field_name: ref _foo} => {} //~ ERROR expected `,`
}
let _: usize = 3usize; //~ ERROR mismatched types
}
11 changes: 11 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,11 @@
// run-rustfix
struct S {
field_name: (),
}

fn main() {
match (S {field_name: ()}) {
S {ref field_name: _foo} => {} //~ ERROR expected `,`
}
let _: usize = 3u8; //~ ERROR mismatched types
}
30 changes: 30 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,30 @@
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[E0308]: mismatched types
--> $DIR/incorrect-placement-of-pattern-modifiers.rs:10: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 2 previous errors

For more information about this error, try `rustc --explain E0308`.

0 comments on commit 505e128

Please sign in to comment.