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(doc_cfg, 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(doc_cfg, 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(doc_cfg, 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(doc_cfg, 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(doc_cfg, 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(doc_cfg, 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(doc_cfg, 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(doc_cfg, 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(doc_cfg, 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(doc_cfg, 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(doc_cfg, 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(doc_cfg, 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(doc_cfg, 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(doc_cfg, 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         /// ```
parse_single(input: ParseStream) -> Result<Self>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 `|`.
parse_multi(input: ParseStream) -> Result<Self>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.
parse_multi_with_leading_vert(input: ParseStream) -> Result<Self>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(doc_cfg, doc(cfg(feature = "parsing")))]
386     impl Parse for PatType {
parse(input: ParseStream) -> Result<Self>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 
multi_pat_impl(input: ParseStream, leading_vert: Option<Token![|]>) -> Result<Pat>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 
pat_path_or_macro_or_struct_or_range(input: ParseStream) -> Result<Pat>419     fn pat_path_or_macro_or_struct_or_range(input: ParseStream) -> Result<Pat> {
420         let (qself, path) = path::parsing::qpath(input, true)?;
421 
422         if qself.is_none()
423             && input.peek(Token![!])
424             && !input.peek(Token![!=])
425             && path.is_mod_style()
426         {
427             let bang_token: Token![!] = input.parse()?;
428             let (delimiter, tokens) = mac::parse_delimiter(input)?;
429             return Ok(Pat::Macro(ExprMacro {
430                 attrs: Vec::new(),
431                 mac: Macro {
432                     path,
433                     bang_token,
434                     delimiter,
435                     tokens,
436                 },
437             }));
438         }
439 
440         if input.peek(token::Brace) {
441             pat_struct(input, qself, path).map(Pat::Struct)
442         } else if input.peek(token::Paren) {
443             pat_tuple_struct(input, qself, path).map(Pat::TupleStruct)
444         } else if input.peek(Token![..]) {
445             pat_range(input, qself, path)
446         } else {
447             Ok(Pat::Path(ExprPath {
448                 attrs: Vec::new(),
449                 qself,
450                 path,
451             }))
452         }
453     }
454 
pat_wild(input: ParseStream) -> Result<PatWild>455     fn pat_wild(input: ParseStream) -> Result<PatWild> {
456         Ok(PatWild {
457             attrs: Vec::new(),
458             underscore_token: input.parse()?,
459         })
460     }
461 
pat_box(begin: ParseBuffer, input: ParseStream) -> Result<Pat>462     fn pat_box(begin: ParseBuffer, input: ParseStream) -> Result<Pat> {
463         input.parse::<Token![box]>()?;
464         Pat::parse_single(input)?;
465         Ok(Pat::Verbatim(verbatim::between(&begin, input)))
466     }
467 
pat_ident(input: ParseStream) -> Result<PatIdent>468     fn pat_ident(input: ParseStream) -> Result<PatIdent> {
469         Ok(PatIdent {
470             attrs: Vec::new(),
471             by_ref: input.parse()?,
472             mutability: input.parse()?,
473             ident: input.call(Ident::parse_any)?,
474             subpat: {
475                 if input.peek(Token![@]) {
476                     let at_token: Token![@] = input.parse()?;
477                     let subpat = Pat::parse_single(input)?;
478                     Some((at_token, Box::new(subpat)))
479                 } else {
480                     None
481                 }
482             },
483         })
484     }
485 
pat_tuple_struct( input: ParseStream, qself: Option<QSelf>, path: Path, ) -> Result<PatTupleStruct>486     fn pat_tuple_struct(
487         input: ParseStream,
488         qself: Option<QSelf>,
489         path: Path,
490     ) -> Result<PatTupleStruct> {
491         let content;
492         let paren_token = parenthesized!(content in input);
493 
494         let mut elems = Punctuated::new();
495         while !content.is_empty() {
496             let value = Pat::parse_multi_with_leading_vert(&content)?;
497             elems.push_value(value);
498             if content.is_empty() {
499                 break;
500             }
501             let punct = content.parse()?;
502             elems.push_punct(punct);
503         }
504 
505         Ok(PatTupleStruct {
506             attrs: Vec::new(),
507             qself,
508             path,
509             paren_token,
510             elems,
511         })
512     }
513 
pat_struct(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<PatStruct>514     fn pat_struct(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<PatStruct> {
515         let content;
516         let brace_token = braced!(content in input);
517 
518         let mut fields = Punctuated::new();
519         let mut rest = None;
520         while !content.is_empty() {
521             let attrs = content.call(Attribute::parse_outer)?;
522             if content.peek(Token![..]) {
523                 rest = Some(PatRest {
524                     attrs,
525                     dot2_token: content.parse()?,
526                 });
527                 break;
528             }
529             let mut value = content.call(field_pat)?;
530             value.attrs = attrs;
531             fields.push_value(value);
532             if content.is_empty() {
533                 break;
534             }
535             let punct: Token![,] = content.parse()?;
536             fields.push_punct(punct);
537         }
538 
539         Ok(PatStruct {
540             attrs: Vec::new(),
541             qself,
542             path,
543             brace_token,
544             fields,
545             rest,
546         })
547     }
548 
field_pat(input: ParseStream) -> Result<FieldPat>549     fn field_pat(input: ParseStream) -> Result<FieldPat> {
550         let begin = input.fork();
551         let boxed: Option<Token![box]> = input.parse()?;
552         let by_ref: Option<Token![ref]> = input.parse()?;
553         let mutability: Option<Token![mut]> = input.parse()?;
554 
555         let member = if boxed.is_some() || by_ref.is_some() || mutability.is_some() {
556             input.parse().map(Member::Named)
557         } else {
558             input.parse()
559         }?;
560 
561         if boxed.is_none() && by_ref.is_none() && mutability.is_none() && input.peek(Token![:])
562             || !member.is_named()
563         {
564             return Ok(FieldPat {
565                 attrs: Vec::new(),
566                 member,
567                 colon_token: Some(input.parse()?),
568                 pat: Box::new(Pat::parse_multi_with_leading_vert(input)?),
569             });
570         }
571 
572         let ident = match member {
573             Member::Named(ident) => ident,
574             Member::Unnamed(_) => unreachable!(),
575         };
576 
577         let pat = if boxed.is_some() {
578             Pat::Verbatim(verbatim::between(&begin, input))
579         } else {
580             Pat::Ident(PatIdent {
581                 attrs: Vec::new(),
582                 by_ref,
583                 mutability,
584                 ident: ident.clone(),
585                 subpat: None,
586             })
587         };
588 
589         Ok(FieldPat {
590             attrs: Vec::new(),
591             member: Member::Named(ident),
592             colon_token: None,
593             pat: Box::new(pat),
594         })
595     }
596 
pat_range(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<Pat>597     fn pat_range(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<Pat> {
598         let limits = RangeLimits::parse_obsolete(input)?;
599         let end = input.call(pat_range_bound)?;
600         if let (RangeLimits::Closed(_), None) = (&limits, &end) {
601             return Err(input.error("expected range upper bound"));
602         }
603         Ok(Pat::Range(ExprRange {
604             attrs: Vec::new(),
605             start: Some(Box::new(Expr::Path(ExprPath {
606                 attrs: Vec::new(),
607                 qself,
608                 path,
609             }))),
610             limits,
611             end: end.map(PatRangeBound::into_expr),
612         }))
613     }
614 
pat_range_half_open(input: ParseStream) -> Result<Pat>615     fn pat_range_half_open(input: ParseStream) -> Result<Pat> {
616         let limits: RangeLimits = input.parse()?;
617         let end = input.call(pat_range_bound)?;
618         if end.is_some() {
619             Ok(Pat::Range(ExprRange {
620                 attrs: Vec::new(),
621                 start: None,
622                 limits,
623                 end: end.map(PatRangeBound::into_expr),
624             }))
625         } else {
626             match limits {
627                 RangeLimits::HalfOpen(dot2_token) => Ok(Pat::Rest(PatRest {
628                     attrs: Vec::new(),
629                     dot2_token,
630                 })),
631                 RangeLimits::Closed(_) => Err(input.error("expected range upper bound")),
632             }
633         }
634     }
635 
pat_paren_or_tuple(input: ParseStream) -> Result<Pat>636     fn pat_paren_or_tuple(input: ParseStream) -> Result<Pat> {
637         let content;
638         let paren_token = parenthesized!(content in input);
639 
640         let mut elems = Punctuated::new();
641         while !content.is_empty() {
642             let value = Pat::parse_multi_with_leading_vert(&content)?;
643             if content.is_empty() {
644                 if elems.is_empty() && !matches!(value, Pat::Rest(_)) {
645                     return Ok(Pat::Paren(PatParen {
646                         attrs: Vec::new(),
647                         paren_token,
648                         pat: Box::new(value),
649                     }));
650                 }
651                 elems.push_value(value);
652                 break;
653             }
654             elems.push_value(value);
655             let punct = content.parse()?;
656             elems.push_punct(punct);
657         }
658 
659         Ok(Pat::Tuple(PatTuple {
660             attrs: Vec::new(),
661             paren_token,
662             elems,
663         }))
664     }
665 
pat_reference(input: ParseStream) -> Result<PatReference>666     fn pat_reference(input: ParseStream) -> Result<PatReference> {
667         Ok(PatReference {
668             attrs: Vec::new(),
669             and_token: input.parse()?,
670             mutability: input.parse()?,
671             pat: Box::new(Pat::parse_single(input)?),
672         })
673     }
674 
pat_lit_or_range(input: ParseStream) -> Result<Pat>675     fn pat_lit_or_range(input: ParseStream) -> Result<Pat> {
676         let start = input.call(pat_range_bound)?.unwrap();
677         if input.peek(Token![..]) {
678             let limits = RangeLimits::parse_obsolete(input)?;
679             let end = input.call(pat_range_bound)?;
680             if let (RangeLimits::Closed(_), None) = (&limits, &end) {
681                 return Err(input.error("expected range upper bound"));
682             }
683             Ok(Pat::Range(ExprRange {
684                 attrs: Vec::new(),
685                 start: Some(start.into_expr()),
686                 limits,
687                 end: end.map(PatRangeBound::into_expr),
688             }))
689         } else {
690             Ok(start.into_pat())
691         }
692     }
693 
694     // Patterns that can appear on either side of a range pattern.
695     enum PatRangeBound {
696         Const(ExprConst),
697         Lit(ExprLit),
698         Path(ExprPath),
699     }
700 
701     impl PatRangeBound {
into_expr(self) -> Box<Expr>702         fn into_expr(self) -> Box<Expr> {
703             Box::new(match self {
704                 PatRangeBound::Const(pat) => Expr::Const(pat),
705                 PatRangeBound::Lit(pat) => Expr::Lit(pat),
706                 PatRangeBound::Path(pat) => Expr::Path(pat),
707             })
708         }
709 
into_pat(self) -> Pat710         fn into_pat(self) -> Pat {
711             match self {
712                 PatRangeBound::Const(pat) => Pat::Const(pat),
713                 PatRangeBound::Lit(pat) => Pat::Lit(pat),
714                 PatRangeBound::Path(pat) => Pat::Path(pat),
715             }
716         }
717     }
718 
pat_range_bound(input: ParseStream) -> Result<Option<PatRangeBound>>719     fn pat_range_bound(input: ParseStream) -> Result<Option<PatRangeBound>> {
720         if input.is_empty()
721             || input.peek(Token![|])
722             || input.peek(Token![=])
723             || input.peek(Token![:]) && !input.peek(Token![::])
724             || input.peek(Token![,])
725             || input.peek(Token![;])
726             || input.peek(Token![if])
727         {
728             return Ok(None);
729         }
730 
731         let lookahead = input.lookahead1();
732         let expr = if lookahead.peek(Lit) {
733             PatRangeBound::Lit(input.parse()?)
734         } else if lookahead.peek(Ident)
735             || lookahead.peek(Token![::])
736             || lookahead.peek(Token![<])
737             || lookahead.peek(Token![self])
738             || lookahead.peek(Token![Self])
739             || lookahead.peek(Token![super])
740             || lookahead.peek(Token![crate])
741         {
742             PatRangeBound::Path(input.parse()?)
743         } else if lookahead.peek(Token![const]) {
744             PatRangeBound::Const(input.parse()?)
745         } else {
746             return Err(lookahead.error());
747         };
748 
749         Ok(Some(expr))
750     }
751 
pat_slice(input: ParseStream) -> Result<PatSlice>752     fn pat_slice(input: ParseStream) -> Result<PatSlice> {
753         let content;
754         let bracket_token = bracketed!(content in input);
755 
756         let mut elems = Punctuated::new();
757         while !content.is_empty() {
758             let value = Pat::parse_multi_with_leading_vert(&content)?;
759             match value {
760                 Pat::Range(pat) if pat.start.is_none() || pat.end.is_none() => {
761                     let (start, end) = match pat.limits {
762                         RangeLimits::HalfOpen(dot_dot) => (dot_dot.spans[0], dot_dot.spans[1]),
763                         RangeLimits::Closed(dot_dot_eq) => {
764                             (dot_dot_eq.spans[0], dot_dot_eq.spans[2])
765                         }
766                     };
767                     let msg = "range pattern is not allowed unparenthesized inside slice pattern";
768                     return Err(error::new2(start, end, msg));
769                 }
770                 _ => {}
771             }
772             elems.push_value(value);
773             if content.is_empty() {
774                 break;
775             }
776             let punct = content.parse()?;
777             elems.push_punct(punct);
778         }
779 
780         Ok(PatSlice {
781             attrs: Vec::new(),
782             bracket_token,
783             elems,
784         })
785     }
786 
pat_const(input: ParseStream) -> Result<TokenStream>787     fn pat_const(input: ParseStream) -> Result<TokenStream> {
788         let begin = input.fork();
789         input.parse::<Token![const]>()?;
790 
791         let content;
792         braced!(content in input);
793         content.call(Attribute::parse_inner)?;
794         content.call(Block::parse_within)?;
795 
796         Ok(verbatim::between(&begin, input))
797     }
798 }
799 
800 #[cfg(feature = "printing")]
801 mod printing {
802     use crate::attr::FilterAttrs;
803     use crate::pat::{
804         FieldPat, Pat, PatIdent, PatOr, PatParen, PatReference, PatRest, PatSlice, PatStruct,
805         PatTuple, PatTupleStruct, PatType, PatWild,
806     };
807     use crate::path;
808     use proc_macro2::TokenStream;
809     use quote::{ToTokens, TokenStreamExt};
810 
811     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
812     impl ToTokens for PatIdent {
to_tokens(&self, tokens: &mut TokenStream)813         fn to_tokens(&self, tokens: &mut TokenStream) {
814             tokens.append_all(self.attrs.outer());
815             self.by_ref.to_tokens(tokens);
816             self.mutability.to_tokens(tokens);
817             self.ident.to_tokens(tokens);
818             if let Some((at_token, subpat)) = &self.subpat {
819                 at_token.to_tokens(tokens);
820                 subpat.to_tokens(tokens);
821             }
822         }
823     }
824 
825     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
826     impl ToTokens for PatOr {
to_tokens(&self, tokens: &mut TokenStream)827         fn to_tokens(&self, tokens: &mut TokenStream) {
828             tokens.append_all(self.attrs.outer());
829             self.leading_vert.to_tokens(tokens);
830             self.cases.to_tokens(tokens);
831         }
832     }
833 
834     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
835     impl ToTokens for PatParen {
to_tokens(&self, tokens: &mut TokenStream)836         fn to_tokens(&self, tokens: &mut TokenStream) {
837             tokens.append_all(self.attrs.outer());
838             self.paren_token.surround(tokens, |tokens| {
839                 self.pat.to_tokens(tokens);
840             });
841         }
842     }
843 
844     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
845     impl ToTokens for PatReference {
to_tokens(&self, tokens: &mut TokenStream)846         fn to_tokens(&self, tokens: &mut TokenStream) {
847             tokens.append_all(self.attrs.outer());
848             self.and_token.to_tokens(tokens);
849             self.mutability.to_tokens(tokens);
850             self.pat.to_tokens(tokens);
851         }
852     }
853 
854     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
855     impl ToTokens for PatRest {
to_tokens(&self, tokens: &mut TokenStream)856         fn to_tokens(&self, tokens: &mut TokenStream) {
857             tokens.append_all(self.attrs.outer());
858             self.dot2_token.to_tokens(tokens);
859         }
860     }
861 
862     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
863     impl ToTokens for PatSlice {
to_tokens(&self, tokens: &mut TokenStream)864         fn to_tokens(&self, tokens: &mut TokenStream) {
865             tokens.append_all(self.attrs.outer());
866             self.bracket_token.surround(tokens, |tokens| {
867                 self.elems.to_tokens(tokens);
868             });
869         }
870     }
871 
872     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
873     impl ToTokens for PatStruct {
to_tokens(&self, tokens: &mut TokenStream)874         fn to_tokens(&self, tokens: &mut TokenStream) {
875             tokens.append_all(self.attrs.outer());
876             path::printing::print_path(tokens, &self.qself, &self.path);
877             self.brace_token.surround(tokens, |tokens| {
878                 self.fields.to_tokens(tokens);
879                 // NOTE: We need a comma before the dot2 token if it is present.
880                 if !self.fields.empty_or_trailing() && self.rest.is_some() {
881                     <Token![,]>::default().to_tokens(tokens);
882                 }
883                 self.rest.to_tokens(tokens);
884             });
885         }
886     }
887 
888     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
889     impl ToTokens for PatTuple {
to_tokens(&self, tokens: &mut TokenStream)890         fn to_tokens(&self, tokens: &mut TokenStream) {
891             tokens.append_all(self.attrs.outer());
892             self.paren_token.surround(tokens, |tokens| {
893                 self.elems.to_tokens(tokens);
894                 // If there is only one element, a trailing comma is needed to
895                 // distinguish PatTuple from PatParen, unless this is `(..)`
896                 // which is a tuple pattern even without comma.
897                 if self.elems.len() == 1
898                     && !self.elems.trailing_punct()
899                     && !matches!(self.elems[0], Pat::Rest { .. })
900                 {
901                     <Token![,]>::default().to_tokens(tokens);
902                 }
903             });
904         }
905     }
906 
907     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
908     impl ToTokens for PatTupleStruct {
to_tokens(&self, tokens: &mut TokenStream)909         fn to_tokens(&self, tokens: &mut TokenStream) {
910             tokens.append_all(self.attrs.outer());
911             path::printing::print_path(tokens, &self.qself, &self.path);
912             self.paren_token.surround(tokens, |tokens| {
913                 self.elems.to_tokens(tokens);
914             });
915         }
916     }
917 
918     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
919     impl ToTokens for PatType {
to_tokens(&self, tokens: &mut TokenStream)920         fn to_tokens(&self, tokens: &mut TokenStream) {
921             tokens.append_all(self.attrs.outer());
922             self.pat.to_tokens(tokens);
923             self.colon_token.to_tokens(tokens);
924             self.ty.to_tokens(tokens);
925         }
926     }
927 
928     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
929     impl ToTokens for PatWild {
to_tokens(&self, tokens: &mut TokenStream)930         fn to_tokens(&self, tokens: &mut TokenStream) {
931             tokens.append_all(self.attrs.outer());
932             self.underscore_token.to_tokens(tokens);
933         }
934     }
935 
936     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
937     impl ToTokens for FieldPat {
to_tokens(&self, tokens: &mut TokenStream)938         fn to_tokens(&self, tokens: &mut TokenStream) {
939             tokens.append_all(self.attrs.outer());
940             if let Some(colon_token) = &self.colon_token {
941                 self.member.to_tokens(tokens);
942                 colon_token.to_tokens(tokens);
943             }
944             self.pat.to_tokens(tokens);
945         }
946     }
947 }
948