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