summaryrefslogtreecommitdiffstats
path: root/rust/syn/generics.rs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-08-30 09:22:00 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-08-30 09:22:00 -0700
commit034dd340b08be1f2f0477ad16131d609f9dbd53c (patch)
tree2536f4b2d7893ccd916b5abdf3c454ad6edc03c2 /rust/syn/generics.rs
downloadlinux-stable-034dd340b08be1f2f0477ad16131d609f9dbd53c.tar.gz
linux-stable-034dd340b08be1f2f0477ad16131d609f9dbd53c.zip
Merge tag 'trace-v7.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-tracegrafted
Pull tracing fixes from Steven Rostedt: - Fix error output of boot instance creation failure Currently if a boot instance creation fails, instead of printing out the name of the instance that failed, it prints "(null)". That is because it prints "cur_str" that had already been processed by strsep(). Print the saved name instead. While at it, print the error code of the failure. - Fix use-after-free for same named historgrams Histograms can be named so that they can be used in multiple events. But if the named histogram has a variable attached, the second event that uses the named histogram which duplicates it and needs to free the original after duplication leaves the old variable in place and still visible. If another histogram uses than variable, it will use the stale one which will try to reference the freed duplicate histogram and crash the kernel. Free the duplicate variables along with the duplicated histogram data. - Check return value of kthread_run() in event self test The events self tests uses a kthread for testing but does not check if it succeeded in creating a kthread. If the kthread creation were to fail, the code will still try to call kthread_stop() on the error returned. - Fix race between reading trace_pipe and updating subbuffer size If a user is reading the trace_pipe file at the same time they update the ring buffer sub-buffer size, can cause the trace_pipe read to read stale data. Add trace_access_lock() around updating the ring buffer sub-buffer size. - Fix eventfs_inode on failure path in creation of the events directory In the creation of the "events" directory, if after allocating the eventfs_inode a failure is detected, it calls cleanup_ei() which calls free_ei(). The free_ei() will test if eventfs_inode being freed has no children. It is a bug if it does. But on the failure case of the creation of the "events" directory, the children lists have not yet been initialized and the free will trigger a warning because list_empty() on an uninitialized list returns false. Move the initialization into init_ei() where it makes more sense and makes sure that a created eventfs_inode has its lists initialized upon creation. - Check return value of kthread_run() in ftrace direct sample code The sample code that shows how to use the ftrace direct calls does not test the return of kthread_run() to see if it succeeds. Return a failure if the kthread_run() doesn't succeed. - Clear user events state on fork in case of alloc failure On fork, the child gets a pointer to the parent's user events state. It makes a copy of it then updates the child's pointer to it. But if the allocation fails, the duplication function leaves the child with a pointer to its parent's descriptor. When the child cleans up its data, it will free the parent's descriptor while the parent is still using it. In the duplication function, set the child's user_event_mm to NULL before testing if the allocation succeeded, and when it exits it will not free the parent's descriptor. - Fix retry exhaustion in simple ring buffer reader swap simple_ring_buffer_swap_reader_page() starts with retry set to 8 and post-decrements it only after a failed link replacement. On the final attempt, a successful replacement leaves retry at zero, while a failed replacement leaves it at -1. But the check for success expects the retry value to be non-zero and exits with an error on zero. This is the opposite result. Fix it. - Fail nicely when the remote swap_reader_page() returns an error Currently, if the swap_reader_page() of a remote buffer fails, it triggers a WARN_ON_ONCE() and continues normally. Instead, have it exit with an error and a pr_warn() print instead of a full WARNING. * tag 'trace-v7.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: ring-buffer: Stop remote reader update when page swap fails tracing: Fix retry exhaustion in simple ring buffer reader swap tracing/user_events: Clear copied tracing state before fork duplication samples/ftrace: Fix kthread_stop() on ERR_PTR in ftrace-direct-multi-modify samples/ftrace: Fix kthread_stop() on ERR_PTR in ftrace-direct-modify eventfs: Initialize ei->children and ei->list in init_ei() tracing: Fix use-after-free in trace_pipe read on sub-buffer order change tracing: Fix crash passing ERR_PTR to kthread_stop() tracing: Fix use-after-free with same-name named triggers tracing: Fix logged instance name on creation failure
Diffstat (limited to 'rust/syn/generics.rs')
-rw-r--r--rust/syn/generics.rs1479
1 files changed, 1479 insertions, 0 deletions
diff --git a/rust/syn/generics.rs b/rust/syn/generics.rs
new file mode 100644
index 000000000..9f8df8a15
--- /dev/null
+++ b/rust/syn/generics.rs
@@ -0,0 +1,1479 @@
+// 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&lt;&hellip;&gt;' 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(&param.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);
+ }),
+ }
+ }
+}