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