1 // SPDX-License-Identifier: Apache-2.0 OR MIT 2 3 use crate::attr::Attribute; 4 use crate::expr::Member; 5 use crate::ident::Ident; 6 use crate::path::{Path, QSelf}; 7 use crate::punctuated::Punctuated; 8 use crate::token; 9 use crate::ty::Type; 10 use proc_macro2::TokenStream; 11 12 pub use crate::expr::{ 13 ExprConst as PatConst, ExprLit as PatLit, ExprMacro as PatMacro, ExprPath as PatPath, 14 ExprRange as PatRange, 15 }; 16 17 ast_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 106 ast_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 121 ast_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 131 ast_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 141 ast_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 152 ast_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 161 ast_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 171 ast_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 184 ast_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 194 ast_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 206 ast_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 217 ast_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 226 ast_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")] 241 pub(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")] 810 mod 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 } 958