Rewrite the AST to be a bit more user-friendly
This commit is a relatively large rewrite of the AST that `syn` exposes. The
main change is to expose enums-of-structs rather than
enums-with-huge-tuple-variants. The best example of this is `ItemKind::Fn` which
changed from:
enum ItemKind {
Fn(Box<FnDecl>, Unsafety, Constness, Option<Abi>, Generics, Box<Block>),
...
}
to
enum ItemKind {
Fn(ItemFn),
...
}
struct ItemFn {
decl: Box<FnDecl>,
unsafety: Unsafety,
constness: Constness,
abi: Option<Abi>,
generics: Generics,
block: Box<Block>,
}
This change serves a few purposes:
* It's now much easier to add fields to each variant of the ast, ast struct
fields tend to be "by default ignored" in most contexts.
* It's much easier to document what each field is, as each field can have
dedicated documentation.
* There's now canonicalized names for each field (the name of the field) which
can help match `match` statements more consistent across a codebase.
A downside of this representation is that it can be a little more verbose to
work with in `match` statements and during constructions. Overall though I'd
feel at least that the readability improved significantly despite the extra
words required to do various operations.
Closes #136
diff --git a/src/ty.rs b/src/ty.rs
index 7b7d3af..4fb3328 100644
--- a/src/ty.rs
+++ b/src/ty.rs
@@ -1,67 +1,95 @@
use super::*;
-/// The different kinds of types recognized by the compiler
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub enum Ty {
- /// A variable-length array (`[T]`)
- Slice(Box<Ty>),
- /// A fixed length array (`[T; n]`)
- Array(Box<Ty>, ConstExpr),
- /// A raw pointer (`*const T` or `*mut T`)
- Ptr(Box<MutTy>),
- /// A reference (`&'a T` or `&'a mut T`)
- Rptr(Option<Lifetime>, Box<MutTy>),
- /// A bare function (e.g. `fn(usize) -> bool`)
- BareFn(Box<BareFnTy>),
- /// The never type (`!`)
- Never,
- /// A tuple (`(A, B, C, D, ...)`)
- Tup(Vec<Ty>),
- /// A path (`module::module::...::Type`), optionally
- /// "qualified", e.g. `<Vec<T> as SomeTrait>::SomeType`.
+ast_enum_of_structs! {
+ /// The different kinds of types recognized by the compiler
+ pub enum Ty {
+ /// A variable-length array (`[T]`)
+ pub Slice(TySlice {
+ pub ty: Box<Ty>,
+ }),
+ /// A fixed length array (`[T; n]`)
+ pub Array(TyArray {
+ pub ty: Box<Ty>,
+ pub amt: ConstExpr,
+ }),
+ /// A raw pointer (`*const T` or `*mut T`)
+ pub Ptr(TyPtr {
+ pub ty: Box<MutTy>,
+ }),
+ /// A reference (`&'a T` or `&'a mut T`)
+ pub Rptr(TyRptr {
+ pub lifetime: Option<Lifetime>,
+ pub ty: Box<MutTy>,
+ }),
+ /// A bare function (e.g. `fn(usize) -> bool`)
+ pub BareFn(TyBareFn {
+ pub ty: Box<BareFnTy>,
+ }),
+ /// The never type (`!`)
+ pub Never(TyNever {}),
+ /// A tuple (`(A, B, C, D, ...)`)
+ pub Tup(TyTup {
+ pub tys: Vec<Ty>,
+ }),
+ /// A path (`module::module::...::Type`), optionally
+ /// "qualified", e.g. `<Vec<T> as SomeTrait>::SomeType`.
+ ///
+ /// Type parameters are stored in the Path itself
+ pub Path(TyPath {
+ pub qself: Option<QSelf>,
+ pub path: Path,
+ }),
+ /// A trait object type `Bound1 + Bound2 + Bound3`
+ /// where `Bound` is a trait or a lifetime.
+ pub TraitObject(TyTraitObject {
+ pub bounds: Vec<TyParamBound>,
+ }),
+ /// An `impl Bound1 + Bound2 + Bound3` type
+ /// where `Bound` is a trait or a lifetime.
+ pub ImplTrait(TyImplTrait {
+ pub bounds: Vec<TyParamBound>,
+ }),
+ /// No-op; kept solely so that we can pretty-print faithfully
+ pub Paren(TyParen {
+ pub ty: Box<Ty>,
+ }),
+ /// TyKind::Infer means the type should be inferred instead of it having been
+ /// specified. This can appear anywhere in a type.
+ pub Infer(TyInfer {}),
+ /// A macro in the type position.
+ pub Mac(Mac),
+ }
+}
+
+ast_struct! {
+ pub struct MutTy {
+ pub ty: Ty,
+ pub mutability: Mutability,
+ }
+}
+
+ast_enum! {
+ #[derive(Copy)]
+ pub enum Mutability {
+ Mutable,
+ Immutable,
+ }
+}
+
+ast_struct! {
+ /// A "Path" is essentially Rust's notion of a name.
///
- /// Type parameters are stored in the Path itself
- Path(Option<QSelf>, Path),
- /// A trait object type `Bound1 + Bound2 + Bound3`
- /// where `Bound` is a trait or a lifetime.
- TraitObject(Vec<TyParamBound>),
- /// An `impl Bound1 + Bound2 + Bound3` type
- /// where `Bound` is a trait or a lifetime.
- ImplTrait(Vec<TyParamBound>),
- /// No-op; kept solely so that we can pretty-print faithfully
- Paren(Box<Ty>),
- /// TyKind::Infer means the type should be inferred instead of it having been
- /// specified. This can appear anywhere in a type.
- Infer,
- /// A macro in the type position.
- Mac(Mac),
-}
-
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct MutTy {
- pub ty: Ty,
- pub mutability: Mutability,
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub enum Mutability {
- Mutable,
- Immutable,
-}
-
-/// A "Path" is essentially Rust's notion of a name.
-///
-/// It's represented as a sequence of identifiers,
-/// along with a bunch of supporting information.
-///
-/// E.g. `std::cmp::PartialEq`
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct Path {
- /// A `::foo` path, is relative to the crate root rather than current
- /// module (like paths in an import).
- pub global: bool,
- /// The segments in the path: the things separated by `::`.
- pub segments: Vec<PathSegment>,
+ /// It's represented as a sequence of identifiers,
+ /// along with a bunch of supporting information.
+ ///
+ /// E.g. `std::cmp::PartialEq`
+ pub struct Path {
+ /// A `::foo` path, is relative to the crate root rather than current
+ /// module (like paths in an import).
+ pub global: bool,
+ /// The segments in the path: the things separated by `::`.
+ pub segments: Vec<PathSegment>,
+ }
}
impl<T> From<T> for Path
@@ -75,19 +103,20 @@
}
}
-/// A segment of a path: an identifier, an optional lifetime, and a set of types.
-///
-/// E.g. `std`, `String` or `Box<T>`
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct PathSegment {
- /// The identifier portion of this path segment.
- pub ident: Ident,
- /// Type/lifetime parameters attached to this path. They come in
- /// two flavors: `Path<A,B,C>` and `Path(A,B) -> C`. Note that
- /// this is more than just simple syntactic sugar; the use of
- /// parens affects the region binding rules, so we preserve the
- /// distinction.
- pub parameters: PathParameters,
+ast_struct! {
+ /// A segment of a path: an identifier, an optional lifetime, and a set of types.
+ ///
+ /// E.g. `std`, `String` or `Box<T>`
+ pub struct PathSegment {
+ /// The identifier portion of this path segment.
+ pub ident: Ident,
+ /// Type/lifetime parameters attached to this path. They come in
+ /// two flavors: `Path<A,B,C>` and `Path(A,B) -> C`. Note that
+ /// this is more than just simple syntactic sugar; the use of
+ /// parens affects the region binding rules, so we preserve the
+ /// distinction.
+ pub parameters: PathParameters,
+ }
}
impl<T> From<T> for PathSegment
@@ -101,15 +130,16 @@
}
}
-/// Parameters of a path segment.
-///
-/// E.g. `<A, B>` as in `Foo<A, B>` or `(A, B)` as in `Foo(A, B)`
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub enum PathParameters {
- /// The `<'a, A, B, C>` in `foo::bar::baz::<'a, A, B, C>`
- AngleBracketed(AngleBracketedParameterData),
- /// The `(A, B)` and `C` in `Foo(A, B) -> C`
- Parenthesized(ParenthesizedParameterData),
+ast_enum! {
+ /// Parameters of a path segment.
+ ///
+ /// E.g. `<A, B>` as in `Foo<A, B>` or `(A, B)` as in `Foo(A, B)`
+ pub enum PathParameters {
+ /// The `<'a, A, B, C>` in `foo::bar::baz::<'a, A, B, C>`
+ AngleBracketed(AngleBracketedParameterData),
+ /// The `(A, B)` and `C` in `Foo(A, B) -> C`
+ Parenthesized(ParenthesizedParameterData),
+ }
}
impl PathParameters {
@@ -128,104 +158,118 @@
}
}
-/// A path like `Foo<'a, T>`
-#[derive(Debug, Clone, Eq, PartialEq, Default, Hash)]
-pub struct AngleBracketedParameterData {
- /// The lifetime parameters for this path segment.
- pub lifetimes: Vec<Lifetime>,
- /// The type parameters for this path segment, if present.
- pub types: Vec<Ty>,
- /// Bindings (equality constraints) on associated types, if present.
+ast_struct! {
+ /// A path like `Foo<'a, T>`
+ #[derive(Default)]
+ pub struct AngleBracketedParameterData {
+ /// The lifetime parameters for this path segment.
+ pub lifetimes: Vec<Lifetime>,
+ /// The type parameters for this path segment, if present.
+ pub types: Vec<Ty>,
+ /// Bindings (equality constraints) on associated types, if present.
+ ///
+ /// E.g., `Foo<A=Bar>`.
+ pub bindings: Vec<TypeBinding>,
+ }
+}
+
+ast_struct! {
+ /// Bind a type to an associated type: `A=Foo`.
+ pub struct TypeBinding {
+ pub ident: Ident,
+ pub ty: Ty,
+ }
+}
+
+
+ast_struct! {
+ /// A path like `Foo(A,B) -> C`
+ pub struct ParenthesizedParameterData {
+ /// `(A, B)`
+ pub inputs: Vec<Ty>,
+ /// `C`
+ pub output: Option<Ty>,
+ }
+}
+
+ast_struct! {
+ pub struct PolyTraitRef {
+ /// The `'a` in `<'a> Foo<&'a T>`
+ pub bound_lifetimes: Vec<LifetimeDef>,
+ /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`
+ pub trait_ref: Path,
+ }
+}
+
+ast_struct! {
+ /// The explicit Self type in a "qualified path". The actual
+ /// path, including the trait and the associated item, is stored
+ /// separately. `position` represents the index of the associated
+ /// item qualified with this Self type.
///
- /// E.g., `Foo<A=Bar>`.
- pub bindings: Vec<TypeBinding>,
-}
-
-/// Bind a type to an associated type: `A=Foo`.
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct TypeBinding {
- pub ident: Ident,
- pub ty: Ty,
-}
-
-/// A path like `Foo(A,B) -> C`
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct ParenthesizedParameterData {
- /// `(A, B)`
- pub inputs: Vec<Ty>,
- /// `C`
- pub output: Option<Ty>,
-}
-
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct PolyTraitRef {
- /// The `'a` in `<'a> Foo<&'a T>`
- pub bound_lifetimes: Vec<LifetimeDef>,
- /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`
- pub trait_ref: Path,
-}
-
-/// The explicit Self type in a "qualified path". The actual
-/// path, including the trait and the associated item, is stored
-/// separately. `position` represents the index of the associated
-/// item qualified with this Self type.
-///
-/// ```rust,ignore
-/// <Vec<T> as a::b::Trait>::AssociatedItem
-/// ^~~~~ ~~~~~~~~~~~~~~^
-/// ty position = 3
-///
-/// <Vec<T>>::AssociatedItem
-/// ^~~~~ ^
-/// ty position = 0
-/// ```
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct QSelf {
- pub ty: Box<Ty>,
- pub position: usize,
-}
-
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct BareFnTy {
- pub unsafety: Unsafety,
- pub abi: Option<Abi>,
- pub lifetimes: Vec<LifetimeDef>,
- pub inputs: Vec<BareFnArg>,
- pub output: FunctionRetTy,
- pub variadic: bool,
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub enum Unsafety {
- Unsafe,
- Normal,
-}
-
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub enum Abi {
- Named(String),
- Rust,
-}
-
-/// An argument in a function type.
-///
-/// E.g. `bar: usize` as in `fn foo(bar: usize)`
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct BareFnArg {
- pub name: Option<Ident>,
- pub ty: Ty,
-}
-
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub enum FunctionRetTy {
- /// Return type is not specified.
+ /// ```rust,ignore
+ /// <Vec<T> as a::b::Trait>::AssociatedItem
+ /// ^~~~~ ~~~~~~~~~~~~~~^
+ /// ty position = 3
///
- /// Functions default to `()` and
- /// closures default to inference. Span points to where return
- /// type would be inserted.
- Default,
- /// Everything else
- Ty(Ty),
+ /// <Vec<T>>::AssociatedItem
+ /// ^~~~~ ^
+ /// ty position = 0
+ /// ```
+ pub struct QSelf {
+ pub ty: Box<Ty>,
+ pub position: usize,
+ }
+}
+
+ast_struct! {
+ pub struct BareFnTy {
+ pub unsafety: Unsafety,
+ pub abi: Option<Abi>,
+ pub lifetimes: Vec<LifetimeDef>,
+ pub inputs: Vec<BareFnArg>,
+ pub output: FunctionRetTy,
+ pub variadic: bool,
+ }
+}
+
+ast_enum! {
+ #[derive(Copy)]
+ pub enum Unsafety {
+ Unsafe,
+ Normal,
+ }
+}
+
+ast_enum! {
+ pub enum Abi {
+ Named(String),
+ Rust,
+ }
+}
+
+ast_struct! {
+ /// An argument in a function type.
+ ///
+ /// E.g. `bar: usize` as in `fn foo(bar: usize)`
+ pub struct BareFnArg {
+ pub name: Option<Ident>,
+ pub ty: Ty,
+ }
+}
+
+
+ast_enum! {
+ pub enum FunctionRetTy {
+ /// Return type is not specified.
+ ///
+ /// Functions default to `()` and
+ /// closures default to inference. Span points to where return
+ /// type would be inserted.
+ Default,
+ /// Everything else
+ Ty(Ty),
+ }
}
#[cfg(feature = "parsing")]
@@ -276,7 +320,7 @@
punct!("[") >>
elem: ty >>
punct!("]") >>
- (Ty::Slice(Box::new(elem)))
+ (TySlice { ty: Box::new(elem) }.into())
));
named!(ty_array -> Ty, do_parse!(
@@ -285,7 +329,7 @@
punct!(";") >>
len: array_len >>
punct!("]") >>
- (Ty::Array(Box::new(elem), len))
+ (TyArray { ty: Box::new(elem), amt: len }.into())
));
#[cfg(not(feature = "full"))]
@@ -309,10 +353,12 @@
keyword!("mut") => { |_| Mutability::Mutable }
) >>
target: ty >>
- (Ty::Ptr(Box::new(MutTy {
- ty: target,
- mutability: mutability,
- })))
+ (TyPtr {
+ ty: Box::new(MutTy {
+ ty: target,
+ mutability: mutability,
+ }),
+ }.into())
));
named!(ty_rptr -> Ty, do_parse!(
@@ -320,10 +366,13 @@
life: option!(lifetime) >>
mutability: mutability >>
target: ty >>
- (Ty::Rptr(life, Box::new(MutTy {
- ty: target,
- mutability: mutability,
- })))
+ (TyRptr {
+ lifetime: life,
+ ty: Box::new(MutTy {
+ ty: target,
+ mutability: mutability,
+ }),
+ }.into())
));
named!(ty_bare_fn -> Ty, do_parse!(
@@ -346,26 +395,28 @@
punct!("->"),
ty
)) >>
- (Ty::BareFn(Box::new(BareFnTy {
- unsafety: unsafety,
- abi: abi,
- lifetimes: lifetimes,
- inputs: inputs,
- output: match output {
- Some(ty) => FunctionRetTy::Ty(ty),
- None => FunctionRetTy::Default,
- },
- variadic: variadic.is_some(),
- })))
+ (TyBareFn {
+ ty: Box::new(BareFnTy {
+ unsafety: unsafety,
+ abi: abi,
+ lifetimes: lifetimes,
+ inputs: inputs,
+ output: match output {
+ Some(ty) => FunctionRetTy::Ty(ty),
+ None => FunctionRetTy::Default,
+ },
+ variadic: variadic.is_some(),
+ }),
+ }.into())
));
- named!(ty_never -> Ty, map!(punct!("!"), |_| Ty::Never));
+ named!(ty_never -> Ty, map!(punct!("!"), |_| TyNever {}.into()));
named!(ty_tup -> Ty, do_parse!(
punct!("(") >>
elems: terminated_list!(punct!(","), ty) >>
punct!(")") >>
- (Ty::Tup(elems))
+ (TyTup { tys: elems }.into())
));
named!(ty_path -> Ty, do_parse!(
@@ -381,7 +432,7 @@
path.segments.last_mut().unwrap().parameters = parenthesized;
}
if bounds.is_empty() {
- Ty::Path(qself, path)
+ TyPath { qself: qself, path: path }.into()
} else {
let path = TyParamBound::Trait(
PolyTraitRef {
@@ -391,7 +442,7 @@
TraitBoundModifier::None,
);
let bounds = Some(path).into_iter().chain(bounds).collect();
- Ty::TraitObject(bounds)
+ TyTraitObject { bounds: bounds }.into()
}
})
));
@@ -447,20 +498,20 @@
named!(ty_poly_trait_ref -> Ty, map!(
separated_nonempty_list!(punct!("+"), ty_param_bound),
- Ty::TraitObject
+ |x| TyTraitObject { bounds: x }.into()
));
named!(ty_impl_trait -> Ty, do_parse!(
keyword!("impl") >>
elem: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
- (Ty::ImplTrait(elem))
+ (TyImplTrait { bounds: elem }.into())
));
named!(ty_paren -> Ty, do_parse!(
punct!("(") >>
elem: ty >>
punct!(")") >>
- (Ty::Paren(Box::new(elem)))
+ (TyParen { ty: Box::new(elem) }.into())
));
named!(pub mutability -> Mutability, alt!(
@@ -604,90 +655,122 @@
use super::*;
use quote::{Tokens, ToTokens};
- impl ToTokens for Ty {
+ impl ToTokens for TySlice {
fn to_tokens(&self, tokens: &mut Tokens) {
- match *self {
- Ty::Slice(ref inner) => {
- tokens.append("[");
- inner.to_tokens(tokens);
- tokens.append("]");
- }
- Ty::Array(ref inner, ref len) => {
- tokens.append("[");
- inner.to_tokens(tokens);
- tokens.append(";");
- len.to_tokens(tokens);
- tokens.append("]");
- }
- Ty::Ptr(ref target) => {
- tokens.append("*");
- match target.mutability {
- Mutability::Mutable => tokens.append("mut"),
- Mutability::Immutable => tokens.append("const"),
- }
- target.ty.to_tokens(tokens);
- }
- Ty::Rptr(ref lifetime, ref target) => {
- tokens.append("&");
- lifetime.to_tokens(tokens);
- target.mutability.to_tokens(tokens);
- target.ty.to_tokens(tokens);
- }
- Ty::BareFn(ref func) => {
- func.to_tokens(tokens);
- }
- Ty::Never => {
- tokens.append("!");
- }
- Ty::Tup(ref elems) => {
- tokens.append("(");
- tokens.append_separated(elems, ",");
- if elems.len() == 1 {
- tokens.append(",");
- }
- tokens.append(")");
- }
- Ty::Path(None, ref path) => {
- path.to_tokens(tokens);
- }
- Ty::Path(Some(ref qself), ref path) => {
- tokens.append("<");
- qself.ty.to_tokens(tokens);
- if qself.position > 0 {
- tokens.append("as");
- for (i, segment) in path.segments
- .iter()
- .take(qself.position)
- .enumerate() {
- if i > 0 || path.global {
- tokens.append("::");
- }
- segment.to_tokens(tokens);
- }
- }
- tokens.append(">");
- for segment in path.segments.iter().skip(qself.position) {
- tokens.append("::");
- segment.to_tokens(tokens);
- }
- }
- Ty::TraitObject(ref bounds) => {
- tokens.append_separated(bounds, "+");
- }
- Ty::ImplTrait(ref bounds) => {
- tokens.append("impl");
- tokens.append_separated(bounds, "+");
- }
- Ty::Paren(ref inner) => {
- tokens.append("(");
- inner.to_tokens(tokens);
- tokens.append(")");
- }
- Ty::Infer => {
- tokens.append("_");
- }
- Ty::Mac(ref mac) => mac.to_tokens(tokens),
+ tokens.append("[");
+ self.ty.to_tokens(tokens);
+ tokens.append("]");
+ }
+ }
+
+ impl ToTokens for TyArray {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ tokens.append("[");
+ self.ty.to_tokens(tokens);
+ tokens.append(";");
+ self.amt.to_tokens(tokens);
+ tokens.append("]");
+ }
+ }
+
+ impl ToTokens for TyPtr {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ tokens.append("*");
+ match self.ty.mutability {
+ Mutability::Mutable => tokens.append("mut"),
+ Mutability::Immutable => tokens.append("const"),
}
+ self.ty.ty.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for TyRptr {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ tokens.append("&");
+ self.lifetime.to_tokens(tokens);
+ match self.ty.mutability {
+ Mutability::Mutable => tokens.append("mut"),
+ Mutability::Immutable => {}
+ }
+ self.ty.ty.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for TyBareFn {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ self.ty.to_tokens(tokens)
+ }
+ }
+
+ impl ToTokens for TyNever {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ tokens.append("!");
+ }
+ }
+
+ impl ToTokens for TyTup {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ tokens.append("(");
+ tokens.append_separated(&self.tys, ",");
+ if self.tys.len() == 1 {
+ tokens.append(",");
+ }
+ tokens.append(")");
+ }
+ }
+
+ impl ToTokens for TyPath {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ let qself = match self.qself {
+ Some(ref qself) => qself,
+ None => return self.path.to_tokens(tokens),
+ };
+ tokens.append("<");
+ qself.ty.to_tokens(tokens);
+ if qself.position > 0 {
+ tokens.append("as");
+ for (i, segment) in self.path.segments
+ .iter()
+ .take(qself.position)
+ .enumerate() {
+ if i > 0 || self.path.global {
+ tokens.append("::");
+ }
+ segment.to_tokens(tokens);
+ }
+ }
+ tokens.append(">");
+ for segment in self.path.segments.iter().skip(qself.position) {
+ tokens.append("::");
+ segment.to_tokens(tokens);
+ }
+ }
+ }
+
+ impl ToTokens for TyTraitObject {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ tokens.append_separated(&self.bounds, "+");
+ }
+ }
+
+ impl ToTokens for TyImplTrait {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ tokens.append("impl");
+ tokens.append_separated(&self.bounds, "+");
+ }
+ }
+
+ impl ToTokens for TyParen {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ tokens.append("(");
+ self.ty.to_tokens(tokens);
+ tokens.append(")");
+ }
+ }
+
+ impl ToTokens for TyInfer {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ tokens.append("_");
}
}