]> git.proxmox.com Git - rustc.git/blame - vendor/syn/src/pat.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / vendor / syn / src / pat.rs
CommitLineData
e74abb32
XL
1use super::*;
2use crate::punctuated::Punctuated;
e74abb32 3use proc_macro2::TokenStream;
e74abb32
XL
4
5ast_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
93ast_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
108ast_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
118ast_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
127ast_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
138ast_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
147ast_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
157ast_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
170ast_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
180ast_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
192ast_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
203ast_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
212ast_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 227pub(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")]
770mod 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}