};
// 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, rt)?;
+ let mut first_pat = self.parse_pat_no_top_alt(expected)?;
+ if rc == RecoverComma::Yes {
+ self.maybe_recover_unexpected_comma(first_pat.span, rt)?;
+ }
// If the next token is not a `|`,
// this is not an or-pattern and we should exit here.
// This complicated procedure is done purely for diagnostics UX.
// Check if the user wrote `foo:bar` instead of `foo::bar`.
- let first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, ra, expected);
+ if ra == RecoverColon::Yes {
+ first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, expected);
+ }
if let Some(leading_vert_span) = leading_vert_span {
// If there was a leading vert, treat this as an or-pattern. This improves
err.span_label(lo, WHILE_PARSING_OR_MSG);
err
})?;
- self.maybe_recover_unexpected_comma(pat.span, rc, rt)?;
+ if rc == RecoverComma::Yes {
+ self.maybe_recover_unexpected_comma(pat.span, rt)?;
+ }
pats.push(pat);
}
let or_pattern_span = lo.to(self.prev_token.span);
if let token::OrOr = self.token.kind {
let span = self.token.span;
let mut err = self.struct_span_err(span, "unexpected `||` before function parameter");
- err.span_suggestion(
- span,
- "remove the `||`",
- String::new(),
- Applicability::MachineApplicable,
- );
+ err.span_suggestion(span, "remove the `||`", "", Applicability::MachineApplicable);
err.note("alternatives in or-patterns are separated with `|`, not `||`");
err.emit();
self.bump();
err.span_suggestion(
self.token.span,
"use a single `|` to separate multiple alternative patterns",
- "|".to_owned(),
+ "|",
Applicability::MachineApplicable,
);
if let Some(lo) = lo {
err.span_suggestion(
span,
&format!("remove the `{}`", pprust::token_to_string(&self.token)),
- String::new(),
+ "",
Applicability::MachineApplicable,
);
if let Some(lo) = lo {
let mutbl = self.parse_mutability();
self.parse_pat_ident(BindingMode::ByRef(mutbl))?
} else if self.eat_keyword(kw::Box) {
- // Parse `box pat`
- let pat = self.parse_pat_with_range_pat(false, None)?;
- self.sess.gated_spans.gate(sym::box_patterns, lo.to(self.prev_token.span));
- PatKind::Box(pat)
+ self.parse_pat_box()?
} else if self.check_inline_const(0) {
// Parse `const pat`
let const_expr = self.parse_const_block(lo.to(self.token.span), true)?;
};
let pat = self.mk_pat(lo.to(self.prev_token.span), pat);
- let pat = self.maybe_recover_from_bad_qpath(pat, true)?;
+ let pat = self.maybe_recover_from_bad_qpath(pat)?;
let pat = self.recover_intersection_pat(pat)?;
if !allow_range_pat {
.span_suggestion_short(
lo,
"for a rest pattern, use `..` instead of `...`",
- "..".to_owned(),
+ "..",
Applicability::MachineApplicable,
)
.emit();
let span = self.prev_token.span;
self.struct_span_err(span, &format!("unexpected lifetime `{}` in pattern", name))
- .span_suggestion(
- span,
- "remove the lifetime",
- String::new(),
- Applicability::MachineApplicable,
- )
+ .span_suggestion(span, "remove the lifetime", "", Applicability::MachineApplicable)
.emit();
}
}
.span_suggestion(
span,
"remove the additional `mut`s",
- String::new(),
+ "",
Applicability::MachineApplicable,
)
.emit();
fn error_inclusive_range_with_extra_equals(&self, span: Span) {
self.struct_span_err(span, "unexpected `=` after inclusive range")
- .span_suggestion_short(
- span,
- "use `..=` instead",
- "..=".to_string(),
- Applicability::MaybeIncorrect,
- )
+ .span_suggestion_short(span, "use `..=` instead", "..=", Applicability::MaybeIncorrect)
.note("inclusive ranges end with a single equals sign (`..=`)")
.emit();
}
fn error_inclusive_range_with_no_end(&self, span: Span) {
struct_span_err!(self.sess.span_diagnostic, span, E0586, "inclusive range with no end")
- .span_suggestion_short(
- span,
- "use `..` instead",
- "..".to_string(),
- Applicability::MachineApplicable,
- )
+ .span_suggestion_short(span, "use `..` instead", "..", Applicability::MachineApplicable)
.note("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)")
.emit();
}
.span_suggestion_short(
re.span,
"use `..=` instead",
- "..=".to_string(),
+ "..=",
Applicability::MachineApplicable,
)
.emit();
Ok(PatKind::TupleStruct(qself, path, fields))
}
+ /// Are we sure this could not possibly be the start of a pattern?
+ ///
+ /// Currently, this only accounts for tokens that can follow identifiers
+ /// in patterns, but this can be extended as necessary.
+ fn isnt_pattern_start(&self) -> bool {
+ [
+ token::Eq,
+ token::Colon,
+ token::Comma,
+ token::Semi,
+ token::At,
+ token::OpenDelim(Delimiter::Brace),
+ token::CloseDelim(Delimiter::Brace),
+ token::CloseDelim(Delimiter::Parenthesis),
+ ]
+ .contains(&self.token.kind)
+ }
+
+ /// Parses `box pat`
+ fn parse_pat_box(&mut self) -> PResult<'a, PatKind> {
+ let box_span = self.prev_token.span;
+
+ if self.isnt_pattern_start() {
+ self.struct_span_err(
+ self.token.span,
+ format!("expected pattern, found {}", super::token_descr(&self.token)),
+ )
+ .span_note(box_span, "`box` is a reserved keyword")
+ .span_suggestion_verbose(
+ box_span.shrink_to_lo(),
+ "escape `box` to use it as an identifier",
+ "r#",
+ Applicability::MaybeIncorrect,
+ )
+ .emit();
+
+ // 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("binding pattern"))?)
+ } else {
+ None
+ };
+
+ Ok(PatKind::Ident(
+ BindingMode::ByValue(Mutability::Not),
+ Ident::new(kw::Box, box_span),
+ sub,
+ ))
+ } else {
+ let pat = self.parse_pat_with_range_pat(false, None)?;
+ self.sess.gated_spans.gate(sym::box_patterns, box_span.to(self.prev_token.span));
+ Ok(PatKind::Box(pat))
+ }
+ }
+
/// Parses the fields of a struct-like pattern.
fn parse_pat_fields(&mut self) -> PResult<'a, (Vec<PatField>, bool)> {
let mut fields = Vec::new();
err.span_suggestion_short(
sp,
"remove this comma",
- String::new(),
+ "",
Applicability::MachineApplicable,
);
}
.span_suggestion(
self.token.span,
"to omit remaining fields, use one fewer `.`",
- "..".to_owned(),
+ "..",
Applicability::MachineApplicable,
)
.emit();