summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_parse/src/parser/pat.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
commitd1b2d29528b7794b41e66fc2136e395a02f8529b (patch)
treea4a17504b260206dec3cf55b2dca82929a348ac2 /compiler/rustc_parse/src/parser/pat.rs
parentReleasing progress-linux version 1.72.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.tar.xz
rustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.zip
Merging upstream version 1.73.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_parse/src/parser/pat.rs')
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs132
1 files changed, 72 insertions, 60 deletions
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index fdf365178..3e4e92789 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -2,13 +2,13 @@ use super::{ForceCollect, Parser, PathStyle, TrailingToken};
use crate::errors::{
self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed,
DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
- ExpectedCommaAfterPatternField, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow,
- InclusiveRangeNoEnd, InvalidMutInPattern, PatternOnWrongSideOfAt, RefMutOrderIncorrect,
- RemoveLet, RepeatedMutInPattern, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg,
- TrailingVertNotAllowed, UnexpectedLifetimeInPattern, UnexpectedVertVertBeforeFunctionParam,
+ ExpectedCommaAfterPatternField, GenericArgsInPatRequireTurbofishSyntax,
+ InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern,
+ PatternOnWrongSideOfAt, RefMutOrderIncorrect, RemoveLet, RepeatedMutInPattern,
+ TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed,
+ UnexpectedLifetimeInPattern, UnexpectedVertVertBeforeFunctionParam,
UnexpectedVertVertInPattern,
};
-use crate::fluent_generated as fluent;
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
use rustc_ast::ptr::P;
@@ -81,7 +81,8 @@ enum EatOrResult {
}
/// The syntax location of a given pattern. Used for diagnostics.
-pub(super) enum PatternLocation {
+#[derive(Clone, Copy)]
+pub enum PatternLocation {
LetBinding,
FunctionParameter,
}
@@ -92,8 +93,12 @@ impl<'a> Parser<'a> {
/// Corresponds to `pat<no_top_alt>` in RFC 2535 and does not admit or-patterns
/// at the top level. Used when parsing the parameters of lambda expressions,
/// functions, function pointers, and `pat` macro fragments.
- pub fn parse_pat_no_top_alt(&mut self, expected: Option<Expected>) -> PResult<'a, P<Pat>> {
- self.parse_pat_with_range_pat(true, expected)
+ pub fn parse_pat_no_top_alt(
+ &mut self,
+ expected: Option<Expected>,
+ syntax_loc: Option<PatternLocation>,
+ ) -> PResult<'a, P<Pat>> {
+ self.parse_pat_with_range_pat(true, expected, syntax_loc)
}
/// Parses a pattern.
@@ -111,7 +116,7 @@ impl<'a> Parser<'a> {
ra: RecoverColon,
rt: CommaRecoveryMode,
) -> PResult<'a, P<Pat>> {
- self.parse_pat_allow_top_alt_inner(expected, rc, ra, rt).map(|(pat, _)| pat)
+ self.parse_pat_allow_top_alt_inner(expected, rc, ra, rt, None).map(|(pat, _)| pat)
}
/// Returns the pattern and a bool indicating whether we recovered from a trailing vert (true =
@@ -122,6 +127,7 @@ impl<'a> Parser<'a> {
rc: RecoverComma,
ra: RecoverColon,
rt: CommaRecoveryMode,
+ syntax_loc: Option<PatternLocation>,
) -> PResult<'a, (P<Pat>, bool)> {
// Keep track of whether we recovered from a trailing vert so that we can avoid duplicated
// suggestions (which bothers rustfix).
@@ -134,9 +140,13 @@ impl<'a> Parser<'a> {
};
// Parse the first pattern (`p_0`).
- let mut first_pat = self.parse_pat_no_top_alt(expected)?;
+ let mut first_pat = self.parse_pat_no_top_alt(expected, syntax_loc)?;
if rc == RecoverComma::Yes {
- self.maybe_recover_unexpected_comma(first_pat.span, rt)?;
+ self.maybe_recover_unexpected_comma(
+ first_pat.span,
+ matches!(first_pat.kind, PatKind::MacCall(_)),
+ rt,
+ )?;
}
// If the next token is not a `|`,
@@ -173,12 +183,12 @@ impl<'a> Parser<'a> {
break;
}
}
- let pat = self.parse_pat_no_top_alt(expected).map_err(|mut err| {
+ let pat = self.parse_pat_no_top_alt(expected, syntax_loc).map_err(|mut err| {
err.span_label(lo, WHILE_PARSING_OR_MSG);
err
})?;
if rc == RecoverComma::Yes {
- self.maybe_recover_unexpected_comma(pat.span, rt)?;
+ self.maybe_recover_unexpected_comma(pat.span, false, rt)?;
}
pats.push(pat);
}
@@ -209,46 +219,31 @@ impl<'a> Parser<'a> {
rc,
RecoverColon::No,
CommaRecoveryMode::LikelyTuple,
+ Some(syntax_loc),
)?;
let colon = self.eat(&token::Colon);
if let PatKind::Or(pats) = &pat.kind {
let span = pat.span;
-
- if trailing_vert {
- // We already emitted an error and suggestion to remove the trailing vert. Don't
- // emit again.
-
- // FIXME(#100717): pass `TopLevelOrPatternNotAllowed::* { sub: None }` to
- // `delay_span_bug()` instead of fluent message
- self.sess.span_diagnostic.delay_span_bug(
- span,
- match syntax_loc {
- PatternLocation::LetBinding => {
- fluent::parse_or_pattern_not_allowed_in_let_binding
- }
- PatternLocation::FunctionParameter => {
- fluent::parse_or_pattern_not_allowed_in_fn_parameters
- }
- },
- );
+ let pat = pprust::pat_to_string(&pat);
+ let sub = if pats.len() == 1 {
+ Some(TopLevelOrPatternNotAllowedSugg::RemoveLeadingVert { span, pat })
} else {
- let pat = pprust::pat_to_string(&pat);
- let sub = if pats.len() == 1 {
- Some(TopLevelOrPatternNotAllowedSugg::RemoveLeadingVert { span, pat })
- } else {
- Some(TopLevelOrPatternNotAllowedSugg::WrapInParens { span, pat })
- };
+ Some(TopLevelOrPatternNotAllowedSugg::WrapInParens { span, pat })
+ };
- self.sess.emit_err(match syntax_loc {
- PatternLocation::LetBinding => {
- TopLevelOrPatternNotAllowed::LetBinding { span, sub }
- }
- PatternLocation::FunctionParameter => {
- TopLevelOrPatternNotAllowed::FunctionParameter { span, sub }
- }
- });
+ let mut err = self.sess.create_err(match syntax_loc {
+ PatternLocation::LetBinding => {
+ TopLevelOrPatternNotAllowed::LetBinding { span, sub }
+ }
+ PatternLocation::FunctionParameter => {
+ TopLevelOrPatternNotAllowed::FunctionParameter { span, sub }
+ }
+ });
+ if trailing_vert {
+ err.delay_as_bug();
}
+ err.emit();
}
Ok((pat, colon))
@@ -336,6 +331,7 @@ impl<'a> Parser<'a> {
&mut self,
allow_range_pat: bool,
expected: Option<Expected>,
+ syntax_loc: Option<PatternLocation>,
) -> PResult<'a, P<Pat>> {
maybe_recover_from_interpolated_ty_qpath!(self, true);
maybe_whole!(self, NtPat, |x| x);
@@ -375,11 +371,11 @@ impl<'a> Parser<'a> {
// Parse _
PatKind::Wild
} else if self.eat_keyword(kw::Mut) {
- self.parse_pat_ident_mut()?
+ self.parse_pat_ident_mut(syntax_loc)?
} else if self.eat_keyword(kw::Ref) {
// Parse ref ident @ pat / ref mut ident @ pat
let mutbl = self.parse_mutability();
- self.parse_pat_ident(BindingAnnotation(ByRef::Yes, mutbl))?
+ self.parse_pat_ident(BindingAnnotation(ByRef::Yes, mutbl), syntax_loc)?
} else if self.eat_keyword(kw::Box) {
self.parse_pat_box()?
} else if self.check_inline_const(0) {
@@ -401,7 +397,7 @@ impl<'a> Parser<'a> {
// Parse `ident @ pat`
// This can give false positives and parse nullary enums,
// they are dealt with later in resolve.
- self.parse_pat_ident(BindingAnnotation::NONE)?
+ self.parse_pat_ident(BindingAnnotation::NONE, syntax_loc)?
} else if self.is_start_of_pat_with_path() {
// Parse pattern starting with a path
let (qself, path) = if self.eat_lt() {
@@ -445,7 +441,7 @@ impl<'a> Parser<'a> {
);
let mut err = self_.struct_span_err(self_.token.span, msg);
- err.span_label(self_.token.span, format!("expected {}", expected));
+ err.span_label(self_.token.span, format!("expected {expected}"));
err
});
PatKind::Lit(self.mk_expr(lo, ExprKind::Lit(lit)))
@@ -502,7 +498,7 @@ impl<'a> Parser<'a> {
// At this point we attempt to parse `@ $pat_rhs` and emit an error.
self.bump(); // `@`
- let mut rhs = self.parse_pat_no_top_alt(None)?;
+ let mut rhs = self.parse_pat_no_top_alt(None, None)?;
let whole_span = lhs.span.to(rhs.span);
if let PatKind::Ident(_, _, sub @ None) = &mut rhs.kind {
@@ -558,7 +554,7 @@ impl<'a> Parser<'a> {
}
let mutbl = self.parse_mutability();
- let subpat = self.parse_pat_with_range_pat(false, expected)?;
+ let subpat = self.parse_pat_with_range_pat(false, expected, None)?;
Ok(PatKind::Ref(subpat, mutbl))
}
@@ -583,12 +579,12 @@ impl<'a> Parser<'a> {
}
/// Parse a mutable binding with the `mut` token already eaten.
- fn parse_pat_ident_mut(&mut self) -> PResult<'a, PatKind> {
+ fn parse_pat_ident_mut(&mut self, syntax_loc: Option<PatternLocation>) -> PResult<'a, PatKind> {
let mut_span = self.prev_token.span;
if self.eat_keyword(kw::Ref) {
self.sess.emit_err(RefMutOrderIncorrect { span: mut_span.to(self.prev_token.span) });
- return self.parse_pat_ident(BindingAnnotation::REF_MUT);
+ return self.parse_pat_ident(BindingAnnotation::REF_MUT, syntax_loc);
}
self.recover_additional_muts();
@@ -601,7 +597,7 @@ impl<'a> Parser<'a> {
}
// Parse the pattern we hope to be an identifier.
- let mut pat = self.parse_pat_no_top_alt(Some(Expected::Identifier))?;
+ let mut pat = self.parse_pat_no_top_alt(Some(Expected::Identifier), None)?;
// If we don't have `mut $ident (@ pat)?`, error.
if let PatKind::Ident(BindingAnnotation(ByRef::No, m @ Mutability::Not), ..) = &mut pat.kind
@@ -681,7 +677,7 @@ impl<'a> Parser<'a> {
let msg = format!("expected {}, found {}", expected, super::token_descr(&self.token));
let mut err = self.struct_span_err(self.token.span, msg);
- err.span_label(self.token.span, format!("expected {}", expected));
+ err.span_label(self.token.span, format!("expected {expected}"));
let sp = self.sess.source_map().start_point(self.token.span);
if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) {
@@ -827,10 +823,26 @@ impl<'a> Parser<'a> {
/// Parses `ident` or `ident @ pat`.
/// Used by the copy foo and ref foo patterns to give a good
/// error message when parsing mistakes like `ref foo(a, b)`.
- fn parse_pat_ident(&mut self, binding_annotation: BindingAnnotation) -> PResult<'a, PatKind> {
+ fn parse_pat_ident(
+ &mut self,
+ binding_annotation: BindingAnnotation,
+ syntax_loc: Option<PatternLocation>,
+ ) -> PResult<'a, PatKind> {
let ident = self.parse_ident()?;
+
+ if self.may_recover()
+ && !matches!(syntax_loc, Some(PatternLocation::FunctionParameter))
+ && self.check_noexpect(&token::Lt)
+ && self.look_ahead(1, |t| t.can_begin_type())
+ {
+ return Err(self.sess.create_err(GenericArgsInPatRequireTurbofishSyntax {
+ span: self.token.span,
+ suggest_turbofish: self.token.span.shrink_to_lo(),
+ }));
+ }
+
let sub = if self.eat(&token::At) {
- Some(self.parse_pat_no_top_alt(Some(Expected::BindingPattern))?)
+ Some(self.parse_pat_no_top_alt(Some(Expected::BindingPattern), None)?)
} else {
None
};
@@ -919,14 +931,14 @@ impl<'a> Parser<'a> {
// We cannot use `parse_pat_ident()` since it will complain `box`
// is not an identifier.
let sub = if self.eat(&token::At) {
- Some(self.parse_pat_no_top_alt(Some(Expected::BindingPattern))?)
+ Some(self.parse_pat_no_top_alt(Some(Expected::BindingPattern), None)?)
} else {
None
};
Ok(PatKind::Ident(BindingAnnotation::NONE, Ident::new(kw::Box, box_span), sub))
} else {
- let pat = self.parse_pat_with_range_pat(false, None)?;
+ let pat = self.parse_pat_with_range_pat(false, None, None)?;
self.sess.gated_spans.gate(sym::box_patterns, box_span.to(self.prev_token.span));
Ok(PatKind::Box(pat))
}
@@ -994,7 +1006,7 @@ impl<'a> Parser<'a> {
break;
}
let token_str = super::token_descr(&self.token);
- let msg = format!("expected `}}`, found {}", token_str);
+ let msg = format!("expected `}}`, found {token_str}");
let mut err = self.struct_span_err(self.token.span, msg);
err.span_label(self.token.span, "expected `}`");