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