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