diff options
| author | Lieselotte <52315535+she3py@users.noreply.github.com> | 2024-01-03 15:27:58 +0100 |
|---|---|---|
| committer | Lieselotte <52315535+she3py@users.noreply.github.com> | 2024-01-03 15:27:58 +0100 |
| commit | 4e0baddbbf1a6ceadda28f2eb7edc188822942f3 (patch) | |
| tree | 9c5fab2d6c7cd2a9c2be4312ac28dbb238ac5337 /compiler/rustc_parse/src | |
| parent | e51e98dde6a60637b6a71b8105245b629ac3fe77 (diff) | |
| download | rust-4e0baddbbf1a6ceadda28f2eb7edc188822942f3.tar.gz rust-4e0baddbbf1a6ceadda28f2eb7edc188822942f3.zip | |
Recover parentheses in range patterns
Co-authored-by: León Orell Valerian Liehr <me@fmease.dev>
Diffstat (limited to 'compiler/rustc_parse/src')
| -rw-r--r-- | compiler/rustc_parse/src/errors.rs | 21 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/pat.rs | 56 |
2 files changed, 74 insertions, 3 deletions
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index e276b34ca37..d67ae149344 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2379,6 +2379,27 @@ pub(crate) struct ExpectedCommaAfterPatternField { } #[derive(Diagnostic)] +#[diag(parse_unexpected_paren_in_range_pat)] +pub(crate) struct UnexpectedParenInRangePat { + #[primary_span] + pub span: Vec<Span>, + #[subdiagnostic] + pub sugg: UnexpectedParenInRangePatSugg, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + parse_unexpected_paren_in_range_pat_sugg, + applicability = "machine-applicable" +)] +pub(crate) struct UnexpectedParenInRangePatSugg { + #[suggestion_part(code = "")] + pub start_span: Span, + #[suggestion_part(code = "")] + pub end_span: Span, +} + +#[derive(Diagnostic)] #[diag(parse_return_types_use_thin_arrow)] pub(crate) struct ReturnTypesUseThinArrow { #[primary_span] diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index afbc2537578..7d17b1d4c4d 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -6,7 +6,8 @@ use crate::errors::{ InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern, PatternOnWrongSideOfAt, RefMutOrderIncorrect, RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, - TrailingVertNotAllowed, UnexpectedLifetimeInPattern, UnexpectedVertVertBeforeFunctionParam, + TrailingVertNotAllowed, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat, + UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, }; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; @@ -579,6 +580,8 @@ impl<'a> Parser<'a> { /// Parse a tuple or parenthesis pattern. fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> { + let open_paren = self.token.span; + let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| { p.parse_pat_allow_top_alt( None, @@ -591,7 +594,29 @@ impl<'a> Parser<'a> { // Here, `(pat,)` is a tuple pattern. // For backward compatibility, `(..)` is a tuple pattern as well. Ok(if fields.len() == 1 && !(trailing_comma || fields[0].is_rest()) { - PatKind::Paren(fields.into_iter().next().unwrap()) + let pat = fields.into_iter().next().unwrap(); + let close_paren = self.prev_token.span; + + match &pat.kind { + // recover ranges with parentheses around the `(start)..` + PatKind::Lit(begin) + if self.may_recover() + && let Some(form) = self.parse_range_end() => + { + self.dcx().emit_err(UnexpectedParenInRangePat { + span: vec![open_paren, close_paren], + sugg: UnexpectedParenInRangePatSugg { + start_span: open_paren, + end_span: close_paren, + }, + }); + + self.parse_pat_range_begin_with(begin.clone(), form)? + } + + // (pat) with optional parentheses + _ => PatKind::Paren(pat), + } } else { PatKind::Tuple(fields) }) @@ -794,11 +819,21 @@ impl<'a> Parser<'a> { || t.can_begin_literal_maybe_minus() // e.g. `42`. || t.is_whole_expr() || t.is_lifetime() // recover `'a` instead of `'a'` + || (self.may_recover() // recover leading `(` + && t.kind == token::OpenDelim(Delimiter::Parenthesis) + && self.look_ahead(dist + 1, |t| t.kind != token::OpenDelim(Delimiter::Parenthesis)) + && self.is_pat_range_end_start(dist + 1)) }) } + /// Parse a range pattern end bound fn parse_pat_range_end(&mut self) -> PResult<'a, P<Expr>> { - if self.check_inline_const(0) { + // recover leading `(` + let open_paren = (self.may_recover() + && self.eat_noexpect(&token::OpenDelim(Delimiter::Parenthesis))) + .then_some(self.prev_token.span); + + let bound = if self.check_inline_const(0) { self.parse_const_block(self.token.span, true) } else if self.check_path() { let lo = self.token.span; @@ -814,7 +849,22 @@ impl<'a> Parser<'a> { Ok(self.mk_expr(lo.to(hi), ExprKind::Path(qself, path))) } else { self.parse_literal_maybe_minus() + }?; + + // recover trailing `)` + if let Some(open_paren) = open_paren { + self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; + + self.dcx().emit_err(UnexpectedParenInRangePat { + span: vec![open_paren, self.prev_token.span], + sugg: UnexpectedParenInRangePatSugg { + start_span: open_paren, + end_span: self.prev_token.span, + }, + }); } + + Ok(bound) } /// Is this the start of a pattern beginning with a path? |
