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