Recover parentheses in range patterns

Co-authored-by: León Orell Valerian Liehr <me@fmease.dev>
This commit is contained in:
Lieselotte 2024-01-03 15:27:58 +01:00
parent e51e98dde6
commit 4e0baddbbf
No known key found for this signature in database
GPG key ID: 43A6A32F83A6F9B1
7 changed files with 151 additions and 18 deletions

View file

@ -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?