Skip to main content

syn/
pat.rs

1use crate::attr::Attribute;
2use crate::expr::{Expr, Member};
3use crate::ident::Ident;
4use crate::path::{Path, QSelf};
5use crate::punctuated::Punctuated;
6use crate::token;
7use crate::ty::Type;
8use alloc::boxed::Box;
9use alloc::vec::Vec;
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
17#[doc =
r" A pattern in a local binding, function signature, match expression, or"]
#[doc = r" various other places."]
#[doc = r""]
#[doc = r" # Syntax tree enum"]
#[doc = r""]
#[doc = r" This type is a [syntax tree enum]."]
#[doc = r""]
#[doc = r" [syntax tree enum]: crate::expr::Expr#syntax-tree-enums"]
#[doc(cfg(feature = "full"))]
#[non_exhaustive]
pub enum Pat {

    #[doc = r" A const block: `const { ... }`."]
    Const(PatConst),

    #[doc = r" A pattern with guard predicate: `Some(x) if x > 0`."]
    Guard(PatGuard),

    #[doc =
    r" A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`."]
    Ident(PatIdent),

    #[doc = r" A literal pattern: `0`."]
    Lit(PatLit),

    #[doc = r" A macro in pattern position."]
    Macro(PatMacro),

    #[doc = r" A pattern that matches any one of a set of cases."]
    Or(PatOr),

    #[doc = r" A parenthesized pattern: `(A | B)`."]
    Paren(PatParen),

    #[doc = r" A path pattern like `Color::Red`, optionally qualified with a"]
    #[doc = r" self-type."]
    #[doc = r""]
    #[doc =
    r" Unqualified path patterns can legally refer to variants, structs,"]
    #[doc =
    r" constants or associated constants. Qualified path patterns like"]
    #[doc =
    r" `<A>::B::C` and `<A as Trait>::B::C` can only legally refer to"]
    #[doc = r" associated constants."]
    Path(PatPath),

    #[doc = r" A range pattern: `1..=2`."]
    Range(PatRange),

    #[doc = r" A reference pattern: `&mut var`."]
    Reference(PatReference),

    #[doc = r" The dots in a tuple or slice pattern: `[0, 1, ..]`."]
    Rest(PatRest),

    #[doc =
    r" A dynamically sized slice pattern: `[a, b, ref i @ .., y, z]`."]
    Slice(PatSlice),

    #[doc = r" A struct or struct variant pattern: `Variant { x, y, .. }`."]
    Struct(PatStruct),

    #[doc = r" A tuple pattern: `(a, b)`."]
    Tuple(PatTuple),

    #[doc =
    r" A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`."]
    TupleStruct(PatTupleStruct),

    #[doc = r" A type ascription pattern: `foo: f64`."]
    Type(PatType),

    #[doc = r" Tokens in pattern position not interpreted by Syn."]
    #[doc = r""]
    #[doc = r#" <div class="warning">"#]
    #[doc = r""]
    #[doc =
    r" Important: see [Compatibility notes][crate#verbatim-variants]."]
    #[doc = r""]
    #[doc = r" </div>"]
    Verbatim(TokenStream),

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