diff options
Diffstat (limited to 'compiler/rustc_parse/src/parser/pat.rs')
-rw-r--r-- | compiler/rustc_parse/src/parser/pat.rs | 37 |
1 files changed, 35 insertions, 2 deletions
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 3e4e92789..0a4c7c17d 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -20,8 +20,9 @@ use rustc_ast::{ use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult}; use rustc_session::errors::ExprParenthesesNeeded; -use rustc_span::source_map::{respan, Span, Spanned}; +use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::Span; use thin_vec::{thin_vec, ThinVec}; #[derive(PartialEq, Copy, Clone)] @@ -967,11 +968,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 +1111,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) { |