1 use crate::attr::Attribute; 2 use crate::expr::Member; 3 use crate::ident::Ident; 4 use crate::path::{Path, QSelf}; 5 use crate::punctuated::Punctuated; 6 use crate::token; 7 use crate::ty::Type; 8 use proc_macro2::TokenStream; 9 10 pub use crate::expr::{ 11 ExprConst as PatConst, ExprLit as PatLit, ExprMacro as PatMacro, ExprPath as PatPath, 12 ExprRange as PatRange, 13 }; 14 15 ast_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(docsrs, 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 104 ast_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(docsrs, 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 119 ast_struct! { 120 /// A pattern that matches any one of a set of cases. 121 #[cfg_attr(docsrs, 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 129 ast_struct! { 130 /// A parenthesized pattern: `(A | B)`. 131 #[cfg_attr(docsrs, 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 139 ast_struct! { 140 /// A reference pattern: `&mut var`. 141 #[cfg_attr(docsrs, 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 150 ast_struct! { 151 /// The dots in a tuple or slice pattern: `[0, 1, ..]`. 152 #[cfg_attr(docsrs, doc(cfg(feature = "full")))] 153 pub struct PatRest { 154 pub attrs: Vec<Attribute>, 155 pub dot2_token: Token![..], 156 } 157 } 158 159 ast_struct! { 160 /// A dynamically sized slice pattern: `[a, b, ref i @ .., y, z]`. 161 #[cfg_attr(docsrs, 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 169 ast_struct! { 170 /// A struct or struct variant pattern: `Variant { x, y, .. }`. 171 #[cfg_attr(docsrs, 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 182 ast_struct! { 183 /// A tuple pattern: `(a, b)`. 184 #[cfg_attr(docsrs, 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 192 ast_struct! { 193 /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`. 194 #[cfg_attr(docsrs, 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 204 ast_struct! { 205 /// A type ascription pattern: `foo: f64`. 206 #[cfg_attr(docsrs, 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 215 ast_struct! { 216 /// A pattern that matches any value: `_`. 217 #[cfg_attr(docsrs, doc(cfg(feature = "full")))] 218 pub struct PatWild { 219 pub attrs: Vec<Attribute>, 220 pub underscore_token: Token![_], 221 } 222 } 223 224 ast_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(docsrs, 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")] 239 pub(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(docsrs, 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(docsrs, 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 expr_style = true; 421 let (qself, path) = path::parsing::qpath(input, expr_style)?; 422 423 if qself.is_none() 424 && input.peek(Token![!]) 425 && !input.peek(Token![!=]) 426 && path.is_mod_style() 427 { 428 let bang_token: Token![!] = input.parse()?; 429 let (delimiter, tokens) = mac::parse_delimiter(input)?; 430 return Ok(Pat::Macro(ExprMacro { 431 attrs: Vec::new(), 432 mac: Macro { 433 path, 434 bang_token, 435 delimiter, 436 tokens, 437 }, 438 })); 439 } 440 441 if input.peek(token::Brace) { 442 pat_struct(input, qself, path).map(Pat::Struct) 443 } else if input.peek(token::Paren) { 444 pat_tuple_struct(input, qself, path).map(Pat::TupleStruct) 445 } else if input.peek(Token![..]) { 446 pat_range(input, qself, path) 447 } else { 448 Ok(Pat::Path(ExprPath { 449 attrs: Vec::new(), 450 qself, 451 path, 452 })) 453 } 454 } 455 456 fn pat_wild(input: ParseStream) -> Result<PatWild> { 457 Ok(PatWild { 458 attrs: Vec::new(), 459 underscore_token: input.parse()?, 460 }) 461 } 462 463 fn pat_box(begin: ParseBuffer, input: ParseStream) -> Result<Pat> { 464 input.parse::<Token![box]>()?; 465 Pat::parse_single(input)?; 466 Ok(Pat::Verbatim(verbatim::between(&begin, input))) 467 } 468 469 fn pat_ident(input: ParseStream) -> Result<PatIdent> { 470 Ok(PatIdent { 471 attrs: Vec::new(), 472 by_ref: input.parse()?, 473 mutability: input.parse()?, 474 ident: { 475 if input.peek(Token![self]) { 476 input.call(Ident::parse_any)? 477 } else { 478 input.parse()? 479 } 480 }, 481 subpat: { 482 if input.peek(Token![@]) { 483 let at_token: Token![@] = input.parse()?; 484 let subpat = Pat::parse_single(input)?; 485 Some((at_token, Box::new(subpat))) 486 } else { 487 None 488 } 489 }, 490 }) 491 } 492 493 fn pat_tuple_struct( 494 input: ParseStream, 495 qself: Option<QSelf>, 496 path: Path, 497 ) -> Result<PatTupleStruct> { 498 let content; 499 let paren_token = parenthesized!(content in input); 500 501 let mut elems = Punctuated::new(); 502 while !content.is_empty() { 503 let value = Pat::parse_multi_with_leading_vert(&content)?; 504 elems.push_value(value); 505 if content.is_empty() { 506 break; 507 } 508 let punct = content.parse()?; 509 elems.push_punct(punct); 510 } 511 512 Ok(PatTupleStruct { 513 attrs: Vec::new(), 514 qself, 515 path, 516 paren_token, 517 elems, 518 }) 519 } 520 521 fn pat_struct(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<PatStruct> { 522 let content; 523 let brace_token = braced!(content in input); 524 525 let mut fields = Punctuated::new(); 526 let mut rest = None; 527 while !content.is_empty() { 528 let attrs = content.call(Attribute::parse_outer)?; 529 if content.peek(Token![..]) { 530 rest = Some(PatRest { 531 attrs, 532 dot2_token: content.parse()?, 533 }); 534 break; 535 } 536 let mut value = content.call(field_pat)?; 537 value.attrs = attrs; 538 fields.push_value(value); 539 if content.is_empty() { 540 break; 541 } 542 let punct: Token![,] = content.parse()?; 543 fields.push_punct(punct); 544 } 545 546 Ok(PatStruct { 547 attrs: Vec::new(), 548 qself, 549 path, 550 brace_token, 551 fields, 552 rest, 553 }) 554 } 555 556 fn field_pat(input: ParseStream) -> Result<FieldPat> { 557 let begin = input.fork(); 558 let boxed: Option<Token![box]> = input.parse()?; 559 let by_ref: Option<Token![ref]> = input.parse()?; 560 let mutability: Option<Token![mut]> = input.parse()?; 561 562 let member = if boxed.is_some() || by_ref.is_some() || mutability.is_some() { 563 input.parse().map(Member::Named) 564 } else { 565 input.parse() 566 }?; 567 568 if boxed.is_none() && by_ref.is_none() && mutability.is_none() && input.peek(Token![:]) 569 || !member.is_named() 570 { 571 return Ok(FieldPat { 572 attrs: Vec::new(), 573 member, 574 colon_token: Some(input.parse()?), 575 pat: Box::new(Pat::parse_multi_with_leading_vert(input)?), 576 }); 577 } 578 579 let ident = match member { 580 Member::Named(ident) => ident, 581 Member::Unnamed(_) => unreachable!(), 582 }; 583 584 let pat = if boxed.is_some() { 585 Pat::Verbatim(verbatim::between(&begin, input)) 586 } else { 587 Pat::Ident(PatIdent { 588 attrs: Vec::new(), 589 by_ref, 590 mutability, 591 ident: ident.clone(), 592 subpat: None, 593 }) 594 }; 595 596 Ok(FieldPat { 597 attrs: Vec::new(), 598 member: Member::Named(ident), 599 colon_token: None, 600 pat: Box::new(pat), 601 }) 602 } 603 604 fn pat_range(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<Pat> { 605 let limits = RangeLimits::parse_obsolete(input)?; 606 let end = input.call(pat_range_bound)?; 607 if let (RangeLimits::Closed(_), None) = (&limits, &end) { 608 return Err(input.error("expected range upper bound")); 609 } 610 Ok(Pat::Range(ExprRange { 611 attrs: Vec::new(), 612 start: Some(Box::new(Expr::Path(ExprPath { 613 attrs: Vec::new(), 614 qself, 615 path, 616 }))), 617 limits, 618 end: end.map(PatRangeBound::into_expr), 619 })) 620 } 621 622 fn pat_range_half_open(input: ParseStream) -> Result<Pat> { 623 let limits: RangeLimits = input.parse()?; 624 let end = input.call(pat_range_bound)?; 625 if end.is_some() { 626 Ok(Pat::Range(ExprRange { 627 attrs: Vec::new(), 628 start: None, 629 limits, 630 end: end.map(PatRangeBound::into_expr), 631 })) 632 } else { 633 match limits { 634 RangeLimits::HalfOpen(dot2_token) => Ok(Pat::Rest(PatRest { 635 attrs: Vec::new(), 636 dot2_token, 637 })), 638 RangeLimits::Closed(_) => Err(input.error("expected range upper bound")), 639 } 640 } 641 } 642 643 fn pat_paren_or_tuple(input: ParseStream) -> Result<Pat> { 644 let content; 645 let paren_token = parenthesized!(content in input); 646 647 let mut elems = Punctuated::new(); 648 while !content.is_empty() { 649 let value = Pat::parse_multi_with_leading_vert(&content)?; 650 if content.is_empty() { 651 if elems.is_empty() && !matches!(value, Pat::Rest(_)) { 652 return Ok(Pat::Paren(PatParen { 653 attrs: Vec::new(), 654 paren_token, 655 pat: Box::new(value), 656 })); 657 } 658 elems.push_value(value); 659 break; 660 } 661 elems.push_value(value); 662 let punct = content.parse()?; 663 elems.push_punct(punct); 664 } 665 666 Ok(Pat::Tuple(PatTuple { 667 attrs: Vec::new(), 668 paren_token, 669 elems, 670 })) 671 } 672 673 fn pat_reference(input: ParseStream) -> Result<PatReference> { 674 Ok(PatReference { 675 attrs: Vec::new(), 676 and_token: input.parse()?, 677 mutability: input.parse()?, 678 pat: Box::new(Pat::parse_single(input)?), 679 }) 680 } 681 682 fn pat_lit_or_range(input: ParseStream) -> Result<Pat> { 683 let start = input.call(pat_range_bound)?.unwrap(); 684 if input.peek(Token![..]) { 685 let limits = RangeLimits::parse_obsolete(input)?; 686 let end = input.call(pat_range_bound)?; 687 if let (RangeLimits::Closed(_), None) = (&limits, &end) { 688 return Err(input.error("expected range upper bound")); 689 } 690 Ok(Pat::Range(ExprRange { 691 attrs: Vec::new(), 692 start: Some(start.into_expr()), 693 limits, 694 end: end.map(PatRangeBound::into_expr), 695 })) 696 } else { 697 Ok(start.into_pat()) 698 } 699 } 700 701 // Patterns that can appear on either side of a range pattern. 702 enum PatRangeBound { 703 Const(ExprConst), 704 Lit(ExprLit), 705 Path(ExprPath), 706 } 707 708 impl PatRangeBound { 709 fn into_expr(self) -> Box<Expr> { 710 Box::new(match self { 711 PatRangeBound::Const(pat) => Expr::Const(pat), 712 PatRangeBound::Lit(pat) => Expr::Lit(pat), 713 PatRangeBound::Path(pat) => Expr::Path(pat), 714 }) 715 } 716 717 fn into_pat(self) -> Pat { 718 match self { 719 PatRangeBound::Const(pat) => Pat::Const(pat), 720 PatRangeBound::Lit(pat) => Pat::Lit(pat), 721 PatRangeBound::Path(pat) => Pat::Path(pat), 722 } 723 } 724 } 725 726 fn pat_range_bound(input: ParseStream) -> Result<Option<PatRangeBound>> { 727 if input.is_empty() 728 || input.peek(Token![|]) 729 || input.peek(Token![=]) 730 || input.peek(Token![:]) && !input.peek(Token![::]) 731 || input.peek(Token![,]) 732 || input.peek(Token![;]) 733 || input.peek(Token![if]) 734 { 735 return Ok(None); 736 } 737 738 let lookahead = input.lookahead1(); 739 let expr = if lookahead.peek(Lit) { 740 PatRangeBound::Lit(input.parse()?) 741 } else if lookahead.peek(Ident) 742 || lookahead.peek(Token![::]) 743 || lookahead.peek(Token![<]) 744 || lookahead.peek(Token![self]) 745 || lookahead.peek(Token![Self]) 746 || lookahead.peek(Token![super]) 747 || lookahead.peek(Token![crate]) 748 { 749 PatRangeBound::Path(input.parse()?) 750 } else if lookahead.peek(Token![const]) { 751 PatRangeBound::Const(input.parse()?) 752 } else { 753 return Err(lookahead.error()); 754 }; 755 756 Ok(Some(expr)) 757 } 758 759 fn pat_slice(input: ParseStream) -> Result<PatSlice> { 760 let content; 761 let bracket_token = bracketed!(content in input); 762 763 let mut elems = Punctuated::new(); 764 while !content.is_empty() { 765 let value = Pat::parse_multi_with_leading_vert(&content)?; 766 match value { 767 Pat::Range(pat) if pat.start.is_none() || pat.end.is_none() => { 768 let (start, end) = match pat.limits { 769 RangeLimits::HalfOpen(dot_dot) => (dot_dot.spans[0], dot_dot.spans[1]), 770 RangeLimits::Closed(dot_dot_eq) => { 771 (dot_dot_eq.spans[0], dot_dot_eq.spans[2]) 772 } 773 }; 774 let msg = "range pattern is not allowed unparenthesized inside slice pattern"; 775 return Err(error::new2(start, end, msg)); 776 } 777 _ => {} 778 } 779 elems.push_value(value); 780 if content.is_empty() { 781 break; 782 } 783 let punct = content.parse()?; 784 elems.push_punct(punct); 785 } 786 787 Ok(PatSlice { 788 attrs: Vec::new(), 789 bracket_token, 790 elems, 791 }) 792 } 793 794 fn pat_const(input: ParseStream) -> Result<TokenStream> { 795 let begin = input.fork(); 796 input.parse::<Token![const]>()?; 797 798 let content; 799 braced!(content in input); 800 content.call(Attribute::parse_inner)?; 801 content.call(Block::parse_within)?; 802 803 Ok(verbatim::between(&begin, input)) 804 } 805 } 806 807 #[cfg(feature = "printing")] 808 mod printing { 809 use crate::attr::FilterAttrs; 810 use crate::pat::{ 811 FieldPat, Pat, PatIdent, PatOr, PatParen, PatReference, PatRest, PatSlice, PatStruct, 812 PatTuple, PatTupleStruct, PatType, PatWild, 813 }; 814 use crate::path; 815 use crate::path::printing::PathStyle; 816 use proc_macro2::TokenStream; 817 use quote::{ToTokens, TokenStreamExt}; 818 819 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 820 impl ToTokens for PatIdent { 821 fn to_tokens(&self, tokens: &mut TokenStream) { 822 tokens.append_all(self.attrs.outer()); 823 self.by_ref.to_tokens(tokens); 824 self.mutability.to_tokens(tokens); 825 self.ident.to_tokens(tokens); 826 if let Some((at_token, subpat)) = &self.subpat { 827 at_token.to_tokens(tokens); 828 subpat.to_tokens(tokens); 829 } 830 } 831 } 832 833 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 834 impl ToTokens for PatOr { 835 fn to_tokens(&self, tokens: &mut TokenStream) { 836 tokens.append_all(self.attrs.outer()); 837 self.leading_vert.to_tokens(tokens); 838 self.cases.to_tokens(tokens); 839 } 840 } 841 842 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 843 impl ToTokens for PatParen { 844 fn to_tokens(&self, tokens: &mut TokenStream) { 845 tokens.append_all(self.attrs.outer()); 846 self.paren_token.surround(tokens, |tokens| { 847 self.pat.to_tokens(tokens); 848 }); 849 } 850 } 851 852 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 853 impl ToTokens for PatReference { 854 fn to_tokens(&self, tokens: &mut TokenStream) { 855 tokens.append_all(self.attrs.outer()); 856 self.and_token.to_tokens(tokens); 857 self.mutability.to_tokens(tokens); 858 self.pat.to_tokens(tokens); 859 } 860 } 861 862 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 863 impl ToTokens for PatRest { 864 fn to_tokens(&self, tokens: &mut TokenStream) { 865 tokens.append_all(self.attrs.outer()); 866 self.dot2_token.to_tokens(tokens); 867 } 868 } 869 870 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 871 impl ToTokens for PatSlice { 872 fn to_tokens(&self, tokens: &mut TokenStream) { 873 tokens.append_all(self.attrs.outer()); 874 self.bracket_token.surround(tokens, |tokens| { 875 self.elems.to_tokens(tokens); 876 }); 877 } 878 } 879 880 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 881 impl ToTokens for PatStruct { 882 fn to_tokens(&self, tokens: &mut TokenStream) { 883 tokens.append_all(self.attrs.outer()); 884 path::printing::print_qpath(tokens, &self.qself, &self.path, PathStyle::Expr); 885 self.brace_token.surround(tokens, |tokens| { 886 self.fields.to_tokens(tokens); 887 // NOTE: We need a comma before the dot2 token if it is present. 888 if !self.fields.empty_or_trailing() && self.rest.is_some() { 889 <Token![,]>::default().to_tokens(tokens); 890 } 891 self.rest.to_tokens(tokens); 892 }); 893 } 894 } 895 896 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 897 impl ToTokens for PatTuple { 898 fn to_tokens(&self, tokens: &mut TokenStream) { 899 tokens.append_all(self.attrs.outer()); 900 self.paren_token.surround(tokens, |tokens| { 901 self.elems.to_tokens(tokens); 902 // If there is only one element, a trailing comma is needed to 903 // distinguish PatTuple from PatParen, unless this is `(..)` 904 // which is a tuple pattern even without comma. 905 if self.elems.len() == 1 906 && !self.elems.trailing_punct() 907 && !matches!(self.elems[0], Pat::Rest { .. }) 908 { 909 <Token![,]>::default().to_tokens(tokens); 910 } 911 }); 912 } 913 } 914 915 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 916 impl ToTokens for PatTupleStruct { 917 fn to_tokens(&self, tokens: &mut TokenStream) { 918 tokens.append_all(self.attrs.outer()); 919 path::printing::print_qpath(tokens, &self.qself, &self.path, PathStyle::Expr); 920 self.paren_token.surround(tokens, |tokens| { 921 self.elems.to_tokens(tokens); 922 }); 923 } 924 } 925 926 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 927 impl ToTokens for PatType { 928 fn to_tokens(&self, tokens: &mut TokenStream) { 929 tokens.append_all(self.attrs.outer()); 930 self.pat.to_tokens(tokens); 931 self.colon_token.to_tokens(tokens); 932 self.ty.to_tokens(tokens); 933 } 934 } 935 936 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 937 impl ToTokens for PatWild { 938 fn to_tokens(&self, tokens: &mut TokenStream) { 939 tokens.append_all(self.attrs.outer()); 940 self.underscore_token.to_tokens(tokens); 941 } 942 } 943 944 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 945 impl ToTokens for FieldPat { 946 fn to_tokens(&self, tokens: &mut TokenStream) { 947 tokens.append_all(self.attrs.outer()); 948 if let Some(colon_token) = &self.colon_token { 949 self.member.to_tokens(tokens); 950 colon_token.to_tokens(tokens); 951 } 952 self.pat.to_tokens(tokens); 953 } 954 } 955 } 956