use super::*; use crate::punctuated::Punctuated; use proc_macro2::TokenStream; ast_enum_of_structs! { /// The possible types that a Rust value could have. /// /// *This type is available only if Syn is built with the `"derive"` or `"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(any(feature = "full", feature = "derive"))))] pub enum Type { /// A fixed size array type: `[T; n]`. Array(TypeArray), /// A bare function type: `fn(usize) -> bool`. BareFn(TypeBareFn), /// A type contained within invisible delimiters. Group(TypeGroup), /// An `impl Bound1 + Bound2 + Bound3` type where `Bound` is a trait or /// a lifetime. ImplTrait(TypeImplTrait), /// Indication that a type should be inferred by the compiler: `_`. Infer(TypeInfer), /// A macro in the type position. Macro(TypeMacro), /// The never type: `!`. Never(TypeNever), /// A parenthesized type equivalent to the inner type. Paren(TypeParen), /// A path like `std::slice::Iter`, optionally qualified with a /// self-type as in ` as SomeTrait>::Associated`. Path(TypePath), /// A raw pointer type: `*const T` or `*mut T`. Ptr(TypePtr), /// A reference type: `&'a T` or `&'a mut T`. Reference(TypeReference), /// A dynamically sized slice type: `[T]`. Slice(TypeSlice), /// A trait object type `Bound1 + Bound2 + Bound3` where `Bound` is a /// trait or a lifetime. TraitObject(TypeTraitObject), /// A tuple type: `(A, B, C, String)`. Tuple(TypeTuple), /// Tokens in type position not interpreted by Syn. Verbatim(TokenStream), // The following is the only supported idiom for exhaustive matching of // this enum. // // match expr { // Type::Array(e) => {...} // Type::BareFn(e) => {...} // ... // Type::Verbatim(e) => {...} // // #[cfg(test)] // Type::__TestExhaustive(_) => unimplemented!(), // #[cfg(not(test))] // _ => { /* 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. // // Once `deny(reachable)` is available in rustc, Type will be // reimplemented as a non_exhaustive enum. // https://github.com/rust-lang/rust/issues/44109#issuecomment-521781237 #[doc(hidden)] __TestExhaustive(crate::private), } } ast_struct! { /// A fixed size array type: `[T; n]`. /// /// *This type is available only if Syn is built with the `"derive"` or /// `"full"` feature.* #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeArray { pub bracket_token: token::Bracket, pub elem: Box, pub semi_token: Token![;], pub len: Expr, } } ast_struct! { /// A bare function type: `fn(usize) -> bool`. /// /// *This type is available only if Syn is built with the `"derive"` or /// `"full"` feature.* #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeBareFn { pub lifetimes: Option, pub unsafety: Option, pub abi: Option, pub fn_token: Token![fn], pub paren_token: token::Paren, pub inputs: Punctuated, pub variadic: Option, pub output: ReturnType, } } ast_struct! { /// A type contained within invisible delimiters. /// /// *This type is available only if Syn is built with the `"derive"` or /// `"full"` feature.* #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeGroup { pub group_token: token::Group, pub elem: Box, } } ast_struct! { /// An `impl Bound1 + Bound2 + Bound3` type where `Bound` is a trait or /// a lifetime. /// /// *This type is available only if Syn is built with the `"derive"` or /// `"full"` feature.* #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeImplTrait { pub impl_token: Token![impl], pub bounds: Punctuated, } } ast_struct! { /// Indication that a type should be inferred by the compiler: `_`. /// /// *This type is available only if Syn is built with the `"derive"` or /// `"full"` feature.* #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeInfer { pub underscore_token: Token![_], } } ast_struct! { /// A macro in the type position. /// /// *This type is available only if Syn is built with the `"derive"` or /// `"full"` feature.* #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeMacro { pub mac: Macro, } } ast_struct! { /// The never type: `!`. /// /// *This type is available only if Syn is built with the `"derive"` or /// `"full"` feature.* #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeNever { pub bang_token: Token![!], } } ast_struct! { /// A parenthesized type equivalent to the inner type. /// /// *This type is available only if Syn is built with the `"derive"` or /// `"full"` feature.* #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeParen { pub paren_token: token::Paren, pub elem: Box, } } ast_struct! { /// A path like `std::slice::Iter`, optionally qualified with a /// self-type as in ` as SomeTrait>::Associated`. /// /// *This type is available only if Syn is built with the `"derive"` or /// `"full"` feature.* #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypePath { pub qself: Option, pub path: Path, } } ast_struct! { /// A raw pointer type: `*const T` or `*mut T`. /// /// *This type is available only if Syn is built with the `"derive"` or /// `"full"` feature.* #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypePtr { pub star_token: Token![*], pub const_token: Option, pub mutability: Option, pub elem: Box, } } ast_struct! { /// A reference type: `&'a T` or `&'a mut T`. /// /// *This type is available only if Syn is built with the `"derive"` or /// `"full"` feature.* #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeReference { pub and_token: Token![&], pub lifetime: Option, pub mutability: Option, pub elem: Box, } } ast_struct! { /// A dynamically sized slice type: `[T]`. /// /// *This type is available only if Syn is built with the `"derive"` or /// `"full"` feature.* #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeSlice { pub bracket_token: token::Bracket, pub elem: Box, } } ast_struct! { /// A trait object type `Bound1 + Bound2 + Bound3` where `Bound` is a /// trait or a lifetime. /// /// *This type is available only if Syn is built with the `"derive"` or /// `"full"` feature.* #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeTraitObject { pub dyn_token: Option, pub bounds: Punctuated, } } ast_struct! { /// A tuple type: `(A, B, C, String)`. /// /// *This type is available only if Syn is built with the `"derive"` or /// `"full"` feature.* #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeTuple { pub paren_token: token::Paren, pub elems: Punctuated, } } ast_struct! { /// The binary interface of a function: `extern "C"`. /// /// *This type is available only if Syn is built with the `"derive"` or `"full"` /// feature.* #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct Abi { pub extern_token: Token![extern], pub name: Option, } } ast_struct! { /// An argument in a function type: the `usize` in `fn(usize) -> bool`. /// /// *This type is available only if Syn is built with the `"derive"` or `"full"` /// feature.* #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct BareFnArg { pub attrs: Vec, pub name: Option<(Ident, Token![:])>, pub ty: Type, } } ast_struct! { /// The variadic argument of a foreign function. /// /// ```rust /// # struct c_char; /// # struct c_int; /// # /// extern "C" { /// fn printf(format: *const c_char, ...) -> c_int; /// // ^^^ /// } /// ``` /// /// *This type is available only if Syn is built with the `"derive"` or `"full"` /// feature.* #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct Variadic { pub attrs: Vec, pub dots: Token![...], } } ast_enum! { /// Return type of a function signature. /// /// *This type is available only if Syn is built with the `"derive"` or `"full"` /// feature.* #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub enum ReturnType { /// Return type is not specified. /// /// Functions default to `()` and closures default to type inference. Default, /// A particular type is returned. Type(Token![->], Box), } } #[cfg(feature = "parsing")] pub mod parsing { use super::*; use crate::ext::IdentExt; use crate::parse::{Parse, ParseStream, Result}; use crate::path; use proc_macro2::{Punct, Spacing, TokenTree}; use std::iter::FromIterator; #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for Type { fn parse(input: ParseStream) -> Result { let allow_plus = true; ambig_ty(input, allow_plus) } } impl Type { /// In some positions, types may not contain the `+` character, to /// disambiguate them. For example in the expression `1 as T`, T may not /// contain a `+` character. /// /// This parser does not allow a `+`, while the default parser does. #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] pub fn without_plus(input: ParseStream) -> Result { let allow_plus = false; ambig_ty(input, allow_plus) } } fn ambig_ty(input: ParseStream, allow_plus: bool) -> Result { let begin = input.fork(); if input.peek(token::Group) { let mut group: TypeGroup = input.parse()?; if input.peek(Token![::]) && input.peek3(Ident::peek_any) { if let Type::Path(mut ty) = *group.elem { Path::parse_rest(input, &mut ty.path, false)?; return Ok(Type::Path(ty)); } else { return Ok(Type::Path(TypePath { qself: Some(QSelf { lt_token: Token![<](group.group_token.span), position: 0, as_token: None, gt_token: Token![>](group.group_token.span), ty: group.elem, }), path: Path::parse_helper(input, false)?, })); } } else if input.peek(Token![<]) || input.peek(Token![::]) && input.peek3(Token![<]) { if let Type::Path(mut ty) = *group.elem { let arguments = &mut ty.path.segments.last_mut().unwrap().arguments; if let PathArguments::None = arguments { *arguments = PathArguments::AngleBracketed(input.parse()?); Path::parse_rest(input, &mut ty.path, false)?; return Ok(Type::Path(ty)); } else { group.elem = Box::new(Type::Path(ty)); } } } return Ok(Type::Group(group)); } let mut lifetimes = None::; let mut lookahead = input.lookahead1(); if lookahead.peek(Token![for]) { lifetimes = input.parse()?; lookahead = input.lookahead1(); if !lookahead.peek(Ident) && !lookahead.peek(Token![fn]) && !lookahead.peek(Token![unsafe]) && !lookahead.peek(Token![extern]) && !lookahead.peek(Token![super]) && !lookahead.peek(Token![self]) && !lookahead.peek(Token![Self]) && !lookahead.peek(Token![crate]) { return Err(lookahead.error()); } } if lookahead.peek(token::Paren) { let content; let paren_token = parenthesized!(content in input); if content.is_empty() { return Ok(Type::Tuple(TypeTuple { paren_token, elems: Punctuated::new(), })); } if content.peek(Lifetime) { return Ok(Type::Paren(TypeParen { paren_token, elem: Box::new(Type::TraitObject(content.parse()?)), })); } if content.peek(Token![?]) { return Ok(Type::TraitObject(TypeTraitObject { dyn_token: None, bounds: { let mut bounds = Punctuated::new(); bounds.push_value(TypeParamBound::Trait(TraitBound { paren_token: Some(paren_token), ..content.parse()? })); while let Some(plus) = input.parse()? { bounds.push_punct(plus); bounds.push_value(input.parse()?); } bounds }, })); } let mut first: Type = content.parse()?; if content.peek(Token![,]) { return Ok(Type::Tuple(TypeTuple { paren_token, elems: { let mut elems = Punctuated::new(); elems.push_value(first); elems.push_punct(content.parse()?); while !content.is_empty() { elems.push_value(content.parse()?); if content.is_empty() { break; } elems.push_punct(content.parse()?); } elems }, })); } if allow_plus && input.peek(Token![+]) { loop { let first = match first { Type::Path(TypePath { qself: None, path }) => { TypeParamBound::Trait(TraitBound { paren_token: Some(paren_token), modifier: TraitBoundModifier::None, lifetimes: None, path, }) } Type::TraitObject(TypeTraitObject { dyn_token: None, bounds, }) => { if bounds.len() > 1 || bounds.trailing_punct() { first = Type::TraitObject(TypeTraitObject { dyn_token: None, bounds, }); break; } match bounds.into_iter().next().unwrap() { TypeParamBound::Trait(trait_bound) => { TypeParamBound::Trait(TraitBound { paren_token: Some(paren_token), ..trait_bound }) } other @ TypeParamBound::Lifetime(_) => other, } } _ => break, }; return Ok(Type::TraitObject(TypeTraitObject { dyn_token: None, bounds: { let mut bounds = Punctuated::new(); bounds.push_value(first); while let Some(plus) = input.parse()? { bounds.push_punct(plus); bounds.push_value(input.parse()?); } bounds }, })); } } Ok(Type::Paren(TypeParen { paren_token, elem: Box::new(first), })) } else if lookahead.peek(Token![fn]) || lookahead.peek(Token![unsafe]) || lookahead.peek(Token![extern]) { let allow_mut_self = true; if let Some(mut bare_fn) = parse_bare_fn(input, allow_mut_self)? { bare_fn.lifetimes = lifetimes; Ok(Type::BareFn(bare_fn)) } else { Ok(Type::Verbatim(verbatim::between(begin, input))) } } else if lookahead.peek(Ident) || input.peek(Token![super]) || input.peek(Token![self]) || input.peek(Token![Self]) || input.peek(Token![crate]) || lookahead.peek(Token![::]) || lookahead.peek(Token![<]) { if input.peek(Token![dyn]) { let mut trait_object: TypeTraitObject = input.parse()?; if lifetimes.is_some() { match trait_object.bounds.iter_mut().next().unwrap() { TypeParamBound::Trait(trait_bound) => { trait_bound.lifetimes = lifetimes; } TypeParamBound::Lifetime(_) => unreachable!(), } } return Ok(Type::TraitObject(trait_object)); } let ty: TypePath = input.parse()?; if ty.qself.is_some() { return Ok(Type::Path(ty)); } if input.peek(Token![!]) && !input.peek(Token![!=]) { let mut contains_arguments = false; for segment in &ty.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(Type::Macro(TypeMacro { mac: Macro { path: ty.path, bang_token, delimiter, tokens, }, })); } } if lifetimes.is_some() || allow_plus && input.peek(Token![+]) { let mut bounds = Punctuated::new(); bounds.push_value(TypeParamBound::Trait(TraitBound { paren_token: None, modifier: TraitBoundModifier::None, lifetimes, path: ty.path, })); if allow_plus { while input.peek(Token![+]) { bounds.push_punct(input.parse()?); if input.peek(Token![>]) { break; } bounds.push_value(input.parse()?); } } return Ok(Type::TraitObject(TypeTraitObject { dyn_token: None, bounds, })); } Ok(Type::Path(ty)) } else if lookahead.peek(token::Bracket) { let content; let bracket_token = bracketed!(content in input); let elem: Type = content.parse()?; if content.peek(Token![;]) { Ok(Type::Array(TypeArray { bracket_token, elem: Box::new(elem), semi_token: content.parse()?, len: content.parse()?, })) } else { Ok(Type::Slice(TypeSlice { bracket_token, elem: Box::new(elem), })) } } else if lookahead.peek(Token![*]) { input.parse().map(Type::Ptr) } else if lookahead.peek(Token![&]) { input.parse().map(Type::Reference) } else if lookahead.peek(Token![!]) && !input.peek(Token![=]) { input.parse().map(Type::Never) } else if lookahead.peek(Token![impl]) { input.parse().map(Type::ImplTrait) } else if lookahead.peek(Token![_]) { input.parse().map(Type::Infer) } else if lookahead.peek(Lifetime) { input.parse().map(Type::TraitObject) } else { Err(lookahead.error()) } } #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for TypeSlice { fn parse(input: ParseStream) -> Result { let content; Ok(TypeSlice { bracket_token: bracketed!(content in input), elem: content.parse()?, }) } } #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for TypeArray { fn parse(input: ParseStream) -> Result { let content; Ok(TypeArray { bracket_token: bracketed!(content in input), elem: content.parse()?, semi_token: content.parse()?, len: content.parse()?, }) } } #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for TypePtr { fn parse(input: ParseStream) -> Result { let star_token: Token![*] = input.parse()?; let lookahead = input.lookahead1(); let (const_token, mutability) = if lookahead.peek(Token![const]) { (Some(input.parse()?), None) } else if lookahead.peek(Token![mut]) { (None, Some(input.parse()?)) } else { return Err(lookahead.error()); }; Ok(TypePtr { star_token, const_token, mutability, elem: Box::new(input.call(Type::without_plus)?), }) } } #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for TypeReference { fn parse(input: ParseStream) -> Result { Ok(TypeReference { and_token: input.parse()?, lifetime: input.parse()?, mutability: input.parse()?, // & binds tighter than +, so we don't allow + here. elem: Box::new(input.call(Type::without_plus)?), }) } } #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for TypeBareFn { fn parse(input: ParseStream) -> Result { let allow_mut_self = false; parse_bare_fn(input, allow_mut_self).map(Option::unwrap) } } fn parse_bare_fn(input: ParseStream, allow_mut_self: bool) -> Result> { let args; let mut variadic = None; let mut has_mut_self = false; let bare_fn = TypeBareFn { lifetimes: input.parse()?, unsafety: input.parse()?, abi: input.parse()?, fn_token: input.parse()?, paren_token: parenthesized!(args in input), inputs: { let mut inputs = Punctuated::new(); while !args.is_empty() { let attrs = args.call(Attribute::parse_outer)?; if inputs.empty_or_trailing() && args.peek(Token![...]) { variadic = Some(Variadic { attrs, dots: args.parse()?, }); break; } if let Some(arg) = parse_bare_fn_arg(&args, allow_mut_self)? { inputs.push_value(BareFnArg { attrs, ..arg }); } else { has_mut_self = true; } if args.is_empty() { break; } inputs.push_punct(args.parse()?); } inputs }, variadic, output: input.call(ReturnType::without_plus)?, }; if has_mut_self { Ok(None) } else { Ok(Some(bare_fn)) } } #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for TypeNever { fn parse(input: ParseStream) -> Result { Ok(TypeNever { bang_token: input.parse()?, }) } } #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for TypeInfer { fn parse(input: ParseStream) -> Result { Ok(TypeInfer { underscore_token: input.parse()?, }) } } #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for TypeTuple { fn parse(input: ParseStream) -> Result { let content; let paren_token = parenthesized!(content in input); if content.is_empty() { return Ok(TypeTuple { paren_token, elems: Punctuated::new(), }); } let first: Type = content.parse()?; Ok(TypeTuple { paren_token, elems: { let mut elems = Punctuated::new(); elems.push_value(first); elems.push_punct(content.parse()?); while !content.is_empty() { elems.push_value(content.parse()?); if content.is_empty() { break; } elems.push_punct(content.parse()?); } elems }, }) } } #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for TypeMacro { fn parse(input: ParseStream) -> Result { Ok(TypeMacro { mac: input.parse()?, }) } } #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for TypePath { fn parse(input: ParseStream) -> Result { let (qself, mut path) = path::parsing::qpath(input, false)?; if path.segments.last().unwrap().arguments.is_empty() && input.peek(token::Paren) { let args: ParenthesizedGenericArguments = input.parse()?; let parenthesized = PathArguments::Parenthesized(args); path.segments.last_mut().unwrap().arguments = parenthesized; } Ok(TypePath { qself, path }) } } impl ReturnType { pub fn without_plus(input: ParseStream) -> Result { let allow_plus = false; Self::parse(input, allow_plus) } #[doc(hidden)] pub fn parse(input: ParseStream, allow_plus: bool) -> Result { if input.peek(Token![->]) { let arrow = input.parse()?; let ty = ambig_ty(input, allow_plus)?; Ok(ReturnType::Type(arrow, Box::new(ty))) } else { Ok(ReturnType::Default) } } } #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for ReturnType { fn parse(input: ParseStream) -> Result { Self::parse(input, true) } } #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for TypeTraitObject { fn parse(input: ParseStream) -> Result { Self::parse(input, true) } } fn at_least_one_type(bounds: &Punctuated) -> bool { for bound in bounds { if let TypeParamBound::Trait(_) = *bound { return true; } } false } impl TypeTraitObject { pub fn without_plus(input: ParseStream) -> Result { let allow_plus = false; Self::parse(input, allow_plus) } // Only allow multiple trait references if allow_plus is true. #[doc(hidden)] pub fn parse(input: ParseStream, allow_plus: bool) -> Result { Ok(TypeTraitObject { dyn_token: input.parse()?, bounds: { let mut bounds = Punctuated::new(); if allow_plus { loop { bounds.push_value(input.parse()?); if !input.peek(Token![+]) { break; } bounds.push_punct(input.parse()?); if input.peek(Token![>]) { break; } } } else { bounds.push_value(input.parse()?); } // Just lifetimes like `'a + 'b` is not a TraitObject. if !at_least_one_type(&bounds) { return Err(input.error("expected at least one type")); } bounds }, }) } } #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for TypeImplTrait { fn parse(input: ParseStream) -> Result { Ok(TypeImplTrait { impl_token: input.parse()?, // NOTE: rust-lang/rust#34511 includes discussion about whether // or not + should be allowed in ImplTrait directly without (). bounds: { let mut bounds = Punctuated::new(); loop { bounds.push_value(input.parse()?); if !input.peek(Token![+]) { break; } bounds.push_punct(input.parse()?); } bounds }, }) } } #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for TypeGroup { fn parse(input: ParseStream) -> Result { let group = crate::group::parse_group(input)?; Ok(TypeGroup { group_token: group.token, elem: group.content.parse()?, }) } } #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for TypeParen { fn parse(input: ParseStream) -> Result { let allow_plus = false; Self::parse(input, allow_plus) } } impl TypeParen { fn parse(input: ParseStream, allow_plus: bool) -> Result { let content; Ok(TypeParen { paren_token: parenthesized!(content in input), elem: Box::new(ambig_ty(&content, allow_plus)?), }) } } #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for BareFnArg { fn parse(input: ParseStream) -> Result { let allow_mut_self = false; parse_bare_fn_arg(input, allow_mut_self).map(Option::unwrap) } } fn parse_bare_fn_arg( input: ParseStream, mut allow_mut_self: bool, ) -> Result> { let mut has_mut_self = false; let arg = BareFnArg { attrs: input.call(Attribute::parse_outer)?, name: { if (input.peek(Ident) || input.peek(Token![_]) || input.peek(Token![self])) && input.peek2(Token![:]) && !input.peek2(Token![::]) { let name = input.call(Ident::parse_any)?; let colon: Token![:] = input.parse()?; Some((name, colon)) } else if allow_mut_self && input.peek(Token![mut]) && input.peek2(Token![self]) && input.peek3(Token![:]) && !input.peek3(Token![::]) { has_mut_self = true; allow_mut_self = false; input.parse::()?; input.parse::()?; input.parse::()?; None } else { None } }, ty: if !has_mut_self && input.peek(Token![...]) { let dot3 = input.parse::()?; let args = vec![ TokenTree::Punct(Punct::new('.', Spacing::Joint)), TokenTree::Punct(Punct::new('.', Spacing::Joint)), TokenTree::Punct(Punct::new('.', Spacing::Alone)), ]; let tokens = TokenStream::from_iter(args.into_iter().zip(&dot3.spans).map( |(mut arg, span)| { arg.set_span(*span); arg }, )); Type::Verbatim(tokens) } else if allow_mut_self && input.peek(Token![mut]) && input.peek2(Token![self]) { has_mut_self = true; input.parse::()?; Type::Path(TypePath { qself: None, path: input.parse::()?.into(), }) } else { input.parse()? }, }; if has_mut_self { Ok(None) } else { Ok(Some(arg)) } } #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for Abi { fn parse(input: ParseStream) -> Result { Ok(Abi { extern_token: input.parse()?, name: input.parse()?, }) } } #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for Option { fn parse(input: ParseStream) -> Result { if input.peek(Token![extern]) { input.parse().map(Some) } else { Ok(None) } } } } #[cfg(feature = "printing")] mod printing { use super::*; use crate::attr::FilterAttrs; use crate::print::TokensOrDefault; use proc_macro2::TokenStream; use quote::{ToTokens, TokenStreamExt}; #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] impl ToTokens for TypeSlice { fn to_tokens(&self, tokens: &mut TokenStream) { self.bracket_token.surround(tokens, |tokens| { self.elem.to_tokens(tokens); }); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] impl ToTokens for TypeArray { fn to_tokens(&self, tokens: &mut TokenStream) { self.bracket_token.surround(tokens, |tokens| { self.elem.to_tokens(tokens); self.semi_token.to_tokens(tokens); self.len.to_tokens(tokens); }); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] impl ToTokens for TypePtr { fn to_tokens(&self, tokens: &mut TokenStream) { self.star_token.to_tokens(tokens); match &self.mutability { Some(tok) => tok.to_tokens(tokens), None => { TokensOrDefault(&self.const_token).to_tokens(tokens); } } self.elem.to_tokens(tokens); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] impl ToTokens for TypeReference { fn to_tokens(&self, tokens: &mut TokenStream) { self.and_token.to_tokens(tokens); self.lifetime.to_tokens(tokens); self.mutability.to_tokens(tokens); self.elem.to_tokens(tokens); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] impl ToTokens for TypeBareFn { fn to_tokens(&self, tokens: &mut TokenStream) { self.lifetimes.to_tokens(tokens); self.unsafety.to_tokens(tokens); self.abi.to_tokens(tokens); self.fn_token.to_tokens(tokens); self.paren_token.surround(tokens, |tokens| { self.inputs.to_tokens(tokens); if let Some(variadic) = &self.variadic { if !self.inputs.empty_or_trailing() { let span = variadic.dots.spans[0]; Token![,](span).to_tokens(tokens); } variadic.to_tokens(tokens); } }); self.output.to_tokens(tokens); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] impl ToTokens for TypeNever { fn to_tokens(&self, tokens: &mut TokenStream) { self.bang_token.to_tokens(tokens); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] impl ToTokens for TypeTuple { fn to_tokens(&self, tokens: &mut TokenStream) { self.paren_token.surround(tokens, |tokens| { self.elems.to_tokens(tokens); }); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] impl ToTokens for TypePath { fn to_tokens(&self, tokens: &mut TokenStream) { private::print_path(tokens, &self.qself, &self.path); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] impl ToTokens for TypeTraitObject { fn to_tokens(&self, tokens: &mut TokenStream) { self.dyn_token.to_tokens(tokens); self.bounds.to_tokens(tokens); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] impl ToTokens for TypeImplTrait { fn to_tokens(&self, tokens: &mut TokenStream) { self.impl_token.to_tokens(tokens); self.bounds.to_tokens(tokens); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] impl ToTokens for TypeGroup { fn to_tokens(&self, tokens: &mut TokenStream) { self.group_token.surround(tokens, |tokens| { self.elem.to_tokens(tokens); }); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] impl ToTokens for TypeParen { fn to_tokens(&self, tokens: &mut TokenStream) { self.paren_token.surround(tokens, |tokens| { self.elem.to_tokens(tokens); }); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] impl ToTokens for TypeInfer { fn to_tokens(&self, tokens: &mut TokenStream) { self.underscore_token.to_tokens(tokens); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] impl ToTokens for TypeMacro { fn to_tokens(&self, tokens: &mut TokenStream) { self.mac.to_tokens(tokens); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] impl ToTokens for ReturnType { fn to_tokens(&self, tokens: &mut TokenStream) { match self { ReturnType::Default => {} ReturnType::Type(arrow, ty) => { arrow.to_tokens(tokens); ty.to_tokens(tokens); } } } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] impl ToTokens for BareFnArg { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append_all(self.attrs.outer()); if let Some((name, colon)) = &self.name { name.to_tokens(tokens); colon.to_tokens(tokens); } self.ty.to_tokens(tokens); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] impl ToTokens for Variadic { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append_all(self.attrs.outer()); self.dots.to_tokens(tokens); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] impl ToTokens for Abi { fn to_tokens(&self, tokens: &mut TokenStream) { self.extern_token.to_tokens(tokens); self.name.to_tokens(tokens); } } }