Skip to main content

syn/
pat.rs

1use crate::attr::Attribute;
2use crate::expr::Member;
3use crate::ident::Ident;
4use crate::path::{Path, QSelf};
5use crate::punctuated::Punctuated;
6use crate::token;
7use crate::ty::Type;
8use proc_macro2::TokenStream;
9
10pub use crate::expr::{
11    ExprConst as PatConst, ExprLit as PatLit, ExprMacro as PatMacro, ExprPath as PatPath,
12    ExprRange as PatRange,
13};
14
15ast_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
104ast_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
119ast_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
129ast_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
139ast_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
150ast_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
159ast_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
169ast_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
182ast_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
192ast_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
204ast_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
215ast_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
224ast_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")]
239pub(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        /// ```
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(doc_cfg, 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 (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
455    fn pat_wild(input: ParseStream) -> Result<PatWild> {
456        Ok(PatWild {
457            attrs: Vec::new(),
458            underscore_token: input.parse()?,
459        })
460    }
461
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
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
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
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
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
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
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
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
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
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 {
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
710        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
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
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
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")]
801mod 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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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}