xref: /linux/rust/syn/pat.rs (revision 784faa8eca8270671e0ed6d9d21f04bbb80fc5f7)
1*69942c0aSMiguel Ojeda // SPDX-License-Identifier: Apache-2.0 OR MIT
2*69942c0aSMiguel Ojeda 
3808c999fSMiguel Ojeda use crate::attr::Attribute;
4808c999fSMiguel Ojeda use crate::expr::Member;
5808c999fSMiguel Ojeda use crate::ident::Ident;
6808c999fSMiguel Ojeda use crate::path::{Path, QSelf};
7808c999fSMiguel Ojeda use crate::punctuated::Punctuated;
8808c999fSMiguel Ojeda use crate::token;
9808c999fSMiguel Ojeda use crate::ty::Type;
10808c999fSMiguel Ojeda use proc_macro2::TokenStream;
11808c999fSMiguel Ojeda 
12808c999fSMiguel Ojeda pub use crate::expr::{
13808c999fSMiguel Ojeda     ExprConst as PatConst, ExprLit as PatLit, ExprMacro as PatMacro, ExprPath as PatPath,
14808c999fSMiguel Ojeda     ExprRange as PatRange,
15808c999fSMiguel Ojeda };
16808c999fSMiguel Ojeda 
17808c999fSMiguel Ojeda ast_enum_of_structs! {
18808c999fSMiguel Ojeda     /// A pattern in a local binding, function signature, match expression, or
19808c999fSMiguel Ojeda     /// various other places.
20808c999fSMiguel Ojeda     ///
21808c999fSMiguel Ojeda     /// # Syntax tree enum
22808c999fSMiguel Ojeda     ///
23808c999fSMiguel Ojeda     /// This type is a [syntax tree enum].
24808c999fSMiguel Ojeda     ///
25808c999fSMiguel Ojeda     /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums
26808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
27808c999fSMiguel Ojeda     #[non_exhaustive]
28808c999fSMiguel Ojeda     pub enum Pat {
29808c999fSMiguel Ojeda         /// A const block: `const { ... }`.
30808c999fSMiguel Ojeda         Const(PatConst),
31808c999fSMiguel Ojeda 
32808c999fSMiguel Ojeda         /// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`.
33808c999fSMiguel Ojeda         Ident(PatIdent),
34808c999fSMiguel Ojeda 
35808c999fSMiguel Ojeda         /// A literal pattern: `0`.
36808c999fSMiguel Ojeda         Lit(PatLit),
37808c999fSMiguel Ojeda 
38808c999fSMiguel Ojeda         /// A macro in pattern position.
39808c999fSMiguel Ojeda         Macro(PatMacro),
40808c999fSMiguel Ojeda 
41808c999fSMiguel Ojeda         /// A pattern that matches any one of a set of cases.
42808c999fSMiguel Ojeda         Or(PatOr),
43808c999fSMiguel Ojeda 
44808c999fSMiguel Ojeda         /// A parenthesized pattern: `(A | B)`.
45808c999fSMiguel Ojeda         Paren(PatParen),
46808c999fSMiguel Ojeda 
47808c999fSMiguel Ojeda         /// A path pattern like `Color::Red`, optionally qualified with a
48808c999fSMiguel Ojeda         /// self-type.
49808c999fSMiguel Ojeda         ///
50808c999fSMiguel Ojeda         /// Unqualified path patterns can legally refer to variants, structs,
51808c999fSMiguel Ojeda         /// constants or associated constants. Qualified path patterns like
52808c999fSMiguel Ojeda         /// `<A>::B::C` and `<A as Trait>::B::C` can only legally refer to
53808c999fSMiguel Ojeda         /// associated constants.
54808c999fSMiguel Ojeda         Path(PatPath),
55808c999fSMiguel Ojeda 
56808c999fSMiguel Ojeda         /// A range pattern: `1..=2`.
57808c999fSMiguel Ojeda         Range(PatRange),
58808c999fSMiguel Ojeda 
59808c999fSMiguel Ojeda         /// A reference pattern: `&mut var`.
60808c999fSMiguel Ojeda         Reference(PatReference),
61808c999fSMiguel Ojeda 
62808c999fSMiguel Ojeda         /// The dots in a tuple or slice pattern: `[0, 1, ..]`.
63808c999fSMiguel Ojeda         Rest(PatRest),
64808c999fSMiguel Ojeda 
65808c999fSMiguel Ojeda         /// A dynamically sized slice pattern: `[a, b, ref i @ .., y, z]`.
66808c999fSMiguel Ojeda         Slice(PatSlice),
67808c999fSMiguel Ojeda 
68808c999fSMiguel Ojeda         /// A struct or struct variant pattern: `Variant { x, y, .. }`.
69808c999fSMiguel Ojeda         Struct(PatStruct),
70808c999fSMiguel Ojeda 
71808c999fSMiguel Ojeda         /// A tuple pattern: `(a, b)`.
72808c999fSMiguel Ojeda         Tuple(PatTuple),
73808c999fSMiguel Ojeda 
74808c999fSMiguel Ojeda         /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`.
75808c999fSMiguel Ojeda         TupleStruct(PatTupleStruct),
76808c999fSMiguel Ojeda 
77808c999fSMiguel Ojeda         /// A type ascription pattern: `foo: f64`.
78808c999fSMiguel Ojeda         Type(PatType),
79808c999fSMiguel Ojeda 
80808c999fSMiguel Ojeda         /// Tokens in pattern position not interpreted by Syn.
81808c999fSMiguel Ojeda         Verbatim(TokenStream),
82808c999fSMiguel Ojeda 
83808c999fSMiguel Ojeda         /// A pattern that matches any value: `_`.
84808c999fSMiguel Ojeda         Wild(PatWild),
85808c999fSMiguel Ojeda 
86808c999fSMiguel Ojeda         // For testing exhaustiveness in downstream code, use the following idiom:
87808c999fSMiguel Ojeda         //
88808c999fSMiguel Ojeda         //     match pat {
89808c999fSMiguel Ojeda         //         #![cfg_attr(test, deny(non_exhaustive_omitted_patterns))]
90808c999fSMiguel Ojeda         //
91808c999fSMiguel Ojeda         //         Pat::Box(pat) => {...}
92808c999fSMiguel Ojeda         //         Pat::Ident(pat) => {...}
93808c999fSMiguel Ojeda         //         ...
94808c999fSMiguel Ojeda         //         Pat::Wild(pat) => {...}
95808c999fSMiguel Ojeda         //
96808c999fSMiguel Ojeda         //         _ => { /* some sane fallback */ }
97808c999fSMiguel Ojeda         //     }
98808c999fSMiguel Ojeda         //
99808c999fSMiguel Ojeda         // This way we fail your tests but don't break your library when adding
100808c999fSMiguel Ojeda         // a variant. You will be notified by a test failure when a variant is
101808c999fSMiguel Ojeda         // added, so that you can add code to handle it, but your library will
102808c999fSMiguel Ojeda         // continue to compile and work for downstream users in the interim.
103808c999fSMiguel Ojeda     }
104808c999fSMiguel Ojeda }
105808c999fSMiguel Ojeda 
106808c999fSMiguel Ojeda ast_struct! {
107808c999fSMiguel Ojeda     /// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`.
108808c999fSMiguel Ojeda     ///
109808c999fSMiguel Ojeda     /// It may also be a unit struct or struct variant (e.g. `None`), or a
110808c999fSMiguel Ojeda     /// constant; these cannot be distinguished syntactically.
111808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
112808c999fSMiguel Ojeda     pub struct PatIdent {
113808c999fSMiguel Ojeda         pub attrs: Vec<Attribute>,
114808c999fSMiguel Ojeda         pub by_ref: Option<Token![ref]>,
115808c999fSMiguel Ojeda         pub mutability: Option<Token![mut]>,
116808c999fSMiguel Ojeda         pub ident: Ident,
117808c999fSMiguel Ojeda         pub subpat: Option<(Token![@], Box<Pat>)>,
118808c999fSMiguel Ojeda     }
119808c999fSMiguel Ojeda }
120808c999fSMiguel Ojeda 
121808c999fSMiguel Ojeda ast_struct! {
122808c999fSMiguel Ojeda     /// A pattern that matches any one of a set of cases.
123808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
124808c999fSMiguel Ojeda     pub struct PatOr {
125808c999fSMiguel Ojeda         pub attrs: Vec<Attribute>,
126808c999fSMiguel Ojeda         pub leading_vert: Option<Token![|]>,
127808c999fSMiguel Ojeda         pub cases: Punctuated<Pat, Token![|]>,
128808c999fSMiguel Ojeda     }
129808c999fSMiguel Ojeda }
130808c999fSMiguel Ojeda 
131808c999fSMiguel Ojeda ast_struct! {
132808c999fSMiguel Ojeda     /// A parenthesized pattern: `(A | B)`.
133808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
134808c999fSMiguel Ojeda     pub struct PatParen {
135808c999fSMiguel Ojeda         pub attrs: Vec<Attribute>,
136808c999fSMiguel Ojeda         pub paren_token: token::Paren,
137808c999fSMiguel Ojeda         pub pat: Box<Pat>,
138808c999fSMiguel Ojeda     }
139808c999fSMiguel Ojeda }
140808c999fSMiguel Ojeda 
141808c999fSMiguel Ojeda ast_struct! {
142808c999fSMiguel Ojeda     /// A reference pattern: `&mut var`.
143808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
144808c999fSMiguel Ojeda     pub struct PatReference {
145808c999fSMiguel Ojeda         pub attrs: Vec<Attribute>,
146808c999fSMiguel Ojeda         pub and_token: Token![&],
147808c999fSMiguel Ojeda         pub mutability: Option<Token![mut]>,
148808c999fSMiguel Ojeda         pub pat: Box<Pat>,
149808c999fSMiguel Ojeda     }
150808c999fSMiguel Ojeda }
151808c999fSMiguel Ojeda 
152808c999fSMiguel Ojeda ast_struct! {
153808c999fSMiguel Ojeda     /// The dots in a tuple or slice pattern: `[0, 1, ..]`.
154808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
155808c999fSMiguel Ojeda     pub struct PatRest {
156808c999fSMiguel Ojeda         pub attrs: Vec<Attribute>,
157808c999fSMiguel Ojeda         pub dot2_token: Token![..],
158808c999fSMiguel Ojeda     }
159808c999fSMiguel Ojeda }
160808c999fSMiguel Ojeda 
161808c999fSMiguel Ojeda ast_struct! {
162808c999fSMiguel Ojeda     /// A dynamically sized slice pattern: `[a, b, ref i @ .., y, z]`.
163808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
164808c999fSMiguel Ojeda     pub struct PatSlice {
165808c999fSMiguel Ojeda         pub attrs: Vec<Attribute>,
166808c999fSMiguel Ojeda         pub bracket_token: token::Bracket,
167808c999fSMiguel Ojeda         pub elems: Punctuated<Pat, Token![,]>,
168808c999fSMiguel Ojeda     }
169808c999fSMiguel Ojeda }
170808c999fSMiguel Ojeda 
171808c999fSMiguel Ojeda ast_struct! {
172808c999fSMiguel Ojeda     /// A struct or struct variant pattern: `Variant { x, y, .. }`.
173808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
174808c999fSMiguel Ojeda     pub struct PatStruct {
175808c999fSMiguel Ojeda         pub attrs: Vec<Attribute>,
176808c999fSMiguel Ojeda         pub qself: Option<QSelf>,
177808c999fSMiguel Ojeda         pub path: Path,
178808c999fSMiguel Ojeda         pub brace_token: token::Brace,
179808c999fSMiguel Ojeda         pub fields: Punctuated<FieldPat, Token![,]>,
180808c999fSMiguel Ojeda         pub rest: Option<PatRest>,
181808c999fSMiguel Ojeda     }
182808c999fSMiguel Ojeda }
183808c999fSMiguel Ojeda 
184808c999fSMiguel Ojeda ast_struct! {
185808c999fSMiguel Ojeda     /// A tuple pattern: `(a, b)`.
186808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
187808c999fSMiguel Ojeda     pub struct PatTuple {
188808c999fSMiguel Ojeda         pub attrs: Vec<Attribute>,
189808c999fSMiguel Ojeda         pub paren_token: token::Paren,
190808c999fSMiguel Ojeda         pub elems: Punctuated<Pat, Token![,]>,
191808c999fSMiguel Ojeda     }
192808c999fSMiguel Ojeda }
193808c999fSMiguel Ojeda 
194808c999fSMiguel Ojeda ast_struct! {
195808c999fSMiguel Ojeda     /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`.
196808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
197808c999fSMiguel Ojeda     pub struct PatTupleStruct {
198808c999fSMiguel Ojeda         pub attrs: Vec<Attribute>,
199808c999fSMiguel Ojeda         pub qself: Option<QSelf>,
200808c999fSMiguel Ojeda         pub path: Path,
201808c999fSMiguel Ojeda         pub paren_token: token::Paren,
202808c999fSMiguel Ojeda         pub elems: Punctuated<Pat, Token![,]>,
203808c999fSMiguel Ojeda     }
204808c999fSMiguel Ojeda }
205808c999fSMiguel Ojeda 
206808c999fSMiguel Ojeda ast_struct! {
207808c999fSMiguel Ojeda     /// A type ascription pattern: `foo: f64`.
208808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
209808c999fSMiguel Ojeda     pub struct PatType {
210808c999fSMiguel Ojeda         pub attrs: Vec<Attribute>,
211808c999fSMiguel Ojeda         pub pat: Box<Pat>,
212808c999fSMiguel Ojeda         pub colon_token: Token![:],
213808c999fSMiguel Ojeda         pub ty: Box<Type>,
214808c999fSMiguel Ojeda     }
215808c999fSMiguel Ojeda }
216808c999fSMiguel Ojeda 
217808c999fSMiguel Ojeda ast_struct! {
218808c999fSMiguel Ojeda     /// A pattern that matches any value: `_`.
219808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
220808c999fSMiguel Ojeda     pub struct PatWild {
221808c999fSMiguel Ojeda         pub attrs: Vec<Attribute>,
222808c999fSMiguel Ojeda         pub underscore_token: Token![_],
223808c999fSMiguel Ojeda     }
224808c999fSMiguel Ojeda }
225808c999fSMiguel Ojeda 
226808c999fSMiguel Ojeda ast_struct! {
227808c999fSMiguel Ojeda     /// A single field in a struct pattern.
228808c999fSMiguel Ojeda     ///
229808c999fSMiguel Ojeda     /// Patterns like the fields of Foo `{ x, ref y, ref mut z }` are treated
230808c999fSMiguel Ojeda     /// the same as `x: x, y: ref y, z: ref mut z` but there is no colon token.
231808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
232808c999fSMiguel Ojeda     pub struct FieldPat {
233808c999fSMiguel Ojeda         pub attrs: Vec<Attribute>,
234808c999fSMiguel Ojeda         pub member: Member,
235808c999fSMiguel Ojeda         pub colon_token: Option<Token![:]>,
236808c999fSMiguel Ojeda         pub pat: Box<Pat>,
237808c999fSMiguel Ojeda     }
238808c999fSMiguel Ojeda }
239808c999fSMiguel Ojeda 
240808c999fSMiguel Ojeda #[cfg(feature = "parsing")]
241808c999fSMiguel Ojeda pub(crate) mod parsing {
242808c999fSMiguel Ojeda     use crate::attr::Attribute;
243808c999fSMiguel Ojeda     use crate::error::{self, Result};
244808c999fSMiguel Ojeda     use crate::expr::{
245808c999fSMiguel Ojeda         Expr, ExprConst, ExprLit, ExprMacro, ExprPath, ExprRange, Member, RangeLimits,
246808c999fSMiguel Ojeda     };
247808c999fSMiguel Ojeda     use crate::ext::IdentExt as _;
248808c999fSMiguel Ojeda     use crate::ident::Ident;
249808c999fSMiguel Ojeda     use crate::lit::Lit;
250808c999fSMiguel Ojeda     use crate::mac::{self, Macro};
251808c999fSMiguel Ojeda     use crate::parse::{Parse, ParseBuffer, ParseStream};
252808c999fSMiguel Ojeda     use crate::pat::{
253808c999fSMiguel Ojeda         FieldPat, Pat, PatIdent, PatOr, PatParen, PatReference, PatRest, PatSlice, PatStruct,
254808c999fSMiguel Ojeda         PatTuple, PatTupleStruct, PatType, PatWild,
255808c999fSMiguel Ojeda     };
256808c999fSMiguel Ojeda     use crate::path::{self, Path, QSelf};
257808c999fSMiguel Ojeda     use crate::punctuated::Punctuated;
258808c999fSMiguel Ojeda     use crate::stmt::Block;
259808c999fSMiguel Ojeda     use crate::token;
260808c999fSMiguel Ojeda     use crate::verbatim;
261808c999fSMiguel Ojeda     use proc_macro2::TokenStream;
262808c999fSMiguel Ojeda 
263808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
264808c999fSMiguel Ojeda     impl Pat {
265808c999fSMiguel Ojeda         /// Parse a pattern that does _not_ involve `|` at the top level.
266808c999fSMiguel Ojeda         ///
267808c999fSMiguel Ojeda         /// This parser matches the behavior of the `$:pat_param` macro_rules
268808c999fSMiguel Ojeda         /// matcher, and on editions prior to Rust 2021, the behavior of
269808c999fSMiguel Ojeda         /// `$:pat`.
270808c999fSMiguel Ojeda         ///
271808c999fSMiguel Ojeda         /// In Rust syntax, some examples of where this syntax would occur are
272808c999fSMiguel Ojeda         /// in the argument pattern of functions and closures. Patterns using
273808c999fSMiguel Ojeda         /// `|` are not allowed to occur in these positions.
274808c999fSMiguel Ojeda         ///
275808c999fSMiguel Ojeda         /// ```compile_fail
276808c999fSMiguel Ojeda         /// fn f(Some(_) | None: Option<T>) {
277808c999fSMiguel Ojeda         ///     let _ = |Some(_) | None: Option<T>| {};
278808c999fSMiguel Ojeda         ///     //       ^^^^^^^^^^^^^^^^^^^^^^^^^??? :(
279808c999fSMiguel Ojeda         /// }
280808c999fSMiguel Ojeda         /// ```
281808c999fSMiguel Ojeda         ///
282808c999fSMiguel Ojeda         /// ```console
283808c999fSMiguel Ojeda         /// error: top-level or-patterns are not allowed in function parameters
284808c999fSMiguel Ojeda         ///  --> src/main.rs:1:6
285808c999fSMiguel Ojeda         ///   |
286808c999fSMiguel Ojeda         /// 1 | fn f(Some(_) | None: Option<T>) {
287808c999fSMiguel Ojeda         ///   |      ^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(Some(_) | None)`
288808c999fSMiguel Ojeda         /// ```
parse_single(input: ParseStream) -> Result<Self>289808c999fSMiguel Ojeda         pub fn parse_single(input: ParseStream) -> Result<Self> {
290808c999fSMiguel Ojeda             let begin = input.fork();
291808c999fSMiguel Ojeda             let lookahead = input.lookahead1();
292808c999fSMiguel Ojeda             if lookahead.peek(Ident)
293808c999fSMiguel Ojeda                 && (input.peek2(Token![::])
294808c999fSMiguel Ojeda                     || input.peek2(Token![!])
295808c999fSMiguel Ojeda                     || input.peek2(token::Brace)
296808c999fSMiguel Ojeda                     || input.peek2(token::Paren)
297808c999fSMiguel Ojeda                     || input.peek2(Token![..]))
298808c999fSMiguel Ojeda                 || input.peek(Token![self]) && input.peek2(Token![::])
299808c999fSMiguel Ojeda                 || lookahead.peek(Token![::])
300808c999fSMiguel Ojeda                 || lookahead.peek(Token![<])
301808c999fSMiguel Ojeda                 || input.peek(Token![Self])
302808c999fSMiguel Ojeda                 || input.peek(Token![super])
303808c999fSMiguel Ojeda                 || input.peek(Token![crate])
304808c999fSMiguel Ojeda             {
305808c999fSMiguel Ojeda                 pat_path_or_macro_or_struct_or_range(input)
306808c999fSMiguel Ojeda             } else if lookahead.peek(Token![_]) {
307808c999fSMiguel Ojeda                 input.call(pat_wild).map(Pat::Wild)
308808c999fSMiguel Ojeda             } else if input.peek(Token![box]) {
309808c999fSMiguel Ojeda                 pat_box(begin, input)
310808c999fSMiguel Ojeda             } else if input.peek(Token![-]) || lookahead.peek(Lit) || lookahead.peek(Token![const])
311808c999fSMiguel Ojeda             {
312808c999fSMiguel Ojeda                 pat_lit_or_range(input)
313808c999fSMiguel Ojeda             } else if lookahead.peek(Token![ref])
314808c999fSMiguel Ojeda                 || lookahead.peek(Token![mut])
315808c999fSMiguel Ojeda                 || input.peek(Token![self])
316808c999fSMiguel Ojeda                 || input.peek(Ident)
317808c999fSMiguel Ojeda             {
318808c999fSMiguel Ojeda                 input.call(pat_ident).map(Pat::Ident)
319808c999fSMiguel Ojeda             } else if lookahead.peek(Token![&]) {
320808c999fSMiguel Ojeda                 input.call(pat_reference).map(Pat::Reference)
321808c999fSMiguel Ojeda             } else if lookahead.peek(token::Paren) {
322808c999fSMiguel Ojeda                 input.call(pat_paren_or_tuple)
323808c999fSMiguel Ojeda             } else if lookahead.peek(token::Bracket) {
324808c999fSMiguel Ojeda                 input.call(pat_slice).map(Pat::Slice)
325808c999fSMiguel Ojeda             } else if lookahead.peek(Token![..]) && !input.peek(Token![...]) {
326808c999fSMiguel Ojeda                 pat_range_half_open(input)
327808c999fSMiguel Ojeda             } else if lookahead.peek(Token![const]) {
328808c999fSMiguel Ojeda                 input.call(pat_const).map(Pat::Verbatim)
329808c999fSMiguel Ojeda             } else {
330808c999fSMiguel Ojeda                 Err(lookahead.error())
331808c999fSMiguel Ojeda             }
332808c999fSMiguel Ojeda         }
333808c999fSMiguel Ojeda 
334808c999fSMiguel Ojeda         /// Parse a pattern, possibly involving `|`, but not a leading `|`.
parse_multi(input: ParseStream) -> Result<Self>335808c999fSMiguel Ojeda         pub fn parse_multi(input: ParseStream) -> Result<Self> {
336808c999fSMiguel Ojeda             multi_pat_impl(input, None)
337808c999fSMiguel Ojeda         }
338808c999fSMiguel Ojeda 
339808c999fSMiguel Ojeda         /// Parse a pattern, possibly involving `|`, possibly including a
340808c999fSMiguel Ojeda         /// leading `|`.
341808c999fSMiguel Ojeda         ///
342808c999fSMiguel Ojeda         /// This parser matches the behavior of the Rust 2021 edition's `$:pat`
343808c999fSMiguel Ojeda         /// macro_rules matcher.
344808c999fSMiguel Ojeda         ///
345808c999fSMiguel Ojeda         /// In Rust syntax, an example of where this syntax would occur is in
346808c999fSMiguel Ojeda         /// the pattern of a `match` arm, where the language permits an optional
347808c999fSMiguel Ojeda         /// leading `|`, although it is not idiomatic to write one there in
348808c999fSMiguel Ojeda         /// handwritten code.
349808c999fSMiguel Ojeda         ///
350808c999fSMiguel Ojeda         /// ```
351808c999fSMiguel Ojeda         /// # let wat = None;
352808c999fSMiguel Ojeda         /// match wat {
353808c999fSMiguel Ojeda         ///     | None | Some(false) => {}
354808c999fSMiguel Ojeda         ///     | Some(true) => {}
355808c999fSMiguel Ojeda         /// }
356808c999fSMiguel Ojeda         /// ```
357808c999fSMiguel Ojeda         ///
358808c999fSMiguel Ojeda         /// The compiler accepts it only to facilitate some situations in
359808c999fSMiguel Ojeda         /// macro-generated code where a macro author might need to write:
360808c999fSMiguel Ojeda         ///
361808c999fSMiguel Ojeda         /// ```
362808c999fSMiguel Ojeda         /// # macro_rules! doc {
363808c999fSMiguel Ojeda         /// #     ($value:expr, ($($conditions1:pat),*), ($($conditions2:pat),*), $then:expr) => {
364808c999fSMiguel Ojeda         /// match $value {
365808c999fSMiguel Ojeda         ///     $(| $conditions1)* $(| $conditions2)* => $then
366808c999fSMiguel Ojeda         /// }
367808c999fSMiguel Ojeda         /// #     };
368808c999fSMiguel Ojeda         /// # }
369808c999fSMiguel Ojeda         /// #
370808c999fSMiguel Ojeda         /// # doc!(true, (true), (false), {});
371808c999fSMiguel Ojeda         /// # doc!(true, (), (true, false), {});
372808c999fSMiguel Ojeda         /// # doc!(true, (true, false), (), {});
373808c999fSMiguel Ojeda         /// ```
374808c999fSMiguel Ojeda         ///
375808c999fSMiguel Ojeda         /// Expressing the same thing correctly in the case that either one (but
376808c999fSMiguel Ojeda         /// not both) of `$conditions1` and `$conditions2` might be empty,
377808c999fSMiguel Ojeda         /// without leading `|`, is complex.
378808c999fSMiguel Ojeda         ///
379808c999fSMiguel Ojeda         /// Use [`Pat::parse_multi`] instead if you are not intending to support
380808c999fSMiguel Ojeda         /// macro-generated macro input.
parse_multi_with_leading_vert(input: ParseStream) -> Result<Self>381808c999fSMiguel Ojeda         pub fn parse_multi_with_leading_vert(input: ParseStream) -> Result<Self> {
382808c999fSMiguel Ojeda             let leading_vert: Option<Token![|]> = input.parse()?;
383808c999fSMiguel Ojeda             multi_pat_impl(input, leading_vert)
384808c999fSMiguel Ojeda         }
385808c999fSMiguel Ojeda     }
386808c999fSMiguel Ojeda 
387808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
388808c999fSMiguel Ojeda     impl Parse for PatType {
parse(input: ParseStream) -> Result<Self>389808c999fSMiguel Ojeda         fn parse(input: ParseStream) -> Result<Self> {
390808c999fSMiguel Ojeda             Ok(PatType {
391808c999fSMiguel Ojeda                 attrs: Vec::new(),
392808c999fSMiguel Ojeda                 pat: Box::new(Pat::parse_single(input)?),
393808c999fSMiguel Ojeda                 colon_token: input.parse()?,
394808c999fSMiguel Ojeda                 ty: input.parse()?,
395808c999fSMiguel Ojeda             })
396808c999fSMiguel Ojeda         }
397808c999fSMiguel Ojeda     }
398808c999fSMiguel Ojeda 
multi_pat_impl(input: ParseStream, leading_vert: Option<Token![|]>) -> Result<Pat>399808c999fSMiguel Ojeda     fn multi_pat_impl(input: ParseStream, leading_vert: Option<Token![|]>) -> Result<Pat> {
400808c999fSMiguel Ojeda         let mut pat = Pat::parse_single(input)?;
401808c999fSMiguel Ojeda         if leading_vert.is_some()
402808c999fSMiguel Ojeda             || input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=])
403808c999fSMiguel Ojeda         {
404808c999fSMiguel Ojeda             let mut cases = Punctuated::new();
405808c999fSMiguel Ojeda             cases.push_value(pat);
406808c999fSMiguel Ojeda             while input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=]) {
407808c999fSMiguel Ojeda                 let punct = input.parse()?;
408808c999fSMiguel Ojeda                 cases.push_punct(punct);
409808c999fSMiguel Ojeda                 let pat = Pat::parse_single(input)?;
410808c999fSMiguel Ojeda                 cases.push_value(pat);
411808c999fSMiguel Ojeda             }
412808c999fSMiguel Ojeda             pat = Pat::Or(PatOr {
413808c999fSMiguel Ojeda                 attrs: Vec::new(),
414808c999fSMiguel Ojeda                 leading_vert,
415808c999fSMiguel Ojeda                 cases,
416808c999fSMiguel Ojeda             });
417808c999fSMiguel Ojeda         }
418808c999fSMiguel Ojeda         Ok(pat)
419808c999fSMiguel Ojeda     }
420808c999fSMiguel Ojeda 
pat_path_or_macro_or_struct_or_range(input: ParseStream) -> Result<Pat>421808c999fSMiguel Ojeda     fn pat_path_or_macro_or_struct_or_range(input: ParseStream) -> Result<Pat> {
422808c999fSMiguel Ojeda         let expr_style = true;
423808c999fSMiguel Ojeda         let (qself, path) = path::parsing::qpath(input, expr_style)?;
424808c999fSMiguel Ojeda 
425808c999fSMiguel Ojeda         if qself.is_none()
426808c999fSMiguel Ojeda             && input.peek(Token![!])
427808c999fSMiguel Ojeda             && !input.peek(Token![!=])
428808c999fSMiguel Ojeda             && path.is_mod_style()
429808c999fSMiguel Ojeda         {
430808c999fSMiguel Ojeda             let bang_token: Token![!] = input.parse()?;
431808c999fSMiguel Ojeda             let (delimiter, tokens) = mac::parse_delimiter(input)?;
432808c999fSMiguel Ojeda             return Ok(Pat::Macro(ExprMacro {
433808c999fSMiguel Ojeda                 attrs: Vec::new(),
434808c999fSMiguel Ojeda                 mac: Macro {
435808c999fSMiguel Ojeda                     path,
436808c999fSMiguel Ojeda                     bang_token,
437808c999fSMiguel Ojeda                     delimiter,
438808c999fSMiguel Ojeda                     tokens,
439808c999fSMiguel Ojeda                 },
440808c999fSMiguel Ojeda             }));
441808c999fSMiguel Ojeda         }
442808c999fSMiguel Ojeda 
443808c999fSMiguel Ojeda         if input.peek(token::Brace) {
444808c999fSMiguel Ojeda             pat_struct(input, qself, path).map(Pat::Struct)
445808c999fSMiguel Ojeda         } else if input.peek(token::Paren) {
446808c999fSMiguel Ojeda             pat_tuple_struct(input, qself, path).map(Pat::TupleStruct)
447808c999fSMiguel Ojeda         } else if input.peek(Token![..]) {
448808c999fSMiguel Ojeda             pat_range(input, qself, path)
449808c999fSMiguel Ojeda         } else {
450808c999fSMiguel Ojeda             Ok(Pat::Path(ExprPath {
451808c999fSMiguel Ojeda                 attrs: Vec::new(),
452808c999fSMiguel Ojeda                 qself,
453808c999fSMiguel Ojeda                 path,
454808c999fSMiguel Ojeda             }))
455808c999fSMiguel Ojeda         }
456808c999fSMiguel Ojeda     }
457808c999fSMiguel Ojeda 
pat_wild(input: ParseStream) -> Result<PatWild>458808c999fSMiguel Ojeda     fn pat_wild(input: ParseStream) -> Result<PatWild> {
459808c999fSMiguel Ojeda         Ok(PatWild {
460808c999fSMiguel Ojeda             attrs: Vec::new(),
461808c999fSMiguel Ojeda             underscore_token: input.parse()?,
462808c999fSMiguel Ojeda         })
463808c999fSMiguel Ojeda     }
464808c999fSMiguel Ojeda 
pat_box(begin: ParseBuffer, input: ParseStream) -> Result<Pat>465808c999fSMiguel Ojeda     fn pat_box(begin: ParseBuffer, input: ParseStream) -> Result<Pat> {
466808c999fSMiguel Ojeda         input.parse::<Token![box]>()?;
467808c999fSMiguel Ojeda         Pat::parse_single(input)?;
468808c999fSMiguel Ojeda         Ok(Pat::Verbatim(verbatim::between(&begin, input)))
469808c999fSMiguel Ojeda     }
470808c999fSMiguel Ojeda 
pat_ident(input: ParseStream) -> Result<PatIdent>471808c999fSMiguel Ojeda     fn pat_ident(input: ParseStream) -> Result<PatIdent> {
472808c999fSMiguel Ojeda         Ok(PatIdent {
473808c999fSMiguel Ojeda             attrs: Vec::new(),
474808c999fSMiguel Ojeda             by_ref: input.parse()?,
475808c999fSMiguel Ojeda             mutability: input.parse()?,
476808c999fSMiguel Ojeda             ident: {
477808c999fSMiguel Ojeda                 if input.peek(Token![self]) {
478808c999fSMiguel Ojeda                     input.call(Ident::parse_any)?
479808c999fSMiguel Ojeda                 } else {
480808c999fSMiguel Ojeda                     input.parse()?
481808c999fSMiguel Ojeda                 }
482808c999fSMiguel Ojeda             },
483808c999fSMiguel Ojeda             subpat: {
484808c999fSMiguel Ojeda                 if input.peek(Token![@]) {
485808c999fSMiguel Ojeda                     let at_token: Token![@] = input.parse()?;
486808c999fSMiguel Ojeda                     let subpat = Pat::parse_single(input)?;
487808c999fSMiguel Ojeda                     Some((at_token, Box::new(subpat)))
488808c999fSMiguel Ojeda                 } else {
489808c999fSMiguel Ojeda                     None
490808c999fSMiguel Ojeda                 }
491808c999fSMiguel Ojeda             },
492808c999fSMiguel Ojeda         })
493808c999fSMiguel Ojeda     }
494808c999fSMiguel Ojeda 
pat_tuple_struct( input: ParseStream, qself: Option<QSelf>, path: Path, ) -> Result<PatTupleStruct>495808c999fSMiguel Ojeda     fn pat_tuple_struct(
496808c999fSMiguel Ojeda         input: ParseStream,
497808c999fSMiguel Ojeda         qself: Option<QSelf>,
498808c999fSMiguel Ojeda         path: Path,
499808c999fSMiguel Ojeda     ) -> Result<PatTupleStruct> {
500808c999fSMiguel Ojeda         let content;
501808c999fSMiguel Ojeda         let paren_token = parenthesized!(content in input);
502808c999fSMiguel Ojeda 
503808c999fSMiguel Ojeda         let mut elems = Punctuated::new();
504808c999fSMiguel Ojeda         while !content.is_empty() {
505808c999fSMiguel Ojeda             let value = Pat::parse_multi_with_leading_vert(&content)?;
506808c999fSMiguel Ojeda             elems.push_value(value);
507808c999fSMiguel Ojeda             if content.is_empty() {
508808c999fSMiguel Ojeda                 break;
509808c999fSMiguel Ojeda             }
510808c999fSMiguel Ojeda             let punct = content.parse()?;
511808c999fSMiguel Ojeda             elems.push_punct(punct);
512808c999fSMiguel Ojeda         }
513808c999fSMiguel Ojeda 
514808c999fSMiguel Ojeda         Ok(PatTupleStruct {
515808c999fSMiguel Ojeda             attrs: Vec::new(),
516808c999fSMiguel Ojeda             qself,
517808c999fSMiguel Ojeda             path,
518808c999fSMiguel Ojeda             paren_token,
519808c999fSMiguel Ojeda             elems,
520808c999fSMiguel Ojeda         })
521808c999fSMiguel Ojeda     }
522808c999fSMiguel Ojeda 
pat_struct(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<PatStruct>523808c999fSMiguel Ojeda     fn pat_struct(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<PatStruct> {
524808c999fSMiguel Ojeda         let content;
525808c999fSMiguel Ojeda         let brace_token = braced!(content in input);
526808c999fSMiguel Ojeda 
527808c999fSMiguel Ojeda         let mut fields = Punctuated::new();
528808c999fSMiguel Ojeda         let mut rest = None;
529808c999fSMiguel Ojeda         while !content.is_empty() {
530808c999fSMiguel Ojeda             let attrs = content.call(Attribute::parse_outer)?;
531808c999fSMiguel Ojeda             if content.peek(Token![..]) {
532808c999fSMiguel Ojeda                 rest = Some(PatRest {
533808c999fSMiguel Ojeda                     attrs,
534808c999fSMiguel Ojeda                     dot2_token: content.parse()?,
535808c999fSMiguel Ojeda                 });
536808c999fSMiguel Ojeda                 break;
537808c999fSMiguel Ojeda             }
538808c999fSMiguel Ojeda             let mut value = content.call(field_pat)?;
539808c999fSMiguel Ojeda             value.attrs = attrs;
540808c999fSMiguel Ojeda             fields.push_value(value);
541808c999fSMiguel Ojeda             if content.is_empty() {
542808c999fSMiguel Ojeda                 break;
543808c999fSMiguel Ojeda             }
544808c999fSMiguel Ojeda             let punct: Token![,] = content.parse()?;
545808c999fSMiguel Ojeda             fields.push_punct(punct);
546808c999fSMiguel Ojeda         }
547808c999fSMiguel Ojeda 
548808c999fSMiguel Ojeda         Ok(PatStruct {
549808c999fSMiguel Ojeda             attrs: Vec::new(),
550808c999fSMiguel Ojeda             qself,
551808c999fSMiguel Ojeda             path,
552808c999fSMiguel Ojeda             brace_token,
553808c999fSMiguel Ojeda             fields,
554808c999fSMiguel Ojeda             rest,
555808c999fSMiguel Ojeda         })
556808c999fSMiguel Ojeda     }
557808c999fSMiguel Ojeda 
field_pat(input: ParseStream) -> Result<FieldPat>558808c999fSMiguel Ojeda     fn field_pat(input: ParseStream) -> Result<FieldPat> {
559808c999fSMiguel Ojeda         let begin = input.fork();
560808c999fSMiguel Ojeda         let boxed: Option<Token![box]> = input.parse()?;
561808c999fSMiguel Ojeda         let by_ref: Option<Token![ref]> = input.parse()?;
562808c999fSMiguel Ojeda         let mutability: Option<Token![mut]> = input.parse()?;
563808c999fSMiguel Ojeda 
564808c999fSMiguel Ojeda         let member = if boxed.is_some() || by_ref.is_some() || mutability.is_some() {
565808c999fSMiguel Ojeda             input.parse().map(Member::Named)
566808c999fSMiguel Ojeda         } else {
567808c999fSMiguel Ojeda             input.parse()
568808c999fSMiguel Ojeda         }?;
569808c999fSMiguel Ojeda 
570808c999fSMiguel Ojeda         if boxed.is_none() && by_ref.is_none() && mutability.is_none() && input.peek(Token![:])
571808c999fSMiguel Ojeda             || !member.is_named()
572808c999fSMiguel Ojeda         {
573808c999fSMiguel Ojeda             return Ok(FieldPat {
574808c999fSMiguel Ojeda                 attrs: Vec::new(),
575808c999fSMiguel Ojeda                 member,
576808c999fSMiguel Ojeda                 colon_token: Some(input.parse()?),
577808c999fSMiguel Ojeda                 pat: Box::new(Pat::parse_multi_with_leading_vert(input)?),
578808c999fSMiguel Ojeda             });
579808c999fSMiguel Ojeda         }
580808c999fSMiguel Ojeda 
581808c999fSMiguel Ojeda         let ident = match member {
582808c999fSMiguel Ojeda             Member::Named(ident) => ident,
583808c999fSMiguel Ojeda             Member::Unnamed(_) => unreachable!(),
584808c999fSMiguel Ojeda         };
585808c999fSMiguel Ojeda 
586808c999fSMiguel Ojeda         let pat = if boxed.is_some() {
587808c999fSMiguel Ojeda             Pat::Verbatim(verbatim::between(&begin, input))
588808c999fSMiguel Ojeda         } else {
589808c999fSMiguel Ojeda             Pat::Ident(PatIdent {
590808c999fSMiguel Ojeda                 attrs: Vec::new(),
591808c999fSMiguel Ojeda                 by_ref,
592808c999fSMiguel Ojeda                 mutability,
593808c999fSMiguel Ojeda                 ident: ident.clone(),
594808c999fSMiguel Ojeda                 subpat: None,
595808c999fSMiguel Ojeda             })
596808c999fSMiguel Ojeda         };
597808c999fSMiguel Ojeda 
598808c999fSMiguel Ojeda         Ok(FieldPat {
599808c999fSMiguel Ojeda             attrs: Vec::new(),
600808c999fSMiguel Ojeda             member: Member::Named(ident),
601808c999fSMiguel Ojeda             colon_token: None,
602808c999fSMiguel Ojeda             pat: Box::new(pat),
603808c999fSMiguel Ojeda         })
604808c999fSMiguel Ojeda     }
605808c999fSMiguel Ojeda 
pat_range(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<Pat>606808c999fSMiguel Ojeda     fn pat_range(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<Pat> {
607808c999fSMiguel Ojeda         let limits = RangeLimits::parse_obsolete(input)?;
608808c999fSMiguel Ojeda         let end = input.call(pat_range_bound)?;
609808c999fSMiguel Ojeda         if let (RangeLimits::Closed(_), None) = (&limits, &end) {
610808c999fSMiguel Ojeda             return Err(input.error("expected range upper bound"));
611808c999fSMiguel Ojeda         }
612808c999fSMiguel Ojeda         Ok(Pat::Range(ExprRange {
613808c999fSMiguel Ojeda             attrs: Vec::new(),
614808c999fSMiguel Ojeda             start: Some(Box::new(Expr::Path(ExprPath {
615808c999fSMiguel Ojeda                 attrs: Vec::new(),
616808c999fSMiguel Ojeda                 qself,
617808c999fSMiguel Ojeda                 path,
618808c999fSMiguel Ojeda             }))),
619808c999fSMiguel Ojeda             limits,
620808c999fSMiguel Ojeda             end: end.map(PatRangeBound::into_expr),
621808c999fSMiguel Ojeda         }))
622808c999fSMiguel Ojeda     }
623808c999fSMiguel Ojeda 
pat_range_half_open(input: ParseStream) -> Result<Pat>624808c999fSMiguel Ojeda     fn pat_range_half_open(input: ParseStream) -> Result<Pat> {
625808c999fSMiguel Ojeda         let limits: RangeLimits = input.parse()?;
626808c999fSMiguel Ojeda         let end = input.call(pat_range_bound)?;
627808c999fSMiguel Ojeda         if end.is_some() {
628808c999fSMiguel Ojeda             Ok(Pat::Range(ExprRange {
629808c999fSMiguel Ojeda                 attrs: Vec::new(),
630808c999fSMiguel Ojeda                 start: None,
631808c999fSMiguel Ojeda                 limits,
632808c999fSMiguel Ojeda                 end: end.map(PatRangeBound::into_expr),
633808c999fSMiguel Ojeda             }))
634808c999fSMiguel Ojeda         } else {
635808c999fSMiguel Ojeda             match limits {
636808c999fSMiguel Ojeda                 RangeLimits::HalfOpen(dot2_token) => Ok(Pat::Rest(PatRest {
637808c999fSMiguel Ojeda                     attrs: Vec::new(),
638808c999fSMiguel Ojeda                     dot2_token,
639808c999fSMiguel Ojeda                 })),
640808c999fSMiguel Ojeda                 RangeLimits::Closed(_) => Err(input.error("expected range upper bound")),
641808c999fSMiguel Ojeda             }
642808c999fSMiguel Ojeda         }
643808c999fSMiguel Ojeda     }
644808c999fSMiguel Ojeda 
pat_paren_or_tuple(input: ParseStream) -> Result<Pat>645808c999fSMiguel Ojeda     fn pat_paren_or_tuple(input: ParseStream) -> Result<Pat> {
646808c999fSMiguel Ojeda         let content;
647808c999fSMiguel Ojeda         let paren_token = parenthesized!(content in input);
648808c999fSMiguel Ojeda 
649808c999fSMiguel Ojeda         let mut elems = Punctuated::new();
650808c999fSMiguel Ojeda         while !content.is_empty() {
651808c999fSMiguel Ojeda             let value = Pat::parse_multi_with_leading_vert(&content)?;
652808c999fSMiguel Ojeda             if content.is_empty() {
653808c999fSMiguel Ojeda                 if elems.is_empty() && !matches!(value, Pat::Rest(_)) {
654808c999fSMiguel Ojeda                     return Ok(Pat::Paren(PatParen {
655808c999fSMiguel Ojeda                         attrs: Vec::new(),
656808c999fSMiguel Ojeda                         paren_token,
657808c999fSMiguel Ojeda                         pat: Box::new(value),
658808c999fSMiguel Ojeda                     }));
659808c999fSMiguel Ojeda                 }
660808c999fSMiguel Ojeda                 elems.push_value(value);
661808c999fSMiguel Ojeda                 break;
662808c999fSMiguel Ojeda             }
663808c999fSMiguel Ojeda             elems.push_value(value);
664808c999fSMiguel Ojeda             let punct = content.parse()?;
665808c999fSMiguel Ojeda             elems.push_punct(punct);
666808c999fSMiguel Ojeda         }
667808c999fSMiguel Ojeda 
668808c999fSMiguel Ojeda         Ok(Pat::Tuple(PatTuple {
669808c999fSMiguel Ojeda             attrs: Vec::new(),
670808c999fSMiguel Ojeda             paren_token,
671808c999fSMiguel Ojeda             elems,
672808c999fSMiguel Ojeda         }))
673808c999fSMiguel Ojeda     }
674808c999fSMiguel Ojeda 
pat_reference(input: ParseStream) -> Result<PatReference>675808c999fSMiguel Ojeda     fn pat_reference(input: ParseStream) -> Result<PatReference> {
676808c999fSMiguel Ojeda         Ok(PatReference {
677808c999fSMiguel Ojeda             attrs: Vec::new(),
678808c999fSMiguel Ojeda             and_token: input.parse()?,
679808c999fSMiguel Ojeda             mutability: input.parse()?,
680808c999fSMiguel Ojeda             pat: Box::new(Pat::parse_single(input)?),
681808c999fSMiguel Ojeda         })
682808c999fSMiguel Ojeda     }
683808c999fSMiguel Ojeda 
pat_lit_or_range(input: ParseStream) -> Result<Pat>684808c999fSMiguel Ojeda     fn pat_lit_or_range(input: ParseStream) -> Result<Pat> {
685808c999fSMiguel Ojeda         let start = input.call(pat_range_bound)?.unwrap();
686808c999fSMiguel Ojeda         if input.peek(Token![..]) {
687808c999fSMiguel Ojeda             let limits = RangeLimits::parse_obsolete(input)?;
688808c999fSMiguel Ojeda             let end = input.call(pat_range_bound)?;
689808c999fSMiguel Ojeda             if let (RangeLimits::Closed(_), None) = (&limits, &end) {
690808c999fSMiguel Ojeda                 return Err(input.error("expected range upper bound"));
691808c999fSMiguel Ojeda             }
692808c999fSMiguel Ojeda             Ok(Pat::Range(ExprRange {
693808c999fSMiguel Ojeda                 attrs: Vec::new(),
694808c999fSMiguel Ojeda                 start: Some(start.into_expr()),
695808c999fSMiguel Ojeda                 limits,
696808c999fSMiguel Ojeda                 end: end.map(PatRangeBound::into_expr),
697808c999fSMiguel Ojeda             }))
698808c999fSMiguel Ojeda         } else {
699808c999fSMiguel Ojeda             Ok(start.into_pat())
700808c999fSMiguel Ojeda         }
701808c999fSMiguel Ojeda     }
702808c999fSMiguel Ojeda 
703808c999fSMiguel Ojeda     // Patterns that can appear on either side of a range pattern.
704808c999fSMiguel Ojeda     enum PatRangeBound {
705808c999fSMiguel Ojeda         Const(ExprConst),
706808c999fSMiguel Ojeda         Lit(ExprLit),
707808c999fSMiguel Ojeda         Path(ExprPath),
708808c999fSMiguel Ojeda     }
709808c999fSMiguel Ojeda 
710808c999fSMiguel Ojeda     impl PatRangeBound {
into_expr(self) -> Box<Expr>711808c999fSMiguel Ojeda         fn into_expr(self) -> Box<Expr> {
712808c999fSMiguel Ojeda             Box::new(match self {
713808c999fSMiguel Ojeda                 PatRangeBound::Const(pat) => Expr::Const(pat),
714808c999fSMiguel Ojeda                 PatRangeBound::Lit(pat) => Expr::Lit(pat),
715808c999fSMiguel Ojeda                 PatRangeBound::Path(pat) => Expr::Path(pat),
716808c999fSMiguel Ojeda             })
717808c999fSMiguel Ojeda         }
718808c999fSMiguel Ojeda 
into_pat(self) -> Pat719808c999fSMiguel Ojeda         fn into_pat(self) -> Pat {
720808c999fSMiguel Ojeda             match self {
721808c999fSMiguel Ojeda                 PatRangeBound::Const(pat) => Pat::Const(pat),
722808c999fSMiguel Ojeda                 PatRangeBound::Lit(pat) => Pat::Lit(pat),
723808c999fSMiguel Ojeda                 PatRangeBound::Path(pat) => Pat::Path(pat),
724808c999fSMiguel Ojeda             }
725808c999fSMiguel Ojeda         }
726808c999fSMiguel Ojeda     }
727808c999fSMiguel Ojeda 
pat_range_bound(input: ParseStream) -> Result<Option<PatRangeBound>>728808c999fSMiguel Ojeda     fn pat_range_bound(input: ParseStream) -> Result<Option<PatRangeBound>> {
729808c999fSMiguel Ojeda         if input.is_empty()
730808c999fSMiguel Ojeda             || input.peek(Token![|])
731808c999fSMiguel Ojeda             || input.peek(Token![=])
732808c999fSMiguel Ojeda             || input.peek(Token![:]) && !input.peek(Token![::])
733808c999fSMiguel Ojeda             || input.peek(Token![,])
734808c999fSMiguel Ojeda             || input.peek(Token![;])
735808c999fSMiguel Ojeda             || input.peek(Token![if])
736808c999fSMiguel Ojeda         {
737808c999fSMiguel Ojeda             return Ok(None);
738808c999fSMiguel Ojeda         }
739808c999fSMiguel Ojeda 
740808c999fSMiguel Ojeda         let lookahead = input.lookahead1();
741808c999fSMiguel Ojeda         let expr = if lookahead.peek(Lit) {
742808c999fSMiguel Ojeda             PatRangeBound::Lit(input.parse()?)
743808c999fSMiguel Ojeda         } else if lookahead.peek(Ident)
744808c999fSMiguel Ojeda             || lookahead.peek(Token![::])
745808c999fSMiguel Ojeda             || lookahead.peek(Token![<])
746808c999fSMiguel Ojeda             || lookahead.peek(Token![self])
747808c999fSMiguel Ojeda             || lookahead.peek(Token![Self])
748808c999fSMiguel Ojeda             || lookahead.peek(Token![super])
749808c999fSMiguel Ojeda             || lookahead.peek(Token![crate])
750808c999fSMiguel Ojeda         {
751808c999fSMiguel Ojeda             PatRangeBound::Path(input.parse()?)
752808c999fSMiguel Ojeda         } else if lookahead.peek(Token![const]) {
753808c999fSMiguel Ojeda             PatRangeBound::Const(input.parse()?)
754808c999fSMiguel Ojeda         } else {
755808c999fSMiguel Ojeda             return Err(lookahead.error());
756808c999fSMiguel Ojeda         };
757808c999fSMiguel Ojeda 
758808c999fSMiguel Ojeda         Ok(Some(expr))
759808c999fSMiguel Ojeda     }
760808c999fSMiguel Ojeda 
pat_slice(input: ParseStream) -> Result<PatSlice>761808c999fSMiguel Ojeda     fn pat_slice(input: ParseStream) -> Result<PatSlice> {
762808c999fSMiguel Ojeda         let content;
763808c999fSMiguel Ojeda         let bracket_token = bracketed!(content in input);
764808c999fSMiguel Ojeda 
765808c999fSMiguel Ojeda         let mut elems = Punctuated::new();
766808c999fSMiguel Ojeda         while !content.is_empty() {
767808c999fSMiguel Ojeda             let value = Pat::parse_multi_with_leading_vert(&content)?;
768808c999fSMiguel Ojeda             match value {
769808c999fSMiguel Ojeda                 Pat::Range(pat) if pat.start.is_none() || pat.end.is_none() => {
770808c999fSMiguel Ojeda                     let (start, end) = match pat.limits {
771808c999fSMiguel Ojeda                         RangeLimits::HalfOpen(dot_dot) => (dot_dot.spans[0], dot_dot.spans[1]),
772808c999fSMiguel Ojeda                         RangeLimits::Closed(dot_dot_eq) => {
773808c999fSMiguel Ojeda                             (dot_dot_eq.spans[0], dot_dot_eq.spans[2])
774808c999fSMiguel Ojeda                         }
775808c999fSMiguel Ojeda                     };
776808c999fSMiguel Ojeda                     let msg = "range pattern is not allowed unparenthesized inside slice pattern";
777808c999fSMiguel Ojeda                     return Err(error::new2(start, end, msg));
778808c999fSMiguel Ojeda                 }
779808c999fSMiguel Ojeda                 _ => {}
780808c999fSMiguel Ojeda             }
781808c999fSMiguel Ojeda             elems.push_value(value);
782808c999fSMiguel Ojeda             if content.is_empty() {
783808c999fSMiguel Ojeda                 break;
784808c999fSMiguel Ojeda             }
785808c999fSMiguel Ojeda             let punct = content.parse()?;
786808c999fSMiguel Ojeda             elems.push_punct(punct);
787808c999fSMiguel Ojeda         }
788808c999fSMiguel Ojeda 
789808c999fSMiguel Ojeda         Ok(PatSlice {
790808c999fSMiguel Ojeda             attrs: Vec::new(),
791808c999fSMiguel Ojeda             bracket_token,
792808c999fSMiguel Ojeda             elems,
793808c999fSMiguel Ojeda         })
794808c999fSMiguel Ojeda     }
795808c999fSMiguel Ojeda 
pat_const(input: ParseStream) -> Result<TokenStream>796808c999fSMiguel Ojeda     fn pat_const(input: ParseStream) -> Result<TokenStream> {
797808c999fSMiguel Ojeda         let begin = input.fork();
798808c999fSMiguel Ojeda         input.parse::<Token![const]>()?;
799808c999fSMiguel Ojeda 
800808c999fSMiguel Ojeda         let content;
801808c999fSMiguel Ojeda         braced!(content in input);
802808c999fSMiguel Ojeda         content.call(Attribute::parse_inner)?;
803808c999fSMiguel Ojeda         content.call(Block::parse_within)?;
804808c999fSMiguel Ojeda 
805808c999fSMiguel Ojeda         Ok(verbatim::between(&begin, input))
806808c999fSMiguel Ojeda     }
807808c999fSMiguel Ojeda }
808808c999fSMiguel Ojeda 
809808c999fSMiguel Ojeda #[cfg(feature = "printing")]
810808c999fSMiguel Ojeda mod printing {
811808c999fSMiguel Ojeda     use crate::attr::FilterAttrs;
812808c999fSMiguel Ojeda     use crate::pat::{
813808c999fSMiguel Ojeda         FieldPat, Pat, PatIdent, PatOr, PatParen, PatReference, PatRest, PatSlice, PatStruct,
814808c999fSMiguel Ojeda         PatTuple, PatTupleStruct, PatType, PatWild,
815808c999fSMiguel Ojeda     };
816808c999fSMiguel Ojeda     use crate::path;
817808c999fSMiguel Ojeda     use crate::path::printing::PathStyle;
818808c999fSMiguel Ojeda     use proc_macro2::TokenStream;
819808c999fSMiguel Ojeda     use quote::{ToTokens, TokenStreamExt};
820808c999fSMiguel Ojeda 
821808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
822808c999fSMiguel Ojeda     impl ToTokens for PatIdent {
to_tokens(&self, tokens: &mut TokenStream)823808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
824808c999fSMiguel Ojeda             tokens.append_all(self.attrs.outer());
825808c999fSMiguel Ojeda             self.by_ref.to_tokens(tokens);
826808c999fSMiguel Ojeda             self.mutability.to_tokens(tokens);
827808c999fSMiguel Ojeda             self.ident.to_tokens(tokens);
828808c999fSMiguel Ojeda             if let Some((at_token, subpat)) = &self.subpat {
829808c999fSMiguel Ojeda                 at_token.to_tokens(tokens);
830808c999fSMiguel Ojeda                 subpat.to_tokens(tokens);
831808c999fSMiguel Ojeda             }
832808c999fSMiguel Ojeda         }
833808c999fSMiguel Ojeda     }
834808c999fSMiguel Ojeda 
835808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
836808c999fSMiguel Ojeda     impl ToTokens for PatOr {
to_tokens(&self, tokens: &mut TokenStream)837808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
838808c999fSMiguel Ojeda             tokens.append_all(self.attrs.outer());
839808c999fSMiguel Ojeda             self.leading_vert.to_tokens(tokens);
840808c999fSMiguel Ojeda             self.cases.to_tokens(tokens);
841808c999fSMiguel Ojeda         }
842808c999fSMiguel Ojeda     }
843808c999fSMiguel Ojeda 
844808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
845808c999fSMiguel Ojeda     impl ToTokens for PatParen {
to_tokens(&self, tokens: &mut TokenStream)846808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
847808c999fSMiguel Ojeda             tokens.append_all(self.attrs.outer());
848808c999fSMiguel Ojeda             self.paren_token.surround(tokens, |tokens| {
849808c999fSMiguel Ojeda                 self.pat.to_tokens(tokens);
850808c999fSMiguel Ojeda             });
851808c999fSMiguel Ojeda         }
852808c999fSMiguel Ojeda     }
853808c999fSMiguel Ojeda 
854808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
855808c999fSMiguel Ojeda     impl ToTokens for PatReference {
to_tokens(&self, tokens: &mut TokenStream)856808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
857808c999fSMiguel Ojeda             tokens.append_all(self.attrs.outer());
858808c999fSMiguel Ojeda             self.and_token.to_tokens(tokens);
859808c999fSMiguel Ojeda             self.mutability.to_tokens(tokens);
860808c999fSMiguel Ojeda             self.pat.to_tokens(tokens);
861808c999fSMiguel Ojeda         }
862808c999fSMiguel Ojeda     }
863808c999fSMiguel Ojeda 
864808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
865808c999fSMiguel Ojeda     impl ToTokens for PatRest {
to_tokens(&self, tokens: &mut TokenStream)866808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
867808c999fSMiguel Ojeda             tokens.append_all(self.attrs.outer());
868808c999fSMiguel Ojeda             self.dot2_token.to_tokens(tokens);
869808c999fSMiguel Ojeda         }
870808c999fSMiguel Ojeda     }
871808c999fSMiguel Ojeda 
872808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
873808c999fSMiguel Ojeda     impl ToTokens for PatSlice {
to_tokens(&self, tokens: &mut TokenStream)874808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
875808c999fSMiguel Ojeda             tokens.append_all(self.attrs.outer());
876808c999fSMiguel Ojeda             self.bracket_token.surround(tokens, |tokens| {
877808c999fSMiguel Ojeda                 self.elems.to_tokens(tokens);
878808c999fSMiguel Ojeda             });
879808c999fSMiguel Ojeda         }
880808c999fSMiguel Ojeda     }
881808c999fSMiguel Ojeda 
882808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
883808c999fSMiguel Ojeda     impl ToTokens for PatStruct {
to_tokens(&self, tokens: &mut TokenStream)884808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
885808c999fSMiguel Ojeda             tokens.append_all(self.attrs.outer());
886808c999fSMiguel Ojeda             path::printing::print_qpath(tokens, &self.qself, &self.path, PathStyle::Expr);
887808c999fSMiguel Ojeda             self.brace_token.surround(tokens, |tokens| {
888808c999fSMiguel Ojeda                 self.fields.to_tokens(tokens);
889808c999fSMiguel Ojeda                 // NOTE: We need a comma before the dot2 token if it is present.
890808c999fSMiguel Ojeda                 if !self.fields.empty_or_trailing() && self.rest.is_some() {
891808c999fSMiguel Ojeda                     <Token![,]>::default().to_tokens(tokens);
892808c999fSMiguel Ojeda                 }
893808c999fSMiguel Ojeda                 self.rest.to_tokens(tokens);
894808c999fSMiguel Ojeda             });
895808c999fSMiguel Ojeda         }
896808c999fSMiguel Ojeda     }
897808c999fSMiguel Ojeda 
898808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
899808c999fSMiguel Ojeda     impl ToTokens for PatTuple {
to_tokens(&self, tokens: &mut TokenStream)900808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
901808c999fSMiguel Ojeda             tokens.append_all(self.attrs.outer());
902808c999fSMiguel Ojeda             self.paren_token.surround(tokens, |tokens| {
903808c999fSMiguel Ojeda                 self.elems.to_tokens(tokens);
904808c999fSMiguel Ojeda                 // If there is only one element, a trailing comma is needed to
905808c999fSMiguel Ojeda                 // distinguish PatTuple from PatParen, unless this is `(..)`
906808c999fSMiguel Ojeda                 // which is a tuple pattern even without comma.
907808c999fSMiguel Ojeda                 if self.elems.len() == 1
908808c999fSMiguel Ojeda                     && !self.elems.trailing_punct()
909808c999fSMiguel Ojeda                     && !matches!(self.elems[0], Pat::Rest { .. })
910808c999fSMiguel Ojeda                 {
911808c999fSMiguel Ojeda                     <Token![,]>::default().to_tokens(tokens);
912808c999fSMiguel Ojeda                 }
913808c999fSMiguel Ojeda             });
914808c999fSMiguel Ojeda         }
915808c999fSMiguel Ojeda     }
916808c999fSMiguel Ojeda 
917808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
918808c999fSMiguel Ojeda     impl ToTokens for PatTupleStruct {
to_tokens(&self, tokens: &mut TokenStream)919808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
920808c999fSMiguel Ojeda             tokens.append_all(self.attrs.outer());
921808c999fSMiguel Ojeda             path::printing::print_qpath(tokens, &self.qself, &self.path, PathStyle::Expr);
922808c999fSMiguel Ojeda             self.paren_token.surround(tokens, |tokens| {
923808c999fSMiguel Ojeda                 self.elems.to_tokens(tokens);
924808c999fSMiguel Ojeda             });
925808c999fSMiguel Ojeda         }
926808c999fSMiguel Ojeda     }
927808c999fSMiguel Ojeda 
928808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
929808c999fSMiguel Ojeda     impl ToTokens for PatType {
to_tokens(&self, tokens: &mut TokenStream)930808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
931808c999fSMiguel Ojeda             tokens.append_all(self.attrs.outer());
932808c999fSMiguel Ojeda             self.pat.to_tokens(tokens);
933808c999fSMiguel Ojeda             self.colon_token.to_tokens(tokens);
934808c999fSMiguel Ojeda             self.ty.to_tokens(tokens);
935808c999fSMiguel Ojeda         }
936808c999fSMiguel Ojeda     }
937808c999fSMiguel Ojeda 
938808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
939808c999fSMiguel Ojeda     impl ToTokens for PatWild {
to_tokens(&self, tokens: &mut TokenStream)940808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
941808c999fSMiguel Ojeda             tokens.append_all(self.attrs.outer());
942808c999fSMiguel Ojeda             self.underscore_token.to_tokens(tokens);
943808c999fSMiguel Ojeda         }
944808c999fSMiguel Ojeda     }
945808c999fSMiguel Ojeda 
946808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
947808c999fSMiguel Ojeda     impl ToTokens for FieldPat {
to_tokens(&self, tokens: &mut TokenStream)948808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
949808c999fSMiguel Ojeda             tokens.append_all(self.attrs.outer());
950808c999fSMiguel Ojeda             if let Some(colon_token) = &self.colon_token {
951808c999fSMiguel Ojeda                 self.member.to_tokens(tokens);
952808c999fSMiguel Ojeda                 colon_token.to_tokens(tokens);
953808c999fSMiguel Ojeda             }
954808c999fSMiguel Ojeda             self.pat.to_tokens(tokens);
955808c999fSMiguel Ojeda         }
956808c999fSMiguel Ojeda     }
957808c999fSMiguel Ojeda }
958