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