957 lines · 31.3 KB · Rust
RawDownload
// SPDX-License-Identifier: Apache-2.0 OR MIT use crate::attr::Attribute;use crate::expr::Member;use crate::ident::Ident;use crate::path::{Path, QSelf};use crate::punctuated::Punctuated;use crate::token;use crate::ty::Type;use proc_macro2::TokenStream; pub use crate::expr::{    ExprConst as PatConst, ExprLit as PatLit, ExprMacro as PatMacro, ExprPath as PatPath,    ExprRange as PatRange,}; ast_enum_of_structs! {    /// A pattern in a local binding, function signature, match expression, or    /// various other places.    ///    /// # Syntax tree enum    ///    /// This type is a [syntax tree enum].    ///    /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]    #[non_exhaustive]    pub enum Pat {        /// A const block: `const { ... }`.        Const(PatConst),         /// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`.        Ident(PatIdent),         /// A literal pattern: `0`.        Lit(PatLit),         /// A macro in pattern position.        Macro(PatMacro),         /// 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.        ///        /// 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.        Path(PatPath),         /// A range pattern: `1..=2`.        Range(PatRange),         /// A reference pattern: `&mut var`.        Reference(PatReference),         /// The dots in a tuple or slice pattern: `[0, 1, ..]`.        Rest(PatRest),         /// A dynamically sized slice pattern: `[a, b, ref i @ .., y, z]`.        Slice(PatSlice),         /// A struct or struct variant pattern: `Variant { x, y, .. }`.        Struct(PatStruct),         /// A tuple pattern: `(a, b)`.        Tuple(PatTuple),         /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`.        TupleStruct(PatTupleStruct),         /// A type ascription pattern: `foo: f64`.        Type(PatType),         /// Tokens in pattern position not interpreted by Syn.        Verbatim(TokenStream),         /// A pattern that matches any value: `_`.        Wild(PatWild),         // For testing exhaustiveness in downstream code, use the following idiom:        //        //     match pat {        //         #![cfg_attr(test, deny(non_exhaustive_omitted_patterns))]        //        //         Pat::Box(pat) => {...}        //         Pat::Ident(pat) => {...}        //         ...        //         Pat::Wild(pat) => {...}        //        //         _ => { /* some sane fallback */ }        //     }        //        // This way we fail your tests but don't break your library when adding        // 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.    }} ast_struct! {    /// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`.    ///    /// It may also be a unit struct or struct variant (e.g. `None`), or a    /// constant; these cannot be distinguished syntactically.    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]    pub struct PatIdent {        pub attrs: Vec<Attribute>,        pub by_ref: Option<Token![ref]>,        pub mutability: Option<Token![mut]>,        pub ident: Ident,        pub subpat: Option<(Token![@], Box<Pat>)>,    }} ast_struct! {    /// A pattern that matches any one of a set of cases.    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]    pub struct PatOr {        pub attrs: Vec<Attribute>,        pub leading_vert: Option<Token![|]>,        pub cases: Punctuated<Pat, Token![|]>,    }} ast_struct! {    /// A parenthesized pattern: `(A | B)`.    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]    pub struct PatParen {        pub attrs: Vec<Attribute>,        pub paren_token: token::Paren,        pub pat: Box<Pat>,    }} ast_struct! {    /// A reference pattern: `&mut var`.    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]    pub struct PatReference {        pub attrs: Vec<Attribute>,        pub and_token: Token![&],        pub mutability: Option<Token![mut]>,        pub pat: Box<Pat>,    }} ast_struct! {    /// The dots in a tuple or slice pattern: `[0, 1, ..]`.    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]    pub struct PatRest {        pub attrs: Vec<Attribute>,        pub dot2_token: Token![..],    }} ast_struct! {    /// A dynamically sized slice pattern: `[a, b, ref i @ .., y, z]`.    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]    pub struct PatSlice {        pub attrs: Vec<Attribute>,        pub bracket_token: token::Bracket,        pub elems: Punctuated<Pat, Token![,]>,    }} ast_struct! {    /// A struct or struct variant pattern: `Variant { x, y, .. }`.    #[cfg_attr(docsrs, 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 rest: Option<PatRest>,    }} ast_struct! {    /// A tuple pattern: `(a, b)`.    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]    pub struct PatTuple {        pub attrs: Vec<Attribute>,        pub paren_token: token::Paren,        pub elems: Punctuated<Pat, Token![,]>,    }} ast_struct! {    /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`.    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]    pub struct PatTupleStruct {        pub attrs: Vec<Attribute>,        pub qself: Option<QSelf>,        pub path: Path,        pub paren_token: token::Paren,        pub elems: Punctuated<Pat, Token![,]>,    }} ast_struct! {    /// A type ascription pattern: `foo: f64`.    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]    pub struct PatType {        pub attrs: Vec<Attribute>,        pub pat: Box<Pat>,        pub colon_token: Token![:],        pub ty: Box<Type>,    }} ast_struct! {    /// A pattern that matches any value: `_`.    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]    pub struct PatWild {        pub attrs: Vec<Attribute>,        pub underscore_token: Token![_],    }} ast_struct! {    /// A single field in a struct pattern.    ///    /// 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.    #[cfg_attr(docsrs, doc(cfg(feature = "full")))]    pub struct FieldPat {        pub attrs: Vec<Attribute>,        pub member: Member,        pub colon_token: Option<Token![:]>,        pub pat: Box<Pat>,    }} #[cfg(feature = "parsing")]pub(crate) mod parsing {    use crate::attr::Attribute;    use crate::error::{self, Result};    use crate::expr::{        Expr, ExprConst, ExprLit, ExprMacro, ExprPath, ExprRange, Member, RangeLimits,    };    use crate::ext::IdentExt as _;    use crate::ident::Ident;    use crate::lit::Lit;    use crate::mac::{self, Macro};    use crate::parse::{Parse, ParseBuffer, ParseStream};    use crate::pat::{        FieldPat, Pat, PatIdent, PatOr, PatParen, PatReference, PatRest, PatSlice, PatStruct,        PatTuple, PatTupleStruct, PatType, PatWild,    };    use crate::path::{self, Path, QSelf};    use crate::punctuated::Punctuated;    use crate::stmt::Block;    use crate::token;    use crate::verbatim;    use proc_macro2::TokenStream;     #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]    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 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])                || input.peek(Token![crate])            {                pat_path_or_macro_or_struct_or_range(input)            } else if lookahead.peek(Token![_]) {                input.call(pat_wild).map(Pat::Wild)            } else if input.peek(Token![box]) {                pat_box(begin, input)            } else if input.peek(Token![-]) || lookahead.peek(Lit) || lookahead.peek(Token![const])            {                pat_lit_or_range(input)            } else if lookahead.peek(Token![ref])                || lookahead.peek(Token![mut])                || input.peek(Token![self])                || input.peek(Ident)            {                input.call(pat_ident).map(Pat::Ident)            } else if lookahead.peek(Token![&]) {                input.call(pat_reference).map(Pat::Reference)            } else if lookahead.peek(token::Paren) {                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)            } 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)        }    }     #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]    impl Parse for PatType {        fn parse(input: ParseStream) -> Result<Self> {            Ok(PatType {                attrs: Vec::new(),                pat: Box::new(Pat::parse_single(input)?),                colon_token: input.parse()?,                ty: input.parse()?,            })        }    }     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 expr_style = true;        let (qself, path) = path::parsing::qpath(input, expr_style)?;         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) {            pat_struct(input, qself, path).map(Pat::Struct)        } else if input.peek(token::Paren) {            pat_tuple_struct(input, qself, path).map(Pat::TupleStruct)        } else if input.peek(Token![..]) {            pat_range(input, qself, path)        } else {            Ok(Pat::Path(ExprPath {                attrs: Vec::new(),                qself,                path,            }))        }    }     fn pat_wild(input: ParseStream) -> Result<PatWild> {        Ok(PatWild {            attrs: Vec::new(),            underscore_token: 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> {        Ok(PatIdent {            attrs: Vec::new(),            by_ref: input.parse()?,            mutability: input.parse()?,            ident: {                if input.peek(Token![self]) {                    input.call(Ident::parse_any)?                } else {                    input.parse()?                }            },            subpat: {                if input.peek(Token![@]) {                    let at_token: Token![@] = input.parse()?;                    let subpat = Pat::parse_single(input)?;                    Some((at_token, Box::new(subpat)))                } else {                    None                }            },        })    }     fn pat_tuple_struct(        input: ParseStream,        qself: Option<QSelf>,        path: Path,    ) -> Result<PatTupleStruct> {        let content;

Lines 1–500 of 957.