mirror of https://github.com/torvalds/linux.git
1480 lines
50 KiB
Rust
1480 lines
50 KiB
Rust
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
|
|
use crate::attr::Attribute;
|
|
use crate::expr::Expr;
|
|
use crate::ident::Ident;
|
|
use crate::lifetime::Lifetime;
|
|
use crate::path::Path;
|
|
use crate::punctuated::{Iter, IterMut, Punctuated};
|
|
use crate::token;
|
|
use crate::ty::Type;
|
|
use proc_macro2::TokenStream;
|
|
#[cfg(all(feature = "printing", feature = "extra-traits"))]
|
|
use std::fmt::{self, Debug};
|
|
#[cfg(all(feature = "printing", feature = "extra-traits"))]
|
|
use std::hash::{Hash, Hasher};
|
|
|
|
ast_struct! {
|
|
/// Lifetimes and type parameters attached to a declaration of a function,
|
|
/// enum, trait, etc.
|
|
///
|
|
/// This struct represents two distinct optional syntactic elements,
|
|
/// [generic parameters] and [where clause]. In some locations of the
|
|
/// grammar, there may be other tokens in between these two things.
|
|
///
|
|
/// [generic parameters]: https://doc.rust-lang.org/stable/reference/items/generics.html#generic-parameters
|
|
/// [where clause]: https://doc.rust-lang.org/stable/reference/items/generics.html#where-clauses
|
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
|
pub struct Generics {
|
|
pub lt_token: Option<Token![<]>,
|
|
pub params: Punctuated<GenericParam, Token![,]>,
|
|
pub gt_token: Option<Token![>]>,
|
|
pub where_clause: Option<WhereClause>,
|
|
}
|
|
}
|
|
|
|
ast_enum_of_structs! {
|
|
/// A generic type parameter, lifetime, or const generic: `T: Into<String>`,
|
|
/// `'a: 'b`, `const LEN: usize`.
|
|
///
|
|
/// # 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"))))]
|
|
pub enum GenericParam {
|
|
/// A lifetime parameter: `'a: 'b + 'c + 'd`.
|
|
Lifetime(LifetimeParam),
|
|
|
|
/// A generic type parameter: `T: Into<String>`.
|
|
Type(TypeParam),
|
|
|
|
/// A const generic parameter: `const LENGTH: usize`.
|
|
Const(ConstParam),
|
|
}
|
|
}
|
|
|
|
ast_struct! {
|
|
/// A lifetime definition: `'a: 'b + 'c + 'd`.
|
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
|
pub struct LifetimeParam {
|
|
pub attrs: Vec<Attribute>,
|
|
pub lifetime: Lifetime,
|
|
pub colon_token: Option<Token![:]>,
|
|
pub bounds: Punctuated<Lifetime, Token![+]>,
|
|
}
|
|
}
|
|
|
|
ast_struct! {
|
|
/// A generic type parameter: `T: Into<String>`.
|
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
|
pub struct TypeParam {
|
|
pub attrs: Vec<Attribute>,
|
|
pub ident: Ident,
|
|
pub colon_token: Option<Token![:]>,
|
|
pub bounds: Punctuated<TypeParamBound, Token![+]>,
|
|
pub eq_token: Option<Token![=]>,
|
|
pub default: Option<Type>,
|
|
}
|
|
}
|
|
|
|
ast_struct! {
|
|
/// A const generic parameter: `const LENGTH: usize`.
|
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
|
pub struct ConstParam {
|
|
pub attrs: Vec<Attribute>,
|
|
pub const_token: Token![const],
|
|
pub ident: Ident,
|
|
pub colon_token: Token![:],
|
|
pub ty: Type,
|
|
pub eq_token: Option<Token![=]>,
|
|
pub default: Option<Expr>,
|
|
}
|
|
}
|
|
|
|
impl Default for Generics {
|
|
fn default() -> Self {
|
|
Generics {
|
|
lt_token: None,
|
|
params: Punctuated::new(),
|
|
gt_token: None,
|
|
where_clause: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Generics {
|
|
return_impl_trait! {
|
|
/// Iterator over the lifetime parameters in `self.params`.
|
|
pub fn lifetimes(&self) -> impl Iterator<Item = &LifetimeParam> [Lifetimes] {
|
|
Lifetimes(self.params.iter())
|
|
}
|
|
}
|
|
|
|
return_impl_trait! {
|
|
/// Iterator over the lifetime parameters in `self.params`.
|
|
pub fn lifetimes_mut(&mut self) -> impl Iterator<Item = &mut LifetimeParam> [LifetimesMut] {
|
|
LifetimesMut(self.params.iter_mut())
|
|
}
|
|
}
|
|
|
|
return_impl_trait! {
|
|
/// Iterator over the type parameters in `self.params`.
|
|
pub fn type_params(&self) -> impl Iterator<Item = &TypeParam> [TypeParams] {
|
|
TypeParams(self.params.iter())
|
|
}
|
|
}
|
|
|
|
return_impl_trait! {
|
|
/// Iterator over the type parameters in `self.params`.
|
|
pub fn type_params_mut(&mut self) -> impl Iterator<Item = &mut TypeParam> [TypeParamsMut] {
|
|
TypeParamsMut(self.params.iter_mut())
|
|
}
|
|
}
|
|
|
|
return_impl_trait! {
|
|
/// Iterator over the constant parameters in `self.params`.
|
|
pub fn const_params(&self) -> impl Iterator<Item = &ConstParam> [ConstParams] {
|
|
ConstParams(self.params.iter())
|
|
}
|
|
}
|
|
|
|
return_impl_trait! {
|
|
/// Iterator over the constant parameters in `self.params`.
|
|
pub fn const_params_mut(&mut self) -> impl Iterator<Item = &mut ConstParam> [ConstParamsMut] {
|
|
ConstParamsMut(self.params.iter_mut())
|
|
}
|
|
}
|
|
|
|
/// Initializes an empty `where`-clause if there is not one present already.
|
|
pub fn make_where_clause(&mut self) -> &mut WhereClause {
|
|
self.where_clause.get_or_insert_with(|| WhereClause {
|
|
where_token: <Token![where]>::default(),
|
|
predicates: Punctuated::new(),
|
|
})
|
|
}
|
|
|
|
/// Split a type's generics into the pieces required for impl'ing a trait
|
|
/// for that type.
|
|
///
|
|
/// ```
|
|
/// # use proc_macro2::{Span, Ident};
|
|
/// # use quote::quote;
|
|
/// #
|
|
/// # let generics: syn::Generics = Default::default();
|
|
/// # let name = Ident::new("MyType", Span::call_site());
|
|
/// #
|
|
/// let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
|
/// quote! {
|
|
/// impl #impl_generics MyTrait for #name #ty_generics #where_clause {
|
|
/// // ...
|
|
/// }
|
|
/// }
|
|
/// # ;
|
|
/// ```
|
|
#[cfg(feature = "printing")]
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
|
pub fn split_for_impl(&self) -> (ImplGenerics, TypeGenerics, Option<&WhereClause>) {
|
|
(
|
|
ImplGenerics(self),
|
|
TypeGenerics(self),
|
|
self.where_clause.as_ref(),
|
|
)
|
|
}
|
|
}
|
|
|
|
pub struct Lifetimes<'a>(Iter<'a, GenericParam>);
|
|
|
|
impl<'a> Iterator for Lifetimes<'a> {
|
|
type Item = &'a LifetimeParam;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
if let GenericParam::Lifetime(lifetime) = self.0.next()? {
|
|
Some(lifetime)
|
|
} else {
|
|
self.next()
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct LifetimesMut<'a>(IterMut<'a, GenericParam>);
|
|
|
|
impl<'a> Iterator for LifetimesMut<'a> {
|
|
type Item = &'a mut LifetimeParam;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
if let GenericParam::Lifetime(lifetime) = self.0.next()? {
|
|
Some(lifetime)
|
|
} else {
|
|
self.next()
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct TypeParams<'a>(Iter<'a, GenericParam>);
|
|
|
|
impl<'a> Iterator for TypeParams<'a> {
|
|
type Item = &'a TypeParam;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
if let GenericParam::Type(type_param) = self.0.next()? {
|
|
Some(type_param)
|
|
} else {
|
|
self.next()
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct TypeParamsMut<'a>(IterMut<'a, GenericParam>);
|
|
|
|
impl<'a> Iterator for TypeParamsMut<'a> {
|
|
type Item = &'a mut TypeParam;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
if let GenericParam::Type(type_param) = self.0.next()? {
|
|
Some(type_param)
|
|
} else {
|
|
self.next()
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct ConstParams<'a>(Iter<'a, GenericParam>);
|
|
|
|
impl<'a> Iterator for ConstParams<'a> {
|
|
type Item = &'a ConstParam;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
if let GenericParam::Const(const_param) = self.0.next()? {
|
|
Some(const_param)
|
|
} else {
|
|
self.next()
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct ConstParamsMut<'a>(IterMut<'a, GenericParam>);
|
|
|
|
impl<'a> Iterator for ConstParamsMut<'a> {
|
|
type Item = &'a mut ConstParam;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
if let GenericParam::Const(const_param) = self.0.next()? {
|
|
Some(const_param)
|
|
} else {
|
|
self.next()
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Returned by `Generics::split_for_impl`.
|
|
#[cfg(feature = "printing")]
|
|
#[cfg_attr(
|
|
docsrs,
|
|
doc(cfg(all(any(feature = "full", feature = "derive"), feature = "printing")))
|
|
)]
|
|
pub struct ImplGenerics<'a>(&'a Generics);
|
|
|
|
/// Returned by `Generics::split_for_impl`.
|
|
#[cfg(feature = "printing")]
|
|
#[cfg_attr(
|
|
docsrs,
|
|
doc(cfg(all(any(feature = "full", feature = "derive"), feature = "printing")))
|
|
)]
|
|
pub struct TypeGenerics<'a>(&'a Generics);
|
|
|
|
/// Returned by `TypeGenerics::as_turbofish`.
|
|
#[cfg(feature = "printing")]
|
|
#[cfg_attr(
|
|
docsrs,
|
|
doc(cfg(all(any(feature = "full", feature = "derive"), feature = "printing")))
|
|
)]
|
|
pub struct Turbofish<'a>(&'a Generics);
|
|
|
|
#[cfg(feature = "printing")]
|
|
macro_rules! generics_wrapper_impls {
|
|
($ty:ident) => {
|
|
#[cfg(feature = "clone-impls")]
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
|
|
impl<'a> Clone for $ty<'a> {
|
|
fn clone(&self) -> Self {
|
|
$ty(self.0)
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "extra-traits")]
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
|
impl<'a> Debug for $ty<'a> {
|
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
formatter
|
|
.debug_tuple(stringify!($ty))
|
|
.field(self.0)
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "extra-traits")]
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
|
impl<'a> Eq for $ty<'a> {}
|
|
|
|
#[cfg(feature = "extra-traits")]
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
|
impl<'a> PartialEq for $ty<'a> {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.0 == other.0
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "extra-traits")]
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
|
impl<'a> Hash for $ty<'a> {
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
self.0.hash(state);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
#[cfg(feature = "printing")]
|
|
generics_wrapper_impls!(ImplGenerics);
|
|
#[cfg(feature = "printing")]
|
|
generics_wrapper_impls!(TypeGenerics);
|
|
#[cfg(feature = "printing")]
|
|
generics_wrapper_impls!(Turbofish);
|
|
|
|
#[cfg(feature = "printing")]
|
|
impl<'a> TypeGenerics<'a> {
|
|
/// Turn a type's generics like `<X, Y>` into a turbofish like `::<X, Y>`.
|
|
pub fn as_turbofish(&self) -> Turbofish<'a> {
|
|
Turbofish(self.0)
|
|
}
|
|
}
|
|
|
|
ast_struct! {
|
|
/// A set of bound lifetimes: `for<'a, 'b, 'c>`.
|
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
|
pub struct BoundLifetimes {
|
|
pub for_token: Token![for],
|
|
pub lt_token: Token![<],
|
|
pub lifetimes: Punctuated<GenericParam, Token![,]>,
|
|
pub gt_token: Token![>],
|
|
}
|
|
}
|
|
|
|
impl Default for BoundLifetimes {
|
|
fn default() -> Self {
|
|
BoundLifetimes {
|
|
for_token: Default::default(),
|
|
lt_token: Default::default(),
|
|
lifetimes: Punctuated::new(),
|
|
gt_token: Default::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl LifetimeParam {
|
|
pub fn new(lifetime: Lifetime) -> Self {
|
|
LifetimeParam {
|
|
attrs: Vec::new(),
|
|
lifetime,
|
|
colon_token: None,
|
|
bounds: Punctuated::new(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Ident> for TypeParam {
|
|
fn from(ident: Ident) -> Self {
|
|
TypeParam {
|
|
attrs: vec![],
|
|
ident,
|
|
colon_token: None,
|
|
bounds: Punctuated::new(),
|
|
eq_token: None,
|
|
default: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
ast_enum_of_structs! {
|
|
/// A trait or lifetime used as a bound on a type parameter.
|
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
|
#[non_exhaustive]
|
|
pub enum TypeParamBound {
|
|
Trait(TraitBound),
|
|
Lifetime(Lifetime),
|
|
PreciseCapture(PreciseCapture),
|
|
Verbatim(TokenStream),
|
|
}
|
|
}
|
|
|
|
ast_struct! {
|
|
/// A trait used as a bound on a type parameter.
|
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
|
pub struct TraitBound {
|
|
pub paren_token: Option<token::Paren>,
|
|
pub modifier: TraitBoundModifier,
|
|
/// The `for<'a>` in `for<'a> Foo<&'a T>`
|
|
pub lifetimes: Option<BoundLifetimes>,
|
|
/// The `Foo<&'a T>` in `for<'a> Foo<&'a T>`
|
|
pub path: Path,
|
|
}
|
|
}
|
|
|
|
ast_enum! {
|
|
/// A modifier on a trait bound, currently only used for the `?` in
|
|
/// `?Sized`.
|
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
|
pub enum TraitBoundModifier {
|
|
None,
|
|
Maybe(Token![?]),
|
|
}
|
|
}
|
|
|
|
ast_struct! {
|
|
/// Precise capturing bound: the 'use<…>' in `impl Trait +
|
|
/// use<'a, T>`.
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
|
pub struct PreciseCapture #full {
|
|
pub use_token: Token![use],
|
|
pub lt_token: Token![<],
|
|
pub params: Punctuated<CapturedParam, Token![,]>,
|
|
pub gt_token: Token![>],
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "full")]
|
|
ast_enum! {
|
|
/// Single parameter in a precise capturing bound.
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
|
#[non_exhaustive]
|
|
pub enum CapturedParam {
|
|
/// A lifetime parameter in precise capturing bound: `fn f<'a>() -> impl
|
|
/// Trait + use<'a>`.
|
|
Lifetime(Lifetime),
|
|
/// A type parameter or const generic parameter in precise capturing
|
|
/// bound: `fn f<T>() -> impl Trait + use<T>` or `fn f<const K: T>() ->
|
|
/// impl Trait + use<K>`.
|
|
Ident(Ident),
|
|
}
|
|
}
|
|
|
|
ast_struct! {
|
|
/// A `where` clause in a definition: `where T: Deserialize<'de>, D:
|
|
/// 'static`.
|
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
|
pub struct WhereClause {
|
|
pub where_token: Token![where],
|
|
pub predicates: Punctuated<WherePredicate, Token![,]>,
|
|
}
|
|
}
|
|
|
|
ast_enum_of_structs! {
|
|
/// A single predicate in a `where` clause: `T: Deserialize<'de>`.
|
|
///
|
|
/// # 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 WherePredicate {
|
|
/// A lifetime predicate in a `where` clause: `'a: 'b + 'c`.
|
|
Lifetime(PredicateLifetime),
|
|
|
|
/// A type predicate in a `where` clause: `for<'c> Foo<'c>: Trait<'c>`.
|
|
Type(PredicateType),
|
|
}
|
|
}
|
|
|
|
ast_struct! {
|
|
/// A lifetime predicate in a `where` clause: `'a: 'b + 'c`.
|
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
|
pub struct PredicateLifetime {
|
|
pub lifetime: Lifetime,
|
|
pub colon_token: Token![:],
|
|
pub bounds: Punctuated<Lifetime, Token![+]>,
|
|
}
|
|
}
|
|
|
|
ast_struct! {
|
|
/// A type predicate in a `where` clause: `for<'c> Foo<'c>: Trait<'c>`.
|
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
|
pub struct PredicateType {
|
|
/// Any lifetimes from a `for` binding
|
|
pub lifetimes: Option<BoundLifetimes>,
|
|
/// The type being bounded
|
|
pub bounded_ty: Type,
|
|
pub colon_token: Token![:],
|
|
/// Trait and lifetime bounds (`Clone+Send+'static`)
|
|
pub bounds: Punctuated<TypeParamBound, Token![+]>,
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "parsing")]
|
|
pub(crate) mod parsing {
|
|
use crate::attr::Attribute;
|
|
#[cfg(feature = "full")]
|
|
use crate::error;
|
|
use crate::error::{Error, Result};
|
|
use crate::ext::IdentExt as _;
|
|
use crate::generics::{
|
|
BoundLifetimes, ConstParam, GenericParam, Generics, LifetimeParam, PredicateLifetime,
|
|
PredicateType, TraitBound, TraitBoundModifier, TypeParam, TypeParamBound, WhereClause,
|
|
WherePredicate,
|
|
};
|
|
#[cfg(feature = "full")]
|
|
use crate::generics::{CapturedParam, PreciseCapture};
|
|
use crate::ident::Ident;
|
|
use crate::lifetime::Lifetime;
|
|
use crate::parse::{Parse, ParseStream};
|
|
use crate::path::{self, ParenthesizedGenericArguments, Path, PathArguments};
|
|
use crate::punctuated::Punctuated;
|
|
use crate::token;
|
|
use crate::ty::Type;
|
|
use crate::verbatim;
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
|
impl Parse for Generics {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
if !input.peek(Token![<]) {
|
|
return Ok(Generics::default());
|
|
}
|
|
|
|
let lt_token: Token![<] = input.parse()?;
|
|
|
|
let mut params = Punctuated::new();
|
|
loop {
|
|
if input.peek(Token![>]) {
|
|
break;
|
|
}
|
|
|
|
let attrs = input.call(Attribute::parse_outer)?;
|
|
let lookahead = input.lookahead1();
|
|
if lookahead.peek(Lifetime) {
|
|
params.push_value(GenericParam::Lifetime(LifetimeParam {
|
|
attrs,
|
|
..input.parse()?
|
|
}));
|
|
} else if lookahead.peek(Ident) {
|
|
params.push_value(GenericParam::Type(TypeParam {
|
|
attrs,
|
|
..input.parse()?
|
|
}));
|
|
} else if lookahead.peek(Token![const]) {
|
|
params.push_value(GenericParam::Const(ConstParam {
|
|
attrs,
|
|
..input.parse()?
|
|
}));
|
|
} else if input.peek(Token![_]) {
|
|
params.push_value(GenericParam::Type(TypeParam {
|
|
attrs,
|
|
ident: input.call(Ident::parse_any)?,
|
|
colon_token: None,
|
|
bounds: Punctuated::new(),
|
|
eq_token: None,
|
|
default: None,
|
|
}));
|
|
} else {
|
|
return Err(lookahead.error());
|
|
}
|
|
|
|
if input.peek(Token![>]) {
|
|
break;
|
|
}
|
|
let punct = input.parse()?;
|
|
params.push_punct(punct);
|
|
}
|
|
|
|
let gt_token: Token![>] = input.parse()?;
|
|
|
|
Ok(Generics {
|
|
lt_token: Some(lt_token),
|
|
params,
|
|
gt_token: Some(gt_token),
|
|
where_clause: None,
|
|
})
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
|
impl Parse for GenericParam {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
let attrs = input.call(Attribute::parse_outer)?;
|
|
|
|
let lookahead = input.lookahead1();
|
|
if lookahead.peek(Ident) {
|
|
Ok(GenericParam::Type(TypeParam {
|
|
attrs,
|
|
..input.parse()?
|
|
}))
|
|
} else if lookahead.peek(Lifetime) {
|
|
Ok(GenericParam::Lifetime(LifetimeParam {
|
|
attrs,
|
|
..input.parse()?
|
|
}))
|
|
} else if lookahead.peek(Token![const]) {
|
|
Ok(GenericParam::Const(ConstParam {
|
|
attrs,
|
|
..input.parse()?
|
|
}))
|
|
} else {
|
|
Err(lookahead.error())
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
|
impl Parse for LifetimeParam {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
let has_colon;
|
|
Ok(LifetimeParam {
|
|
attrs: input.call(Attribute::parse_outer)?,
|
|
lifetime: input.parse()?,
|
|
colon_token: {
|
|
if input.peek(Token![:]) {
|
|
has_colon = true;
|
|
Some(input.parse()?)
|
|
} else {
|
|
has_colon = false;
|
|
None
|
|
}
|
|
},
|
|
bounds: {
|
|
let mut bounds = Punctuated::new();
|
|
if has_colon {
|
|
loop {
|
|
if input.peek(Token![,]) || input.peek(Token![>]) {
|
|
break;
|
|
}
|
|
let value = input.parse()?;
|
|
bounds.push_value(value);
|
|
if !input.peek(Token![+]) {
|
|
break;
|
|
}
|
|
let punct = input.parse()?;
|
|
bounds.push_punct(punct);
|
|
}
|
|
}
|
|
bounds
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
|
impl Parse for BoundLifetimes {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
Ok(BoundLifetimes {
|
|
for_token: input.parse()?,
|
|
lt_token: input.parse()?,
|
|
lifetimes: {
|
|
let mut lifetimes = Punctuated::new();
|
|
while !input.peek(Token![>]) {
|
|
lifetimes.push_value(input.parse()?);
|
|
if input.peek(Token![>]) {
|
|
break;
|
|
}
|
|
lifetimes.push_punct(input.parse()?);
|
|
}
|
|
lifetimes
|
|
},
|
|
gt_token: input.parse()?,
|
|
})
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
|
impl Parse for Option<BoundLifetimes> {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
if input.peek(Token![for]) {
|
|
input.parse().map(Some)
|
|
} else {
|
|
Ok(None)
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
|
impl Parse for TypeParam {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
let attrs = input.call(Attribute::parse_outer)?;
|
|
let ident: Ident = input.parse()?;
|
|
let colon_token: Option<Token![:]> = input.parse()?;
|
|
|
|
let mut bounds = Punctuated::new();
|
|
if colon_token.is_some() {
|
|
loop {
|
|
if input.peek(Token![,]) || input.peek(Token![>]) || input.peek(Token![=]) {
|
|
break;
|
|
}
|
|
bounds.push_value({
|
|
let allow_precise_capture = false;
|
|
let allow_const = true;
|
|
TypeParamBound::parse_single(input, allow_precise_capture, allow_const)?
|
|
});
|
|
if !input.peek(Token![+]) {
|
|
break;
|
|
}
|
|
let punct: Token![+] = input.parse()?;
|
|
bounds.push_punct(punct);
|
|
}
|
|
}
|
|
|
|
let eq_token: Option<Token![=]> = input.parse()?;
|
|
let default = if eq_token.is_some() {
|
|
Some(input.parse::<Type>()?)
|
|
} else {
|
|
None
|
|
};
|
|
|
|
Ok(TypeParam {
|
|
attrs,
|
|
ident,
|
|
colon_token,
|
|
bounds,
|
|
eq_token,
|
|
default,
|
|
})
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
|
impl Parse for TypeParamBound {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
let allow_precise_capture = true;
|
|
let allow_const = true;
|
|
Self::parse_single(input, allow_precise_capture, allow_const)
|
|
}
|
|
}
|
|
|
|
impl TypeParamBound {
|
|
pub(crate) fn parse_single(
|
|
input: ParseStream,
|
|
#[cfg_attr(not(feature = "full"), allow(unused_variables))] allow_precise_capture: bool,
|
|
allow_const: bool,
|
|
) -> Result<Self> {
|
|
if input.peek(Lifetime) {
|
|
return input.parse().map(TypeParamBound::Lifetime);
|
|
}
|
|
|
|
#[cfg(feature = "full")]
|
|
{
|
|
if input.peek(Token![use]) {
|
|
let precise_capture: PreciseCapture = input.parse()?;
|
|
return if allow_precise_capture {
|
|
Ok(TypeParamBound::PreciseCapture(precise_capture))
|
|
} else {
|
|
let msg = "`use<...>` precise capturing syntax is not allowed here";
|
|
Err(error::new2(
|
|
precise_capture.use_token.span,
|
|
precise_capture.gt_token.span,
|
|
msg,
|
|
))
|
|
};
|
|
}
|
|
}
|
|
|
|
let begin = input.fork();
|
|
|
|
let content;
|
|
let (paren_token, content) = if input.peek(token::Paren) {
|
|
(Some(parenthesized!(content in input)), &content)
|
|
} else {
|
|
(None, input)
|
|
};
|
|
|
|
if let Some(mut bound) = TraitBound::do_parse(content, allow_const)? {
|
|
bound.paren_token = paren_token;
|
|
Ok(TypeParamBound::Trait(bound))
|
|
} else {
|
|
Ok(TypeParamBound::Verbatim(verbatim::between(&begin, input)))
|
|
}
|
|
}
|
|
|
|
pub(crate) fn parse_multiple(
|
|
input: ParseStream,
|
|
allow_plus: bool,
|
|
allow_precise_capture: bool,
|
|
allow_const: bool,
|
|
) -> Result<Punctuated<Self, Token![+]>> {
|
|
let mut bounds = Punctuated::new();
|
|
loop {
|
|
let bound = Self::parse_single(input, allow_precise_capture, allow_const)?;
|
|
bounds.push_value(bound);
|
|
if !(allow_plus && input.peek(Token![+])) {
|
|
break;
|
|
}
|
|
bounds.push_punct(input.parse()?);
|
|
if !(input.peek(Ident::peek_any)
|
|
|| input.peek(Token![::])
|
|
|| input.peek(Token![?])
|
|
|| input.peek(Lifetime)
|
|
|| input.peek(token::Paren)
|
|
|| (allow_const && (input.peek(token::Bracket) || input.peek(Token![const]))))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
Ok(bounds)
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
|
impl Parse for TraitBound {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
let allow_const = false;
|
|
Self::do_parse(input, allow_const).map(Option::unwrap)
|
|
}
|
|
}
|
|
|
|
impl TraitBound {
|
|
fn do_parse(input: ParseStream, allow_const: bool) -> Result<Option<Self>> {
|
|
let mut lifetimes: Option<BoundLifetimes> = input.parse()?;
|
|
|
|
let is_conditionally_const = cfg!(feature = "full") && input.peek(token::Bracket);
|
|
let is_unconditionally_const = cfg!(feature = "full") && input.peek(Token![const]);
|
|
if is_conditionally_const {
|
|
let conditionally_const;
|
|
let bracket_token = bracketed!(conditionally_const in input);
|
|
conditionally_const.parse::<Token![const]>()?;
|
|
if !allow_const {
|
|
let msg = "`[const]` is not allowed here";
|
|
return Err(Error::new(bracket_token.span.join(), msg));
|
|
}
|
|
} else if is_unconditionally_const {
|
|
let const_token: Token![const] = input.parse()?;
|
|
if !allow_const {
|
|
let msg = "`const` is not allowed here";
|
|
return Err(Error::new(const_token.span, msg));
|
|
}
|
|
}
|
|
|
|
let modifier: TraitBoundModifier = input.parse()?;
|
|
if lifetimes.is_none() && matches!(modifier, TraitBoundModifier::Maybe(_)) {
|
|
lifetimes = input.parse()?;
|
|
}
|
|
|
|
let mut path: Path = input.parse()?;
|
|
if path.segments.last().unwrap().arguments.is_empty()
|
|
&& (input.peek(token::Paren) || input.peek(Token![::]) && input.peek3(token::Paren))
|
|
{
|
|
input.parse::<Option<Token![::]>>()?;
|
|
let args: ParenthesizedGenericArguments = input.parse()?;
|
|
let parenthesized = PathArguments::Parenthesized(args);
|
|
path.segments.last_mut().unwrap().arguments = parenthesized;
|
|
}
|
|
|
|
if lifetimes.is_some() {
|
|
match modifier {
|
|
TraitBoundModifier::None => {}
|
|
TraitBoundModifier::Maybe(maybe) => {
|
|
let msg = "`for<...>` binder not allowed with `?` trait polarity modifier";
|
|
return Err(Error::new(maybe.span, msg));
|
|
}
|
|
}
|
|
}
|
|
|
|
if is_conditionally_const || is_unconditionally_const {
|
|
Ok(None)
|
|
} else {
|
|
Ok(Some(TraitBound {
|
|
paren_token: None,
|
|
modifier,
|
|
lifetimes,
|
|
path,
|
|
}))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
|
impl Parse for TraitBoundModifier {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
if input.peek(Token![?]) {
|
|
input.parse().map(TraitBoundModifier::Maybe)
|
|
} else {
|
|
Ok(TraitBoundModifier::None)
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
|
impl Parse for ConstParam {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
let mut default = None;
|
|
Ok(ConstParam {
|
|
attrs: input.call(Attribute::parse_outer)?,
|
|
const_token: input.parse()?,
|
|
ident: input.parse()?,
|
|
colon_token: input.parse()?,
|
|
ty: input.parse()?,
|
|
eq_token: {
|
|
if input.peek(Token![=]) {
|
|
let eq_token = input.parse()?;
|
|
default = Some(path::parsing::const_argument(input)?);
|
|
Some(eq_token)
|
|
} else {
|
|
None
|
|
}
|
|
},
|
|
default,
|
|
})
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
|
impl Parse for WhereClause {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
let where_token: Token![where] = input.parse()?;
|
|
|
|
if choose_generics_over_qpath(input) {
|
|
return Err(input
|
|
.error("generic parameters on `where` clauses are reserved for future use"));
|
|
}
|
|
|
|
Ok(WhereClause {
|
|
where_token,
|
|
predicates: {
|
|
let mut predicates = Punctuated::new();
|
|
loop {
|
|
if input.is_empty()
|
|
|| input.peek(token::Brace)
|
|
|| input.peek(Token![,])
|
|
|| input.peek(Token![;])
|
|
|| input.peek(Token![:]) && !input.peek(Token![::])
|
|
|| input.peek(Token![=])
|
|
{
|
|
break;
|
|
}
|
|
let value = input.parse()?;
|
|
predicates.push_value(value);
|
|
if !input.peek(Token![,]) {
|
|
break;
|
|
}
|
|
let punct = input.parse()?;
|
|
predicates.push_punct(punct);
|
|
}
|
|
predicates
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
|
impl Parse for Option<WhereClause> {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
if input.peek(Token![where]) {
|
|
input.parse().map(Some)
|
|
} else {
|
|
Ok(None)
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
|
impl Parse for WherePredicate {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
if input.peek(Lifetime) && input.peek2(Token![:]) {
|
|
Ok(WherePredicate::Lifetime(PredicateLifetime {
|
|
lifetime: input.parse()?,
|
|
colon_token: input.parse()?,
|
|
bounds: {
|
|
let mut bounds = Punctuated::new();
|
|
loop {
|
|
if input.is_empty()
|
|
|| input.peek(token::Brace)
|
|
|| input.peek(Token![,])
|
|
|| input.peek(Token![;])
|
|
|| input.peek(Token![:])
|
|
|| input.peek(Token![=])
|
|
{
|
|
break;
|
|
}
|
|
let value = input.parse()?;
|
|
bounds.push_value(value);
|
|
if !input.peek(Token![+]) {
|
|
break;
|
|
}
|
|
let punct = input.parse()?;
|
|
bounds.push_punct(punct);
|
|
}
|
|
bounds
|
|
},
|
|
}))
|
|
} else {
|
|
Ok(WherePredicate::Type(PredicateType {
|
|
lifetimes: input.parse()?,
|
|
bounded_ty: input.parse()?,
|
|
colon_token: input.parse()?,
|
|
bounds: {
|
|
let mut bounds = Punctuated::new();
|
|
loop {
|
|
if input.is_empty()
|
|
|| input.peek(token::Brace)
|
|
|| input.peek(Token![,])
|
|
|| input.peek(Token![;])
|
|
|| input.peek(Token![:]) && !input.peek(Token![::])
|
|
|| input.peek(Token![=])
|
|
{
|
|
break;
|
|
}
|
|
bounds.push_value({
|
|
let allow_precise_capture = false;
|
|
let allow_const = true;
|
|
TypeParamBound::parse_single(
|
|
input,
|
|
allow_precise_capture,
|
|
allow_const,
|
|
)?
|
|
});
|
|
if !input.peek(Token![+]) {
|
|
break;
|
|
}
|
|
let punct = input.parse()?;
|
|
bounds.push_punct(punct);
|
|
}
|
|
bounds
|
|
},
|
|
}))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "full")]
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
|
impl Parse for PreciseCapture {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
let use_token: Token![use] = input.parse()?;
|
|
let lt_token: Token![<] = input.parse()?;
|
|
let mut params = Punctuated::new();
|
|
loop {
|
|
let lookahead = input.lookahead1();
|
|
params.push_value(
|
|
if lookahead.peek(Lifetime) || lookahead.peek(Ident) || input.peek(Token![Self])
|
|
{
|
|
input.parse::<CapturedParam>()?
|
|
} else if lookahead.peek(Token![>]) {
|
|
break;
|
|
} else {
|
|
return Err(lookahead.error());
|
|
},
|
|
);
|
|
let lookahead = input.lookahead1();
|
|
params.push_punct(if lookahead.peek(Token![,]) {
|
|
input.parse::<Token![,]>()?
|
|
} else if lookahead.peek(Token![>]) {
|
|
break;
|
|
} else {
|
|
return Err(lookahead.error());
|
|
});
|
|
}
|
|
let gt_token: Token![>] = input.parse()?;
|
|
Ok(PreciseCapture {
|
|
use_token,
|
|
lt_token,
|
|
params,
|
|
gt_token,
|
|
})
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "full")]
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
|
impl Parse for CapturedParam {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
let lookahead = input.lookahead1();
|
|
if lookahead.peek(Lifetime) {
|
|
input.parse().map(CapturedParam::Lifetime)
|
|
} else if lookahead.peek(Ident) || input.peek(Token![Self]) {
|
|
input.call(Ident::parse_any).map(CapturedParam::Ident)
|
|
} else {
|
|
Err(lookahead.error())
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(crate) fn choose_generics_over_qpath(input: ParseStream) -> bool {
|
|
// Rust syntax has an ambiguity between generic parameters and qualified
|
|
// paths. In `impl <T> :: Thing<T, U> {}` this may either be a generic
|
|
// inherent impl `impl<T> ::Thing<T, U>` or a non-generic inherent impl
|
|
// for an associated type `impl <T>::Thing<T, U>`.
|
|
//
|
|
// After `<` the following continuations can only begin generics, not a
|
|
// qualified path:
|
|
//
|
|
// `<` `>` - empty generic parameters
|
|
// `<` `#` - generic parameters with attribute
|
|
// `<` LIFETIME `>` - single lifetime parameter
|
|
// `<` (LIFETIME|IDENT) `,` - first generic parameter in a list
|
|
// `<` (LIFETIME|IDENT) `:` - generic parameter with bounds
|
|
// `<` (LIFETIME|IDENT) `=` - generic parameter with a default
|
|
// `<` const - generic const parameter
|
|
//
|
|
// The only truly ambiguous case is:
|
|
//
|
|
// `<` IDENT `>` `::` IDENT ...
|
|
//
|
|
// which we disambiguate in favor of generics because this is almost
|
|
// always the expected one in the context of real-world code.
|
|
input.peek(Token![<])
|
|
&& (input.peek2(Token![>])
|
|
|| input.peek2(Token![#])
|
|
|| (input.peek2(Lifetime) || input.peek2(Ident))
|
|
&& (input.peek3(Token![>])
|
|
|| input.peek3(Token![,])
|
|
|| input.peek3(Token![:]) && !input.peek3(Token![::])
|
|
|| input.peek3(Token![=]))
|
|
|| input.peek2(Token![const]))
|
|
}
|
|
|
|
#[cfg(feature = "full")]
|
|
pub(crate) fn choose_generics_over_qpath_after_keyword(input: ParseStream) -> bool {
|
|
let input = input.fork();
|
|
input.call(Ident::parse_any).unwrap(); // `impl` or `for` or `where`
|
|
choose_generics_over_qpath(&input)
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "printing")]
|
|
pub(crate) mod printing {
|
|
use crate::attr::FilterAttrs;
|
|
#[cfg(feature = "full")]
|
|
use crate::expr;
|
|
use crate::expr::Expr;
|
|
#[cfg(feature = "full")]
|
|
use crate::fixup::FixupContext;
|
|
use crate::generics::{
|
|
BoundLifetimes, ConstParam, GenericParam, Generics, ImplGenerics, LifetimeParam,
|
|
PredicateLifetime, PredicateType, TraitBound, TraitBoundModifier, Turbofish, TypeGenerics,
|
|
TypeParam, WhereClause,
|
|
};
|
|
#[cfg(feature = "full")]
|
|
use crate::generics::{CapturedParam, PreciseCapture};
|
|
use crate::print::TokensOrDefault;
|
|
use crate::token;
|
|
use proc_macro2::TokenStream;
|
|
use quote::{ToTokens, TokenStreamExt};
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
|
impl ToTokens for Generics {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
if self.params.is_empty() {
|
|
return;
|
|
}
|
|
|
|
TokensOrDefault(&self.lt_token).to_tokens(tokens);
|
|
|
|
// Print lifetimes before types and consts, regardless of their
|
|
// order in self.params.
|
|
let mut trailing_or_empty = true;
|
|
for param in self.params.pairs() {
|
|
if let GenericParam::Lifetime(_) = **param.value() {
|
|
param.to_tokens(tokens);
|
|
trailing_or_empty = param.punct().is_some();
|
|
}
|
|
}
|
|
for param in self.params.pairs() {
|
|
match param.value() {
|
|
GenericParam::Type(_) | GenericParam::Const(_) => {
|
|
if !trailing_or_empty {
|
|
<Token![,]>::default().to_tokens(tokens);
|
|
trailing_or_empty = true;
|
|
}
|
|
param.to_tokens(tokens);
|
|
}
|
|
GenericParam::Lifetime(_) => {}
|
|
}
|
|
}
|
|
|
|
TokensOrDefault(&self.gt_token).to_tokens(tokens);
|
|
}
|
|
}
|
|
|
|
impl<'a> ToTokens for ImplGenerics<'a> {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
if self.0.params.is_empty() {
|
|
return;
|
|
}
|
|
|
|
TokensOrDefault(&self.0.lt_token).to_tokens(tokens);
|
|
|
|
// Print lifetimes before types and consts, regardless of their
|
|
// order in self.params.
|
|
let mut trailing_or_empty = true;
|
|
for param in self.0.params.pairs() {
|
|
if let GenericParam::Lifetime(_) = **param.value() {
|
|
param.to_tokens(tokens);
|
|
trailing_or_empty = param.punct().is_some();
|
|
}
|
|
}
|
|
for param in self.0.params.pairs() {
|
|
if let GenericParam::Lifetime(_) = **param.value() {
|
|
continue;
|
|
}
|
|
if !trailing_or_empty {
|
|
<Token![,]>::default().to_tokens(tokens);
|
|
trailing_or_empty = true;
|
|
}
|
|
match param.value() {
|
|
GenericParam::Lifetime(_) => unreachable!(),
|
|
GenericParam::Type(param) => {
|
|
// Leave off the type parameter defaults
|
|
tokens.append_all(param.attrs.outer());
|
|
param.ident.to_tokens(tokens);
|
|
if !param.bounds.is_empty() {
|
|
TokensOrDefault(¶m.colon_token).to_tokens(tokens);
|
|
param.bounds.to_tokens(tokens);
|
|
}
|
|
}
|
|
GenericParam::Const(param) => {
|
|
// Leave off the const parameter defaults
|
|
tokens.append_all(param.attrs.outer());
|
|
param.const_token.to_tokens(tokens);
|
|
param.ident.to_tokens(tokens);
|
|
param.colon_token.to_tokens(tokens);
|
|
param.ty.to_tokens(tokens);
|
|
}
|
|
}
|
|
param.punct().to_tokens(tokens);
|
|
}
|
|
|
|
TokensOrDefault(&self.0.gt_token).to_tokens(tokens);
|
|
}
|
|
}
|
|
|
|
impl<'a> ToTokens for TypeGenerics<'a> {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
if self.0.params.is_empty() {
|
|
return;
|
|
}
|
|
|
|
TokensOrDefault(&self.0.lt_token).to_tokens(tokens);
|
|
|
|
// Print lifetimes before types and consts, regardless of their
|
|
// order in self.params.
|
|
let mut trailing_or_empty = true;
|
|
for param in self.0.params.pairs() {
|
|
if let GenericParam::Lifetime(def) = *param.value() {
|
|
// Leave off the lifetime bounds and attributes
|
|
def.lifetime.to_tokens(tokens);
|
|
param.punct().to_tokens(tokens);
|
|
trailing_or_empty = param.punct().is_some();
|
|
}
|
|
}
|
|
for param in self.0.params.pairs() {
|
|
if let GenericParam::Lifetime(_) = **param.value() {
|
|
continue;
|
|
}
|
|
if !trailing_or_empty {
|
|
<Token![,]>::default().to_tokens(tokens);
|
|
trailing_or_empty = true;
|
|
}
|
|
match param.value() {
|
|
GenericParam::Lifetime(_) => unreachable!(),
|
|
GenericParam::Type(param) => {
|
|
// Leave off the type parameter defaults
|
|
param.ident.to_tokens(tokens);
|
|
}
|
|
GenericParam::Const(param) => {
|
|
// Leave off the const parameter defaults
|
|
param.ident.to_tokens(tokens);
|
|
}
|
|
}
|
|
param.punct().to_tokens(tokens);
|
|
}
|
|
|
|
TokensOrDefault(&self.0.gt_token).to_tokens(tokens);
|
|
}
|
|
}
|
|
|
|
impl<'a> ToTokens for Turbofish<'a> {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
if !self.0.params.is_empty() {
|
|
<Token![::]>::default().to_tokens(tokens);
|
|
TypeGenerics(self.0).to_tokens(tokens);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
|
impl ToTokens for BoundLifetimes {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
self.for_token.to_tokens(tokens);
|
|
self.lt_token.to_tokens(tokens);
|
|
self.lifetimes.to_tokens(tokens);
|
|
self.gt_token.to_tokens(tokens);
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
|
impl ToTokens for LifetimeParam {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
tokens.append_all(self.attrs.outer());
|
|
self.lifetime.to_tokens(tokens);
|
|
if !self.bounds.is_empty() {
|
|
TokensOrDefault(&self.colon_token).to_tokens(tokens);
|
|
self.bounds.to_tokens(tokens);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
|
impl ToTokens for TypeParam {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
tokens.append_all(self.attrs.outer());
|
|
self.ident.to_tokens(tokens);
|
|
if !self.bounds.is_empty() {
|
|
TokensOrDefault(&self.colon_token).to_tokens(tokens);
|
|
self.bounds.to_tokens(tokens);
|
|
}
|
|
if let Some(default) = &self.default {
|
|
TokensOrDefault(&self.eq_token).to_tokens(tokens);
|
|
default.to_tokens(tokens);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
|
impl ToTokens for TraitBound {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
let to_tokens = |tokens: &mut TokenStream| {
|
|
self.modifier.to_tokens(tokens);
|
|
self.lifetimes.to_tokens(tokens);
|
|
self.path.to_tokens(tokens);
|
|
};
|
|
match &self.paren_token {
|
|
Some(paren) => paren.surround(tokens, to_tokens),
|
|
None => to_tokens(tokens),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
|
impl ToTokens for TraitBoundModifier {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
match self {
|
|
TraitBoundModifier::None => {}
|
|
TraitBoundModifier::Maybe(t) => t.to_tokens(tokens),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
|
impl ToTokens for ConstParam {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
tokens.append_all(self.attrs.outer());
|
|
self.const_token.to_tokens(tokens);
|
|
self.ident.to_tokens(tokens);
|
|
self.colon_token.to_tokens(tokens);
|
|
self.ty.to_tokens(tokens);
|
|
if let Some(default) = &self.default {
|
|
TokensOrDefault(&self.eq_token).to_tokens(tokens);
|
|
print_const_argument(default, tokens);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
|
impl ToTokens for WhereClause {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
if !self.predicates.is_empty() {
|
|
self.where_token.to_tokens(tokens);
|
|
self.predicates.to_tokens(tokens);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
|
impl ToTokens for PredicateLifetime {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
self.lifetime.to_tokens(tokens);
|
|
self.colon_token.to_tokens(tokens);
|
|
self.bounds.to_tokens(tokens);
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
|
impl ToTokens for PredicateType {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
self.lifetimes.to_tokens(tokens);
|
|
self.bounded_ty.to_tokens(tokens);
|
|
self.colon_token.to_tokens(tokens);
|
|
self.bounds.to_tokens(tokens);
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "full")]
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
|
impl ToTokens for PreciseCapture {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
self.use_token.to_tokens(tokens);
|
|
self.lt_token.to_tokens(tokens);
|
|
|
|
// Print lifetimes before types and consts, regardless of their
|
|
// order in self.params.
|
|
let mut trailing_or_empty = true;
|
|
for param in self.params.pairs() {
|
|
if let CapturedParam::Lifetime(_) = **param.value() {
|
|
param.to_tokens(tokens);
|
|
trailing_or_empty = param.punct().is_some();
|
|
}
|
|
}
|
|
for param in self.params.pairs() {
|
|
if let CapturedParam::Ident(_) = **param.value() {
|
|
if !trailing_or_empty {
|
|
<Token![,]>::default().to_tokens(tokens);
|
|
trailing_or_empty = true;
|
|
}
|
|
param.to_tokens(tokens);
|
|
}
|
|
}
|
|
|
|
self.gt_token.to_tokens(tokens);
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "full")]
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
|
impl ToTokens for CapturedParam {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
match self {
|
|
CapturedParam::Lifetime(lifetime) => lifetime.to_tokens(tokens),
|
|
CapturedParam::Ident(ident) => ident.to_tokens(tokens),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(crate) fn print_const_argument(expr: &Expr, tokens: &mut TokenStream) {
|
|
match expr {
|
|
Expr::Lit(expr) => expr.to_tokens(tokens),
|
|
|
|
Expr::Path(expr)
|
|
if expr.attrs.is_empty()
|
|
&& expr.qself.is_none()
|
|
&& expr.path.get_ident().is_some() =>
|
|
{
|
|
expr.to_tokens(tokens);
|
|
}
|
|
|
|
#[cfg(feature = "full")]
|
|
Expr::Block(expr) => expr.to_tokens(tokens),
|
|
|
|
#[cfg(not(feature = "full"))]
|
|
Expr::Verbatim(expr) => expr.to_tokens(tokens),
|
|
|
|
// ERROR CORRECTION: Add braces to make sure that the
|
|
// generated code is valid.
|
|
_ => token::Brace::default().surround(tokens, |tokens| {
|
|
#[cfg(feature = "full")]
|
|
expr::printing::print_expr(expr, tokens, FixupContext::new_stmt());
|
|
|
|
#[cfg(not(feature = "full"))]
|
|
expr.to_tokens(tokens);
|
|
}),
|
|
}
|
|
}
|
|
}
|