Skip to main content

syn/
pat.rs

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