diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:20:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:20:39 +0000 |
commit | 1376c5a617be5c25655d0d7cb63e3beaa5a6e026 (patch) | |
tree | 3bb8d61aee02bc7a15eab3f36e3b921afc2075d0 /vendor/syn/src/pat.rs | |
parent | Releasing progress-linux version 1.69.0+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-1376c5a617be5c25655d0d7cb63e3beaa5a6e026.tar.xz rustc-1376c5a617be5c25655d0d7cb63e3beaa5a6e026.zip |
Merging upstream version 1.70.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/syn/src/pat.rs')
-rw-r--r-- | vendor/syn/src/pat.rs | 684 |
1 files changed, 330 insertions, 354 deletions
diff --git a/vendor/syn/src/pat.rs b/vendor/syn/src/pat.rs index b279186aa..5833eeb33 100644 --- a/vendor/syn/src/pat.rs +++ b/vendor/syn/src/pat.rs @@ -6,26 +6,21 @@ ast_enum_of_structs! { /// A pattern in a local binding, function signature, match expression, or /// various other places. /// - /// *This type is available only if Syn is built with the `"full"` feature.* - /// /// # Syntax tree enum /// /// This type is a [syntax tree enum]. /// /// [syntax tree enum]: Expr#syntax-tree-enums #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] - #[cfg_attr(not(syn_no_non_exhaustive), non_exhaustive)] + #[non_exhaustive] pub enum Pat { - /// A box pattern: `box v`. - Box(PatBox), + /// A const block: `const { ... }`. + Const(PatConst), /// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`. Ident(PatIdent), /// A literal pattern: `0`. - /// - /// This holds an `Expr` rather than a `Lit` because negative numbers - /// are represented as an `Expr::Unary`. Lit(PatLit), /// A macro in pattern position. @@ -34,6 +29,9 @@ ast_enum_of_structs! { /// A pattern that matches any one of a set of cases. Or(PatOr), + /// A parenthesized pattern: `(A | B)`. + Paren(PatParen), + /// A path pattern like `Color::Red`, optionally qualified with a /// self-type. /// @@ -49,7 +47,7 @@ ast_enum_of_structs! { /// A reference pattern: `&mut var`. Reference(PatReference), - /// The dots in a tuple or slice pattern: `[0, 1, ..]` + /// The dots in a tuple or slice pattern: `[0, 1, ..]`. Rest(PatRest), /// A dynamically sized slice pattern: `[a, b, ref i @ .., y, z]`. @@ -73,8 +71,6 @@ ast_enum_of_structs! { /// A pattern that matches any value: `_`. Wild(PatWild), - // Not public API. - // // For testing exhaustiveness in downstream code, use the following idiom: // // match pat { @@ -91,21 +87,6 @@ ast_enum_of_structs! { // a variant. You will be notified by a test failure when a variant is // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. - #[cfg(syn_no_non_exhaustive)] - #[doc(hidden)] - __NonExhaustive, - } -} - -ast_struct! { - /// A box pattern: `box v`. - /// - /// *This type is available only if Syn is built with the `"full"` feature.* - #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] - pub struct PatBox { - pub attrs: Vec<Attribute>, - pub box_token: Token![box], - pub pat: Box<Pat>, } } @@ -114,8 +95,6 @@ ast_struct! { /// /// It may also be a unit struct or struct variant (e.g. `None`), or a /// constant; these cannot be distinguished syntactically. - /// - /// *This type is available only if Syn is built with the `"full"` feature.* #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] pub struct PatIdent { pub attrs: Vec<Attribute>, @@ -127,34 +106,7 @@ ast_struct! { } ast_struct! { - /// A literal pattern: `0`. - /// - /// This holds an `Expr` rather than a `Lit` because negative numbers - /// are represented as an `Expr::Unary`. - /// - /// *This type is available only if Syn is built with the `"full"` feature.* - #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] - pub struct PatLit { - pub attrs: Vec<Attribute>, - pub expr: Box<Expr>, - } -} - -ast_struct! { - /// A macro in pattern position. - /// - /// *This type is available only if Syn is built with the `"full"` feature.* - #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] - pub struct PatMacro { - pub attrs: Vec<Attribute>, - pub mac: Macro, - } -} - -ast_struct! { /// A pattern that matches any one of a set of cases. - /// - /// *This type is available only if Syn is built with the `"full"` feature.* #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] pub struct PatOr { pub attrs: Vec<Attribute>, @@ -164,40 +116,16 @@ ast_struct! { } ast_struct! { - /// A path pattern like `Color::Red`, optionally qualified with a - /// self-type. - /// - /// Unqualified path patterns can legally refer to variants, structs, - /// constants or associated constants. Qualified path patterns like - /// `<A>::B::C` and `<A as Trait>::B::C` can only legally refer to - /// associated constants. - /// - /// *This type is available only if Syn is built with the `"full"` feature.* - #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] - pub struct PatPath { - pub attrs: Vec<Attribute>, - pub qself: Option<QSelf>, - pub path: Path, - } -} - -ast_struct! { - /// A range pattern: `1..=2`. - /// - /// *This type is available only if Syn is built with the `"full"` feature.* - #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] - pub struct PatRange { + /// A parenthesized pattern: `(A | B)`. + pub struct PatParen { pub attrs: Vec<Attribute>, - pub lo: Box<Expr>, - pub limits: RangeLimits, - pub hi: Box<Expr>, + pub paren_token: token::Paren, + pub pat: Box<Pat>, } } ast_struct! { /// A reference pattern: `&mut var`. - /// - /// *This type is available only if Syn is built with the `"full"` feature.* #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] pub struct PatReference { pub attrs: Vec<Attribute>, @@ -208,9 +136,7 @@ ast_struct! { } ast_struct! { - /// The dots in a tuple or slice pattern: `[0, 1, ..]` - /// - /// *This type is available only if Syn is built with the `"full"` feature.* + /// The dots in a tuple or slice pattern: `[0, 1, ..]`. #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] pub struct PatRest { pub attrs: Vec<Attribute>, @@ -220,8 +146,6 @@ ast_struct! { ast_struct! { /// A dynamically sized slice pattern: `[a, b, ref i @ .., y, z]`. - /// - /// *This type is available only if Syn is built with the `"full"` feature.* #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] pub struct PatSlice { pub attrs: Vec<Attribute>, @@ -232,22 +156,19 @@ ast_struct! { ast_struct! { /// A struct or struct variant pattern: `Variant { x, y, .. }`. - /// - /// *This type is available only if Syn is built with the `"full"` feature.* #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] pub struct PatStruct { pub attrs: Vec<Attribute>, + pub qself: Option<QSelf>, pub path: Path, pub brace_token: token::Brace, pub fields: Punctuated<FieldPat, Token![,]>, - pub dot2_token: Option<Token![..]>, + pub rest: Option<PatRest>, } } ast_struct! { /// A tuple pattern: `(a, b)`. - /// - /// *This type is available only if Syn is built with the `"full"` feature.* #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] pub struct PatTuple { pub attrs: Vec<Attribute>, @@ -258,20 +179,18 @@ ast_struct! { ast_struct! { /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`. - /// - /// *This type is available only if Syn is built with the `"full"` feature.* #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] pub struct PatTupleStruct { pub attrs: Vec<Attribute>, + pub qself: Option<QSelf>, pub path: Path, - pub pat: PatTuple, + pub paren_token: token::Paren, + pub elems: Punctuated<Pat, Token![,]>, } } ast_struct! { /// A type ascription pattern: `foo: f64`. - /// - /// *This type is available only if Syn is built with the `"full"` feature.* #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] pub struct PatType { pub attrs: Vec<Attribute>, @@ -283,8 +202,6 @@ ast_struct! { ast_struct! { /// A pattern that matches any value: `_`. - /// - /// *This type is available only if Syn is built with the `"full"` feature.* #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] pub struct PatWild { pub attrs: Vec<Attribute>, @@ -297,8 +214,6 @@ ast_struct! { /// /// Patterns like the fields of Foo `{ x, ref y, ref mut z }` are treated /// the same as `x: x, y: ref y, z: ref mut z` but there is no colon token. - /// - /// *This type is available only if Syn is built with the `"full"` feature.* #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] pub struct FieldPat { pub attrs: Vec<Attribute>, @@ -309,31 +224,49 @@ ast_struct! { } #[cfg(feature = "parsing")] -pub mod parsing { +pub(crate) mod parsing { use super::*; use crate::ext::IdentExt; - use crate::parse::{Parse, ParseBuffer, ParseStream, Result}; + use crate::parse::{ParseBuffer, ParseStream, Result}; use crate::path; #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] - impl Parse for Pat { - fn parse(input: ParseStream) -> Result<Self> { + impl Pat { + /// Parse a pattern that does _not_ involve `|` at the top level. + /// + /// This parser matches the behavior of the `$:pat_param` macro_rules + /// matcher, and on editions prior to Rust 2021, the behavior of + /// `$:pat`. + /// + /// In Rust syntax, some examples of where this syntax would occur are + /// in the argument pattern of functions and closures. Patterns using + /// `|` are not allowed to occur in these positions. + /// + /// ```compile_fail + /// fn f(Some(_) | None: Option<T>) { + /// let _ = |Some(_) | None: Option<T>| {}; + /// // ^^^^^^^^^^^^^^^^^^^^^^^^^??? :( + /// } + /// ``` + /// + /// ```console + /// error: top-level or-patterns are not allowed in function parameters + /// --> src/main.rs:1:6 + /// | + /// 1 | fn f(Some(_) | None: Option<T>) { + /// | ^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(Some(_) | None)` + /// ``` + pub fn parse_single(input: ParseStream) -> Result<Self> { let begin = input.fork(); let lookahead = input.lookahead1(); - if { - let ahead = input.fork(); - ahead.parse::<Option<Ident>>()?.is_some() - && (ahead.peek(Token![::]) - || ahead.peek(Token![!]) - || ahead.peek(token::Brace) - || ahead.peek(token::Paren) - || ahead.peek(Token![..]) - && ahead.parse::<RangeLimits>().is_ok() - && !(ahead.is_empty() || ahead.peek(Token![,]))) - } || { - let ahead = input.fork(); - ahead.parse::<Option<Token![self]>>()?.is_some() && ahead.peek(Token![::]) - } || lookahead.peek(Token![::]) + if lookahead.peek(Ident) + && (input.peek2(Token![::]) + || input.peek2(Token![!]) + || input.peek2(token::Brace) + || input.peek2(token::Paren) + || input.peek2(Token![..])) + || input.peek(Token![self]) && input.peek2(Token![::]) + || lookahead.peek(Token![::]) || lookahead.peek(Token![<]) || input.peek(Token![Self]) || input.peek(Token![super]) @@ -343,7 +276,7 @@ pub mod parsing { } else if lookahead.peek(Token![_]) { input.call(pat_wild).map(Pat::Wild) } else if input.peek(Token![box]) { - input.call(pat_box).map(Pat::Box) + pat_box(begin, input) } else if input.peek(Token![-]) || lookahead.peek(Lit) || lookahead.peek(Token![const]) { pat_lit_or_range(input) @@ -356,67 +289,122 @@ pub mod parsing { } else if lookahead.peek(Token![&]) { input.call(pat_reference).map(Pat::Reference) } else if lookahead.peek(token::Paren) { - input.call(pat_tuple).map(Pat::Tuple) + input.call(pat_paren_or_tuple) } else if lookahead.peek(token::Bracket) { input.call(pat_slice).map(Pat::Slice) } else if lookahead.peek(Token![..]) && !input.peek(Token![...]) { - pat_range_half_open(input, begin) + pat_range_half_open(input) } else if lookahead.peek(Token![const]) { input.call(pat_const).map(Pat::Verbatim) } else { Err(lookahead.error()) } } + + /// Parse a pattern, possibly involving `|`, but not a leading `|`. + pub fn parse_multi(input: ParseStream) -> Result<Self> { + multi_pat_impl(input, None) + } + + /// Parse a pattern, possibly involving `|`, possibly including a + /// leading `|`. + /// + /// This parser matches the behavior of the Rust 2021 edition's `$:pat` + /// macro_rules matcher. + /// + /// In Rust syntax, an example of where this syntax would occur is in + /// the pattern of a `match` arm, where the language permits an optional + /// leading `|`, although it is not idiomatic to write one there in + /// handwritten code. + /// + /// ``` + /// # let wat = None; + /// match wat { + /// | None | Some(false) => {} + /// | Some(true) => {} + /// } + /// ``` + /// + /// The compiler accepts it only to facilitate some situations in + /// macro-generated code where a macro author might need to write: + /// + /// ``` + /// # macro_rules! doc { + /// # ($value:expr, ($($conditions1:pat),*), ($($conditions2:pat),*), $then:expr) => { + /// match $value { + /// $(| $conditions1)* $(| $conditions2)* => $then + /// } + /// # }; + /// # } + /// # + /// # doc!(true, (true), (false), {}); + /// # doc!(true, (), (true, false), {}); + /// # doc!(true, (true, false), (), {}); + /// ``` + /// + /// Expressing the same thing correctly in the case that either one (but + /// not both) of `$conditions1` and `$conditions2` might be empty, + /// without leading `|`, is complex. + /// + /// Use [`Pat::parse_multi`] instead if you are not intending to support + /// macro-generated macro input. + pub fn parse_multi_with_leading_vert(input: ParseStream) -> Result<Self> { + let leading_vert: Option<Token![|]> = input.parse()?; + multi_pat_impl(input, leading_vert) + } + } + + fn multi_pat_impl(input: ParseStream, leading_vert: Option<Token![|]>) -> Result<Pat> { + let mut pat = Pat::parse_single(input)?; + if leading_vert.is_some() + || input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=]) + { + let mut cases = Punctuated::new(); + cases.push_value(pat); + while input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=]) { + let punct = input.parse()?; + cases.push_punct(punct); + let pat = Pat::parse_single(input)?; + cases.push_value(pat); + } + pat = Pat::Or(PatOr { + attrs: Vec::new(), + leading_vert, + cases, + }); + } + Ok(pat) } fn pat_path_or_macro_or_struct_or_range(input: ParseStream) -> Result<Pat> { - let begin = input.fork(); let (qself, path) = path::parsing::qpath(input, true)?; - if qself.is_none() && input.peek(Token![!]) && !input.peek(Token![!=]) { - let mut contains_arguments = false; - for segment in &path.segments { - match segment.arguments { - PathArguments::None => {} - PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => { - contains_arguments = true; - } - } - } - - if !contains_arguments { - let bang_token: Token![!] = input.parse()?; - let (delimiter, tokens) = mac::parse_delimiter(input)?; - return Ok(Pat::Macro(PatMacro { - attrs: Vec::new(), - mac: Macro { - path, - bang_token, - delimiter, - tokens, - }, - })); - } + if qself.is_none() + && input.peek(Token![!]) + && !input.peek(Token![!=]) + && path.is_mod_style() + { + let bang_token: Token![!] = input.parse()?; + let (delimiter, tokens) = mac::parse_delimiter(input)?; + return Ok(Pat::Macro(ExprMacro { + attrs: Vec::new(), + mac: Macro { + path, + bang_token, + delimiter, + tokens, + }, + })); } if input.peek(token::Brace) { - let pat = pat_struct(begin.fork(), input, path)?; - if qself.is_some() { - Ok(Pat::Verbatim(verbatim::between(begin, input))) - } else { - Ok(pat) - } + pat_struct(input, qself, path).map(Pat::Struct) } else if input.peek(token::Paren) { - let pat = pat_tuple_struct(input, path)?; - if qself.is_some() { - Ok(Pat::Verbatim(verbatim::between(begin, input))) - } else { - Ok(Pat::TupleStruct(pat)) - } + pat_tuple_struct(input, qself, path).map(Pat::TupleStruct) } else if input.peek(Token![..]) { - pat_range(input, begin, qself, path) + pat_range(input, qself, path) } else { - Ok(Pat::Path(PatPath { + Ok(Pat::Path(ExprPath { attrs: Vec::new(), qself, path, @@ -431,12 +419,10 @@ pub mod parsing { }) } - fn pat_box(input: ParseStream) -> Result<PatBox> { - Ok(PatBox { - attrs: Vec::new(), - box_token: input.parse()?, - pat: input.parse()?, - }) + fn pat_box(begin: ParseBuffer, input: ParseStream) -> Result<Pat> { + input.parse::<Token![box]>()?; + Pat::parse_single(input)?; + Ok(Pat::Verbatim(verbatim::between(begin, input))) } fn pat_ident(input: ParseStream) -> Result<PatIdent> { @@ -448,7 +434,7 @@ pub mod parsing { subpat: { if input.peek(Token![@]) { let at_token: Token![@] = input.parse()?; - let subpat: Pat = input.parse()?; + let subpat = Pat::parse_single(input)?; Some((at_token, Box::new(subpat))) } else { None @@ -457,27 +443,47 @@ pub mod parsing { }) } - fn pat_tuple_struct(input: ParseStream, path: Path) -> Result<PatTupleStruct> { + fn pat_tuple_struct( + input: ParseStream, + qself: Option<QSelf>, + path: Path, + ) -> Result<PatTupleStruct> { + let content; + let paren_token = parenthesized!(content in input); + + let mut elems = Punctuated::new(); + while !content.is_empty() { + let value = Pat::parse_multi_with_leading_vert(&content)?; + elems.push_value(value); + if content.is_empty() { + break; + } + let punct = content.parse()?; + elems.push_punct(punct); + } + Ok(PatTupleStruct { attrs: Vec::new(), + qself, path, - pat: input.call(pat_tuple)?, + paren_token, + elems, }) } - fn pat_struct(begin: ParseBuffer, input: ParseStream, path: Path) -> Result<Pat> { + fn pat_struct(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<PatStruct> { let content; let brace_token = braced!(content in input); let mut fields = Punctuated::new(); - let mut dot2_token = None; + let mut rest = None; while !content.is_empty() { let attrs = content.call(Attribute::parse_outer)?; if content.peek(Token![..]) { - dot2_token = Some(content.parse()?); - if !attrs.is_empty() { - return Ok(Pat::Verbatim(verbatim::between(begin, input))); - } + rest = Some(PatRest { + attrs, + dot2_token: content.parse()?, + }); break; } let mut value = content.call(field_pat)?; @@ -490,18 +496,19 @@ pub mod parsing { fields.push_punct(punct); } - Ok(Pat::Struct(PatStruct { + Ok(PatStruct { attrs: Vec::new(), + qself, path, brace_token, fields, - dot2_token, - })) + rest, + }) } impl Member { fn is_unnamed(&self) -> bool { - match *self { + match self { Member::Named(_) => false, Member::Unnamed(_) => true, } @@ -509,10 +516,16 @@ pub mod parsing { } fn field_pat(input: ParseStream) -> Result<FieldPat> { + let begin = input.fork(); let boxed: Option<Token![box]> = input.parse()?; let by_ref: Option<Token![ref]> = input.parse()?; let mutability: Option<Token![mut]> = input.parse()?; - let member: Member = input.parse()?; + + let member = if boxed.is_some() || by_ref.is_some() || mutability.is_some() { + input.parse().map(Member::Named) + } else { + input.parse() + }?; if boxed.is_none() && by_ref.is_none() && mutability.is_none() && input.peek(Token![:]) || member.is_unnamed() @@ -520,8 +533,8 @@ pub mod parsing { return Ok(FieldPat { attrs: Vec::new(), member, - colon_token: input.parse()?, - pat: Box::new(multi_pat_with_leading_vert(input)?), + colon_token: Some(input.parse()?), + pat: Box::new(Pat::parse_multi_with_leading_vert(input)?), }); } @@ -538,12 +551,8 @@ pub mod parsing { subpat: None, }); - if let Some(boxed) = boxed { - pat = Pat::Box(PatBox { - attrs: Vec::new(), - box_token: boxed, - pat: Box::new(pat), - }); + if boxed.is_some() { + pat = Pat::Verbatim(verbatim::between(begin, input)); } Ok(FieldPat { @@ -554,35 +563,34 @@ pub mod parsing { }) } - fn pat_range( - input: ParseStream, - begin: ParseBuffer, - qself: Option<QSelf>, - path: Path, - ) -> Result<Pat> { - let limits: RangeLimits = input.parse()?; - let hi = input.call(pat_lit_expr)?; - if let Some(hi) = hi { - Ok(Pat::Range(PatRange { - attrs: Vec::new(), - lo: Box::new(Expr::Path(ExprPath { - attrs: Vec::new(), - qself, - path, - })), - limits, - hi, - })) - } else { - Ok(Pat::Verbatim(verbatim::between(begin, input))) + fn pat_range(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<Pat> { + let limits = RangeLimits::parse_obsolete(input)?; + let end = input.call(pat_range_bound)?; + if let (RangeLimits::Closed(_), None) = (&limits, &end) { + return Err(input.error("expected range upper bound")); } + Ok(Pat::Range(ExprRange { + attrs: Vec::new(), + start: Some(Box::new(Expr::Path(ExprPath { + attrs: Vec::new(), + qself, + path, + }))), + limits, + end: end.map(PatRangeBound::into_expr), + })) } - fn pat_range_half_open(input: ParseStream, begin: ParseBuffer) -> Result<Pat> { + fn pat_range_half_open(input: ParseStream) -> Result<Pat> { let limits: RangeLimits = input.parse()?; - let hi = input.call(pat_lit_expr)?; - if hi.is_some() { - Ok(Pat::Verbatim(verbatim::between(begin, input))) + let end = input.call(pat_range_bound)?; + if end.is_some() { + Ok(Pat::Range(ExprRange { + attrs: Vec::new(), + start: None, + limits, + end: end.map(PatRangeBound::into_expr), + })) } else { match limits { RangeLimits::HalfOpen(dot2_token) => Ok(Pat::Rest(PatRest { @@ -594,26 +602,34 @@ pub mod parsing { } } - fn pat_tuple(input: ParseStream) -> Result<PatTuple> { + fn pat_paren_or_tuple(input: ParseStream) -> Result<Pat> { let content; let paren_token = parenthesized!(content in input); let mut elems = Punctuated::new(); while !content.is_empty() { - let value = multi_pat_with_leading_vert(&content)?; - elems.push_value(value); + let value = Pat::parse_multi_with_leading_vert(&content)?; if content.is_empty() { + if elems.is_empty() && !matches!(value, Pat::Rest(_)) { + return Ok(Pat::Paren(PatParen { + attrs: Vec::new(), + paren_token, + pat: Box::new(value), + })); + } + elems.push_value(value); break; } + elems.push_value(value); let punct = content.parse()?; elems.push_punct(punct); } - Ok(PatTuple { + Ok(Pat::Tuple(PatTuple { attrs: Vec::new(), paren_token, elems, - }) + })) } fn pat_reference(input: ParseStream) -> Result<PatReference> { @@ -621,52 +637,69 @@ pub mod parsing { attrs: Vec::new(), and_token: input.parse()?, mutability: input.parse()?, - pat: input.parse()?, + pat: Box::new(Pat::parse_single(input)?), }) } fn pat_lit_or_range(input: ParseStream) -> Result<Pat> { - let begin = input.fork(); - let lo = input.call(pat_lit_expr)?.unwrap(); + let start = input.call(pat_range_bound)?.unwrap(); if input.peek(Token![..]) { - let limits: RangeLimits = input.parse()?; - let hi = input.call(pat_lit_expr)?; - if let Some(hi) = hi { - Ok(Pat::Range(PatRange { - attrs: Vec::new(), - lo, - limits, - hi, - })) - } else { - Ok(Pat::Verbatim(verbatim::between(begin, input))) + let limits = RangeLimits::parse_obsolete(input)?; + let end = input.call(pat_range_bound)?; + if let (RangeLimits::Closed(_), None) = (&limits, &end) { + return Err(input.error("expected range upper bound")); } - } else if let Expr::Verbatim(verbatim) = *lo { - Ok(Pat::Verbatim(verbatim)) - } else { - Ok(Pat::Lit(PatLit { + Ok(Pat::Range(ExprRange { attrs: Vec::new(), - expr: lo, + start: Some(start.into_expr()), + limits, + end: end.map(PatRangeBound::into_expr), })) + } else { + Ok(start.into_pat()) } } - fn pat_lit_expr(input: ParseStream) -> Result<Option<Box<Expr>>> { + // Patterns that can appear on either side of a range pattern. + enum PatRangeBound { + Const(ExprConst), + Lit(ExprLit), + Path(ExprPath), + } + + impl PatRangeBound { + fn into_expr(self) -> Box<Expr> { + Box::new(match self { + PatRangeBound::Const(pat) => Expr::Const(pat), + PatRangeBound::Lit(pat) => Expr::Lit(pat), + PatRangeBound::Path(pat) => Expr::Path(pat), + }) + } + + fn into_pat(self) -> Pat { + match self { + PatRangeBound::Const(pat) => Pat::Const(pat), + PatRangeBound::Lit(pat) => Pat::Lit(pat), + PatRangeBound::Path(pat) => Pat::Path(pat), + } + } + } + + fn pat_range_bound(input: ParseStream) -> Result<Option<PatRangeBound>> { if input.is_empty() || input.peek(Token![|]) || input.peek(Token![=]) || input.peek(Token![:]) && !input.peek(Token![::]) || input.peek(Token![,]) || input.peek(Token![;]) + || input.peek(Token![if]) { return Ok(None); } - let neg: Option<Token![-]> = input.parse()?; - let lookahead = input.lookahead1(); let expr = if lookahead.peek(Lit) { - Expr::Lit(input.parse()?) + PatRangeBound::Lit(input.parse()?) } else if lookahead.peek(Ident) || lookahead.peek(Token![::]) || lookahead.peek(Token![<]) @@ -675,22 +708,14 @@ pub mod parsing { || lookahead.peek(Token![super]) || lookahead.peek(Token![crate]) { - Expr::Path(input.parse()?) + PatRangeBound::Path(input.parse()?) } else if lookahead.peek(Token![const]) { - Expr::Verbatim(input.call(expr::parsing::expr_const)?) + PatRangeBound::Const(input.parse()?) } else { return Err(lookahead.error()); }; - Ok(Some(Box::new(if let Some(neg) = neg { - Expr::Unary(ExprUnary { - attrs: Vec::new(), - op: UnOp::Neg(neg), - expr: Box::new(expr), - }) - } else { - expr - }))) + Ok(Some(expr)) } fn pat_slice(input: ParseStream) -> Result<PatSlice> { @@ -699,7 +724,20 @@ pub mod parsing { let mut elems = Punctuated::new(); while !content.is_empty() { - let value = multi_pat_with_leading_vert(&content)?; + let value = Pat::parse_multi_with_leading_vert(&content)?; + match value { + Pat::Range(pat) if pat.start.is_none() || pat.end.is_none() => { + let (start, end) = match pat.limits { + RangeLimits::HalfOpen(dot_dot) => (dot_dot.spans[0], dot_dot.spans[1]), + RangeLimits::Closed(dot_dot_eq) => { + (dot_dot_eq.spans[0], dot_dot_eq.spans[2]) + } + }; + let msg = "range pattern is not allowed unparenthesized inside slice pattern"; + return Err(error::new2(start, end, msg)); + } + _ => {} + } elems.push_value(value); if content.is_empty() { break; @@ -726,37 +764,6 @@ pub mod parsing { Ok(verbatim::between(begin, input)) } - - pub fn multi_pat(input: ParseStream) -> Result<Pat> { - multi_pat_impl(input, None) - } - - pub fn multi_pat_with_leading_vert(input: ParseStream) -> Result<Pat> { - let leading_vert: Option<Token![|]> = input.parse()?; - multi_pat_impl(input, leading_vert) - } - - fn multi_pat_impl(input: ParseStream, leading_vert: Option<Token![|]>) -> Result<Pat> { - let mut pat: Pat = input.parse()?; - if leading_vert.is_some() - || input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=]) - { - let mut cases = Punctuated::new(); - cases.push_value(pat); - while input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=]) { - let punct = input.parse()?; - cases.push_punct(punct); - let pat: Pat = input.parse()?; - cases.push_value(pat); - } - pat = Pat::Or(PatOr { - attrs: Vec::new(), - leading_vert, - cases, - }); - } - Ok(pat) - } } #[cfg(feature = "printing")] @@ -767,14 +774,6 @@ mod printing { use quote::{ToTokens, TokenStreamExt}; #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] - impl ToTokens for PatWild { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.underscore_token.to_tokens(tokens); - } - } - - #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] impl ToTokens for PatIdent { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append_all(self.attrs.outer()); @@ -789,127 +788,104 @@ mod printing { } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] - impl ToTokens for PatStruct { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.path.to_tokens(tokens); - self.brace_token.surround(tokens, |tokens| { - self.fields.to_tokens(tokens); - // NOTE: We need a comma before the dot2 token if it is present. - if !self.fields.empty_or_trailing() && self.dot2_token.is_some() { - <Token![,]>::default().to_tokens(tokens); - } - self.dot2_token.to_tokens(tokens); - }); - } - } - - #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] - impl ToTokens for PatTupleStruct { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.path.to_tokens(tokens); - self.pat.to_tokens(tokens); - } - } - - #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] - impl ToTokens for PatType { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.pat.to_tokens(tokens); - self.colon_token.to_tokens(tokens); - self.ty.to_tokens(tokens); - } - } - - #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] - impl ToTokens for PatPath { + impl ToTokens for PatOr { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append_all(self.attrs.outer()); - path::printing::print_path(tokens, &self.qself, &self.path); + self.leading_vert.to_tokens(tokens); + self.cases.to_tokens(tokens); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] - impl ToTokens for PatTuple { + impl ToTokens for PatParen { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append_all(self.attrs.outer()); self.paren_token.surround(tokens, |tokens| { - self.elems.to_tokens(tokens); + self.pat.to_tokens(tokens); }); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] - impl ToTokens for PatBox { + impl ToTokens for PatReference { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append_all(self.attrs.outer()); - self.box_token.to_tokens(tokens); + self.and_token.to_tokens(tokens); + self.mutability.to_tokens(tokens); self.pat.to_tokens(tokens); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] - impl ToTokens for PatReference { + impl ToTokens for PatRest { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append_all(self.attrs.outer()); - self.and_token.to_tokens(tokens); - self.mutability.to_tokens(tokens); - self.pat.to_tokens(tokens); + self.dot2_token.to_tokens(tokens); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] - impl ToTokens for PatRest { + impl ToTokens for PatSlice { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append_all(self.attrs.outer()); - self.dot2_token.to_tokens(tokens); + self.bracket_token.surround(tokens, |tokens| { + self.elems.to_tokens(tokens); + }); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] - impl ToTokens for PatLit { + impl ToTokens for PatStruct { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append_all(self.attrs.outer()); - self.expr.to_tokens(tokens); + path::printing::print_path(tokens, &self.qself, &self.path); + self.brace_token.surround(tokens, |tokens| { + self.fields.to_tokens(tokens); + // NOTE: We need a comma before the dot2 token if it is present. + if !self.fields.empty_or_trailing() && self.rest.is_some() { + <Token![,]>::default().to_tokens(tokens); + } + self.rest.to_tokens(tokens); + }); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] - impl ToTokens for PatRange { + impl ToTokens for PatTuple { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append_all(self.attrs.outer()); - self.lo.to_tokens(tokens); - self.limits.to_tokens(tokens); - self.hi.to_tokens(tokens); + self.paren_token.surround(tokens, |tokens| { + self.elems.to_tokens(tokens); + }); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] - impl ToTokens for PatSlice { + impl ToTokens for PatTupleStruct { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append_all(self.attrs.outer()); - self.bracket_token.surround(tokens, |tokens| { + path::printing::print_path(tokens, &self.qself, &self.path); + self.paren_token.surround(tokens, |tokens| { self.elems.to_tokens(tokens); }); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] - impl ToTokens for PatMacro { + impl ToTokens for PatType { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append_all(self.attrs.outer()); - self.mac.to_tokens(tokens); + self.pat.to_tokens(tokens); + self.colon_token.to_tokens(tokens); + self.ty.to_tokens(tokens); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] - impl ToTokens for PatOr { + impl ToTokens for PatWild { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append_all(self.attrs.outer()); - self.leading_vert.to_tokens(tokens); - self.cases.to_tokens(tokens); + self.underscore_token.to_tokens(tokens); } } |