• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use super::*;
2 use crate::punctuated::Punctuated;
3 use proc_macro2::TokenStream;
4 
5 ast_enum_of_structs! {
6     /// A pattern in a local binding, function signature, match expression, or
7     /// various other places.
8     ///
9     /// # Syntax tree enum
10     ///
11     /// This type is a [syntax tree enum].
12     ///
13     /// [syntax tree enum]: Expr#syntax-tree-enums
14     #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
15     #[non_exhaustive]
16     pub enum Pat {
17         /// A const block: `const { ... }`.
18         Const(PatConst),
19 
20         /// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`.
21         Ident(PatIdent),
22 
23         /// A literal pattern: `0`.
24         Lit(PatLit),
25 
26         /// A macro in pattern position.
27         Macro(PatMacro),
28 
29         /// A pattern that matches any one of a set of cases.
30         Or(PatOr),
31 
32         /// A parenthesized pattern: `(A | B)`.
33         Paren(PatParen),
34 
35         /// A path pattern like `Color::Red`, optionally qualified with a
36         /// self-type.
37         ///
38         /// Unqualified path patterns can legally refer to variants, structs,
39         /// constants or associated constants. Qualified path patterns like
40         /// `<A>::B::C` and `<A as Trait>::B::C` can only legally refer to
41         /// associated constants.
42         Path(PatPath),
43 
44         /// A range pattern: `1..=2`.
45         Range(PatRange),
46 
47         /// A reference pattern: `&mut var`.
48         Reference(PatReference),
49 
50         /// The dots in a tuple or slice pattern: `[0, 1, ..]`.
51         Rest(PatRest),
52 
53         /// A dynamically sized slice pattern: `[a, b, ref i @ .., y, z]`.
54         Slice(PatSlice),
55 
56         /// A struct or struct variant pattern: `Variant { x, y, .. }`.
57         Struct(PatStruct),
58 
59         /// A tuple pattern: `(a, b)`.
60         Tuple(PatTuple),
61 
62         /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`.
63         TupleStruct(PatTupleStruct),
64 
65         /// A type ascription pattern: `foo: f64`.
66         Type(PatType),
67 
68         /// Tokens in pattern position not interpreted by Syn.
69         Verbatim(TokenStream),
70 
71         /// A pattern that matches any value: `_`.
72         Wild(PatWild),
73 
74         // For testing exhaustiveness in downstream code, use the following idiom:
75         //
76         //     match pat {
77         //         Pat::Box(pat) => {...}
78         //         Pat::Ident(pat) => {...}
79         //         ...
80         //         Pat::Wild(pat) => {...}
81         //
82         //         #[cfg_attr(test, deny(non_exhaustive_omitted_patterns))]
83         //         _ => { /* some sane fallback */ }
84         //     }
85         //
86         // This way we fail your tests but don't break your library when adding
87         // a variant. You will be notified by a test failure when a variant is
88         // added, so that you can add code to handle it, but your library will
89         // continue to compile and work for downstream users in the interim.
90     }
91 }
92 
93 ast_struct! {
94     /// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`.
95     ///
96     /// It may also be a unit struct or struct variant (e.g. `None`), or a
97     /// constant; these cannot be distinguished syntactically.
98     #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
99     pub struct PatIdent {
100         pub attrs: Vec<Attribute>,
101         pub by_ref: Option<Token![ref]>,
102         pub mutability: Option<Token![mut]>,
103         pub ident: Ident,
104         pub subpat: Option<(Token![@], Box<Pat>)>,
105     }
106 }
107 
108 ast_struct! {
109     /// A pattern that matches any one of a set of cases.
110     #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
111     pub struct PatOr {
112         pub attrs: Vec<Attribute>,
113         pub leading_vert: Option<Token![|]>,
114         pub cases: Punctuated<Pat, Token![|]>,
115     }
116 }
117 
118 ast_struct! {
119     /// A parenthesized pattern: `(A | B)`.
120     pub struct PatParen {
121         pub attrs: Vec<Attribute>,
122         pub paren_token: token::Paren,
123         pub pat: Box<Pat>,
124     }
125 }
126 
127 ast_struct! {
128     /// A reference pattern: `&mut var`.
129     #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
130     pub struct PatReference {
131         pub attrs: Vec<Attribute>,
132         pub and_token: Token![&],
133         pub mutability: Option<Token![mut]>,
134         pub pat: Box<Pat>,
135     }
136 }
137 
138 ast_struct! {
139     /// The dots in a tuple or slice pattern: `[0, 1, ..]`.
140     #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
141     pub struct PatRest {
142         pub attrs: Vec<Attribute>,
143         pub dot2_token: Token![..],
144     }
145 }
146 
147 ast_struct! {
148     /// A dynamically sized slice pattern: `[a, b, ref i @ .., y, z]`.
149     #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
150     pub struct PatSlice {
151         pub attrs: Vec<Attribute>,
152         pub bracket_token: token::Bracket,
153         pub elems: Punctuated<Pat, Token![,]>,
154     }
155 }
156 
157 ast_struct! {
158     /// A struct or struct variant pattern: `Variant { x, y, .. }`.
159     #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
160     pub struct PatStruct {
161         pub attrs: Vec<Attribute>,
162         pub qself: Option<QSelf>,
163         pub path: Path,
164         pub brace_token: token::Brace,
165         pub fields: Punctuated<FieldPat, Token![,]>,
166         pub rest: Option<PatRest>,
167     }
168 }
169 
170 ast_struct! {
171     /// A tuple pattern: `(a, b)`.
172     #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
173     pub struct PatTuple {
174         pub attrs: Vec<Attribute>,
175         pub paren_token: token::Paren,
176         pub elems: Punctuated<Pat, Token![,]>,
177     }
178 }
179 
180 ast_struct! {
181     /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`.
182     #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
183     pub struct PatTupleStruct {
184         pub attrs: Vec<Attribute>,
185         pub qself: Option<QSelf>,
186         pub path: Path,
187         pub paren_token: token::Paren,
188         pub elems: Punctuated<Pat, Token![,]>,
189     }
190 }
191 
192 ast_struct! {
193     /// A type ascription pattern: `foo: f64`.
194     #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
195     pub struct PatType {
196         pub attrs: Vec<Attribute>,
197         pub pat: Box<Pat>,
198         pub colon_token: Token![:],
199         pub ty: Box<Type>,
200     }
201 }
202 
203 ast_struct! {
204     /// A pattern that matches any value: `_`.
205     #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
206     pub struct PatWild {
207         pub attrs: Vec<Attribute>,
208         pub underscore_token: Token![_],
209     }
210 }
211 
212 ast_struct! {
213     /// A single field in a struct pattern.
214     ///
215     /// Patterns like the fields of Foo `{ x, ref y, ref mut z }` are treated
216     /// the same as `x: x, y: ref y, z: ref mut z` but there is no colon token.
217     #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
218     pub struct FieldPat {
219         pub attrs: Vec<Attribute>,
220         pub member: Member,
221         pub colon_token: Option<Token![:]>,
222         pub pat: Box<Pat>,
223     }
224 }
225 
226 #[cfg(feature = "parsing")]
227 pub(crate) mod parsing {
228     use super::*;
229     use crate::ext::IdentExt;
230     use crate::parse::{ParseBuffer, ParseStream, Result};
231     use crate::path;
232 
233     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
234     impl Pat {
235         /// Parse a pattern that does _not_ involve `|` at the top level.
236         ///
237         /// This parser matches the behavior of the `$:pat_param` macro_rules
238         /// matcher, and on editions prior to Rust 2021, the behavior of
239         /// `$:pat`.
240         ///
241         /// In Rust syntax, some examples of where this syntax would occur are
242         /// in the argument pattern of functions and closures. Patterns using
243         /// `|` are not allowed to occur in these positions.
244         ///
245         /// ```compile_fail
246         /// fn f(Some(_) | None: Option<T>) {
247         ///     let _ = |Some(_) | None: Option<T>| {};
248         ///     //       ^^^^^^^^^^^^^^^^^^^^^^^^^??? :(
249         /// }
250         /// ```
251         ///
252         /// ```console
253         /// error: top-level or-patterns are not allowed in function parameters
254         ///  --> src/main.rs:1:6
255         ///   |
256         /// 1 | fn f(Some(_) | None: Option<T>) {
257         ///   |      ^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(Some(_) | None)`
258         /// ```
parse_single(input: ParseStream) -> Result<Self>259         pub fn parse_single(input: ParseStream) -> Result<Self> {
260             let begin = input.fork();
261             let lookahead = input.lookahead1();
262             if lookahead.peek(Ident)
263                 && (input.peek2(Token![::])
264                     || input.peek2(Token![!])
265                     || input.peek2(token::Brace)
266                     || input.peek2(token::Paren)
267                     || input.peek2(Token![..]))
268                 || input.peek(Token![self]) && input.peek2(Token![::])
269                 || lookahead.peek(Token![::])
270                 || lookahead.peek(Token![<])
271                 || input.peek(Token![Self])
272                 || input.peek(Token![super])
273                 || input.peek(Token![crate])
274             {
275                 pat_path_or_macro_or_struct_or_range(input)
276             } else if lookahead.peek(Token![_]) {
277                 input.call(pat_wild).map(Pat::Wild)
278             } else if input.peek(Token![box]) {
279                 pat_box(begin, input)
280             } else if input.peek(Token![-]) || lookahead.peek(Lit) || lookahead.peek(Token![const])
281             {
282                 pat_lit_or_range(input)
283             } else if lookahead.peek(Token![ref])
284                 || lookahead.peek(Token![mut])
285                 || input.peek(Token![self])
286                 || input.peek(Ident)
287             {
288                 input.call(pat_ident).map(Pat::Ident)
289             } else if lookahead.peek(Token![&]) {
290                 input.call(pat_reference).map(Pat::Reference)
291             } else if lookahead.peek(token::Paren) {
292                 input.call(pat_paren_or_tuple)
293             } else if lookahead.peek(token::Bracket) {
294                 input.call(pat_slice).map(Pat::Slice)
295             } else if lookahead.peek(Token![..]) && !input.peek(Token![...]) {
296                 pat_range_half_open(input)
297             } else if lookahead.peek(Token![const]) {
298                 input.call(pat_const).map(Pat::Verbatim)
299             } else {
300                 Err(lookahead.error())
301             }
302         }
303 
304         /// Parse a pattern, possibly involving `|`, but not a leading `|`.
parse_multi(input: ParseStream) -> Result<Self>305         pub fn parse_multi(input: ParseStream) -> Result<Self> {
306             multi_pat_impl(input, None)
307         }
308 
309         /// Parse a pattern, possibly involving `|`, possibly including a
310         /// leading `|`.
311         ///
312         /// This parser matches the behavior of the Rust 2021 edition's `$:pat`
313         /// macro_rules matcher.
314         ///
315         /// In Rust syntax, an example of where this syntax would occur is in
316         /// the pattern of a `match` arm, where the language permits an optional
317         /// leading `|`, although it is not idiomatic to write one there in
318         /// handwritten code.
319         ///
320         /// ```
321         /// # let wat = None;
322         /// match wat {
323         ///     | None | Some(false) => {}
324         ///     | Some(true) => {}
325         /// }
326         /// ```
327         ///
328         /// The compiler accepts it only to facilitate some situations in
329         /// macro-generated code where a macro author might need to write:
330         ///
331         /// ```
332         /// # macro_rules! doc {
333         /// #     ($value:expr, ($($conditions1:pat),*), ($($conditions2:pat),*), $then:expr) => {
334         /// match $value {
335         ///     $(| $conditions1)* $(| $conditions2)* => $then
336         /// }
337         /// #     };
338         /// # }
339         /// #
340         /// # doc!(true, (true), (false), {});
341         /// # doc!(true, (), (true, false), {});
342         /// # doc!(true, (true, false), (), {});
343         /// ```
344         ///
345         /// Expressing the same thing correctly in the case that either one (but
346         /// not both) of `$conditions1` and `$conditions2` might be empty,
347         /// without leading `|`, is complex.
348         ///
349         /// Use [`Pat::parse_multi`] instead if you are not intending to support
350         /// macro-generated macro input.
parse_multi_with_leading_vert(input: ParseStream) -> Result<Self>351         pub fn parse_multi_with_leading_vert(input: ParseStream) -> Result<Self> {
352             let leading_vert: Option<Token![|]> = input.parse()?;
353             multi_pat_impl(input, leading_vert)
354         }
355     }
356 
multi_pat_impl(input: ParseStream, leading_vert: Option<Token![|]>) -> Result<Pat>357     fn multi_pat_impl(input: ParseStream, leading_vert: Option<Token![|]>) -> Result<Pat> {
358         let mut pat = Pat::parse_single(input)?;
359         if leading_vert.is_some()
360             || input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=])
361         {
362             let mut cases = Punctuated::new();
363             cases.push_value(pat);
364             while input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=]) {
365                 let punct = input.parse()?;
366                 cases.push_punct(punct);
367                 let pat = Pat::parse_single(input)?;
368                 cases.push_value(pat);
369             }
370             pat = Pat::Or(PatOr {
371                 attrs: Vec::new(),
372                 leading_vert,
373                 cases,
374             });
375         }
376         Ok(pat)
377     }
378 
pat_path_or_macro_or_struct_or_range(input: ParseStream) -> Result<Pat>379     fn pat_path_or_macro_or_struct_or_range(input: ParseStream) -> Result<Pat> {
380         let (qself, path) = path::parsing::qpath(input, true)?;
381 
382         if qself.is_none()
383             && input.peek(Token![!])
384             && !input.peek(Token![!=])
385             && path.is_mod_style()
386         {
387             let bang_token: Token![!] = input.parse()?;
388             let (delimiter, tokens) = mac::parse_delimiter(input)?;
389             return Ok(Pat::Macro(ExprMacro {
390                 attrs: Vec::new(),
391                 mac: Macro {
392                     path,
393                     bang_token,
394                     delimiter,
395                     tokens,
396                 },
397             }));
398         }
399 
400         if input.peek(token::Brace) {
401             pat_struct(input, qself, path).map(Pat::Struct)
402         } else if input.peek(token::Paren) {
403             pat_tuple_struct(input, qself, path).map(Pat::TupleStruct)
404         } else if input.peek(Token![..]) {
405             pat_range(input, qself, path)
406         } else {
407             Ok(Pat::Path(ExprPath {
408                 attrs: Vec::new(),
409                 qself,
410                 path,
411             }))
412         }
413     }
414 
pat_wild(input: ParseStream) -> Result<PatWild>415     fn pat_wild(input: ParseStream) -> Result<PatWild> {
416         Ok(PatWild {
417             attrs: Vec::new(),
418             underscore_token: input.parse()?,
419         })
420     }
421 
pat_box(begin: ParseBuffer, input: ParseStream) -> Result<Pat>422     fn pat_box(begin: ParseBuffer, input: ParseStream) -> Result<Pat> {
423         input.parse::<Token![box]>()?;
424         Pat::parse_single(input)?;
425         Ok(Pat::Verbatim(verbatim::between(&begin, input)))
426     }
427 
pat_ident(input: ParseStream) -> Result<PatIdent>428     fn pat_ident(input: ParseStream) -> Result<PatIdent> {
429         Ok(PatIdent {
430             attrs: Vec::new(),
431             by_ref: input.parse()?,
432             mutability: input.parse()?,
433             ident: input.call(Ident::parse_any)?,
434             subpat: {
435                 if input.peek(Token![@]) {
436                     let at_token: Token![@] = input.parse()?;
437                     let subpat = Pat::parse_single(input)?;
438                     Some((at_token, Box::new(subpat)))
439                 } else {
440                     None
441                 }
442             },
443         })
444     }
445 
pat_tuple_struct( input: ParseStream, qself: Option<QSelf>, path: Path, ) -> Result<PatTupleStruct>446     fn pat_tuple_struct(
447         input: ParseStream,
448         qself: Option<QSelf>,
449         path: Path,
450     ) -> Result<PatTupleStruct> {
451         let content;
452         let paren_token = parenthesized!(content in input);
453 
454         let mut elems = Punctuated::new();
455         while !content.is_empty() {
456             let value = Pat::parse_multi_with_leading_vert(&content)?;
457             elems.push_value(value);
458             if content.is_empty() {
459                 break;
460             }
461             let punct = content.parse()?;
462             elems.push_punct(punct);
463         }
464 
465         Ok(PatTupleStruct {
466             attrs: Vec::new(),
467             qself,
468             path,
469             paren_token,
470             elems,
471         })
472     }
473 
pat_struct(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<PatStruct>474     fn pat_struct(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<PatStruct> {
475         let content;
476         let brace_token = braced!(content in input);
477 
478         let mut fields = Punctuated::new();
479         let mut rest = None;
480         while !content.is_empty() {
481             let attrs = content.call(Attribute::parse_outer)?;
482             if content.peek(Token![..]) {
483                 rest = Some(PatRest {
484                     attrs,
485                     dot2_token: content.parse()?,
486                 });
487                 break;
488             }
489             let mut value = content.call(field_pat)?;
490             value.attrs = attrs;
491             fields.push_value(value);
492             if content.is_empty() {
493                 break;
494             }
495             let punct: Token![,] = content.parse()?;
496             fields.push_punct(punct);
497         }
498 
499         Ok(PatStruct {
500             attrs: Vec::new(),
501             qself,
502             path,
503             brace_token,
504             fields,
505             rest,
506         })
507     }
508 
509     impl Member {
is_unnamed(&self) -> bool510         fn is_unnamed(&self) -> bool {
511             match self {
512                 Member::Named(_) => false,
513                 Member::Unnamed(_) => true,
514             }
515         }
516     }
517 
field_pat(input: ParseStream) -> Result<FieldPat>518     fn field_pat(input: ParseStream) -> Result<FieldPat> {
519         let begin = input.fork();
520         let boxed: Option<Token![box]> = input.parse()?;
521         let by_ref: Option<Token![ref]> = input.parse()?;
522         let mutability: Option<Token![mut]> = input.parse()?;
523 
524         let member = if boxed.is_some() || by_ref.is_some() || mutability.is_some() {
525             input.parse().map(Member::Named)
526         } else {
527             input.parse()
528         }?;
529 
530         if boxed.is_none() && by_ref.is_none() && mutability.is_none() && input.peek(Token![:])
531             || member.is_unnamed()
532         {
533             return Ok(FieldPat {
534                 attrs: Vec::new(),
535                 member,
536                 colon_token: Some(input.parse()?),
537                 pat: Box::new(Pat::parse_multi_with_leading_vert(input)?),
538             });
539         }
540 
541         let ident = match member {
542             Member::Named(ident) => ident,
543             Member::Unnamed(_) => unreachable!(),
544         };
545 
546         let pat = if boxed.is_some() {
547             Pat::Verbatim(verbatim::between(&begin, input))
548         } else {
549             Pat::Ident(PatIdent {
550                 attrs: Vec::new(),
551                 by_ref,
552                 mutability,
553                 ident: ident.clone(),
554                 subpat: None,
555             })
556         };
557 
558         Ok(FieldPat {
559             attrs: Vec::new(),
560             member: Member::Named(ident),
561             colon_token: None,
562             pat: Box::new(pat),
563         })
564     }
565 
pat_range(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<Pat>566     fn pat_range(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<Pat> {
567         let limits = RangeLimits::parse_obsolete(input)?;
568         let end = input.call(pat_range_bound)?;
569         if let (RangeLimits::Closed(_), None) = (&limits, &end) {
570             return Err(input.error("expected range upper bound"));
571         }
572         Ok(Pat::Range(ExprRange {
573             attrs: Vec::new(),
574             start: Some(Box::new(Expr::Path(ExprPath {
575                 attrs: Vec::new(),
576                 qself,
577                 path,
578             }))),
579             limits,
580             end: end.map(PatRangeBound::into_expr),
581         }))
582     }
583 
pat_range_half_open(input: ParseStream) -> Result<Pat>584     fn pat_range_half_open(input: ParseStream) -> Result<Pat> {
585         let limits: RangeLimits = input.parse()?;
586         let end = input.call(pat_range_bound)?;
587         if end.is_some() {
588             Ok(Pat::Range(ExprRange {
589                 attrs: Vec::new(),
590                 start: None,
591                 limits,
592                 end: end.map(PatRangeBound::into_expr),
593             }))
594         } else {
595             match limits {
596                 RangeLimits::HalfOpen(dot2_token) => Ok(Pat::Rest(PatRest {
597                     attrs: Vec::new(),
598                     dot2_token,
599                 })),
600                 RangeLimits::Closed(_) => Err(input.error("expected range upper bound")),
601             }
602         }
603     }
604 
pat_paren_or_tuple(input: ParseStream) -> Result<Pat>605     fn pat_paren_or_tuple(input: ParseStream) -> Result<Pat> {
606         let content;
607         let paren_token = parenthesized!(content in input);
608 
609         let mut elems = Punctuated::new();
610         while !content.is_empty() {
611             let value = Pat::parse_multi_with_leading_vert(&content)?;
612             if content.is_empty() {
613                 if elems.is_empty() && !matches!(value, Pat::Rest(_)) {
614                     return Ok(Pat::Paren(PatParen {
615                         attrs: Vec::new(),
616                         paren_token,
617                         pat: Box::new(value),
618                     }));
619                 }
620                 elems.push_value(value);
621                 break;
622             }
623             elems.push_value(value);
624             let punct = content.parse()?;
625             elems.push_punct(punct);
626         }
627 
628         Ok(Pat::Tuple(PatTuple {
629             attrs: Vec::new(),
630             paren_token,
631             elems,
632         }))
633     }
634 
pat_reference(input: ParseStream) -> Result<PatReference>635     fn pat_reference(input: ParseStream) -> Result<PatReference> {
636         Ok(PatReference {
637             attrs: Vec::new(),
638             and_token: input.parse()?,
639             mutability: input.parse()?,
640             pat: Box::new(Pat::parse_single(input)?),
641         })
642     }
643 
pat_lit_or_range(input: ParseStream) -> Result<Pat>644     fn pat_lit_or_range(input: ParseStream) -> Result<Pat> {
645         let start = input.call(pat_range_bound)?.unwrap();
646         if input.peek(Token![..]) {
647             let limits = RangeLimits::parse_obsolete(input)?;
648             let end = input.call(pat_range_bound)?;
649             if let (RangeLimits::Closed(_), None) = (&limits, &end) {
650                 return Err(input.error("expected range upper bound"));
651             }
652             Ok(Pat::Range(ExprRange {
653                 attrs: Vec::new(),
654                 start: Some(start.into_expr()),
655                 limits,
656                 end: end.map(PatRangeBound::into_expr),
657             }))
658         } else {
659             Ok(start.into_pat())
660         }
661     }
662 
663     // Patterns that can appear on either side of a range pattern.
664     enum PatRangeBound {
665         Const(ExprConst),
666         Lit(ExprLit),
667         Path(ExprPath),
668     }
669 
670     impl PatRangeBound {
into_expr(self) -> Box<Expr>671         fn into_expr(self) -> Box<Expr> {
672             Box::new(match self {
673                 PatRangeBound::Const(pat) => Expr::Const(pat),
674                 PatRangeBound::Lit(pat) => Expr::Lit(pat),
675                 PatRangeBound::Path(pat) => Expr::Path(pat),
676             })
677         }
678 
into_pat(self) -> Pat679         fn into_pat(self) -> Pat {
680             match self {
681                 PatRangeBound::Const(pat) => Pat::Const(pat),
682                 PatRangeBound::Lit(pat) => Pat::Lit(pat),
683                 PatRangeBound::Path(pat) => Pat::Path(pat),
684             }
685         }
686     }
687 
pat_range_bound(input: ParseStream) -> Result<Option<PatRangeBound>>688     fn pat_range_bound(input: ParseStream) -> Result<Option<PatRangeBound>> {
689         if input.is_empty()
690             || input.peek(Token![|])
691             || input.peek(Token![=])
692             || input.peek(Token![:]) && !input.peek(Token![::])
693             || input.peek(Token![,])
694             || input.peek(Token![;])
695             || input.peek(Token![if])
696         {
697             return Ok(None);
698         }
699 
700         let lookahead = input.lookahead1();
701         let expr = if lookahead.peek(Lit) {
702             PatRangeBound::Lit(input.parse()?)
703         } else if lookahead.peek(Ident)
704             || lookahead.peek(Token![::])
705             || lookahead.peek(Token![<])
706             || lookahead.peek(Token![self])
707             || lookahead.peek(Token![Self])
708             || lookahead.peek(Token![super])
709             || lookahead.peek(Token![crate])
710         {
711             PatRangeBound::Path(input.parse()?)
712         } else if lookahead.peek(Token![const]) {
713             PatRangeBound::Const(input.parse()?)
714         } else {
715             return Err(lookahead.error());
716         };
717 
718         Ok(Some(expr))
719     }
720 
pat_slice(input: ParseStream) -> Result<PatSlice>721     fn pat_slice(input: ParseStream) -> Result<PatSlice> {
722         let content;
723         let bracket_token = bracketed!(content in input);
724 
725         let mut elems = Punctuated::new();
726         while !content.is_empty() {
727             let value = Pat::parse_multi_with_leading_vert(&content)?;
728             match value {
729                 Pat::Range(pat) if pat.start.is_none() || pat.end.is_none() => {
730                     let (start, end) = match pat.limits {
731                         RangeLimits::HalfOpen(dot_dot) => (dot_dot.spans[0], dot_dot.spans[1]),
732                         RangeLimits::Closed(dot_dot_eq) => {
733                             (dot_dot_eq.spans[0], dot_dot_eq.spans[2])
734                         }
735                     };
736                     let msg = "range pattern is not allowed unparenthesized inside slice pattern";
737                     return Err(error::new2(start, end, msg));
738                 }
739                 _ => {}
740             }
741             elems.push_value(value);
742             if content.is_empty() {
743                 break;
744             }
745             let punct = content.parse()?;
746             elems.push_punct(punct);
747         }
748 
749         Ok(PatSlice {
750             attrs: Vec::new(),
751             bracket_token,
752             elems,
753         })
754     }
755 
pat_const(input: ParseStream) -> Result<TokenStream>756     fn pat_const(input: ParseStream) -> Result<TokenStream> {
757         let begin = input.fork();
758         input.parse::<Token![const]>()?;
759 
760         let content;
761         braced!(content in input);
762         content.call(Attribute::parse_inner)?;
763         content.call(Block::parse_within)?;
764 
765         Ok(verbatim::between(&begin, input))
766     }
767 }
768 
769 #[cfg(feature = "printing")]
770 mod printing {
771     use super::*;
772     use crate::attr::FilterAttrs;
773     use proc_macro2::TokenStream;
774     use quote::{ToTokens, TokenStreamExt};
775 
776     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
777     impl ToTokens for PatIdent {
to_tokens(&self, tokens: &mut TokenStream)778         fn to_tokens(&self, tokens: &mut TokenStream) {
779             tokens.append_all(self.attrs.outer());
780             self.by_ref.to_tokens(tokens);
781             self.mutability.to_tokens(tokens);
782             self.ident.to_tokens(tokens);
783             if let Some((at_token, subpat)) = &self.subpat {
784                 at_token.to_tokens(tokens);
785                 subpat.to_tokens(tokens);
786             }
787         }
788     }
789 
790     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
791     impl ToTokens for PatOr {
to_tokens(&self, tokens: &mut TokenStream)792         fn to_tokens(&self, tokens: &mut TokenStream) {
793             tokens.append_all(self.attrs.outer());
794             self.leading_vert.to_tokens(tokens);
795             self.cases.to_tokens(tokens);
796         }
797     }
798 
799     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
800     impl ToTokens for PatParen {
to_tokens(&self, tokens: &mut TokenStream)801         fn to_tokens(&self, tokens: &mut TokenStream) {
802             tokens.append_all(self.attrs.outer());
803             self.paren_token.surround(tokens, |tokens| {
804                 self.pat.to_tokens(tokens);
805             });
806         }
807     }
808 
809     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
810     impl ToTokens for PatReference {
to_tokens(&self, tokens: &mut TokenStream)811         fn to_tokens(&self, tokens: &mut TokenStream) {
812             tokens.append_all(self.attrs.outer());
813             self.and_token.to_tokens(tokens);
814             self.mutability.to_tokens(tokens);
815             self.pat.to_tokens(tokens);
816         }
817     }
818 
819     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
820     impl ToTokens for PatRest {
to_tokens(&self, tokens: &mut TokenStream)821         fn to_tokens(&self, tokens: &mut TokenStream) {
822             tokens.append_all(self.attrs.outer());
823             self.dot2_token.to_tokens(tokens);
824         }
825     }
826 
827     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
828     impl ToTokens for PatSlice {
to_tokens(&self, tokens: &mut TokenStream)829         fn to_tokens(&self, tokens: &mut TokenStream) {
830             tokens.append_all(self.attrs.outer());
831             self.bracket_token.surround(tokens, |tokens| {
832                 self.elems.to_tokens(tokens);
833             });
834         }
835     }
836 
837     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
838     impl ToTokens for PatStruct {
to_tokens(&self, tokens: &mut TokenStream)839         fn to_tokens(&self, tokens: &mut TokenStream) {
840             tokens.append_all(self.attrs.outer());
841             path::printing::print_path(tokens, &self.qself, &self.path);
842             self.brace_token.surround(tokens, |tokens| {
843                 self.fields.to_tokens(tokens);
844                 // NOTE: We need a comma before the dot2 token if it is present.
845                 if !self.fields.empty_or_trailing() && self.rest.is_some() {
846                     <Token![,]>::default().to_tokens(tokens);
847                 }
848                 self.rest.to_tokens(tokens);
849             });
850         }
851     }
852 
853     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
854     impl ToTokens for PatTuple {
to_tokens(&self, tokens: &mut TokenStream)855         fn to_tokens(&self, tokens: &mut TokenStream) {
856             tokens.append_all(self.attrs.outer());
857             self.paren_token.surround(tokens, |tokens| {
858                 self.elems.to_tokens(tokens);
859             });
860         }
861     }
862 
863     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
864     impl ToTokens for PatTupleStruct {
to_tokens(&self, tokens: &mut TokenStream)865         fn to_tokens(&self, tokens: &mut TokenStream) {
866             tokens.append_all(self.attrs.outer());
867             path::printing::print_path(tokens, &self.qself, &self.path);
868             self.paren_token.surround(tokens, |tokens| {
869                 self.elems.to_tokens(tokens);
870             });
871         }
872     }
873 
874     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
875     impl ToTokens for PatType {
to_tokens(&self, tokens: &mut TokenStream)876         fn to_tokens(&self, tokens: &mut TokenStream) {
877             tokens.append_all(self.attrs.outer());
878             self.pat.to_tokens(tokens);
879             self.colon_token.to_tokens(tokens);
880             self.ty.to_tokens(tokens);
881         }
882     }
883 
884     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
885     impl ToTokens for PatWild {
to_tokens(&self, tokens: &mut TokenStream)886         fn to_tokens(&self, tokens: &mut TokenStream) {
887             tokens.append_all(self.attrs.outer());
888             self.underscore_token.to_tokens(tokens);
889         }
890     }
891 
892     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
893     impl ToTokens for FieldPat {
to_tokens(&self, tokens: &mut TokenStream)894         fn to_tokens(&self, tokens: &mut TokenStream) {
895             tokens.append_all(self.attrs.outer());
896             if let Some(colon_token) = &self.colon_token {
897                 self.member.to_tokens(tokens);
898                 colon_token.to_tokens(tokens);
899             }
900             self.pat.to_tokens(tokens);
901         }
902     }
903 }
904