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