// SPDX-License-Identifier: Apache-2.0 OR MIT use crate::attr::Attribute;use crate::expr::Expr;use crate::generics::{BoundLifetimes, TypeParamBound};use crate::ident::Ident;use crate::lifetime::Lifetime;use crate::lit::LitStr;use crate::mac::Macro;use crate::path::{Path, QSelf};use crate::punctuated::Punctuated;use crate::token;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]: crate::expr::Expr#syntax-tree-enums #[cfg_attr(docsrs, 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 `<Vec<T> 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 { // #![cfg_attr(test, deny(non_exhaustive_omitted_patterns))] // // Type::Array(ty) => {...} // Type::BareFn(ty) => {...} // ... // Type::Verbatim(ty) => {...} // // _ => { /* 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(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeArray { pub bracket_token: token::Bracket, pub elem: Box<Type>, pub semi_token: Token![;], pub len: Expr, }} ast_struct! { /// A bare function type: `fn(usize) -> bool`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeBareFn { pub lifetimes: Option<BoundLifetimes>, pub unsafety: Option<Token![unsafe]>, pub abi: Option<Abi>, pub fn_token: Token![fn], pub paren_token: token::Paren, pub inputs: Punctuated<BareFnArg, Token![,]>, pub variadic: Option<BareVariadic>, pub output: ReturnType, }} ast_struct! { /// A type contained within invisible delimiters. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeGroup { pub group_token: token::Group, pub elem: Box<Type>, }} ast_struct! { /// An `impl Bound1 + Bound2 + Bound3` type where `Bound` is a trait or /// a lifetime. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeImplTrait { pub impl_token: Token![impl], pub bounds: Punctuated<TypeParamBound, Token![+]>, }} ast_struct! { /// Indication that a type should be inferred by the compiler: `_`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeInfer { pub underscore_token: Token![_], }} ast_struct! { /// A macro in the type position. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeMacro { pub mac: Macro, }} ast_struct! { /// The never type: `!`. #[cfg_attr(docsrs, 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(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeParen { pub paren_token: token::Paren, pub elem: Box<Type>, }} ast_struct! { /// A path like `std::slice::Iter`, optionally qualified with a /// self-type as in `<Vec<T> as SomeTrait>::Associated`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypePath { pub qself: Option<QSelf>, pub path: Path, }} ast_struct! { /// A raw pointer type: `*const T` or `*mut T`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypePtr { pub star_token: Token![*], pub const_token: Option<Token![const]>, pub mutability: Option<Token![mut]>, pub elem: Box<Type>, }} ast_struct! { /// A reference type: `&'a T` or `&'a mut T`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeReference { pub and_token: Token![&], pub lifetime: Option<Lifetime>, pub mutability: Option<Token![mut]>, pub elem: Box<Type>, }} ast_struct! { /// A dynamically sized slice type: `[T]`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeSlice { pub bracket_token: token::Bracket, pub elem: Box<Type>, }} ast_struct! { /// A trait object type `dyn Bound1 + Bound2 + Bound3` where `Bound` is a /// trait or a lifetime. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeTraitObject { pub dyn_token: Option<Token![dyn]>, pub bounds: Punctuated<TypeParamBound, Token![+]>, }} ast_struct! { /// A tuple type: `(A, B, C, String)`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeTuple { pub paren_token: token::Paren, pub elems: Punctuated<Type, Token![,]>, }} ast_struct! { /// The binary interface of a function: `extern "C"`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct Abi { pub extern_token: Token![extern], pub name: Option<LitStr>, }} ast_struct! { /// An argument in a function type: the `usize` in `fn(usize) -> bool`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct BareFnArg { pub attrs: Vec<Attribute>, pub name: Option<(Ident, Token![:])>, pub ty: Type, }} ast_struct! { /// The variadic argument of a function pointer like `fn(usize, ...)`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct BareVariadic { pub attrs: Vec<Attribute>, pub name: Option<(Ident, Token![:])>, pub dots: Token![...], pub comma: Option<Token![,]>, }} ast_enum! { /// Return type of a function signature. #[cfg_attr(docsrs, 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<Type>), }} #[cfg(feature = "parsing")]pub(crate) mod parsing { use crate::attr::Attribute; use crate::error::{self, Result}; use crate::ext::IdentExt as _; use crate::generics::{BoundLifetimes, TraitBound, TraitBoundModifier, TypeParamBound}; use crate::ident::Ident; use crate::lifetime::Lifetime; use crate::mac::{self, Macro}; use crate::parse::{Parse, ParseStream}; use crate::path; use crate::path::{Path, PathArguments, QSelf}; use crate::punctuated::Punctuated; use crate::token; use crate::ty::{ Abi, BareFnArg, BareVariadic, ReturnType, Type, TypeArray, TypeBareFn, TypeGroup, TypeImplTrait, TypeInfer, TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference, TypeSlice, TypeTraitObject, TypeTuple, }; use crate::verbatim; use proc_macro2::Span; #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] impl Parse for Type { fn parse(input: ParseStream) -> Result<Self> { 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(docsrs, doc(cfg(feature = "parsing")))] pub fn without_plus(input: ParseStream) -> Result<Self> { 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<Type> { 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, position: 0, as_token: None, gt_token: Token, 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::<BoundLifetimes>; 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({ let allow_precise_capture = false; let allow_const = false; TypeParamBound::parse_single( input, allow_precise_capture, allow_const, )? }); } 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::PreciseCapture(_) | 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({ let allow_precise_capture = false; let allow_const = false; TypeParamBound::parse_single( input, allow_precise_capture, allow_const, )? }); } bounds }, })); } } Ok(Type::Paren(TypeParen { paren_token, elem: Box::new(first),Lines 1–500 of 1273. Load more
// SPDX-License-Identifier: Apache-2.0 OR MIT use crate::attr::Attribute; use crate::expr::Expr; use crate::generics::{BoundLifetimes, TypeParamBound}; use crate::ident::Ident; use crate::lifetime::Lifetime; use crate::lit::LitStr; use crate::mac::Macro; use crate::path::{Path, QSelf}; use crate::punctuated::Punctuated; use crate::token; 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]: crate::expr::Expr#syntax-tree-enums #[cfg_attr(docsrs, 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 `<Vec<T> 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 { // #![cfg_attr(test, deny(non_exhaustive_omitted_patterns))] // // Type::Array(ty) => {...} // Type::BareFn(ty) => {...} // ... // Type::Verbatim(ty) => {...} // // _ => { /* 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(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeArray { pub bracket_token: token::Bracket, pub elem: Box<Type>, pub semi_token: Token![;], pub len: Expr, } } ast_struct! { /// A bare function type: `fn(usize) -> bool`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeBareFn { pub lifetimes: Option<BoundLifetimes>, pub unsafety: Option<Token![unsafe]>, pub abi: Option<Abi>, pub fn_token: Token![fn], pub paren_token: token::Paren, pub inputs: Punctuated<BareFnArg, Token![,]>, pub variadic: Option<BareVariadic>, pub output: ReturnType, } } ast_struct! { /// A type contained within invisible delimiters. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeGroup { pub group_token: token::Group, pub elem: Box<Type>, } } ast_struct! { /// An `impl Bound1 + Bound2 + Bound3` type where `Bound` is a trait or /// a lifetime. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeImplTrait { pub impl_token: Token![impl], pub bounds: Punctuated<TypeParamBound, Token![+]>, } } ast_struct! { /// Indication that a type should be inferred by the compiler: `_`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeInfer { pub underscore_token: Token![_], } } ast_struct! { /// A macro in the type position. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeMacro { pub mac: Macro, } } ast_struct! { /// The never type: `!`. #[cfg_attr(docsrs, 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(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeParen { pub paren_token: token::Paren, pub elem: Box<Type>, } } ast_struct! { /// A path like `std::slice::Iter`, optionally qualified with a /// self-type as in `<Vec<T> as SomeTrait>::Associated`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypePath { pub qself: Option<QSelf>, pub path: Path, } } ast_struct! { /// A raw pointer type: `*const T` or `*mut T`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypePtr { pub star_token: Token![*], pub const_token: Option<Token![const]>, pub mutability: Option<Token![mut]>, pub elem: Box<Type>, } } ast_struct! { /// A reference type: `&'a T` or `&'a mut T`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeReference { pub and_token: Token![&], pub lifetime: Option<Lifetime>, pub mutability: Option<Token![mut]>, pub elem: Box<Type>, } } ast_struct! { /// A dynamically sized slice type: `[T]`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeSlice { pub bracket_token: token::Bracket, pub elem: Box<Type>, } } ast_struct! { /// A trait object type `dyn Bound1 + Bound2 + Bound3` where `Bound` is a /// trait or a lifetime. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeTraitObject { pub dyn_token: Option<Token![dyn]>, pub bounds: Punctuated<TypeParamBound, Token![+]>, } } ast_struct! { /// A tuple type: `(A, B, C, String)`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct TypeTuple { pub paren_token: token::Paren, pub elems: Punctuated<Type, Token![,]>, } } ast_struct! { /// The binary interface of a function: `extern "C"`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct Abi { pub extern_token: Token![extern], pub name: Option<LitStr>, } } ast_struct! { /// An argument in a function type: the `usize` in `fn(usize) -> bool`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct BareFnArg { pub attrs: Vec<Attribute>, pub name: Option<(Ident, Token![:])>, pub ty: Type, } } ast_struct! { /// The variadic argument of a function pointer like `fn(usize, ...)`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct BareVariadic { pub attrs: Vec<Attribute>, pub name: Option<(Ident, Token![:])>, pub dots: Token![...], pub comma: Option<Token![,]>, } } ast_enum! { /// Return type of a function signature. #[cfg_attr(docsrs, 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<Type>), } } #[cfg(feature = "parsing")] pub(crate) mod parsing { use crate::attr::Attribute; use crate::error::{self, Result}; use crate::ext::IdentExt as _; use crate::generics::{BoundLifetimes, TraitBound, TraitBoundModifier, TypeParamBound}; use crate::ident::Ident; use crate::lifetime::Lifetime; use crate::mac::{self, Macro}; use crate::parse::{Parse, ParseStream}; use crate::path; use crate::path::{Path, PathArguments, QSelf}; use crate::punctuated::Punctuated; use crate::token; use crate::ty::{ Abi, BareFnArg, BareVariadic, ReturnType, Type, TypeArray, TypeBareFn, TypeGroup, TypeImplTrait, TypeInfer, TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference, TypeSlice, TypeTraitObject, TypeTuple, }; use crate::verbatim; use proc_macro2::Span; #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] impl Parse for Type { fn parse(input: ParseStream) -> Result<Self> { 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(docsrs, doc(cfg(feature = "parsing")))] pub fn without_plus(input: ParseStream) -> Result<Self> { 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<Type> { 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, position: 0, as_token: None, gt_token: Token, 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::<BoundLifetimes>; 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({ let allow_precise_capture = false; let allow_const = false; TypeParamBound::parse_single( input, allow_precise_capture, allow_const, )? }); } 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::PreciseCapture(_) | 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({ let allow_precise_capture = false; let allow_const = false; TypeParamBound::parse_single( input, allow_precise_capture, allow_const, )? }); } bounds }, })); } } Ok(Type::Paren(TypeParen { paren_token, elem: Box::new(first),