1 use super::{ForceCollect, Parser, PathStyle, TrailingToken}
;
2 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}
;
3 use rustc_ast
::mut_visit
::{noop_visit_pat, MutVisitor}
;
6 use rustc_ast
::{self as ast, AttrVec, Attribute, MacCall, Pat, PatField, PatKind, RangeEnd}
;
7 use rustc_ast
::{BindingMode, Expr, ExprKind, Mutability, Path, QSelf, RangeSyntax}
;
8 use rustc_ast_pretty
::pprust
;
9 use rustc_errors
::{struct_span_err, Applicability, DiagnosticBuilder, PResult}
;
10 use rustc_span
::source_map
::{respan, Span, Spanned}
;
11 use rustc_span
::symbol
::{kw, sym, Ident}
;
13 type Expected
= Option
<&'
static str>;
15 /// `Expected` for function and lambda parameter patterns.
16 pub(super) const PARAM_EXPECTED
: Expected
= Some("parameter name");
18 const WHILE_PARSING_OR_MSG
: &str = "while parsing this or-pattern starting here";
20 /// Whether or not to recover a `,` when parsing or-patterns.
21 #[derive(PartialEq, Copy, Clone)]
22 pub enum RecoverComma
{
27 /// Whether or not to recover a `:` when parsing patterns that were meant to be paths.
28 #[derive(PartialEq, Copy, Clone)]
29 pub enum RecoverColon
{
34 /// The result of `eat_or_separator`. We want to distinguish which case we are in to avoid
35 /// emitting duplicate diagnostics.
36 #[derive(Debug, Clone, Copy)]
38 /// We recovered from a trailing vert.
40 /// We ate an `|` (or `||` and recovered).
42 /// We did not eat anything (i.e. the current token is not `|` or `||`).
49 /// Corresponds to `pat<no_top_alt>` in RFC 2535 and does not admit or-patterns
50 /// at the top level. Used when parsing the parameters of lambda expressions,
51 /// functions, function pointers, and `pat` macro fragments.
52 pub fn parse_pat_no_top_alt(&mut self, expected
: Expected
) -> PResult
<'a
, P
<Pat
>> {
53 self.parse_pat_with_range_pat(true, expected
)
58 /// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level.
59 /// Used for parsing patterns in all cases when `pat<no_top_alt>` is not used.
61 /// Note that after the FCP in <https://github.com/rust-lang/rust/issues/81415>,
62 /// a leading vert is allowed in nested or-patterns, too. This allows us to
63 /// simplify the grammar somewhat.
64 pub fn parse_pat_allow_top_alt(
69 ) -> PResult
<'a
, P
<Pat
>> {
70 self.parse_pat_allow_top_alt_inner(expected
, rc
, ra
).map(|(pat
, _
)| pat
)
73 /// Returns the pattern and a bool indicating whether we recovered from a trailing vert (true =
75 fn parse_pat_allow_top_alt_inner(
80 ) -> PResult
<'a
, (P
<Pat
>, bool
)> {
81 // Keep track of whether we recovered from a trailing vert so that we can avoid duplicated
82 // suggestions (which bothers rustfix).
84 // Allow a '|' before the pats (RFCs 1925, 2530, and 2535).
85 let (leading_vert_span
, mut trailing_vert
) = match self.eat_or_separator(None
) {
86 EatOrResult
::AteOr
=> (Some(self.prev_token
.span
), false),
87 EatOrResult
::TrailingVert
=> (None
, true),
88 EatOrResult
::None
=> (None
, false),
91 // Parse the first pattern (`p_0`).
92 let first_pat
= self.parse_pat_no_top_alt(expected
)?
;
93 self.maybe_recover_unexpected_comma(first_pat
.span
, rc
)?
;
95 // If the next token is not a `|`,
96 // this is not an or-pattern and we should exit here.
97 if !self.check(&token
::BinOp(token
::Or
)) && self.token
!= token
::OrOr
{
98 // If we parsed a leading `|` which should be gated,
99 // then we should really gate the leading `|`.
100 // This complicated procedure is done purely for diagnostics UX.
101 let mut first_pat
= first_pat
;
103 if let (RecoverColon
::Yes
, token
::Colon
) = (ra
, &self.token
.kind
) {
106 PatKind
::Ident(BindingMode
::ByValue(Mutability
::Not
), _
, None
)
108 ) && self.look_ahead(1, |token
| token
.is_ident() && !token
.is_reserved_ident())
110 // The pattern looks like it might be a path with a `::` -> `:` typo:
111 // `match foo { bar:baz => {} }`
112 let span
= self.token
.span
;
113 // We only emit "unexpected `:`" error here if we can successfully parse the
114 // whole pattern correctly in that case.
115 let snapshot
= self.clone();
117 // Create error for "unexpected `:`".
118 match self.expected_one_of_not_found(&[], &[]) {
120 self.bump(); // Skip the `:`.
121 match self.parse_pat_no_top_alt(expected
) {
122 Err(mut inner_err
) => {
123 // Carry on as if we had not done anything, callers will emit a
130 // We've parsed the rest of the pattern.
133 "maybe write a path separator here",
135 Applicability
::MachineApplicable
,
139 self.mk_pat(first_pat
.span
.to(pat
.span
), PatKind
::Wild
);
144 // Carry on as if we had not done anything. This should be unreachable.
151 if let Some(leading_vert_span
) = leading_vert_span
{
152 // If there was a leading vert, treat this as an or-pattern. This improves
154 let span
= leading_vert_span
.to(self.prev_token
.span
);
155 return Ok((self.mk_pat(span
, PatKind
::Or(vec
![first_pat
])), trailing_vert
));
158 return Ok((first_pat
, trailing_vert
));
161 // Parse the patterns `p_1 | ... | p_n` where `n > 0`.
162 let lo
= leading_vert_span
.unwrap_or(first_pat
.span
);
163 let mut pats
= vec
![first_pat
];
165 match self.eat_or_separator(Some(lo
)) {
166 EatOrResult
::AteOr
=> {}
167 EatOrResult
::None
=> break,
168 EatOrResult
::TrailingVert
=> {
169 trailing_vert
= true;
173 let pat
= self.parse_pat_no_top_alt(expected
).map_err(|mut err
| {
174 err
.span_label(lo
, WHILE_PARSING_OR_MSG
);
177 self.maybe_recover_unexpected_comma(pat
.span
, rc
)?
;
180 let or_pattern_span
= lo
.to(self.prev_token
.span
);
182 Ok((self.mk_pat(or_pattern_span
, PatKind
::Or(pats
)), trailing_vert
))
185 /// Parse a pattern and (maybe) a `Colon` in positions where a pattern may be followed by a
186 /// type annotation (e.g. for `let` bindings or `fn` params).
188 /// Generally, this corresponds to `pat_no_top_alt` followed by an optional `Colon`. It will
189 /// eat the `Colon` token if one is present.
191 /// The return value represents the parsed pattern and `true` if a `Colon` was parsed (`false`
193 pub(super) fn parse_pat_before_ty(
198 ) -> PResult
<'a
, (P
<Pat
>, bool
)> {
199 // We use `parse_pat_allow_top_alt` regardless of whether we actually want top-level
200 // or-patterns so that we can detect when a user tries to use it. This allows us to print a
201 // better error message.
202 let (pat
, trailing_vert
) =
203 self.parse_pat_allow_top_alt_inner(expected
, rc
, RecoverColon
::No
)?
;
204 let colon
= self.eat(&token
::Colon
);
206 if let PatKind
::Or(pats
) = &pat
.kind
{
207 let msg
= format
!("top-level or-patterns are not allowed in {}", syntax_loc
);
208 let (help
, fix
) = if pats
.len() == 1 {
209 // If all we have is a leading vert, then print a special message. This is the case
210 // if `parse_pat_allow_top_alt` returns an or-pattern with one variant.
211 let msg
= "remove the `|`";
212 let fix
= pprust
::pat_to_string(&pat
);
215 let msg
= "wrap the pattern in parentheses";
216 let fix
= format
!("({})", pprust
::pat_to_string(&pat
));
221 // We already emitted an error and suggestion to remove the trailing vert. Don't
223 self.sess
.span_diagnostic
.delay_span_bug(pat
.span
, &msg
);
225 self.struct_span_err(pat
.span
, &msg
)
226 .span_suggestion(pat
.span
, help
, fix
, Applicability
::MachineApplicable
)
234 /// Parse the pattern for a function or function pointer parameter, followed by a colon.
236 /// The return value represents the parsed pattern and `true` if a `Colon` was parsed (`false`
238 pub(super) fn parse_fn_param_pat_colon(&mut self) -> PResult
<'a
, (P
<Pat
>, bool
)> {
239 // In order to get good UX, we first recover in the case of a leading vert for an illegal
240 // top-level or-pat. Normally, this means recovering both `|` and `||`, but in this case,
241 // a leading `||` probably doesn't indicate an or-pattern attempt, so we handle that
243 if let token
::OrOr
= self.token
.kind
{
244 let span
= self.token
.span
;
245 let mut err
= self.struct_span_err(span
, "unexpected `||` before function parameter");
250 Applicability
::MachineApplicable
,
252 err
.note("alternatives in or-patterns are separated with `|`, not `||`");
257 self.parse_pat_before_ty(PARAM_EXPECTED
, RecoverComma
::No
, "function parameters")
260 /// Eat the or-pattern `|` separator.
261 /// If instead a `||` token is encountered, recover and pretend we parsed `|`.
262 fn eat_or_separator(&mut self, lo
: Option
<Span
>) -> EatOrResult
{
263 if self.recover_trailing_vert(lo
) {
264 EatOrResult
::TrailingVert
265 } else if matches
!(self.token
.kind
, token
::OrOr
) {
266 // Found `||`; Recover and pretend we parsed `|`.
267 self.ban_unexpected_or_or(lo
);
270 } else if self.eat(&token
::BinOp(token
::Or
)) {
277 /// Recover if `|` or `||` is the current token and we have one of the
278 /// tokens `=>`, `if`, `=`, `:`, `;`, `,`, `]`, `)`, or `}` ahead of us.
280 /// These tokens all indicate that we reached the end of the or-pattern
281 /// list and can now reliably say that the `|` was an illegal trailing vert.
282 /// Note that there are more tokens such as `@` for which we know that the `|`
283 /// is an illegal parse. However, the user's intent is less clear in that case.
284 fn recover_trailing_vert(&mut self, lo
: Option
<Span
>) -> bool
{
285 let is_end_ahead
= self.look_ahead(1, |token
| {
287 &token
.uninterpolate().kind
,
288 token
::FatArrow
// e.g. `a | => 0,`.
289 | token
::Ident(kw
::If
, false) // e.g. `a | if expr`.
290 | token
::Eq
// e.g. `let a | = 0`.
291 | token
::Semi
// e.g. `let a |;`.
292 | token
::Colon
// e.g. `let a | :`.
293 | token
::Comma
// e.g. `let (a |,)`.
294 | token
::CloseDelim(token
::Bracket
) // e.g. `let [a | ]`.
295 | token
::CloseDelim(token
::Paren
) // e.g. `let (a | )`.
296 | token
::CloseDelim(token
::Brace
) // e.g. `let A { f: a | }`.
299 match (is_end_ahead
, &self.token
.kind
) {
300 (true, token
::BinOp(token
::Or
) | token
::OrOr
) => {
301 self.ban_illegal_vert(lo
, "trailing", "not allowed in an or-pattern");
309 /// We have parsed `||` instead of `|`. Error and suggest `|` instead.
310 fn ban_unexpected_or_or(&mut self, lo
: Option
<Span
>) {
311 let mut err
= self.struct_span_err(self.token
.span
, "unexpected token `||` in pattern");
314 "use a single `|` to separate multiple alternative patterns",
316 Applicability
::MachineApplicable
,
318 if let Some(lo
) = lo
{
319 err
.span_label(lo
, WHILE_PARSING_OR_MSG
);
324 /// Some special error handling for the "top-level" patterns in a match arm,
325 /// `for` loop, `let`, &c. (in contrast to subpatterns within such).
326 fn maybe_recover_unexpected_comma(&mut self, lo
: Span
, rc
: RecoverComma
) -> PResult
<'a
, ()> {
327 if rc
== RecoverComma
::No
|| self.token
!= token
::Comma
{
331 // An unexpected comma after a top-level pattern is a clue that the
332 // user (perhaps more accustomed to some other language) forgot the
333 // parentheses in what should have been a tuple pattern; return a
334 // suggestion-enhanced error here rather than choking on the comma later.
335 let comma_span
= self.token
.span
;
337 if let Err(mut err
) = self.skip_pat_list() {
338 // We didn't expect this to work anyway; we just wanted to advance to the
339 // end of the comma-sequence so we know the span to suggest parenthesizing.
342 let seq_span
= lo
.to(self.prev_token
.span
);
343 let mut err
= self.struct_span_err(comma_span
, "unexpected `,` in pattern");
344 if let Ok(seq_snippet
) = self.span_to_snippet(seq_span
) {
345 const MSG
: &str = "try adding parentheses to match on a tuple...";
350 format
!("({})", seq_snippet
),
351 Applicability
::MachineApplicable
,
355 "...or a vertical bar to match on multiple alternatives",
356 seq_snippet
.replace(",", " |"),
357 Applicability
::MachineApplicable
,
363 /// Parse and throw away a parenthesized comma separated
364 /// sequence of patterns until `)` is reached.
365 fn skip_pat_list(&mut self) -> PResult
<'a
, ()> {
366 while !self.check(&token
::CloseDelim(token
::Paren
)) {
367 self.parse_pat_no_top_alt(None
)?
;
368 if !self.eat(&token
::Comma
) {
375 /// A `|` or possibly `||` token shouldn't be here. Ban it.
376 fn ban_illegal_vert(&mut self, lo
: Option
<Span
>, pos
: &str, ctx
: &str) {
377 let span
= self.token
.span
;
378 let mut err
= self.struct_span_err(span
, &format
!("a {} `|` is {}", pos
, ctx
));
381 &format
!("remove the `{}`", pprust
::token_to_string(&self.token
)),
383 Applicability
::MachineApplicable
,
385 if let Some(lo
) = lo
{
386 err
.span_label(lo
, WHILE_PARSING_OR_MSG
);
388 if let token
::OrOr
= self.token
.kind
{
389 err
.note("alternatives in or-patterns are separated with `|`, not `||`");
394 /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
396 fn parse_pat_with_range_pat(
398 allow_range_pat
: bool
,
400 ) -> PResult
<'a
, P
<Pat
>> {
401 maybe_recover_from_interpolated_ty_qpath
!(self, true);
402 maybe_whole
!(self, NtPat
, |x
| x
);
404 let lo
= self.token
.span
;
406 let pat
= if self.check(&token
::BinOp(token
::And
)) || self.token
.kind
== token
::AndAnd
{
407 self.parse_pat_deref(expected
)?
408 } else if self.check(&token
::OpenDelim(token
::Paren
)) {
409 self.parse_pat_tuple_or_parens()?
410 } else if self.check(&token
::OpenDelim(token
::Bracket
)) {
411 // Parse `[pat, pat,...]` as a slice pattern.
412 let (pats
, _
) = self.parse_delim_comma_seq(token
::Bracket
, |p
| {
413 p
.parse_pat_allow_top_alt(None
, RecoverComma
::No
, RecoverColon
::No
)
416 } else if self.check(&token
::DotDot
) && !self.is_pat_range_end_start(1) {
417 // A rest pattern `..`.
420 } else if self.check(&token
::DotDotDot
) && !self.is_pat_range_end_start(1) {
421 self.recover_dotdotdot_rest_pat(lo
)
422 } else if let Some(form
) = self.parse_range_end() {
423 self.parse_pat_range_to(form
)?
// `..=X`, `...X`, or `..X`.
424 } else if self.eat_keyword(kw
::Underscore
) {
427 } else if self.eat_keyword(kw
::Mut
) {
428 self.parse_pat_ident_mut()?
429 } else if self.eat_keyword(kw
::Ref
) {
430 // Parse ref ident @ pat / ref mut ident @ pat
431 let mutbl
= self.parse_mutability();
432 self.parse_pat_ident(BindingMode
::ByRef(mutbl
))?
433 } else if self.eat_keyword(kw
::Box
) {
435 let pat
= self.parse_pat_with_range_pat(false, None
)?
;
436 self.sess
.gated_spans
.gate(sym
::box_patterns
, lo
.to(self.prev_token
.span
));
438 } else if self.check_inline_const(0) {
440 let const_expr
= self.parse_const_block(lo
.to(self.token
.span
))?
;
442 if let Some(re
) = self.parse_range_end() {
443 self.parse_pat_range_begin_with(const_expr
, re
)?
445 PatKind
::Lit(const_expr
)
447 } else if self.can_be_ident_pat() {
448 // Parse `ident @ pat`
449 // This can give false positives and parse nullary enums,
450 // they are dealt with later in resolve.
451 self.parse_pat_ident(BindingMode
::ByValue(Mutability
::Not
))?
452 } else if self.is_start_of_pat_with_path() {
453 // Parse pattern starting with a path
454 let (qself
, path
) = if self.eat_lt() {
455 // Parse a qualified path
456 let (qself
, path
) = self.parse_qpath(PathStyle
::Expr
)?
;
459 // Parse an unqualified path
460 (None
, self.parse_path(PathStyle
::Expr
)?
)
462 let span
= lo
.to(self.prev_token
.span
);
464 if qself
.is_none() && self.check(&token
::Not
) {
465 self.parse_pat_mac_invoc(path
)?
466 } else if let Some(form
) = self.parse_range_end() {
467 let begin
= self.mk_expr(span
, ExprKind
::Path(qself
, path
), AttrVec
::new());
468 self.parse_pat_range_begin_with(begin
, form
)?
469 } else if self.check(&token
::OpenDelim(token
::Brace
)) {
470 self.parse_pat_struct(qself
, path
)?
471 } else if self.check(&token
::OpenDelim(token
::Paren
)) {
472 self.parse_pat_tuple_struct(qself
, path
)?
474 PatKind
::Path(qself
, path
)
477 // Try to parse everything else as literal with optional minus
478 match self.parse_literal_maybe_minus() {
479 Ok(begin
) => match self.parse_range_end() {
480 Some(form
) => self.parse_pat_range_begin_with(begin
, form
)?
,
481 None
=> PatKind
::Lit(begin
),
483 Err(err
) => return self.fatal_unexpected_non_pat(err
, expected
),
487 let pat
= self.mk_pat(lo
.to(self.prev_token
.span
), pat
);
488 let pat
= self.maybe_recover_from_bad_qpath(pat
, true)?
;
489 let pat
= self.recover_intersection_pat(pat
)?
;
491 if !allow_range_pat
{
492 self.ban_pat_range_if_ambiguous(&pat
)
498 /// Recover from a typoed `...` pattern that was encountered
499 /// Ref: Issue #70388
500 fn recover_dotdotdot_rest_pat(&mut self, lo
: Span
) -> PatKind
{
501 // A typoed rest pattern `...`.
502 self.bump(); // `...`
504 // The user probably mistook `...` for a rest pattern `..`.
505 self.struct_span_err(lo
, "unexpected `...`")
506 .span_label(lo
, "not a valid pattern")
507 .span_suggestion_short(
509 "for a rest pattern, use `..` instead of `...`",
511 Applicability
::MachineApplicable
,
517 /// Try to recover the more general form `intersect ::= $pat_lhs @ $pat_rhs`.
519 /// Allowed binding patterns generated by `binding ::= ref? mut? $ident @ $pat_rhs`
520 /// should already have been parsed by now at this point,
521 /// if the next token is `@` then we can try to parse the more general form.
523 /// Consult `parse_pat_ident` for the `binding` grammar.
525 /// The notion of intersection patterns are found in
526 /// e.g. [F#][and] where they are called AND-patterns.
528 /// [and]: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/pattern-matching
529 fn recover_intersection_pat(&mut self, lhs
: P
<Pat
>) -> PResult
<'a
, P
<Pat
>> {
530 if self.token
.kind
!= token
::At
{
531 // Next token is not `@` so it's not going to be an intersection pattern.
535 // At this point we attempt to parse `@ $pat_rhs` and emit an error.
537 let mut rhs
= self.parse_pat_no_top_alt(None
)?
;
538 let sp
= lhs
.span
.to(rhs
.span
);
540 if let PatKind
::Ident(_
, _
, ref mut sub @ None
) = rhs
.kind
{
541 // The user inverted the order, so help them fix that.
542 let mut applicability
= Applicability
::MachineApplicable
;
543 // FIXME(bindings_after_at): Remove this code when stabilizing the feature.
544 lhs
.walk(&mut |p
| match p
.kind
{
545 // `check_match` is unhappy if the subpattern has a binding anywhere.
546 PatKind
::Ident(..) => {
547 applicability
= Applicability
::MaybeIncorrect
;
548 false // Short-circuit.
553 let lhs_span
= lhs
.span
;
554 // Move the LHS into the RHS as a subpattern.
555 // The RHS is now the full pattern.
558 self.struct_span_err(sp
, "pattern on wrong side of `@`")
559 .span_label(lhs_span
, "pattern on the left, should be on the right")
560 .span_label(rhs
.span
, "binding on the right, should be on the left")
561 .span_suggestion(sp
, "switch the order", pprust
::pat_to_string(&rhs
), applicability
)
564 // The special case above doesn't apply so we may have e.g. `A(x) @ B(y)`.
565 rhs
.kind
= PatKind
::Wild
;
566 self.struct_span_err(sp
, "left-hand side of `@` must be a binding")
567 .span_label(lhs
.span
, "interpreted as a pattern, not a binding")
568 .span_label(rhs
.span
, "also a pattern")
569 .note("bindings are `x`, `mut x`, `ref x`, and `ref mut x`")
577 /// Ban a range pattern if it has an ambiguous interpretation.
578 fn ban_pat_range_if_ambiguous(&self, pat
: &Pat
) {
582 Spanned { node: RangeEnd::Included(RangeSyntax::DotDotDot), .. }
,
584 PatKind
::Range(..) => {}
588 self.struct_span_err(pat
.span
, "the range pattern here has ambiguous interpretation")
591 "add parentheses to clarify the precedence",
592 format
!("({})", pprust
::pat_to_string(&pat
)),
593 // "ambiguous interpretation" implies that we have to be guessing
594 Applicability
::MaybeIncorrect
,
599 /// Parse `&pat` / `&mut pat`.
600 fn parse_pat_deref(&mut self, expected
: Expected
) -> PResult
<'a
, PatKind
> {
602 self.recover_lifetime_in_deref_pat();
603 let mutbl
= self.parse_mutability();
604 let subpat
= self.parse_pat_with_range_pat(false, expected
)?
;
605 Ok(PatKind
::Ref(subpat
, mutbl
))
608 fn recover_lifetime_in_deref_pat(&mut self) {
609 if let token
::Lifetime(name
) = self.token
.kind
{
612 let span
= self.prev_token
.span
;
613 self.struct_span_err(span
, &format
!("unexpected lifetime `{}` in pattern", name
))
616 "remove the lifetime",
618 Applicability
::MachineApplicable
,
624 /// Parse a tuple or parenthesis pattern.
625 fn parse_pat_tuple_or_parens(&mut self) -> PResult
<'a
, PatKind
> {
626 let (fields
, trailing_comma
) = self.parse_paren_comma_seq(|p
| {
627 p
.parse_pat_allow_top_alt(None
, RecoverComma
::No
, RecoverColon
::No
)
630 // Here, `(pat,)` is a tuple pattern.
631 // For backward compatibility, `(..)` is a tuple pattern as well.
632 Ok(if fields
.len() == 1 && !(trailing_comma
|| fields
[0].is_rest()) {
633 PatKind
::Paren(fields
.into_iter().next().unwrap())
635 PatKind
::Tuple(fields
)
639 /// Parse a mutable binding with the `mut` token already eaten.
640 fn parse_pat_ident_mut(&mut self) -> PResult
<'a
, PatKind
> {
641 let mut_span
= self.prev_token
.span
;
643 if self.eat_keyword(kw
::Ref
) {
644 return self.recover_mut_ref_ident(mut_span
);
647 self.recover_additional_muts();
649 // Make sure we don't allow e.g. `let mut $p;` where `$p:pat`.
650 if let token
::Interpolated(ref nt
) = self.token
.kind
{
651 if let token
::NtPat(_
) = **nt
{
652 self.expected_ident_found().emit();
656 // Parse the pattern we hope to be an identifier.
657 let mut pat
= self.parse_pat_no_top_alt(Some("identifier"))?
;
659 // If we don't have `mut $ident (@ pat)?`, error.
660 if let PatKind
::Ident(BindingMode
::ByValue(m @ Mutability
::Not
), ..) = &mut pat
.kind
{
661 // Don't recurse into the subpattern.
662 // `mut` on the outer binding doesn't affect the inner bindings.
663 *m
= Mutability
::Mut
;
665 // Add `mut` to any binding in the parsed pattern.
666 let changed_any_binding
= Self::make_all_value_bindings_mutable(&mut pat
);
667 self.ban_mut_general_pat(mut_span
, &pat
, changed_any_binding
);
670 Ok(pat
.into_inner().kind
)
673 /// Recover on `mut ref? ident @ pat` and suggest
674 /// that the order of `mut` and `ref` is incorrect.
675 fn recover_mut_ref_ident(&mut self, lo
: Span
) -> PResult
<'a
, PatKind
> {
676 let mutref_span
= lo
.to(self.prev_token
.span
);
677 self.struct_span_err(mutref_span
, "the order of `mut` and `ref` is incorrect")
680 "try switching the order",
682 Applicability
::MachineApplicable
,
686 self.parse_pat_ident(BindingMode
::ByRef(Mutability
::Mut
))
689 /// Turn all by-value immutable bindings in a pattern into mutable bindings.
690 /// Returns `true` if any change was made.
691 fn make_all_value_bindings_mutable(pat
: &mut P
<Pat
>) -> bool
{
693 impl MutVisitor
for AddMut
{
694 fn visit_pat(&mut self, pat
: &mut P
<Pat
>) {
695 if let PatKind
::Ident(BindingMode
::ByValue(m @ Mutability
::Not
), ..) = &mut pat
.kind
698 *m
= Mutability
::Mut
;
700 noop_visit_pat(pat
, self);
704 let mut add_mut
= AddMut(false);
705 add_mut
.visit_pat(pat
);
709 /// Error on `mut $pat` where `$pat` is not an ident.
710 fn ban_mut_general_pat(&self, lo
: Span
, pat
: &Pat
, changed_any_binding
: bool
) {
711 let span
= lo
.to(pat
.span
);
712 let fix
= pprust
::pat_to_string(&pat
);
713 let (problem
, suggestion
) = if changed_any_binding
{
714 ("`mut` must be attached to each individual binding", "add `mut` to each binding")
716 ("`mut` must be followed by a named binding", "remove the `mut` prefix")
718 self.struct_span_err(span
, problem
)
719 .span_suggestion(span
, suggestion
, fix
, Applicability
::MachineApplicable
)
720 .note("`mut` may be followed by `variable` and `variable @ pattern`")
724 /// Eat any extraneous `mut`s and error + recover if we ate any.
725 fn recover_additional_muts(&mut self) {
726 let lo
= self.token
.span
;
727 while self.eat_keyword(kw
::Mut
) {}
728 if lo
== self.token
.span
{
732 let span
= lo
.to(self.prev_token
.span
);
733 self.struct_span_err(span
, "`mut` on a binding may not be repeated")
736 "remove the additional `mut`s",
738 Applicability
::MachineApplicable
,
743 /// Parse macro invocation
744 fn parse_pat_mac_invoc(&mut self, path
: Path
) -> PResult
<'a
, PatKind
> {
746 let args
= self.parse_mac_args()?
;
747 let mac
= MacCall { path, args, prior_type_ascription: self.last_type_ascription }
;
748 Ok(PatKind
::MacCall(mac
))
751 fn fatal_unexpected_non_pat(
753 mut err
: DiagnosticBuilder
<'a
>,
755 ) -> PResult
<'a
, P
<Pat
>> {
758 let expected
= expected
.unwrap_or("pattern");
759 let msg
= format
!("expected {}, found {}", expected
, super::token_descr(&self.token
));
761 let mut err
= self.struct_span_err(self.token
.span
, &msg
);
762 err
.span_label(self.token
.span
, format
!("expected {}", expected
));
764 let sp
= self.sess
.source_map().start_point(self.token
.span
);
765 if let Some(sp
) = self.sess
.ambiguous_block_expr_parse
.borrow().get(&sp
) {
766 self.sess
.expr_parentheses_needed(&mut err
, *sp
, None
);
772 /// Parses the range pattern end form `".." | "..." | "..=" ;`.
773 fn parse_range_end(&mut self) -> Option
<Spanned
<RangeEnd
>> {
774 let re
= if self.eat(&token
::DotDotDot
) {
775 RangeEnd
::Included(RangeSyntax
::DotDotDot
)
776 } else if self.eat(&token
::DotDotEq
) {
777 RangeEnd
::Included(RangeSyntax
::DotDotEq
)
778 } else if self.eat(&token
::DotDot
) {
783 Some(respan(self.prev_token
.span
, re
))
786 /// Parse a range pattern `$begin $form $end?` where `$form = ".." | "..." | "..=" ;`.
787 /// `$begin $form` has already been parsed.
788 fn parse_pat_range_begin_with(
791 re
: Spanned
<RangeEnd
>,
792 ) -> PResult
<'a
, PatKind
> {
793 let end
= if self.is_pat_range_end_start(0) {
794 // Parsing e.g. `X..=Y`.
795 Some(self.parse_pat_range_end()?
)
797 // Parsing e.g. `X..`.
798 if let RangeEnd
::Included(_
) = re
.node
{
799 // FIXME(Centril): Consider semantic errors instead in `ast_validation`.
800 self.inclusive_range_with_incorrect_end(re
.span
);
804 Ok(PatKind
::Range(Some(begin
), end
, re
))
807 pub(super) fn inclusive_range_with_incorrect_end(&mut self, span
: Span
) {
808 let tok
= &self.token
;
810 // If the user typed "..==" instead of "..=", we want to give them
811 // a specific error message telling them to use "..=".
812 // Otherwise, we assume that they meant to type a half open exclusive
813 // range and give them an error telling them to do that instead.
814 if matches
!(tok
.kind
, token
::Eq
) && tok
.span
.lo() == span
.hi() {
815 let span_with_eq
= span
.to(tok
.span
);
817 // Ensure the user doesn't receive unhelpful unexpected token errors
819 if self.is_pat_range_end_start(0) {
820 let _
= self.parse_pat_range_end();
823 self.error_inclusive_range_with_extra_equals(span_with_eq
);
825 self.error_inclusive_range_with_no_end(span
);
829 fn error_inclusive_range_with_extra_equals(&self, span
: Span
) {
830 self.struct_span_err(span
, "unexpected `=` after inclusive range")
831 .span_suggestion_short(
835 Applicability
::MaybeIncorrect
,
837 .note("inclusive ranges end with a single equals sign (`..=`)")
841 fn error_inclusive_range_with_no_end(&self, span
: Span
) {
842 struct_span_err
!(self.sess
.span_diagnostic
, span
, E0586
, "inclusive range with no end")
843 .span_suggestion_short(
847 Applicability
::MachineApplicable
,
849 .note("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)")
853 /// Parse a range-to pattern, `..X` or `..=X` where `X` remains to be parsed.
855 /// The form `...X` is prohibited to reduce confusion with the potential
856 /// expression syntax `...expr` for splatting in expressions.
857 fn parse_pat_range_to(&mut self, mut re
: Spanned
<RangeEnd
>) -> PResult
<'a
, PatKind
> {
858 let end
= self.parse_pat_range_end()?
;
859 self.sess
.gated_spans
.gate(sym
::half_open_range_patterns
, re
.span
.to(self.prev_token
.span
));
860 if let RangeEnd
::Included(ref mut syn @ RangeSyntax
::DotDotDot
) = &mut re
.node
{
861 *syn
= RangeSyntax
::DotDotEq
;
862 self.struct_span_err(re
.span
, "range-to patterns with `...` are not allowed")
863 .span_suggestion_short(
867 Applicability
::MachineApplicable
,
871 Ok(PatKind
::Range(None
, Some(end
), re
))
874 /// Is the token `dist` away from the current suitable as the start of a range patterns end?
875 fn is_pat_range_end_start(&self, dist
: usize) -> bool
{
876 self.check_inline_const(dist
)
877 || self.look_ahead(dist
, |t
| {
878 t
.is_path_start() // e.g. `MY_CONST`;
879 || t
.kind
== token
::Dot
// e.g. `.5` for recovery;
880 || t
.can_begin_literal_maybe_minus() // e.g. `42`.
885 fn parse_pat_range_end(&mut self) -> PResult
<'a
, P
<Expr
>> {
886 if self.check_inline_const(0) {
887 self.parse_const_block(self.token
.span
)
888 } else if self.check_path() {
889 let lo
= self.token
.span
;
890 let (qself
, path
) = if self.eat_lt() {
891 // Parse a qualified path
892 let (qself
, path
) = self.parse_qpath(PathStyle
::Expr
)?
;
895 // Parse an unqualified path
896 (None
, self.parse_path(PathStyle
::Expr
)?
)
898 let hi
= self.prev_token
.span
;
899 Ok(self.mk_expr(lo
.to(hi
), ExprKind
::Path(qself
, path
), AttrVec
::new()))
901 self.parse_literal_maybe_minus()
905 /// Is this the start of a pattern beginning with a path?
906 fn is_start_of_pat_with_path(&mut self) -> bool
{
908 // Just for recovery (see `can_be_ident`).
909 || self.token
.is_ident() && !self.token
.is_bool_lit() && !self.token
.is_keyword(kw
::In
)
912 /// Would `parse_pat_ident` be appropriate here?
913 fn can_be_ident_pat(&mut self) -> bool
{
915 && !self.token
.is_bool_lit() // Avoid `true` or `false` as a binding as it is a literal.
916 && !self.token
.is_path_segment_keyword() // Avoid e.g. `Self` as it is a path.
917 // Avoid `in`. Due to recovery in the list parser this messes with `for ( $pat in $expr )`.
918 && !self.token
.is_keyword(kw
::In
)
919 // Try to do something more complex?
920 && self.look_ahead(1, |t
| !matches
!(t
.kind
, token
::OpenDelim(token
::Paren
) // A tuple struct pattern.
921 | token
::OpenDelim(token
::Brace
) // A struct pattern.
922 | token
::DotDotDot
| token
::DotDotEq
| token
::DotDot
// A range pattern.
923 | token
::ModSep
// A tuple / struct variant pattern.
924 | token
::Not
)) // A macro expanding to a pattern.
927 /// Parses `ident` or `ident @ pat`.
928 /// Used by the copy foo and ref foo patterns to give a good
929 /// error message when parsing mistakes like `ref foo(a, b)`.
930 fn parse_pat_ident(&mut self, binding_mode
: BindingMode
) -> PResult
<'a
, PatKind
> {
931 let ident
= self.parse_ident()?
;
932 let sub
= if self.eat(&token
::At
) {
933 Some(self.parse_pat_no_top_alt(Some("binding pattern"))?
)
938 // Just to be friendly, if they write something like `ref Some(i)`,
939 // we end up here with `(` as the current token.
940 // This shortly leads to a parse error. Note that if there is no explicit
941 // binding mode then we do not end up here, because the lookahead
942 // will direct us over to `parse_enum_variant()`.
943 if self.token
== token
::OpenDelim(token
::Paren
) {
945 .struct_span_err(self.prev_token
.span
, "expected identifier, found enum pattern"));
948 Ok(PatKind
::Ident(binding_mode
, ident
, sub
))
951 /// Parse a struct ("record") pattern (e.g. `Foo { ... }` or `Foo::Bar { ... }`).
952 fn parse_pat_struct(&mut self, qself
: Option
<QSelf
>, path
: Path
) -> PResult
<'a
, PatKind
> {
954 // Feature gate the use of qualified paths in patterns
955 self.sess
.gated_spans
.gate(sym
::more_qualified_paths
, path
.span
);
958 let (fields
, etc
) = self.parse_pat_fields().unwrap_or_else(|mut e
| {
959 e
.span_label(path
.span
, "while parsing the fields for this pattern");
965 Ok(PatKind
::Struct(qself
, path
, fields
, etc
))
968 /// Parse tuple struct or tuple variant pattern (e.g. `Foo(...)` or `Foo::Bar(...)`).
969 fn parse_pat_tuple_struct(&mut self, qself
: Option
<QSelf
>, path
: Path
) -> PResult
<'a
, PatKind
> {
970 let (fields
, _
) = self.parse_paren_comma_seq(|p
| {
971 p
.parse_pat_allow_top_alt(None
, RecoverComma
::No
, RecoverColon
::No
)
974 self.sess
.gated_spans
.gate(sym
::more_qualified_paths
, path
.span
);
976 Ok(PatKind
::TupleStruct(qself
, path
, fields
))
979 /// Parses the fields of a struct-like pattern.
980 fn parse_pat_fields(&mut self) -> PResult
<'a
, (Vec
<PatField
>, bool
)> {
981 let mut fields
= Vec
::new();
983 let mut ate_comma
= true;
984 let mut delayed_err
: Option
<DiagnosticBuilder
<'a
>> = None
;
985 let mut etc_span
= None
;
987 while self.token
!= token
::CloseDelim(token
::Brace
) {
988 let attrs
= match self.parse_outer_attributes() {
991 if let Some(mut delayed
) = delayed_err
{
997 let lo
= self.token
.span
;
999 // check that a comma comes after every field
1001 let err
= self.struct_span_err(self.token
.span
, "expected `,`");
1002 if let Some(mut delayed
) = delayed_err
{
1009 if self.check(&token
::DotDot
) || self.token
== token
::DotDotDot
{
1011 let mut etc_sp
= self.token
.span
;
1013 self.recover_one_fewer_dotdot();
1014 self.bump(); // `..` || `...`
1016 if self.token
== token
::CloseDelim(token
::Brace
) {
1017 etc_span
= Some(etc_sp
);
1020 let token_str
= super::token_descr(&self.token
);
1021 let msg
= &format
!("expected `}}`, found {}", token_str
);
1022 let mut err
= self.struct_span_err(self.token
.span
, msg
);
1024 err
.span_label(self.token
.span
, "expected `}`");
1025 let mut comma_sp
= None
;
1026 if self.token
== token
::Comma
{
1028 let nw_span
= self.sess
.source_map().span_until_non_whitespace(self.token
.span
);
1029 etc_sp
= etc_sp
.to(nw_span
);
1032 "`..` must be at the end and cannot have a trailing comma",
1034 comma_sp
= Some(self.token
.span
);
1039 etc_span
= Some(etc_sp
.until(self.token
.span
));
1040 if self.token
== token
::CloseDelim(token
::Brace
) {
1041 // If the struct looks otherwise well formed, recover and continue.
1042 if let Some(sp
) = comma_sp
{
1043 err
.span_suggestion_short(
1045 "remove this comma",
1047 Applicability
::MachineApplicable
,
1052 } else if self.token
.is_ident() && ate_comma
{
1053 // Accept fields coming after `..,`.
1054 // This way we avoid "pattern missing fields" errors afterwards.
1055 // We delay this error until the end in order to have a span for a
1057 if let Some(mut delayed_err
) = delayed_err
{
1061 delayed_err
= Some(err
);
1064 if let Some(mut err
) = delayed_err
{
1072 self.collect_tokens_trailing_token(attrs
, ForceCollect
::No
, |this
, attrs
| {
1073 let field
= match this
.parse_pat_field(lo
, attrs
) {
1074 Ok(field
) => Ok(field
),
1076 if let Some(mut delayed_err
) = delayed_err
.take() {
1082 ate_comma
= this
.eat(&token
::Comma
);
1083 // We just ate a comma, so there's no need to use
1084 // `TrailingToken::Comma`
1085 Ok((field
, TrailingToken
::None
))
1091 if let Some(mut err
) = delayed_err
{
1092 if let Some(etc_span
) = etc_span
{
1093 err
.multipart_suggestion(
1094 "move the `..` to the end of the field list",
1096 (etc_span
, String
::new()),
1097 (self.token
.span
, format
!("{}.. }}", if ate_comma { "" }
else { ", " }
)),
1099 Applicability
::MachineApplicable
,
1107 /// Recover on `...` as if it were `..` to avoid further errors.
1108 /// See issue #46718.
1109 fn recover_one_fewer_dotdot(&self) {
1110 if self.token
!= token
::DotDotDot
{
1114 self.struct_span_err(self.token
.span
, "expected field pattern, found `...`")
1117 "to omit remaining fields, use one fewer `.`",
1119 Applicability
::MachineApplicable
,
1124 fn parse_pat_field(&mut self, lo
: Span
, attrs
: Vec
<Attribute
>) -> PResult
<'a
, PatField
> {
1125 // Check if a colon exists one ahead. This means we're parsing a fieldname.
1127 let (subpat
, fieldname
, is_shorthand
) = if self.look_ahead(1, |t
| t
== &token
::Colon
) {
1128 // Parsing a pattern of the form `fieldname: pat`.
1129 let fieldname
= self.parse_field_name()?
;
1131 let pat
= self.parse_pat_allow_top_alt(None
, RecoverComma
::No
, RecoverColon
::No
)?
;
1133 (pat
, fieldname
, false)
1135 // Parsing a pattern of the form `(box) (ref) (mut) fieldname`.
1136 let is_box
= self.eat_keyword(kw
::Box
);
1137 let boxed_span
= self.token
.span
;
1138 let is_ref
= self.eat_keyword(kw
::Ref
);
1139 let is_mut
= self.eat_keyword(kw
::Mut
);
1140 let fieldname
= self.parse_field_name()?
;
1141 hi
= self.prev_token
.span
;
1143 let bind_type
= match (is_ref
, is_mut
) {
1144 (true, true) => BindingMode
::ByRef(Mutability
::Mut
),
1145 (true, false) => BindingMode
::ByRef(Mutability
::Not
),
1146 (false, true) => BindingMode
::ByValue(Mutability
::Mut
),
1147 (false, false) => BindingMode
::ByValue(Mutability
::Not
),
1150 let fieldpat
= self.mk_pat_ident(boxed_span
.to(hi
), bind_type
, fieldname
);
1152 if is_box { self.mk_pat(lo.to(hi), PatKind::Box(fieldpat)) }
else { fieldpat }
;
1153 (subpat
, fieldname
, true)
1160 attrs
: attrs
.into(),
1161 id
: ast
::DUMMY_NODE_ID
,
1163 is_placeholder
: false,
1167 pub(super) fn mk_pat_ident(&self, span
: Span
, bm
: BindingMode
, ident
: Ident
) -> P
<Pat
> {
1168 self.mk_pat(span
, PatKind
::Ident(bm
, ident
, None
))
1171 fn mk_pat(&self, span
: Span
, kind
: PatKind
) -> P
<Pat
> {
1172 P(Pat { kind, span, id: ast::DUMMY_NODE_ID, tokens: None }
)