1 use super::{Parser, PResult, PathStyle};
3 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
5 use crate::ast::{self, Attribute, Pat, PatKind, FieldPat, RangeEnd, RangeSyntax, Mac};
6 use crate::ast::{BindingMode, Ident, Mutability, Path, QSelf, Expr, ExprKind};
7 use crate::parse::token::{self};
8 use crate::print::pprust;
9 use crate::source_map::{respan, Span, Spanned};
10 use crate::symbol::kw;
13 use errors::{Applicability, DiagnosticBuilder};
19 expected: Option<&'static str>
20 ) -> PResult<'a, P<Pat>> {
21 self.parse_pat_with_range_pat(true, expected)
24 /// Parses patterns, separated by '|' s.
25 pub(super) fn parse_pats(&mut self) -> PResult<'a, Vec<P<Pat>>> {
26 // Allow a '|' before the pats (RFC 1925 + RFC 2530)
27 self.eat(&token::BinOp(token::Or));
29 let mut pats = Vec::new();
31 pats.push(self.parse_top_level_pat()?);
33 if self.token == token::OrOr {
34 self.struct_span_err(self.token.span, "unexpected token `||` after pattern")
37 "use a single `|` to specify multiple patterns",
39 Applicability::MachineApplicable
43 } else if self.eat(&token::BinOp(token::Or)) {
44 // This is a No-op. Continue the loop to parse the next
52 /// A wrapper around `parse_pat` with some special error handling for the
53 /// "top-level" patterns in a match arm, `for` loop, `let`, &c. (in contrast
54 /// to subpatterns within such).
55 pub(super) fn parse_top_level_pat(&mut self) -> PResult<'a, P<Pat>> {
56 let pat = self.parse_pat(None)?;
57 if self.token == token::Comma {
58 // An unexpected comma after a top-level pattern is a clue that the
59 // user (perhaps more accustomed to some other language) forgot the
60 // parentheses in what should have been a tuple pattern; return a
61 // suggestion-enhanced error here rather than choking on the comma
63 let comma_span = self.token.span;
65 if let Err(mut err) = self.skip_pat_list() {
66 // We didn't expect this to work anyway; we just wanted
67 // to advance to the end of the comma-sequence so we know
68 // the span to suggest parenthesizing
71 let seq_span = pat.span.to(self.prev_span);
72 let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern");
73 if let Ok(seq_snippet) = self.span_to_snippet(seq_span) {
76 "try adding parentheses to match on a tuple..",
77 format!("({})", seq_snippet),
78 Applicability::MachineApplicable
81 "..or a vertical bar to match on multiple alternatives",
82 format!("{}", seq_snippet.replace(",", " |")),
83 Applicability::MachineApplicable
91 /// Parse and throw away a parentesized comma separated
92 /// sequence of patterns until `)` is reached.
93 fn skip_pat_list(&mut self) -> PResult<'a, ()> {
94 while !self.check(&token::CloseDelim(token::Paren)) {
95 self.parse_pat(None)?;
96 if !self.eat(&token::Comma) {
103 /// Parses a pattern, that may be a or-pattern (e.g. `Some(Foo | Bar)`).
104 fn parse_pat_with_or(&mut self, expected: Option<&'static str>) -> PResult<'a, P<Pat>> {
105 // Parse the first pattern.
106 let first_pat = self.parse_pat(expected)?;
108 // If the next token is not a `|`, this is not an or-pattern and
109 // we should exit here.
110 if !self.check(&token::BinOp(token::Or)) {
114 let lo = first_pat.span;
116 let mut pats = vec![first_pat];
118 while self.eat(&token::BinOp(token::Or)) {
119 pats.push(self.parse_pat_with_range_pat(
124 let or_pattern_span = lo.to(self.prev_span);
126 self.sess.gated_spans.or_patterns.borrow_mut().push(or_pattern_span);
128 Ok(self.mk_pat(or_pattern_span, PatKind::Or(pats)))
131 /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
133 fn parse_pat_with_range_pat(
135 allow_range_pat: bool,
136 expected: Option<&'static str>,
137 ) -> PResult<'a, P<Pat>> {
138 maybe_recover_from_interpolated_ty_qpath!(self, true);
139 maybe_whole!(self, NtPat, |x| x);
141 let lo = self.token.span;
142 let pat = match self.token.kind {
143 token::BinOp(token::And) | token::AndAnd => self.parse_pat_deref(expected)?,
144 token::OpenDelim(token::Paren) => self.parse_pat_tuple_or_parens()?,
145 token::OpenDelim(token::Bracket) => {
146 // Parse `[pat, pat,...]` as a slice pattern.
147 PatKind::Slice(self.parse_delim_comma_seq(token::Bracket, |p| p.parse_pat(None))?.0)
151 if self.is_pat_range_end_start() {
152 // Parse `..42` for recovery.
153 self.parse_pat_range_to(RangeEnd::Excluded, "..")?
155 // A rest pattern `..`.
160 // Parse `..=42` for recovery.
162 self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotEq), "..=")?
164 token::DotDotDot => {
165 // Parse `...42` for recovery.
167 self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotDot), "...")?
169 // At this point, token != &, &&, (, [
170 _ => if self.eat_keyword(kw::Underscore) {
173 } else if self.eat_keyword(kw::Mut) {
174 self.recover_pat_ident_mut_first()?
175 } else if self.eat_keyword(kw::Ref) {
176 // Parse ref ident @ pat / ref mut ident @ pat
177 let mutbl = self.parse_mutability();
178 self.parse_pat_ident(BindingMode::ByRef(mutbl))?
179 } else if self.eat_keyword(kw::Box) {
181 PatKind::Box(self.parse_pat_with_range_pat(false, None)?)
182 } else if self.token.is_ident() && !self.token.is_reserved_ident() &&
183 self.parse_as_ident() {
184 // Parse `ident @ pat`
185 // This can give false positives and parse nullary enums,
186 // they are dealt with later in resolve.
187 self.parse_pat_ident(BindingMode::ByValue(Mutability::Immutable))?
188 } else if self.token.is_path_start() {
189 // Parse pattern starting with a path
190 let (qself, path) = if self.eat_lt() {
191 // Parse a qualified path
192 let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
195 // Parse an unqualified path
196 (None, self.parse_path(PathStyle::Expr)?)
198 match self.token.kind {
199 token::Not if qself.is_none() => self.parse_pat_mac_invoc(lo, path)?,
200 token::DotDotDot | token::DotDotEq | token::DotDot => {
201 self.parse_pat_range_starting_with_path(lo, qself, path)?
203 token::OpenDelim(token::Brace) => self.parse_pat_struct(qself, path)?,
204 token::OpenDelim(token::Paren) => self.parse_pat_tuple_struct(qself, path)?,
205 _ => PatKind::Path(qself, path),
208 // Try to parse everything else as literal with optional minus
209 match self.parse_literal_maybe_minus() {
211 if self.check(&token::DotDot)
212 || self.check(&token::DotDotEq)
213 || self.check(&token::DotDotDot) =>
215 self.parse_pat_range_starting_with_lit(begin)?
217 Ok(begin) => PatKind::Lit(begin),
218 Err(err) => return self.fatal_unexpected_non_pat(err, expected),
223 let pat = self.mk_pat(lo.to(self.prev_span), pat);
224 let pat = self.maybe_recover_from_bad_qpath(pat, true)?;
226 if !allow_range_pat {
227 self.ban_pat_range_if_ambiguous(&pat)?
233 /// Ban a range pattern if it has an ambiguous interpretation.
234 fn ban_pat_range_if_ambiguous(&self, pat: &Pat) -> PResult<'a, ()> {
237 .., Spanned { node: RangeEnd::Included(RangeSyntax::DotDotDot), .. }
239 PatKind::Range(..) => {}
243 let mut err = self.struct_span_err(
245 "the range pattern here has ambiguous interpretation",
249 "add parentheses to clarify the precedence",
250 format!("({})", pprust::pat_to_string(&pat)),
251 // "ambiguous interpretation" implies that we have to be guessing
252 Applicability::MaybeIncorrect
257 /// Parse `&pat` / `&mut pat`.
258 fn parse_pat_deref(&mut self, expected: Option<&'static str>) -> PResult<'a, PatKind> {
260 let mutbl = self.parse_mutability();
262 if let token::Lifetime(name) = self.token.kind {
263 let mut err = self.fatal(&format!("unexpected lifetime `{}` in pattern", name));
264 err.span_label(self.token.span, "unexpected lifetime");
268 let subpat = self.parse_pat_with_range_pat(false, expected)?;
269 Ok(PatKind::Ref(subpat, mutbl))
272 /// Parse a tuple or parenthesis pattern.
273 fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> {
274 let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| {
275 p.parse_pat_with_or(None)
278 // Here, `(pat,)` is a tuple pattern.
279 // For backward compatibility, `(..)` is a tuple pattern as well.
280 Ok(if fields.len() == 1 && !(trailing_comma || fields[0].is_rest()) {
281 PatKind::Paren(fields.into_iter().nth(0).unwrap())
283 PatKind::Tuple(fields)
287 /// Recover on `mut ref? ident @ pat` and suggest
288 /// that the order of `mut` and `ref` is incorrect.
289 fn recover_pat_ident_mut_first(&mut self) -> PResult<'a, PatKind> {
290 let mutref_span = self.prev_span.to(self.token.span);
291 let binding_mode = if self.eat_keyword(kw::Ref) {
292 self.struct_span_err(mutref_span, "the order of `mut` and `ref` is incorrect")
295 "try switching the order",
297 Applicability::MachineApplicable
300 BindingMode::ByRef(Mutability::Mutable)
302 BindingMode::ByValue(Mutability::Mutable)
304 self.parse_pat_ident(binding_mode)
307 /// Parse macro invocation
308 fn parse_pat_mac_invoc(&mut self, lo: Span, path: Path) -> PResult<'a, PatKind> {
310 let (delim, tts) = self.expect_delimited_token_tree()?;
315 span: lo.to(self.prev_span),
316 prior_type_ascription: self.last_type_ascription,
318 Ok(PatKind::Mac(mac))
321 /// Parse a range pattern `$path $form $end?` where `$form = ".." | "..." | "..=" ;`.
322 /// The `$path` has already been parsed and the next token is the `$form`.
323 fn parse_pat_range_starting_with_path(
326 qself: Option<QSelf>,
328 ) -> PResult<'a, PatKind> {
329 let (end_kind, form) = match self.token.kind {
330 token::DotDot => (RangeEnd::Excluded, ".."),
331 token::DotDotDot => (RangeEnd::Included(RangeSyntax::DotDotDot), "..."),
332 token::DotDotEq => (RangeEnd::Included(RangeSyntax::DotDotEq), "..="),
333 _ => panic!("can only parse `..`/`...`/`..=` for ranges (checked above)"),
335 let op_span = self.token.span;
337 let span = lo.to(self.prev_span);
338 let begin = self.mk_expr(span, ExprKind::Path(qself, path), ThinVec::new());
340 let end = self.parse_pat_range_end_opt(&begin, form)?;
341 Ok(PatKind::Range(begin, end, respan(op_span, end_kind)))
344 /// Parse a range pattern `$literal $form $end?` where `$form = ".." | "..." | "..=" ;`.
345 /// The `$path` has already been parsed and the next token is the `$form`.
346 fn parse_pat_range_starting_with_lit(&mut self, begin: P<Expr>) -> PResult<'a, PatKind> {
347 let op_span = self.token.span;
348 let (end_kind, form) = if self.eat(&token::DotDotDot) {
349 (RangeEnd::Included(RangeSyntax::DotDotDot), "...")
350 } else if self.eat(&token::DotDotEq) {
351 (RangeEnd::Included(RangeSyntax::DotDotEq), "..=")
352 } else if self.eat(&token::DotDot) {
353 (RangeEnd::Excluded, "..")
355 panic!("impossible case: we already matched on a range-operator token")
357 let end = self.parse_pat_range_end_opt(&begin, form)?;
358 Ok(PatKind::Range(begin, end, respan(op_span, end_kind)))
361 fn fatal_unexpected_non_pat(
363 mut err: DiagnosticBuilder<'a>,
364 expected: Option<&'static str>,
365 ) -> PResult<'a, P<Pat>> {
366 self.cancel(&mut err);
368 let expected = expected.unwrap_or("pattern");
369 let msg = format!("expected {}, found {}", expected, self.this_token_descr());
371 let mut err = self.fatal(&msg);
372 err.span_label(self.token.span, format!("expected {}", expected));
374 let sp = self.sess.source_map().start_point(self.token.span);
375 if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) {
376 self.sess.expr_parentheses_needed(&mut err, *sp, None);
382 // Helper function to decide whether to parse as ident binding
383 // or to try to do something more complex like range patterns.
384 fn parse_as_ident(&mut self) -> bool {
385 self.look_ahead(1, |t| match t.kind {
386 token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) |
387 token::DotDotDot | token::DotDotEq | token::DotDot |
388 token::ModSep | token::Not => false,
393 /// Is the current token suitable as the start of a range patterns end?
394 fn is_pat_range_end_start(&self) -> bool {
395 self.token.is_path_start() // e.g. `MY_CONST`;
396 || self.token == token::Dot // e.g. `.5` for recovery;
397 || self.token.can_begin_literal_or_bool() // e.g. `42`.
398 || self.token.is_whole_expr()
401 /// Parse a range-to pattern, e.g. `..X` and `..=X` for recovery.
402 fn parse_pat_range_to(&mut self, re: RangeEnd, form: &str) -> PResult<'a, PatKind> {
403 let lo = self.prev_span;
404 let end = self.parse_pat_range_end()?;
405 let range_span = lo.to(end.span);
406 let begin = self.mk_expr(range_span, ExprKind::Err, ThinVec::new());
409 .struct_span_err(range_span, &format!("`{}X` range patterns are not supported", form))
412 "try using the minimum value for the type",
413 format!("MIN{}{}", form, pprust::expr_to_string(&end)),
414 Applicability::HasPlaceholders,
418 Ok(PatKind::Range(begin, end, respan(lo, re)))
421 /// Parse the end of a `X..Y`, `X..=Y`, or `X...Y` range pattern or recover
422 /// if that end is missing treating it as `X..`, `X..=`, or `X...` respectively.
423 fn parse_pat_range_end_opt(&mut self, begin: &Expr, form: &str) -> PResult<'a, P<Expr>> {
424 if self.is_pat_range_end_start() {
425 // Parsing e.g. `X..=Y`.
426 self.parse_pat_range_end()
428 // Parsing e.g. `X..`.
429 let range_span = begin.span.to(self.prev_span);
434 &format!("`X{}` range patterns are not supported", form),
438 "try using the maximum value for the type",
439 format!("{}{}MAX", pprust::expr_to_string(&begin), form),
440 Applicability::HasPlaceholders,
444 Ok(self.mk_expr(range_span, ExprKind::Err, ThinVec::new()))
448 fn parse_pat_range_end(&mut self) -> PResult<'a, P<Expr>> {
449 if self.token.is_path_start() {
450 let lo = self.token.span;
451 let (qself, path) = if self.eat_lt() {
452 // Parse a qualified path
453 let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
456 // Parse an unqualified path
457 (None, self.parse_path(PathStyle::Expr)?)
459 let hi = self.prev_span;
460 Ok(self.mk_expr(lo.to(hi), ExprKind::Path(qself, path), ThinVec::new()))
462 self.parse_literal_maybe_minus()
466 /// Parses `ident` or `ident @ pat`.
467 /// Used by the copy foo and ref foo patterns to give a good
468 /// error message when parsing mistakes like `ref foo(a, b)`.
469 fn parse_pat_ident(&mut self, binding_mode: BindingMode) -> PResult<'a, PatKind> {
470 let ident = self.parse_ident()?;
471 let sub = if self.eat(&token::At) {
472 Some(self.parse_pat(Some("binding pattern"))?)
477 // Just to be friendly, if they write something like `ref Some(i)`,
478 // we end up here with `(` as the current token.
479 // This shortly leads to a parse error. Note that if there is no explicit
480 // binding mode then we do not end up here, because the lookahead
481 // will direct us over to `parse_enum_variant()`.
482 if self.token == token::OpenDelim(token::Paren) {
483 return Err(self.span_fatal(
485 "expected identifier, found enum pattern",
489 Ok(PatKind::Ident(binding_mode, ident, sub))
492 /// Parse a struct ("record") pattern (e.g. `Foo { ... }` or `Foo::Bar { ... }`).
493 fn parse_pat_struct(&mut self, qself: Option<QSelf>, path: Path) -> PResult<'a, PatKind> {
495 let msg = "unexpected `{` after qualified path";
496 let mut err = self.fatal(msg);
497 err.span_label(self.token.span, msg);
502 let (fields, etc) = self.parse_pat_fields().unwrap_or_else(|mut e| {
508 Ok(PatKind::Struct(path, fields, etc))
511 /// Parse tuple struct or tuple variant pattern (e.g. `Foo(...)` or `Foo::Bar(...)`).
512 fn parse_pat_tuple_struct(&mut self, qself: Option<QSelf>, path: Path) -> PResult<'a, PatKind> {
514 let msg = "unexpected `(` after qualified path";
515 let mut err = self.fatal(msg);
516 err.span_label(self.token.span, msg);
519 let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or(None))?;
520 Ok(PatKind::TupleStruct(path, fields))
523 /// Parses the fields of a struct-like pattern.
524 fn parse_pat_fields(&mut self) -> PResult<'a, (Vec<FieldPat>, bool)> {
525 let mut fields = Vec::new();
527 let mut ate_comma = true;
528 let mut delayed_err: Option<DiagnosticBuilder<'a>> = None;
529 let mut etc_span = None;
531 while self.token != token::CloseDelim(token::Brace) {
532 let attrs = match self.parse_outer_attributes() {
535 if let Some(mut delayed) = delayed_err {
541 let lo = self.token.span;
543 // check that a comma comes after every field
545 let err = self.struct_span_err(self.prev_span, "expected `,`");
546 if let Some(mut delayed) = delayed_err {
553 if self.check(&token::DotDot) || self.token == token::DotDotDot {
555 let mut etc_sp = self.token.span;
557 self.recover_one_fewer_dotdot();
558 self.bump(); // `..` || `...`
560 if self.token == token::CloseDelim(token::Brace) {
561 etc_span = Some(etc_sp);
564 let token_str = self.this_token_descr();
565 let mut err = self.fatal(&format!("expected `}}`, found {}", token_str));
567 err.span_label(self.token.span, "expected `}`");
568 let mut comma_sp = None;
569 if self.token == token::Comma { // Issue #49257
570 let nw_span = self.sess.source_map().span_until_non_whitespace(self.token.span);
571 etc_sp = etc_sp.to(nw_span);
572 err.span_label(etc_sp,
573 "`..` must be at the end and cannot have a trailing comma");
574 comma_sp = Some(self.token.span);
579 etc_span = Some(etc_sp.until(self.token.span));
580 if self.token == token::CloseDelim(token::Brace) {
581 // If the struct looks otherwise well formed, recover and continue.
582 if let Some(sp) = comma_sp {
583 err.span_suggestion_short(
587 Applicability::MachineApplicable,
592 } else if self.token.is_ident() && ate_comma {
593 // Accept fields coming after `..,`.
594 // This way we avoid "pattern missing fields" errors afterwards.
595 // We delay this error until the end in order to have a span for a
597 if let Some(mut delayed_err) = delayed_err {
601 delayed_err = Some(err);
604 if let Some(mut err) = delayed_err {
611 fields.push(match self.parse_pat_field(lo, attrs) {
614 if let Some(mut delayed_err) = delayed_err {
620 ate_comma = self.eat(&token::Comma);
623 if let Some(mut err) = delayed_err {
624 if let Some(etc_span) = etc_span {
625 err.multipart_suggestion(
626 "move the `..` to the end of the field list",
628 (etc_span, String::new()),
629 (self.token.span, format!("{}.. }}", if ate_comma { "" } else { ", " })),
631 Applicability::MachineApplicable,
636 return Ok((fields, etc));
639 /// Recover on `...` as if it were `..` to avoid further errors.
640 /// See issue #46718.
641 fn recover_one_fewer_dotdot(&self) {
642 if self.token != token::DotDotDot {
646 self.struct_span_err(self.token.span, "expected field pattern, found `...`")
649 "to omit remaining fields, use one fewer `.`",
651 Applicability::MachineApplicable
656 fn parse_pat_field(&mut self, lo: Span, attrs: Vec<Attribute>) -> PResult<'a, FieldPat> {
657 // Check if a colon exists one ahead. This means we're parsing a fieldname.
659 let (subpat, fieldname, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) {
660 // Parsing a pattern of the form "fieldname: pat"
661 let fieldname = self.parse_field_name()?;
663 let pat = self.parse_pat_with_or(None)?;
665 (pat, fieldname, false)
667 // Parsing a pattern of the form "(box) (ref) (mut) fieldname"
668 let is_box = self.eat_keyword(kw::Box);
669 let boxed_span = self.token.span;
670 let is_ref = self.eat_keyword(kw::Ref);
671 let is_mut = self.eat_keyword(kw::Mut);
672 let fieldname = self.parse_ident()?;
675 let bind_type = match (is_ref, is_mut) {
676 (true, true) => BindingMode::ByRef(Mutability::Mutable),
677 (true, false) => BindingMode::ByRef(Mutability::Immutable),
678 (false, true) => BindingMode::ByValue(Mutability::Mutable),
679 (false, false) => BindingMode::ByValue(Mutability::Immutable),
682 let fieldpat = self.mk_pat_ident(boxed_span.to(hi), bind_type, fieldname);
683 let subpat = if is_box {
684 self.mk_pat(lo.to(hi), PatKind::Box(fieldpat))
688 (subpat, fieldname, true)
696 id: ast::DUMMY_NODE_ID,
701 pub(super) fn mk_pat_ident(&self, span: Span, bm: BindingMode, ident: Ident) -> P<Pat> {
702 self.mk_pat(span, PatKind::Ident(bm, ident, None))
705 fn mk_pat(&self, span: Span, node: PatKind) -> P<Pat> {
706 P(Pat { node, span, id: ast::DUMMY_NODE_ID })