use super::*; use crate::punctuated::Punctuated; use proc_macro2::TokenStream; ast_enum_of_structs! { /// The possible types that a Rust value could have. /// /// # 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"))))] #[non_exhaustive] 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 `dyn 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), // For testing exhaustiveness in downstream code, use the following idiom: // // match ty { // Type::Array(ty) => {...} // Type::BareFn(ty) => {...} // ... // Type::Verbatim(ty) => {...} // // #[cfg_attr(test, deny(non_exhaustive_omitted_patterns))] // _ => { /* 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 fixed size array type: `[T; n]`. #[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`. #[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. #[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. #[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: `_`. #[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. #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeMacro { pub mac: Macro, } } ast_struct! { /// The never type: `!`. #[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. #[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`. #[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`. #[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`. #[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]`. #[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 `dyn Bound1 + Bound2 + Bound3` where `Bound` is a /// trait or a lifetime. #[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)`. #[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"`. #[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`. #[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 function pointer like `fn(usize, ...)`. #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct BareVariadic { pub attrs: Vec, pub name: Option<(Ident, Token![:])>, pub dots: Token![...], pub comma: Option, } } ast_enum! { /// Return type of a function signature. #[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(crate) mod parsing { use super::*; use crate::ext::IdentExt; use crate::parse::{Parse, ParseStream, Result}; use crate::path; use proc_macro2::Span; #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for Type { fn parse(input: ParseStream) -> Result { let allow_plus = true; let allow_group_generic = true; ambig_ty(input, allow_plus, allow_group_generic) } } 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; let allow_group_generic = true; ambig_ty(input, allow_plus, allow_group_generic) } } pub(crate) fn ambig_ty( input: ParseStream, allow_plus: bool, allow_group_generic: 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![<]) && allow_group_generic || 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 arguments.is_none() { *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]) || input.peek(Token![dyn]) { 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(_) | TypeParamBound::Verbatim(_)) => 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 mut bare_fn: TypeBareFn = input.parse()?; bare_fn.lifetimes = lifetimes; Ok(Type::BareFn(bare_fn)) } 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![<]) { let ty: TypePath = input.parse()?; if ty.qself.is_some() { return Ok(Type::Path(ty)); } if input.peek(Token![!]) && !input.peek(Token![!=]) && ty.path.is_mod_style() { 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(Ident::peek_any) || input.peek(Token![::]) || input.peek(Token![?]) || input.peek(Lifetime) || input.peek(token::Paren)) { break; } bounds.push_value(input.parse()?); } } return Ok(Type::TraitObject(TypeTraitObject { dyn_token: None, bounds, })); } Ok(Type::Path(ty)) } else if lookahead.peek(Token![dyn]) { let dyn_token: Token![dyn] = input.parse()?; let dyn_span = dyn_token.span; let star_token: Option = input.parse()?; let bounds = TypeTraitObject::parse_bounds(dyn_span, input, allow_plus)?; return Ok(if star_token.is_some() { Type::Verbatim(verbatim::between(&begin, input)) } else { Type::TraitObject(TypeTraitObject { dyn_token: Some(dyn_token), bounds, }) }); } 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]) { TypeImplTrait::parse(input, allow_plus).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 args; let mut variadic = None; Ok(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![...]) || args.peek(Ident) && args.peek2(Token![:]) && args.peek3(Token![...])) { variadic = Some(parse_bare_variadic(&args, attrs)?); break; } let allow_self = inputs.is_empty(); let arg = parse_bare_fn_arg(&args, allow_self)?; inputs.push_value(BareFnArg { attrs, ..arg }); if args.is_empty() { break; } let comma = args.parse()?; inputs.push_punct(comma); } inputs }, variadic, output: input.call(ReturnType::without_plus)?, }) } } #[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 expr_style = false; let (qself, path) = path::parsing::qpath(input, expr_style)?; Ok(TypePath { qself, path }) } } impl ReturnType { #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] pub fn without_plus(input: ParseStream) -> Result { let allow_plus = false; Self::parse(input, allow_plus) } pub(crate) fn parse(input: ParseStream, allow_plus: bool) -> Result { if input.peek(Token![->]) { let arrow = input.parse()?; let allow_group_generic = true; let ty = ambig_ty(input, allow_plus, allow_group_generic)?; 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 { let allow_plus = true; Self::parse(input, allow_plus) } } #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for TypeTraitObject { fn parse(input: ParseStream) -> Result { let allow_plus = true; Self::parse(input, allow_plus) } } impl TypeTraitObject { #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 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. pub(crate) fn parse(input: ParseStream, allow_plus: bool) -> Result { let dyn_token: Option = input.parse()?; let dyn_span = match &dyn_token { Some(token) => token.span, None => input.span(), }; let bounds = Self::parse_bounds(dyn_span, input, allow_plus)?; Ok(TypeTraitObject { dyn_token, bounds }) } fn parse_bounds( dyn_span: Span, input: ParseStream, allow_plus: bool, ) -> Result> { let bounds = TypeParamBound::parse_multiple(input, allow_plus)?; let mut last_lifetime_span = None; let mut at_least_one_trait = false; for bound in &bounds { match bound { TypeParamBound::Trait(_) | TypeParamBound::Verbatim(_) => { at_least_one_trait = true; break; } TypeParamBound::Lifetime(lifetime) => { last_lifetime_span = Some(lifetime.ident.span()); } } } // Just lifetimes like `'a + 'b` is not a TraitObject. if !at_least_one_trait { let msg = "at least one trait is required for an object type"; return Err(error::new2(dyn_span, last_lifetime_span.unwrap(), msg)); } Ok(bounds) } } #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for TypeImplTrait { fn parse(input: ParseStream) -> Result { let allow_plus = true; Self::parse(input, allow_plus) } } impl TypeImplTrait { #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] pub fn without_plus(input: ParseStream) -> Result { let allow_plus = false; Self::parse(input, allow_plus) } pub(crate) fn parse(input: ParseStream, allow_plus: bool) -> Result { let impl_token: Token![impl] = input.parse()?; let bounds = TypeParamBound::parse_multiple(input, allow_plus)?; let mut last_lifetime_span = None; let mut at_least_one_trait = false; for bound in &bounds { match bound { TypeParamBound::Trait(_) | TypeParamBound::Verbatim(_) => { at_least_one_trait = true; break; } TypeParamBound::Lifetime(lifetime) => { last_lifetime_span = Some(lifetime.ident.span()); } } } if !at_least_one_trait { let msg = "at least one trait must be specified"; return Err(error::new2( impl_token.span, last_lifetime_span.unwrap(), msg, )); } Ok(TypeImplTrait { impl_token, 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({ let allow_group_generic = true; ambig_ty(&content, allow_plus, allow_group_generic)? }), }) } } #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for BareFnArg { fn parse(input: ParseStream) -> Result { let allow_self = false; parse_bare_fn_arg(input, allow_self) } } fn parse_bare_fn_arg(input: ParseStream, allow_self: bool) -> Result { let attrs = input.call(Attribute::parse_outer)?; let begin = input.fork(); let has_mut_self = allow_self && input.peek(Token![mut]) && input.peek2(Token![self]); if has_mut_self { input.parse::()?; } let mut has_self = false; let mut name = if (input.peek(Ident) || input.peek(Token![_]) || { has_self = allow_self && input.peek(Token![self]); has_self }) && input.peek2(Token![:]) && !input.peek2(Token![::]) { let name = input.call(Ident::parse_any)?; let colon: Token![:] = input.parse()?; Some((name, colon)) } else { has_self = false; None }; let ty = if allow_self && !has_self && input.peek(Token![mut]) && input.peek2(Token![self]) { input.parse::()?; input.parse::()?; None } else if has_mut_self && name.is_none() { input.parse::()?; None } else { Some(input.parse()?) }; let ty = match ty { Some(ty) if !has_mut_self => ty, _ => { name = None; Type::Verbatim(verbatim::between(&begin, input)) } }; Ok(BareFnArg { attrs, name, ty }) } fn parse_bare_variadic(input: ParseStream, attrs: Vec) -> Result { Ok(BareVariadic { attrs, name: if input.peek(Ident) || input.peek(Token![_]) { let name = input.call(Ident::parse_any)?; let colon: Token![:] = input.parse()?; Some((name, colon)) } else { None }, dots: input.parse()?, comma: input.parse()?, }) } #[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); // If we only have one argument, we need a trailing comma to // distinguish TypeTuple from TypeParen. if self.elems.len() == 1 && !self.elems.trailing_punct() { ::default().to_tokens(tokens); } }); } } #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] impl ToTokens for TypePath { fn to_tokens(&self, tokens: &mut TokenStream) { path::printing::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 BareVariadic { 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.dots.to_tokens(tokens); self.comma.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); } } }