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