PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
};
use rustc_ast_pretty::pprust;
-use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
use rustc_span::source_map::{respan, Span, Spanned};
use rustc_span::symbol::{kw, sym, Ident};
No,
}
+/// Whether or not to recover a `a, b` when parsing patterns as `(a, b)` or that *and* `a | b`.
+#[derive(PartialEq, Copy, Clone)]
+pub enum CommaRecoveryMode {
+ LikelyTuple,
+ EitherTupleOrPipe,
+}
+
/// The result of `eat_or_separator`. We want to distinguish which case we are in to avoid
/// emitting duplicate diagnostics.
#[derive(Debug, Clone, Copy)]
expected: Expected,
rc: RecoverComma,
ra: RecoverColon,
+ rt: CommaRecoveryMode,
) -> PResult<'a, P<Pat>> {
- self.parse_pat_allow_top_alt_inner(expected, rc, ra).map(|(pat, _)| pat)
+ self.parse_pat_allow_top_alt_inner(expected, rc, ra, rt).map(|(pat, _)| pat)
}
/// Returns the pattern and a bool indicating whether we recovered from a trailing vert (true =
expected: Expected,
rc: RecoverComma,
ra: RecoverColon,
+ rt: CommaRecoveryMode,
) -> 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).
// Parse the first pattern (`p_0`).
let first_pat = self.parse_pat_no_top_alt(expected)?;
- self.maybe_recover_unexpected_comma(first_pat.span, rc)?;
+ self.maybe_recover_unexpected_comma(first_pat.span, rc, rt)?;
// If the next token is not a `|`,
// this is not an or-pattern and we should exit here.
err.span_label(lo, WHILE_PARSING_OR_MSG);
err
})?;
- self.maybe_recover_unexpected_comma(pat.span, rc)?;
+ self.maybe_recover_unexpected_comma(pat.span, rc, rt)?;
pats.push(pat);
}
let or_pattern_span = lo.to(self.prev_token.span);
// We use `parse_pat_allow_top_alt` regardless of whether we actually want top-level
// or-patterns so that we can detect when a user tries to use it. This allows us to print a
// better error message.
- let (pat, trailing_vert) =
- self.parse_pat_allow_top_alt_inner(expected, rc, RecoverColon::No)?;
+ let (pat, trailing_vert) = self.parse_pat_allow_top_alt_inner(
+ expected,
+ rc,
+ RecoverColon::No,
+ CommaRecoveryMode::LikelyTuple,
+ )?;
let colon = self.eat(&token::Colon);
if let PatKind::Or(pats) = &pat.kind {
} else if self.check(&token::OpenDelim(token::Bracket)) {
// Parse `[pat, pat,...]` as a slice pattern.
let (pats, _) = self.parse_delim_comma_seq(token::Bracket, |p| {
- p.parse_pat_allow_top_alt(None, RecoverComma::No, RecoverColon::No)
+ p.parse_pat_allow_top_alt(
+ None,
+ RecoverComma::No,
+ RecoverColon::No,
+ CommaRecoveryMode::EitherTupleOrPipe,
+ )
})?;
PatKind::Slice(pats)
} else if self.check(&token::DotDot) && !self.is_pat_range_end_start(1) {
/// Parse a tuple or parenthesis pattern.
fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> {
let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| {
- p.parse_pat_allow_top_alt(None, RecoverComma::No, RecoverColon::No)
+ p.parse_pat_allow_top_alt(
+ None,
+ RecoverComma::No,
+ RecoverColon::No,
+ CommaRecoveryMode::LikelyTuple,
+ )
})?;
// Here, `(pat,)` is a tuple pattern.
fn fatal_unexpected_non_pat(
&mut self,
- mut err: DiagnosticBuilder<'a>,
+ err: DiagnosticBuilder<'a, ErrorGuaranteed>,
expected: Expected,
) -> PResult<'a, P<Pat>> {
err.cancel();
// Ensure the user doesn't receive unhelpful unexpected token errors
self.bump();
if self.is_pat_range_end_start(0) {
- let _ = self.parse_pat_range_end().map_err(|mut e| e.cancel());
+ let _ = self.parse_pat_range_end().map_err(|e| e.cancel());
}
self.error_inclusive_range_with_extra_equals(span_with_eq);
/// Parse tuple struct or tuple variant pattern (e.g. `Foo(...)` or `Foo::Bar(...)`).
fn parse_pat_tuple_struct(&mut self, qself: Option<QSelf>, path: Path) -> PResult<'a, PatKind> {
let (fields, _) = self.parse_paren_comma_seq(|p| {
- p.parse_pat_allow_top_alt(None, RecoverComma::No, RecoverColon::No)
+ p.parse_pat_allow_top_alt(
+ None,
+ RecoverComma::No,
+ RecoverColon::No,
+ CommaRecoveryMode::EitherTupleOrPipe,
+ )
})?;
if qself.is_some() {
self.sess.gated_spans.gate(sym::more_qualified_paths, path.span);
let mut fields = Vec::new();
let mut etc = false;
let mut ate_comma = true;
- let mut delayed_err: Option<DiagnosticBuilder<'a>> = None;
+ let mut delayed_err: Option<DiagnosticBuilder<'a, ErrorGuaranteed>> = None;
let mut etc_span = None;
while self.token != token::CloseDelim(token::Brace) {
// Parsing a pattern of the form `fieldname: pat`.
let fieldname = self.parse_field_name()?;
self.bump();
- let pat = self.parse_pat_allow_top_alt(None, RecoverComma::No, RecoverColon::No)?;
+ let pat = self.parse_pat_allow_top_alt(
+ None,
+ RecoverComma::No,
+ RecoverColon::No,
+ CommaRecoveryMode::EitherTupleOrPipe,
+ )?;
hi = pat.span;
(pat, fieldname, false)
} else {