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