Repository: dtolnay/syn
Pull request #8 (2016-09-12 00:25:34)

Things needed by serde_derive


Patch:
diff --git a/Cargo.toml b/Cargo.toml
index 8d424966..91a89f97 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -10,8 +10,10 @@ include = ["Cargo.toml", "src/**/*.rs"]
 
 [features]
 default = ["parsing", "printing"]
+aster = []
 parsing = ["nom"]
 printing = ["quote"]
+visit = []
 
 [dependencies]
 nom = { version = "1.2.4", optional = true }
diff --git a/src/aster/generics.rs b/src/aster/generics.rs
new file mode 100644
index 00000000..c3c48463
--- /dev/null
+++ b/src/aster/generics.rs
@@ -0,0 +1,241 @@
+use {
+    Generics,
+    Ident,
+    LifetimeDef,
+    TyParam,
+    WhereClause,
+    WherePredicate,
+};
+use aster::invoke::{Identity, Invoke};
+use aster::lifetime::{IntoLifetime, LifetimeDefBuilder, IntoLifetimeDef};
+use aster::path::IntoPath;
+use aster::ty_param::TyParamBuilder;
+use aster::where_predicate::WherePredicateBuilder;
+
+pub struct GenericsBuilder<F=Identity> {
+    callback: F,
+    lifetimes: Vec<LifetimeDef>,
+    ty_params: Vec<TyParam>,
+    predicates: Vec<WherePredicate>,
+}
+
+impl GenericsBuilder {
+    pub fn new() -> Self {
+        GenericsBuilder::with_callback(Identity)
+    }
+
+    pub fn from_generics(generics: Generics) -> Self {
+        GenericsBuilder::from_generics_with_callback(generics, Identity)
+    }
+}
+
+impl<F> GenericsBuilder<F>
+    where F: Invoke<Generics>,
+{
+    pub fn with_callback(callback: F) -> Self {
+        GenericsBuilder {
+            callback: callback,
+            lifetimes: Vec::new(),
+            ty_params: Vec::new(),
+            predicates: Vec::new(),
+        }
+    }
+
+    pub fn from_generics_with_callback(generics: Generics, callback: F) -> Self {
+        GenericsBuilder {
+            callback: callback,
+            lifetimes: generics.lifetimes,
+            ty_params: generics.ty_params,
+            predicates: generics.where_clause.predicates,
+        }
+    }
+
+    pub fn with(self, generics: Generics) -> Self {
+        self.with_lifetimes(generics.lifetimes.into_iter())
+            .with_ty_params(generics.ty_params.into_iter())
+            .with_predicates(generics.where_clause.predicates.into_iter())
+    }
+
+    pub fn with_lifetimes<I, L>(mut self, iter: I) -> Self
+        where I: IntoIterator<Item=L>,
+              L: IntoLifetimeDef,
+    {
+        let iter = iter.into_iter().map(|lifetime_def| lifetime_def.into_lifetime_def());
+        self.lifetimes.extend(iter);
+        self
+    }
+
+    pub fn with_lifetime_names<I, N>(mut self, iter: I) -> Self
+        where I: IntoIterator<Item=N>,
+              N: Into<Ident>,
+    {
+        for name in iter {
+            self = self.lifetime_name(name);
+        }
+        self
+    }
+
+    pub fn with_lifetime(mut self, lifetime: LifetimeDef) -> Self {
+        self.lifetimes.push(lifetime);
+        self
+    }
+
+    pub fn lifetime_name<N>(self, name: N) -> Self
+        where N: Into<Ident>,
+    {
+        self.lifetime(name).build()
+    }
+
+    pub fn lifetime<N>(self, name: N) -> LifetimeDefBuilder<Self>
+        where N: Into<Ident>,
+    {
+        LifetimeDefBuilder::with_callback(name, self)
+    }
+
+    pub fn with_ty_params<I>(mut self, iter: I) -> Self
+        where I: IntoIterator<Item=TyParam>,
+    {
+        self.ty_params.extend(iter);
+        self
+    }
+
+    pub fn with_ty_param_ids<I, T>(mut self, iter: I) -> Self
+        where I: IntoIterator<Item=T>,
+              T: Into<Ident>,
+    {
+        for id in iter {
+            self = self.ty_param_id(id);
+        }
+        self
+    }
+
+    pub fn with_ty_param(mut self, ty_param: TyParam) -> Self {
+        self.ty_params.push(ty_param);
+        self
+    }
+
+    pub fn ty_param_id<I>(self, id: I) -> Self
+        where I: Into<Ident>,
+    {
+        self.ty_param(id).build()
+    }
+
+    pub fn ty_param<I>(self, id: I) -> TyParamBuilder<Self>
+        where I: Into<Ident>,
+    {
+        TyParamBuilder::with_callback(id, self)
+    }
+
+    pub fn with_predicates<I>(mut self, iter: I) -> Self
+        where I: IntoIterator<Item=WherePredicate>,
+    {
+        self.predicates.extend(iter);
+        self
+    }
+
+    pub fn with_predicate(mut self, predicate: WherePredicate) -> Self {
+        self.predicates.push(predicate);
+        self
+    }
+
+    pub fn predicate(self) -> WherePredicateBuilder<Self> {
+        WherePredicateBuilder::with_callback(self)
+    }
+
+    pub fn add_lifetime_bound<L>(mut self, lifetime: L) -> Self
+        where L: IntoLifetime,
+    {
+        let lifetime = lifetime.into_lifetime();
+
+        for lifetime_def in &mut self.lifetimes {
+            lifetime_def.bounds.push(lifetime.clone());
+        }
+
+        for ty_param in &mut self.ty_params {
+            *ty_param = TyParamBuilder::from_ty_param(ty_param.clone())
+                .lifetime_bound(lifetime.clone())
+                .build();
+        }
+
+        self
+    }
+
+    pub fn add_ty_param_bound<P>(mut self, path: P) -> Self
+        where P: IntoPath,
+    {
+        let path = path.into_path();
+
+        for ty_param in &mut self.ty_params {
+            *ty_param = TyParamBuilder::from_ty_param(ty_param.clone())
+                .trait_bound(path.clone()).build()
+                .build();
+        }
+
+        self
+    }
+
+    pub fn strip_bounds(self) -> Self {
+        self.strip_lifetimes()
+            .strip_ty_params()
+            .strip_predicates()
+    }
+
+    pub fn strip_lifetimes(mut self) -> Self {
+        for lifetime in &mut self.lifetimes {
+            lifetime.bounds = vec![];
+        }
+        self
+    }
+
+    pub fn strip_ty_params(mut self) -> Self {
+        for ty_param in &mut self.ty_params {
+            ty_param.bounds = vec![];
+        }
+        self
+    }
+
+    pub fn strip_predicates(mut self) -> Self {
+        self.predicates = vec![];
+        self
+    }
+
+    pub fn build(self) -> F::Result {
+        self.callback.invoke(Generics {
+            lifetimes: self.lifetimes,
+            ty_params: self.ty_params,
+            where_clause: WhereClause {
+                predicates: self.predicates,
+            },
+        })
+    }
+}
+
+impl<F> Invoke<LifetimeDef> for GenericsBuilder<F>
+    where F: Invoke<Generics>,
+{
+    type Result = Self;
+
+    fn invoke(self, lifetime: LifetimeDef) -> Self {
+        self.with_lifetime(lifetime)
+    }
+}
+
+impl<F> Invoke<TyParam> for GenericsBuilder<F>
+    where F: Invoke<Generics>,
+{
+    type Result = Self;
+
+    fn invoke(self, ty_param: TyParam) -> Self {
+        self.with_ty_param(ty_param)
+    }
+}
+
+impl<F> Invoke<WherePredicate> for GenericsBuilder<F>
+    where F: Invoke<Generics>,
+{
+    type Result = Self;
+
+    fn invoke(self, predicate: WherePredicate) -> Self {
+        self.with_predicate(predicate)
+    }
+}
diff --git a/src/aster/ident.rs b/src/aster/ident.rs
new file mode 100644
index 00000000..586e471e
--- /dev/null
+++ b/src/aster/ident.rs
@@ -0,0 +1,35 @@
+use Ident;
+
+pub trait ToIdent {
+    fn to_ident(&self) -> Ident;
+}
+
+impl ToIdent for Ident {
+    fn to_ident(&self) -> Ident {
+        self.clone()
+    }
+}
+
+impl<'a> ToIdent for &'a str {
+    fn to_ident(&self) -> Ident {
+        (**self).into()
+    }
+}
+
+impl ToIdent for String {
+    fn to_ident(&self) -> Ident {
+        self.clone().into()
+    }
+}
+
+impl<'a, T> ToIdent for &'a T where T: ToIdent {
+    fn to_ident(&self) -> Ident {
+        (**self).to_ident()
+    }
+}
+
+impl<'a, T> ToIdent for &'a mut T where T: ToIdent {
+    fn to_ident(&self) -> Ident {
+        (**self).to_ident()
+    }
+}
diff --git a/src/aster/invoke.rs b/src/aster/invoke.rs
new file mode 100644
index 00000000..cf799e2a
--- /dev/null
+++ b/src/aster/invoke.rs
@@ -0,0 +1,14 @@
+pub trait Invoke<A> {
+    type Result;
+
+    fn invoke(self, arg: A) -> Self::Result;
+}
+
+#[derive(Copy, Clone)]
+pub struct Identity;
+
+impl<A> Invoke<A> for Identity {
+    type Result = A;
+
+    fn invoke(self, arg: A) -> A { arg }
+}
diff --git a/src/aster/lifetime.rs b/src/aster/lifetime.rs
new file mode 100644
index 00000000..517aff52
--- /dev/null
+++ b/src/aster/lifetime.rs
@@ -0,0 +1,111 @@
+use {
+    Ident,
+    Lifetime,
+    LifetimeDef,
+};
+use aster::invoke::{Invoke, Identity};
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub trait IntoLifetime {
+    fn into_lifetime(self) -> Lifetime;
+}
+
+impl IntoLifetime for Lifetime {
+    fn into_lifetime(self) -> Lifetime {
+        self
+    }
+}
+
+impl<'a> IntoLifetime for &'a str {
+    fn into_lifetime(self) -> Lifetime {
+        Lifetime {
+            ident: self.into(),
+        }
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub trait IntoLifetimeDef {
+    fn into_lifetime_def(self) -> LifetimeDef;
+}
+
+impl IntoLifetimeDef for LifetimeDef {
+    fn into_lifetime_def(self) -> LifetimeDef {
+        self
+    }
+}
+
+impl IntoLifetimeDef for Lifetime {
+    fn into_lifetime_def(self) -> LifetimeDef {
+        LifetimeDef {
+            lifetime: self,
+            bounds: vec![],
+        }
+    }
+}
+
+impl<'a> IntoLifetimeDef for &'a str {
+    fn into_lifetime_def(self) -> LifetimeDef {
+        self.into_lifetime().into_lifetime_def()
+    }
+}
+
+impl IntoLifetimeDef for String {
+    fn into_lifetime_def(self) -> LifetimeDef {
+        (*self).into_lifetime().into_lifetime_def()
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct LifetimeDefBuilder<F=Identity> {
+    callback: F,
+    lifetime: Lifetime,
+    bounds: Vec<Lifetime>,
+}
+
+impl LifetimeDefBuilder {
+    pub fn new<N>(name: N) -> Self
+        where N: Into<Ident>,
+    {
+        LifetimeDefBuilder::with_callback(name, Identity)
+    }
+}
+
+impl<F> LifetimeDefBuilder<F>
+    where F: Invoke<LifetimeDef>,
+{
+    pub fn with_callback<N>(name: N, callback: F) -> Self
+        where N: Into<Ident>,
+    {
+        let lifetime = Lifetime {
+            ident: name.into(),
+        };
+
+        LifetimeDefBuilder {
+            callback: callback,
+            lifetime: lifetime,
+            bounds: Vec::new(),
+        }
+    }
+
+    pub fn bound<N>(mut self, name: N) -> Self
+        where N: Into<Ident>,
+    {
+        let lifetime = Lifetime {
+            ident: name.into(),
+        };
+
+        self.bounds.push(lifetime);
+        self
+    }
+
+    pub fn build(self) -> F::Result {
+        self.callback.invoke(LifetimeDef {
+            lifetime: self.lifetime,
+            bounds: self.bounds,
+        })
+    }
+}
diff --git a/src/aster/mod.rs b/src/aster/mod.rs
new file mode 100644
index 00000000..9e30e228
--- /dev/null
+++ b/src/aster/mod.rs
@@ -0,0 +1,33 @@
+use super::*;
+
+pub mod generics;
+pub mod ident;
+pub mod invoke;
+pub mod lifetime;
+pub mod path;
+pub mod qpath;
+pub mod ty;
+pub mod ty_param;
+pub mod where_predicate;
+
+pub fn id<I>(id: I) -> Ident
+    where I: Into<Ident>
+{
+    id.into()
+}
+
+pub fn from_generics(generics: Generics) -> generics::GenericsBuilder {
+    generics::GenericsBuilder::from_generics(generics)
+}
+
+pub fn where_predicate() -> where_predicate::WherePredicateBuilder {
+    where_predicate::WherePredicateBuilder::new()
+}
+
+pub fn ty() -> ty::TyBuilder {
+    ty::TyBuilder::new()
+}
+
+pub fn path() -> path::PathBuilder {
+    path::PathBuilder::new()
+}
diff --git a/src/aster/path.rs b/src/aster/path.rs
new file mode 100644
index 00000000..14695e01
--- /dev/null
+++ b/src/aster/path.rs
@@ -0,0 +1,339 @@
+use {
+    AngleBracketedParameterData,
+    Generics,
+    Ident,
+    Lifetime,
+    ParenthesizedParameterData,
+    Path,
+    PathParameters,
+    PathSegment,
+    Ty,
+    TypeBinding,
+};
+use aster::ident::ToIdent;
+use aster::invoke::{Invoke, Identity};
+use aster::lifetime::IntoLifetime;
+use aster::ty::TyBuilder;
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub trait IntoPath {
+    fn into_path(self) -> Path;
+}
+
+impl IntoPath for Path {
+    fn into_path(self) -> Path {
+        self
+    }
+}
+
+impl IntoPath for Ident {
+    fn into_path(self) -> Path {
+        PathBuilder::new().id(self).build()
+    }
+}
+
+impl<'a> IntoPath for &'a str {
+    fn into_path(self) -> Path {
+        PathBuilder::new().id(self).build()
+    }
+}
+
+impl IntoPath for String {
+    fn into_path(self) -> Path {
+        (&*self).into_path()
+    }
+}
+
+impl<'a, T> IntoPath for &'a [T] where T: ToIdent {
+    fn into_path(self) -> Path {
+        PathBuilder::new().ids(self).build()
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct PathBuilder<F=Identity> {
+    callback: F,
+    global: bool,
+}
+
+impl PathBuilder {
+    pub fn new() -> Self {
+        PathBuilder::with_callback(Identity)
+    }
+}
+
+impl<F> PathBuilder<F>
+    where F: Invoke<Path>,
+{
+    pub fn with_callback(callback: F) -> Self {
+        PathBuilder {
+            callback: callback,
+            global: false,
+        }
+    }
+
+    pub fn build(self, path: Path) -> F::Result {
+        self.callback.invoke(path)
+    }
+
+    pub fn global(mut self) -> Self {
+        self.global = true;
+        self
+    }
+
+    pub fn ids<I, T>(self, ids: I) -> PathSegmentsBuilder<F>
+        where I: IntoIterator<Item=T>,
+              T: ToIdent,
+    {
+        let mut ids = ids.into_iter();
+        let id = ids.next().expect("passed path with no id");
+
+        self.id(id).ids(ids)
+    }
+
+    pub fn id<I>(self, id: I) -> PathSegmentsBuilder<F>
+        where I: ToIdent,
+    {
+        self.segment(id).build()
+    }
+
+    pub fn segment<I>(self, id: I)
+        -> PathSegmentBuilder<PathSegmentsBuilder<F>>
+        where I: ToIdent,
+    {
+        PathSegmentBuilder::with_callback(id, PathSegmentsBuilder {
+            callback: self.callback,
+            global: self.global,
+            segments: Vec::new(),
+        })
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct PathSegmentsBuilder<F=Identity> {
+    callback: F,
+    global: bool,
+    segments: Vec<PathSegment>,
+}
+
+impl<F> PathSegmentsBuilder<F>
+    where F: Invoke<Path>,
+{
+    pub fn ids<I, T>(mut self, ids: I) -> PathSegmentsBuilder<F>
+        where I: IntoIterator<Item=T>,
+              T: ToIdent,
+    {
+        for id in ids {
+            self = self.id(id);
+        }
+
+        self
+    }
+
+    pub fn id<T>(self, id: T) -> PathSegmentsBuilder<F>
+        where T: ToIdent,
+    {
+        self.segment(id).build()
+    }
+
+    pub fn segment<T>(self, id: T) -> PathSegmentBuilder<Self>
+        where T: ToIdent,
+    {
+        PathSegmentBuilder::with_callback(id, self)
+    }
+
+    pub fn build(self) -> F::Result {
+        self.callback.invoke(Path {
+            global: self.global,
+            segments: self.segments,
+        })
+    }
+}
+
+impl<F> Invoke<PathSegment> for PathSegmentsBuilder<F> {
+    type Result = Self;
+
+    fn invoke(mut self, segment: PathSegment) -> Self {
+        self.segments.push(segment);
+        self
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct PathSegmentBuilder<F=Identity> {
+    callback: F,
+    id: Ident,
+    lifetimes: Vec<Lifetime>,
+    tys: Vec<Ty>,
+    bindings: Vec<TypeBinding>,
+}
+
+impl<F> PathSegmentBuilder<F>
+    where F: Invoke<PathSegment>,
+{
+    pub fn with_callback<I>(id: I, callback: F) -> Self
+        where I: ToIdent,
+    {
+        PathSegmentBuilder {
+            callback: callback,
+            id: id.to_ident(),
+            lifetimes: Vec::new(),
+            tys: Vec::new(),
+            bindings: Vec::new(),
+        }
+    }
+
+    pub fn with_generics(self, generics: Generics) -> Self {
+        // Strip off the bounds.
+        let lifetimes = generics.lifetimes.iter()
+            .map(|lifetime_def| lifetime_def.lifetime.clone());
+
+        let tys = generics.ty_params.iter()
+            .map(|ty_param| TyBuilder::new().id(ty_param.ident.clone()));
+
+        self.with_lifetimes(lifetimes)
+            .with_tys(tys)
+    }
+
+    pub fn with_lifetimes<I, L>(mut self, iter: I) -> Self
+        where I: IntoIterator<Item=L>,
+              L: IntoLifetime,
+    {
+        let iter = iter.into_iter().map(|lifetime| lifetime.into_lifetime());
+        self.lifetimes.extend(iter);
+        self
+    }
+
+    pub fn with_lifetime<L>(mut self, lifetime: L) -> Self
+        where L: IntoLifetime,
+    {
+        self.lifetimes.push(lifetime.into_lifetime());
+        self
+    }
+
+    pub fn lifetime<N>(self, name: N) -> Self
+        where N: ToIdent,
+    {
+        let lifetime = Lifetime {
+            ident: name.to_ident(),
+        };
+        self.with_lifetime(lifetime)
+    }
+
+    pub fn with_tys<I>(mut self, iter: I) -> Self
+        where I: IntoIterator<Item=Ty>,
+    {
+        self.tys.extend(iter);
+        self
+    }
+
+    pub fn with_ty(mut self, ty: Ty) -> Self {
+        self.tys.push(ty);
+        self
+    }
+
+    pub fn ty(self) -> TyBuilder<Self> {
+        TyBuilder::with_callback(self)
+    }
+
+    pub fn with_binding(mut self, binding: TypeBinding) -> Self {
+        self.bindings.push(binding);
+        self
+    }
+
+    pub fn binding<T>(self, id: T) -> TyBuilder<TypeBindingBuilder<F>>
+        where T: ToIdent,
+    {
+        TyBuilder::with_callback(TypeBindingBuilder {
+            id: id.to_ident(),
+            builder: self,
+        })
+    }
+
+    pub fn no_return(self) -> F::Result {
+        self.build_return(None)
+    }
+
+    pub fn return_(self) -> TyBuilder<PathSegmentReturnBuilder<F>> {
+        TyBuilder::with_callback(PathSegmentReturnBuilder(self))
+    }
+
+    pub fn build_return(self, output: Option<Ty>) -> F::Result {
+        let data = ParenthesizedParameterData {
+            inputs: self.tys,
+            output: output,
+        };
+
+        let parameters = PathParameters::Parenthesized(data);
+
+        self.callback.invoke(PathSegment {
+            ident: self.id,
+            parameters: parameters,
+        })
+    }
+
+    pub fn build(self) -> F::Result {
+        let data = AngleBracketedParameterData {
+            lifetimes: self.lifetimes,
+            types: self.tys,
+            bindings: self.bindings,
+        };
+
+        let parameters = PathParameters::AngleBracketed(data);
+
+        self.callback.invoke(PathSegment {
+            ident: self.id,
+            parameters: parameters,
+        })
+    }
+}
+
+impl<F> Invoke<Ty> for PathSegmentBuilder<F>
+    where F: Invoke<PathSegment>
+{
+    type Result = Self;
+
+    fn invoke(self, ty: Ty) -> Self {
+        self.with_ty(ty)
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct TypeBindingBuilder<F> {
+    id: Ident,
+    builder: PathSegmentBuilder<F>,
+}
+
+impl<F> Invoke<Ty> for TypeBindingBuilder<F>
+    where F: Invoke<PathSegment>
+{
+    type Result = PathSegmentBuilder<F>;
+
+    fn invoke(self, ty: Ty) -> Self::Result {
+        let id = self.id;
+
+        self.builder.with_binding(TypeBinding {
+            ident: id,
+            ty: ty,
+        })
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct PathSegmentReturnBuilder<F>(PathSegmentBuilder<F>);
+
+impl<F> Invoke<Ty> for PathSegmentReturnBuilder<F>
+    where F: Invoke<PathSegment>
+{
+    type Result = F::Result;
+
+    fn invoke(self, ty: Ty) -> Self::Result {
+        self.0.build_return(Some(ty))
+    }
+}
diff --git a/src/aster/qpath.rs b/src/aster/qpath.rs
new file mode 100644
index 00000000..ab2516e8
--- /dev/null
+++ b/src/aster/qpath.rs
@@ -0,0 +1,150 @@
+use {
+    Path,
+    PathSegment,
+    QSelf,
+    Ty,
+};
+use aster::ident::ToIdent;
+use aster::invoke::{Invoke, Identity};
+use aster::path::{PathBuilder, PathSegmentBuilder};
+use aster::ty::TyBuilder;
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct QPathBuilder<F=Identity> {
+    callback: F,
+}
+
+impl QPathBuilder {
+    pub fn new() -> Self {
+        QPathBuilder::with_callback(Identity)
+    }
+}
+
+impl<F> QPathBuilder<F>
+    where F: Invoke<(QSelf, Path)>,
+{
+    /// Construct a `QPathBuilder` that will call the `callback` with a constructed `QSelf`
+    /// and `Path`.
+    pub fn with_callback(callback: F) -> Self {
+        QPathBuilder {
+            callback: callback,
+        }
+    }
+
+    /// Build a qualified path first by starting with a type builder.
+    pub fn with_ty(self, ty: Ty) -> QPathTyBuilder<F> {
+        QPathTyBuilder {
+            builder: self,
+            ty: ty,
+        }
+    }
+
+    /// Build a qualified path first by starting with a type builder.
+    pub fn ty(self) -> TyBuilder<Self> {
+        TyBuilder::with_callback(self)
+    }
+
+    /// Build a qualified path with a concrete type and path.
+    pub fn build(self, qself: QSelf, path: Path) -> F::Result {
+        self.callback.invoke((qself, path))
+    }
+}
+
+impl<F> Invoke<Ty> for QPathBuilder<F>
+    where F: Invoke<(QSelf, Path)>,
+{
+    type Result = QPathTyBuilder<F>;
+
+    fn invoke(self, ty: Ty) -> QPathTyBuilder<F> {
+        self.with_ty(ty)
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct QPathTyBuilder<F> {
+    builder: QPathBuilder<F>,
+    ty: Ty,
+}
+
+impl<F> QPathTyBuilder<F>
+    where F: Invoke<(QSelf, Path)>,
+{
+    /// Build a qualified path with a path builder.
+    pub fn as_(self) -> PathBuilder<Self> {
+        PathBuilder::with_callback(self)
+    }
+
+    pub fn id<T>(self, id: T) -> F::Result
+        where T: ToIdent,
+    {
+        let path = Path {
+            global: false,
+            segments: vec![],
+        };
+        self.as_().build(path).id(id)
+    }
+
+    pub fn segment<T>(self, id: T) -> PathSegmentBuilder<QPathQSelfBuilder<F>>
+        where T: ToIdent,
+    {
+        let path = Path {
+            global: false,
+            segments: vec![],
+        };
+        self.as_().build(path).segment(id)
+    }
+}
+
+impl<F> Invoke<Path> for QPathTyBuilder<F>
+    where F: Invoke<(QSelf, Path)>,
+{
+    type Result = QPathQSelfBuilder<F>;
+
+    fn invoke(self, path: Path) -> QPathQSelfBuilder<F> {
+        QPathQSelfBuilder {
+            builder: self.builder,
+            qself: QSelf {
+                ty: Box::new(self.ty),
+                position: path.segments.len(),
+            },
+            path: path,
+        }
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct QPathQSelfBuilder<F> {
+    builder: QPathBuilder<F>,
+    qself: QSelf,
+    path: Path,
+}
+
+impl<F> QPathQSelfBuilder<F>
+    where F: Invoke<(QSelf, Path)>,
+{
+    pub fn id<T>(self, id: T) -> F::Result
+        where T: ToIdent,
+    {
+        self.segment(id).build()
+    }
+
+    pub fn segment<T>(self, id: T) -> PathSegmentBuilder<QPathQSelfBuilder<F>>
+        where T: ToIdent,
+    {
+        PathSegmentBuilder::with_callback(id, self)
+    }
+}
+
+impl<F> Invoke<PathSegment> for QPathQSelfBuilder<F>
+    where F: Invoke<(QSelf, Path)>,
+{
+    type Result = F::Result;
+
+    fn invoke(mut self, segment: PathSegment) -> F::Result {
+        self.path.segments.push(segment);
+        self.builder.build(self.qself, self.path)
+    }
+}
diff --git a/src/aster/ty.rs b/src/aster/ty.rs
new file mode 100644
index 00000000..04ff2a9f
--- /dev/null
+++ b/src/aster/ty.rs
@@ -0,0 +1,591 @@
+use {
+    Generics,
+    Lifetime,
+    MutTy,
+    Mutability,
+    Path,
+    QSelf,
+    Ty,
+    TyParamBound,
+};
+use aster::ident::ToIdent;
+use aster::invoke::{Invoke, Identity};
+use aster::lifetime::IntoLifetime;
+use aster::path::PathBuilder;
+use aster::qpath::QPathBuilder;
+use aster::ty_param::TyParamBoundBuilder;
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct TyBuilder<F=Identity> {
+    callback: F,
+}
+
+impl TyBuilder {
+    pub fn new() -> Self {
+        TyBuilder::with_callback(Identity)
+    }
+}
+
+impl<F> TyBuilder<F>
+    where F: Invoke<Ty>,
+{
+    pub fn with_callback(callback: F) -> Self {
+        TyBuilder {
+            callback: callback,
+        }
+    }
+
+    pub fn build(self, ty: Ty) -> F::Result {
+        self.callback.invoke(ty)
+    }
+
+    pub fn id<I>(self, id: I) -> F::Result
+        where I: ToIdent,
+    {
+        self.path().id(id).build()
+    }
+
+    pub fn build_path(self, path: Path) -> F::Result {
+        self.build(Ty::Path(None, path))
+    }
+
+    pub fn build_qpath(self, qself: QSelf, path: Path) -> F::Result {
+        self.build(Ty::Path(Some(qself), path))
+    }
+
+    pub fn path(self) -> PathBuilder<TyPathBuilder<F>> {
+        PathBuilder::with_callback(TyPathBuilder(self))
+    }
+
+    pub fn qpath(self) -> QPathBuilder<TyQPathBuilder<F>> {
+        QPathBuilder::with_callback(TyQPathBuilder(self))
+    }
+
+    pub fn isize(self) -> F::Result {
+        self.id("isize")
+    }
+
+    pub fn i8(self) -> F::Result {
+        self.id("i8")
+    }
+
+    pub fn i16(self) -> F::Result {
+        self.id("i16")
+    }
+
+    pub fn i32(self) -> F::Result {
+        self.id("i32")
+    }
+
+    pub fn i64(self) -> F::Result {
+        self.id("i64")
+    }
+
+    pub fn usize(self) -> F::Result {
+        self.id("usize")
+    }
+
+    pub fn u8(self) -> F::Result {
+        self.id("u8")
+    }
+
+    pub fn u16(self) -> F::Result {
+        self.id("u16")
+    }
+
+    pub fn u32(self) -> F::Result {
+        self.id("u32")
+    }
+
+    pub fn u64(self) -> F::Result {
+        self.id("u64")
+    }
+
+    pub fn f32(self) -> F::Result {
+        self.id("f32")
+    }
+
+    pub fn f64(self) -> F::Result {
+        self.id("f64")
+    }
+
+    pub fn bool(self) -> F::Result {
+        self.id("bool")
+    }
+
+    pub fn unit(self) -> F::Result {
+        self.tuple().build()
+    }
+
+    pub fn tuple(self) -> TyTupleBuilder<F> {
+        TyTupleBuilder {
+            builder: self,
+            tys: vec![],
+        }
+    }
+
+    pub fn build_slice(self, ty: Ty) -> F::Result {
+        self.build(Ty::Vec(Box::new(ty)))
+    }
+
+    pub fn slice(self) -> TyBuilder<TySliceBuilder<F>> {
+        TyBuilder::with_callback(TySliceBuilder(self))
+    }
+
+    pub fn ref_(self) -> TyRefBuilder<F> {
+        TyRefBuilder {
+            builder: self,
+            lifetime: None,
+            mutability: Mutability::Immutable,
+        }
+    }
+
+    pub fn never(self) -> F::Result {
+        self.build(Ty::Never)
+    }
+
+    pub fn infer(self) -> F::Result {
+        self.build(Ty::Infer)
+    }
+
+    pub fn option(self) -> TyBuilder<TyOptionBuilder<F>> {
+        TyBuilder::with_callback(TyOptionBuilder(self))
+    }
+
+    pub fn result(self) -> TyBuilder<TyResultOkBuilder<F>> {
+        TyBuilder::with_callback(TyResultOkBuilder(self))
+    }
+
+    pub fn phantom_data(self) -> TyBuilder<TyPhantomDataBuilder<F>> {
+        TyBuilder::with_callback(TyPhantomDataBuilder(self))
+    }
+
+    pub fn box_(self) -> TyBuilder<TyBoxBuilder<F>> {
+        TyBuilder::with_callback(TyBoxBuilder(self))
+    }
+
+    pub fn iterator(self) -> TyBuilder<TyIteratorBuilder<F>> {
+        TyBuilder::with_callback(TyIteratorBuilder(self))
+    }
+
+    pub fn object_sum(self) -> TyBuilder<TyObjectSumBuilder<F>> {
+        TyBuilder::with_callback(TyObjectSumBuilder {
+            builder: self,
+        })
+    }
+
+    pub fn impl_trait(self) -> TyImplTraitTyBuilder<F> {
+        TyImplTraitTyBuilder { builder: self, bounds: Vec::new() }
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct TyPathBuilder<F>(TyBuilder<F>);
+
+impl<F> Invoke<Path> for TyPathBuilder<F>
+    where F: Invoke<Ty>,
+{
+    type Result = F::Result;
+
+    fn invoke(self, path: Path) -> F::Result {
+        self.0.build_path(path)
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct TyQPathBuilder<F>(TyBuilder<F>);
+
+impl<F> Invoke<(QSelf, Path)> for TyQPathBuilder<F>
+    where F: Invoke<Ty>,
+{
+    type Result = F::Result;
+
+    fn invoke(self, (qself, path): (QSelf, Path)) -> F::Result {
+        self.0.build_qpath(qself, path)
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct TySliceBuilder<F>(TyBuilder<F>);
+
+impl<F> Invoke<Ty> for TySliceBuilder<F>
+    where F: Invoke<Ty>,
+{
+    type Result = F::Result;
+
+    fn invoke(self, ty: Ty) -> F::Result {
+        self.0.build_slice(ty)
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct TyRefBuilder<F> {
+    builder: TyBuilder<F>,
+    lifetime: Option<Lifetime>,
+    mutability: Mutability,
+}
+
+impl<F> TyRefBuilder<F>
+    where F: Invoke<Ty>,
+{
+    pub fn mut_(mut self) -> Self {
+        self.mutability = Mutability::Mutable;
+        self
+    }
+
+    pub fn lifetime<N>(mut self, name: N) -> Self
+        where N: ToIdent,
+    {
+        self.lifetime = Some(Lifetime {
+            ident: name.to_ident(),
+        });
+        self
+    }
+
+    pub fn build_ty(self, ty: Ty) -> F::Result {
+        let ty = MutTy {
+            ty: ty,
+            mutability: self.mutability,
+        };
+        self.builder.build(Ty::Rptr(self.lifetime, Box::new(ty)))
+    }
+
+    pub fn ty(self) -> TyBuilder<Self> {
+        TyBuilder::with_callback(self)
+    }
+}
+
+impl<F> Invoke<Ty> for TyRefBuilder<F>
+    where F: Invoke<Ty>,
+{
+    type Result = F::Result;
+
+    fn invoke(self, ty: Ty) -> F::Result {
+        self.build_ty(ty)
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct TyOptionBuilder<F>(TyBuilder<F>);
+
+impl<F> Invoke<Ty> for TyOptionBuilder<F>
+    where F: Invoke<Ty>,
+{
+    type Result = F::Result;
+
+    fn invoke(self, ty: Ty) -> F::Result {
+        let path = PathBuilder::new()
+            .global()
+            .id("std")
+            .id("option")
+            .segment("Option")
+                .with_ty(ty)
+                .build()
+            .build();
+
+        self.0.build_path(path)
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct TyResultOkBuilder<F>(TyBuilder<F>);
+
+impl<F> Invoke<Ty> for TyResultOkBuilder<F>
+    where F: Invoke<Ty>,
+{
+    type Result = TyBuilder<TyResultErrBuilder<F>>;
+
+    fn invoke(self, ty: Ty) -> TyBuilder<TyResultErrBuilder<F>> {
+        TyBuilder::with_callback(TyResultErrBuilder(self.0, ty))
+    }
+}
+
+pub struct TyResultErrBuilder<F>(TyBuilder<F>, Ty);
+
+impl<F> Invoke<Ty> for TyResultErrBuilder<F>
+    where F: Invoke<Ty>,
+{
+    type Result = F::Result;
+
+    fn invoke(self, ty: Ty) -> F::Result {
+        let path = PathBuilder::new()
+            .global()
+            .id("std")
+            .id("result")
+            .segment("Result")
+                .with_ty(self.1)
+                .with_ty(ty)
+                .build()
+            .build();
+
+        self.0.build_path(path)
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct TyPhantomDataBuilder<F>(TyBuilder<F>);
+
+impl<F> Invoke<Ty> for TyPhantomDataBuilder<F>
+    where F: Invoke<Ty>,
+{
+    type Result = F::Result;
+
+    fn invoke(self, ty: Ty) -> F::Result {
+        let path = PathBuilder::new()
+            .global()
+            .id("std")
+            .id("marker")
+            .segment("PhantomData")
+                .with_ty(ty)
+                .build()
+            .build();
+
+        self.0.build_path(path)
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct TyBoxBuilder<F>(TyBuilder<F>);
+
+impl<F> Invoke<Ty> for TyBoxBuilder<F>
+    where F: Invoke<Ty>,
+{
+    type Result = F::Result;
+
+    fn invoke(self, ty: Ty) -> F::Result {
+        let path = PathBuilder::new()
+            .global()
+            .id("std")
+            .id("boxed")
+            .segment("Box")
+                .with_ty(ty)
+                .build()
+            .build();
+
+        self.0.build_path(path)
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct TyIteratorBuilder<F>(TyBuilder<F>);
+
+impl<F> Invoke<Ty> for TyIteratorBuilder<F>
+    where F: Invoke<Ty>,
+{
+    type Result = F::Result;
+
+    fn invoke(self, ty: Ty) -> F::Result {
+        let path = PathBuilder::new()
+            .global()
+            .id("std")
+            .id("iter")
+            .segment("Iterator")
+                .binding("Item").build(ty.clone())
+                .build()
+            .build();
+
+        self.0.build_path(path)
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct TyObjectSumBuilder<F> {
+    builder: TyBuilder<F>,
+}
+
+impl<F> Invoke<Ty> for TyObjectSumBuilder<F>
+    where F: Invoke<Ty>,
+{
+    type Result = TyObjectSumTyBuilder<F>;
+
+    fn invoke(self, ty: Ty) -> Self::Result {
+        TyObjectSumTyBuilder {
+            builder: self.builder,
+            ty: ty,
+            bounds: Vec::new(),
+        }
+    }
+}
+
+pub struct TyObjectSumTyBuilder<F> {
+    builder: TyBuilder<F>,
+    ty: Ty,
+    bounds: Vec<TyParamBound>,
+}
+
+impl<F> TyObjectSumTyBuilder<F>
+    where F: Invoke<Ty>,
+{
+    pub fn with_bounds<I>(mut self, iter: I) -> Self
+        where I: Iterator<Item=TyParamBound>,
+    {
+        self.bounds.extend(iter);
+        self
+    }
+
+    pub fn with_bound(mut self, bound: TyParamBound) -> Self {
+        self.bounds.push(bound);
+        self
+    }
+
+    pub fn bound(self) -> TyParamBoundBuilder<Self> {
+        TyParamBoundBuilder::with_callback(self)
+    }
+
+    pub fn with_generics(self, generics: Generics) -> Self {
+        self.with_lifetimes(
+            generics.lifetimes.into_iter()
+                .map(|def| def.lifetime)
+        )
+    }
+
+    pub fn with_lifetimes<I, L>(mut self, lifetimes: I) -> Self
+        where I: Iterator<Item=L>,
+              L: IntoLifetime,
+    {
+        for lifetime in lifetimes {
+            self = self.lifetime(lifetime);
+        }
+
+        self
+    }
+
+    pub fn lifetime<L>(self, lifetime: L) -> Self
+        where L: IntoLifetime,
+    {
+        self.bound().lifetime(lifetime)
+    }
+
+    pub fn build(self) -> F::Result {
+        let bounds = self.bounds;
+        self.builder.build(Ty::ObjectSum(Box::new(self.ty), bounds))
+    }
+}
+
+impl<F> Invoke<TyParamBound> for TyObjectSumTyBuilder<F>
+    where F: Invoke<Ty>,
+{
+    type Result = Self;
+
+    fn invoke(self, bound: TyParamBound) -> Self {
+        self.with_bound(bound)
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct TyImplTraitTyBuilder<F> {
+    builder: TyBuilder<F>,
+    bounds: Vec<TyParamBound>,
+}
+
+impl<F> TyImplTraitTyBuilder<F>
+    where F: Invoke<Ty>,
+{
+    pub fn with_bounds<I>(mut self, iter: I) -> Self
+        where I: Iterator<Item=TyParamBound>,
+    {
+        self.bounds.extend(iter);
+        self
+    }
+
+    pub fn with_bound(mut self, bound: TyParamBound) -> Self {
+        self.bounds.push(bound);
+        self
+    }
+
+    pub fn bound(self) -> TyParamBoundBuilder<Self> {
+        TyParamBoundBuilder::with_callback(self)
+    }
+
+    pub fn with_generics(self, generics: Generics) -> Self {
+        self.with_lifetimes(
+            generics.lifetimes.into_iter()
+                .map(|def| def.lifetime)
+        )
+    }
+
+    pub fn with_lifetimes<I, L>(mut self, lifetimes: I) -> Self
+        where I: Iterator<Item=L>,
+              L: IntoLifetime,
+    {
+        for lifetime in lifetimes {
+            self = self.lifetime(lifetime);
+        }
+
+        self
+    }
+
+    pub fn lifetime<L>(self, lifetime: L) -> Self
+        where L: IntoLifetime,
+    {
+        self.bound().lifetime(lifetime)
+    }
+
+    pub fn build(self) -> F::Result {
+        let bounds = self.bounds;
+        self.builder.build(Ty::ImplTrait(bounds))
+    }
+}
+
+impl<F> Invoke<TyParamBound> for TyImplTraitTyBuilder<F>
+    where F: Invoke<Ty>,
+{
+    type Result = Self;
+
+    fn invoke(self, bound: TyParamBound) -> Self {
+        self.with_bound(bound)
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct TyTupleBuilder<F> {
+    builder: TyBuilder<F>,
+    tys: Vec<Ty>,
+}
+
+impl<F> TyTupleBuilder<F>
+    where F: Invoke<Ty>,
+{
+    pub fn with_tys<I>(mut self, iter: I) -> Self
+        where I: IntoIterator<Item=Ty>,
+    {
+        self.tys.extend(iter);
+        self
+    }
+
+    pub fn with_ty(mut self, ty: Ty) -> Self {
+        self.tys.push(ty);
+        self
+    }
+
+    pub fn ty(self) -> TyBuilder<Self> {
+        TyBuilder::with_callback(self)
+    }
+
+    pub fn build(self) -> F::Result {
+        self.builder.build(Ty::Tup(self.tys))
+    }
+}
+
+impl<F> Invoke<Ty> for TyTupleBuilder<F>
+    where F: Invoke<Ty>,
+{
+    type Result = Self;
+
+    fn invoke(self, ty: Ty) -> Self {
+        self.with_ty(ty)
+    }
+}
diff --git a/src/aster/ty_param.rs b/src/aster/ty_param.rs
new file mode 100644
index 00000000..592afd21
--- /dev/null
+++ b/src/aster/ty_param.rs
@@ -0,0 +1,273 @@
+use {
+    Ident,
+    LifetimeDef,
+    Path,
+    PolyTraitRef,
+    TraitBoundModifier,
+    Ty,
+    TyParam,
+    TyParamBound,
+};
+use aster::invoke::{Invoke, Identity};
+use aster::lifetime::{IntoLifetime, IntoLifetimeDef, LifetimeDefBuilder};
+use aster::path::{IntoPath, PathBuilder};
+use aster::ty::TyBuilder;
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct TyParamBuilder<F=Identity> {
+    callback: F,
+    id: Ident,
+    bounds: Vec<TyParamBound>,
+    default: Option<Ty>,
+}
+
+impl TyParamBuilder {
+    pub fn new<I>(id: I) -> Self
+        where I: Into<Ident>,
+    {
+        TyParamBuilder::with_callback(id, Identity)
+    }
+
+    pub fn from_ty_param(ty_param: TyParam) -> Self {
+        TyParamBuilder::from_ty_param_with_callback(Identity, ty_param)
+    }
+}
+
+impl<F> TyParamBuilder<F>
+    where F: Invoke<TyParam>,
+{
+    pub fn with_callback<I>(id: I, callback: F) -> Self
+        where I: Into<Ident>
+    {
+        TyParamBuilder {
+            callback: callback,
+            id: id.into(),
+            bounds: Vec::new(),
+            default: None,
+        }
+    }
+
+    pub fn from_ty_param_with_callback(callback: F, ty_param: TyParam) -> Self {
+        TyParamBuilder {
+            callback: callback,
+            id: ty_param.ident,
+            bounds: ty_param.bounds,
+            default: ty_param.default,
+        }
+    }
+
+    pub fn with_default(mut self, ty: Ty) -> Self {
+        self.default = Some(ty);
+        self
+    }
+
+    pub fn default(self) -> TyBuilder<Self> {
+        TyBuilder::with_callback(self)
+    }
+
+    pub fn with_bound(mut self, bound: TyParamBound) -> Self {
+        self.bounds.push(bound);
+        self
+    }
+
+    pub fn bound(self) -> TyParamBoundBuilder<Self> {
+        TyParamBoundBuilder::with_callback(self)
+    }
+
+    pub fn with_trait_bound(self, trait_ref: PolyTraitRef) -> Self {
+        self.bound().build_trait(trait_ref, TraitBoundModifier::None)
+    }
+
+    pub fn trait_bound<P>(self, path: P) -> PolyTraitRefBuilder<Self>
+        where P: IntoPath,
+    {
+        PolyTraitRefBuilder::with_callback(path, self)
+    }
+
+    pub fn lifetime_bound<L>(mut self, lifetime: L) -> Self
+        where L: IntoLifetime,
+    {
+        let lifetime = lifetime.into_lifetime();
+
+        self.bounds.push(TyParamBound::Region(lifetime));
+        self
+    }
+
+    pub fn build(self) -> F::Result {
+        self.callback.invoke(TyParam {
+            ident: self.id,
+            bounds: self.bounds,
+            default: self.default,
+        })
+    }
+}
+
+impl<F> Invoke<Ty> for TyParamBuilder<F>
+    where F: Invoke<TyParam>,
+{
+    type Result = Self;
+
+    fn invoke(self, ty: Ty) -> Self {
+        self.with_default(ty)
+    }
+}
+
+impl<F> Invoke<TyParamBound> for TyParamBuilder<F>
+    where F: Invoke<TyParam>,
+{
+    type Result = Self;
+
+    fn invoke(self, bound: TyParamBound) -> Self {
+        self.with_bound(bound)
+    }
+}
+
+impl<F> Invoke<PolyTraitRef> for TyParamBuilder<F>
+    where F: Invoke<TyParam>,
+{
+    type Result = Self;
+
+    fn invoke(self, trait_ref: PolyTraitRef) -> Self {
+        self.with_trait_bound(trait_ref)
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct TyParamBoundBuilder<F=Identity> {
+    callback: F,
+}
+
+impl TyParamBoundBuilder {
+    pub fn new() -> Self {
+        TyParamBoundBuilder::with_callback(Identity)
+    }
+}
+
+impl<F> TyParamBoundBuilder<F>
+    where F: Invoke<TyParamBound>,
+{
+    pub fn with_callback(callback: F) -> Self {
+        TyParamBoundBuilder {
+            callback: callback,
+        }
+    }
+
+    pub fn build_trait(self,
+                             poly_trait: PolyTraitRef,
+                             modifier: TraitBoundModifier) -> F::Result {
+        let bound = TyParamBound::Trait(poly_trait, modifier);
+        self.callback.invoke(bound)
+    }
+
+    pub fn trait_<P>(self, path: P) -> PolyTraitRefBuilder<TraitTyParamBoundBuilder<F>>
+        where P: IntoPath,
+    {
+        let builder = TraitTyParamBoundBuilder {
+            builder: self,
+            modifier: TraitBoundModifier::None,
+        };
+
+        PolyTraitRefBuilder::with_callback(path, builder)
+    }
+
+    pub fn maybe_trait<P>(self, path: P) -> PolyTraitRefBuilder<TraitTyParamBoundBuilder<F>>
+        where P: IntoPath,
+    {
+        let builder = TraitTyParamBoundBuilder {
+            builder: self,
+            modifier: TraitBoundModifier::Maybe,
+        };
+
+        PolyTraitRefBuilder::with_callback(path, builder)
+    }
+
+    pub fn iterator(self, ty: Ty) -> PolyTraitRefBuilder<TraitTyParamBoundBuilder<F>> {
+        let path = PathBuilder::new()
+            .global()
+            .id("std")
+            .id("iter")
+            .segment("Iterator")
+                .binding("Item").build(ty)
+                .build()
+                .build();
+        self.trait_(path)
+    }
+
+    pub fn lifetime<L>(self, lifetime: L) -> F::Result
+        where L: IntoLifetime,
+    {
+        let lifetime = lifetime.into_lifetime();
+        self.callback.invoke(TyParamBound::Region(lifetime))
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct TraitTyParamBoundBuilder<F> {
+    builder: TyParamBoundBuilder<F>,
+    modifier: TraitBoundModifier,
+}
+
+impl<F> Invoke<PolyTraitRef> for TraitTyParamBoundBuilder<F>
+    where F: Invoke<TyParamBound>,
+{
+    type Result = F::Result;
+
+    fn invoke(self, poly_trait: PolyTraitRef) -> Self::Result {
+        self.builder.build_trait(poly_trait, self.modifier)
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct PolyTraitRefBuilder<F> {
+    callback: F,
+    trait_ref: Path,
+    lifetimes: Vec<LifetimeDef>,
+}
+
+impl<F> PolyTraitRefBuilder<F>
+    where F: Invoke<PolyTraitRef>,
+{
+    pub fn with_callback<P>(path: P, callback: F) -> Self
+        where P: IntoPath,
+    {
+        PolyTraitRefBuilder {
+            callback: callback,
+            trait_ref: path.into_path(),
+            lifetimes: Vec::new(),
+        }
+    }
+
+    pub fn with_lifetime<L>(mut self, lifetime: L) -> Self
+        where L: IntoLifetimeDef,
+    {
+        self.lifetimes.push(lifetime.into_lifetime_def());
+        self
+    }
+
+    pub fn lifetime<N>(self, name: N) -> LifetimeDefBuilder<Self>
+        where N: Into<Ident>,
+    {
+        LifetimeDefBuilder::with_callback(name, self)
+    }
+
+    pub fn build(self) -> F::Result {
+        self.callback.invoke(PolyTraitRef {
+            bound_lifetimes: self.lifetimes,
+            trait_ref: self.trait_ref,
+        })
+    }
+}
+
+impl<F> Invoke<LifetimeDef> for PolyTraitRefBuilder<F>
+    where F: Invoke<PolyTraitRef>,
+{
+    type Result = Self;
+
+    fn invoke(self, lifetime: LifetimeDef) -> Self {
+        self.with_lifetime(lifetime)
+    }
+}
diff --git a/src/aster/where_predicate.rs b/src/aster/where_predicate.rs
new file mode 100644
index 00000000..22464cde
--- /dev/null
+++ b/src/aster/where_predicate.rs
@@ -0,0 +1,272 @@
+use {
+    Ident,
+    Lifetime,
+    LifetimeDef,
+    Ty,
+    TyParamBound,
+    WhereBoundPredicate,
+    WherePredicate,
+    WhereRegionPredicate,
+};
+use aster::invoke::{Invoke, Identity};
+use aster::lifetime::{IntoLifetime, IntoLifetimeDef, LifetimeDefBuilder};
+use aster::path::IntoPath;
+use aster::ty::TyBuilder;
+use aster::ty_param::{TyParamBoundBuilder, PolyTraitRefBuilder, TraitTyParamBoundBuilder};
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct WherePredicateBuilder<F=Identity> {
+    callback: F,
+}
+
+impl WherePredicateBuilder {
+    pub fn new() -> Self {
+        WherePredicateBuilder::with_callback(Identity)
+    }
+}
+
+impl<F> WherePredicateBuilder<F>
+    where F: Invoke<WherePredicate>,
+{
+    pub fn with_callback(callback: F) -> Self {
+        WherePredicateBuilder {
+            callback: callback,
+        }
+    }
+
+    pub fn bound(self) -> TyBuilder<Self> {
+        TyBuilder::with_callback(self)
+    }
+
+    pub fn lifetime<L>(self, lifetime: L) -> WhereRegionPredicateBuilder<F>
+        where L: IntoLifetime,
+    {
+        WhereRegionPredicateBuilder {
+            callback: self.callback,
+            lifetime: lifetime.into_lifetime(),
+            bounds: Vec::new(),
+        }
+    }
+}
+
+impl<F> Invoke<Ty> for WherePredicateBuilder<F>
+    where F: Invoke<WherePredicate>,
+{
+    type Result = WhereBoundPredicateTyBuilder<F>;
+
+    fn invoke(self, ty: Ty) -> Self::Result {
+        WhereBoundPredicateTyBuilder {
+            callback: self.callback,
+            ty: ty,
+            bound_lifetimes: Vec::new(),
+        }
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct WhereBoundPredicateBuilder<F> {
+    callback: F,
+}
+
+impl<F> Invoke<Ty> for WhereBoundPredicateBuilder<F>
+    where F: Invoke<WherePredicate>,
+{
+    type Result = WhereBoundPredicateTyBuilder<F>;
+
+    fn invoke(self, ty: Ty) -> Self::Result {
+        WhereBoundPredicateTyBuilder {
+            callback: self.callback,
+            ty: ty,
+            bound_lifetimes: Vec::new(),
+        }
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct WhereBoundPredicateTyBuilder<F> {
+    callback: F,
+    ty: Ty,
+    bound_lifetimes: Vec<LifetimeDef>,
+}
+
+impl<F> WhereBoundPredicateTyBuilder<F>
+    where F: Invoke<WherePredicate>,
+{
+    pub fn with_for_lifetime<L>(mut self, lifetime: L) -> Self
+        where L: IntoLifetimeDef,
+    {
+        self.bound_lifetimes.push(lifetime.into_lifetime_def());
+        self
+    }
+
+    pub fn for_lifetime<N>(self, name: N) -> LifetimeDefBuilder<Self>
+        where N: Into<Ident>,
+    {
+        LifetimeDefBuilder::with_callback(name, self)
+    }
+
+    pub fn with_bound(self, bound: TyParamBound) -> WhereBoundPredicateTyBoundsBuilder<F> {
+        WhereBoundPredicateTyBoundsBuilder {
+            callback: self.callback,
+            ty: self.ty,
+            bound_lifetimes: self.bound_lifetimes,
+            bounds: vec![bound],
+        }
+    }
+
+    pub fn bound(self) -> TyParamBoundBuilder<WhereBoundPredicateTyBoundsBuilder<F>> {
+        let builder = WhereBoundPredicateTyBoundsBuilder {
+            callback: self.callback,
+            ty: self.ty,
+            bound_lifetimes: self.bound_lifetimes,
+            bounds: vec![],
+        };
+        TyParamBoundBuilder::with_callback(builder)
+    }
+
+    pub fn trait_<P>(self, path: P)
+        -> PolyTraitRefBuilder<
+            TraitTyParamBoundBuilder<
+                WhereBoundPredicateTyBoundsBuilder<F>
+            >
+        >
+        where P: IntoPath,
+    {
+        self.bound().trait_(path)
+    }
+
+    pub fn lifetime<L>(self, lifetime: L) -> WhereBoundPredicateTyBoundsBuilder<F>
+        where L: IntoLifetime,
+    {
+        self.bound().lifetime(lifetime)
+    }
+}
+
+impl<F> Invoke<LifetimeDef> for WhereBoundPredicateTyBuilder<F>
+    where F: Invoke<WherePredicate>,
+{
+    type Result = Self;
+
+    fn invoke(self, lifetime: LifetimeDef) -> Self {
+        self.with_for_lifetime(lifetime)
+    }
+}
+
+impl<F> Invoke<TyParamBound> for WhereBoundPredicateTyBuilder<F>
+    where F: Invoke<WherePredicate>,
+{
+    type Result = WhereBoundPredicateTyBoundsBuilder<F>;
+
+    fn invoke(self, bound: TyParamBound) -> Self::Result {
+        self.with_bound(bound)
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct WhereBoundPredicateTyBoundsBuilder<F> {
+    callback: F,
+    ty: Ty,
+    bound_lifetimes: Vec<LifetimeDef>,
+    bounds: Vec<TyParamBound>,
+}
+
+impl<F> WhereBoundPredicateTyBoundsBuilder<F>
+    where F: Invoke<WherePredicate>,
+{
+    pub fn with_for_lifetime<L>(mut self, lifetime: L) -> Self
+        where L: IntoLifetimeDef,
+    {
+        self.bound_lifetimes.push(lifetime.into_lifetime_def());
+        self
+    }
+
+    pub fn for_lifetime<N>(self, name: N) -> LifetimeDefBuilder<Self>
+        where N: Into<Ident>,
+    {
+        LifetimeDefBuilder::with_callback(name, self)
+    }
+
+    pub fn with_bound(mut self, bound: TyParamBound) -> Self {
+        self.bounds.push(bound);
+        self
+    }
+
+    pub fn bound(self) -> TyParamBoundBuilder<Self> {
+        TyParamBoundBuilder::with_callback(self)
+    }
+
+    pub fn trait_<P>(self, path: P)
+        -> PolyTraitRefBuilder<TraitTyParamBoundBuilder<Self>>
+        where P: IntoPath,
+    {
+        self.bound().trait_(path)
+    }
+
+    pub fn lifetime<L>(self, lifetime: L) -> Self
+        where L: IntoLifetime,
+    {
+        self.bound().lifetime(lifetime)
+    }
+
+    pub fn build(self) -> F::Result {
+        let predicate = WhereBoundPredicate {
+            bound_lifetimes: self.bound_lifetimes,
+            bounded_ty: self.ty,
+            bounds: self.bounds,
+        };
+
+        self.callback.invoke(WherePredicate::BoundPredicate(predicate))
+    }
+}
+
+impl<F> Invoke<LifetimeDef> for WhereBoundPredicateTyBoundsBuilder<F>
+    where F: Invoke<WherePredicate>,
+{
+    type Result = Self;
+
+    fn invoke(self, lifetime: LifetimeDef) -> Self {
+        self.with_for_lifetime(lifetime)
+    }
+}
+
+impl<F> Invoke<TyParamBound> for WhereBoundPredicateTyBoundsBuilder<F>
+    where F: Invoke<WherePredicate>,
+{
+    type Result = Self;
+
+    fn invoke(self, bound: TyParamBound) -> Self {
+        self.with_bound(bound)
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+pub struct WhereRegionPredicateBuilder<F> {
+    callback: F,
+    lifetime: Lifetime,
+    bounds: Vec<Lifetime>,
+}
+
+impl<F> WhereRegionPredicateBuilder<F>
+    where F: Invoke<WherePredicate>,
+{
+    pub fn bound<L>(mut self, lifetime: L) -> Self
+        where L: IntoLifetime,
+    {
+        self.bounds.push(lifetime.into_lifetime());
+        self
+    }
+
+    pub fn build(self) -> F::Result {
+        let predicate = WhereRegionPredicate {
+            lifetime: self.lifetime,
+            bounds: self.bounds,
+        };
+
+        self.callback.invoke(WherePredicate::RegionPredicate(predicate))
+    }
+}
diff --git a/src/attr.rs b/src/attr.rs
index 7e14f2d9..4bfba227 100644
--- a/src/attr.rs
+++ b/src/attr.rs
@@ -28,8 +28,8 @@ pub enum MetaItem {
 #[cfg(feature = "parsing")]
 pub mod parsing {
     use super::*;
-    use common::parsing::word;
     use helper::escaped_string;
+    use ident::parsing::ident;
     use nom::multispace;
 
     named!(pub attribute<&str, Attribute>, alt_complete!(
@@ -60,21 +60,21 @@ pub mod parsing {
 
     named!(meta_item<&str, MetaItem>, alt_complete!(
         do_parse!(
-            ident: word >>
+            id: ident >>
             punct!("(") >>
             inner: separated_list!(punct!(","), meta_item) >>
             punct!(")") >>
-            (MetaItem::List(ident, inner))
+            (MetaItem::List(id, inner))
         )
         |
         do_parse!(
-            ident: word >>
+            id: ident >>
             punct!("=") >>
             string: quoted >>
-            (MetaItem::NameValue(ident, string))
+            (MetaItem::NameValue(id, string))
         )
         |
-        map!(word, MetaItem::Word)
+        map!(ident, MetaItem::Word)
     ));
 
     named!(quoted<&str, String>, delimited!(
diff --git a/src/generics.rs b/src/generics.rs
index 05d351f0..8fceaca3 100644
--- a/src/generics.rs
+++ b/src/generics.rs
@@ -4,7 +4,7 @@ use super::*;
 pub struct Generics {
     pub lifetimes: Vec<LifetimeDef>,
     pub ty_params: Vec<TyParam>,
-    pub where_clause: Vec<WherePredicate>,
+    pub where_clause: WhereClause,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
@@ -27,9 +27,19 @@ pub struct TyParam {
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub enum TyParamBound {
-    MaybeSized,
+    Trait(PolyTraitRef, TraitBoundModifier),
     Region(Lifetime),
-    Trait(PolyTraitRef),
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum TraitBoundModifier {
+    None,
+    Maybe,
+}
+
+#[derive(Debug, Clone, Eq, PartialEq, Default)]
+pub struct WhereClause {
+    pub predicates: Vec<WherePredicate>,
 }
 
 /// A single predicate in a `where` clause
@@ -66,7 +76,7 @@ pub struct WhereRegionPredicate {
 #[cfg(feature = "parsing")]
 pub mod parsing {
     use super::*;
-    use common::parsing::word;
+    use ident::parsing::ident;
     use ty::parsing::{ty, poly_trait_ref};
     use nom::multispace;
 
@@ -85,13 +95,7 @@ pub mod parsing {
             |
             epsilon!() => { |_| (Vec::new(), Vec::new()) }
         ) >>
-        where_clause: opt_vec!(do_parse!(
-            punct!("where") >>
-            multispace >>
-            predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
-            option!(punct!(",")) >>
-            (predicates)
-        )) >>
+        where_clause: where_clause >>
         (Generics {
             lifetimes: bracketed.0,
             ty_params: bracketed.1,
@@ -101,8 +105,8 @@ pub mod parsing {
 
     named!(pub lifetime<&str, Lifetime>, preceded!(
         punct!("'"),
-        map!(word, |ident| Lifetime {
-            ident: format!("'{}", ident).into(),
+        map!(ident, |id| Lifetime {
+            ident: format!("'{}", id).into(),
         })
     ));
 
@@ -127,7 +131,7 @@ pub mod parsing {
     )));
 
     named!(ty_param<&str, TyParam>, do_parse!(
-        ident: word >>
+        id: ident >>
         bounds: opt_vec!(preceded!(
             punct!(":"),
             separated_nonempty_list!(punct!("+"), ty_param_bound)
@@ -137,18 +141,34 @@ pub mod parsing {
             ty
         )) >>
         (TyParam {
-            ident: ident,
+            ident: id,
             bounds: bounds,
             default: default,
         })
     ));
 
     named!(pub ty_param_bound<&str, TyParamBound>, alt_complete!(
-        tuple!(punct!("?"), punct!("Sized")) => { |_| TyParamBound::MaybeSized }
+        preceded!(punct!("?"), poly_trait_ref) => {
+            |poly| TyParamBound::Trait(poly, TraitBoundModifier::Maybe)
+        }
         |
         lifetime => { TyParamBound::Region }
         |
-        poly_trait_ref => { TyParamBound::Trait }
+        poly_trait_ref => {
+            |poly| TyParamBound::Trait(poly, TraitBoundModifier::None)
+        }
+    ));
+
+    named!(pub where_clause<&str, WhereClause>, alt_complete!(
+        do_parse!(
+            punct!("where") >>
+            multispace >>
+            predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
+            option!(punct!(",")) >>
+            (WhereClause { predicates: predicates })
+        )
+        |
+        epsilon!() => { |_| Default::default() }
     ));
 
     named!(where_predicate<&str, WherePredicate>, alt_complete!(
@@ -194,10 +214,6 @@ mod printing {
                 tokens.append_separated(&self.ty_params, ",");
                 tokens.append(">");
             }
-            if !self.where_clause.is_empty() {
-                tokens.append("where");
-                tokens.append_separated(&self.where_clause, ",");
-            }
         }
     }
 
@@ -234,9 +250,23 @@ mod printing {
     impl ToTokens for TyParamBound {
         fn to_tokens(&self, tokens: &mut Tokens) {
             match *self {
-                TyParamBound::MaybeSized => tokens.append("?Sized"),
                 TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
-                TyParamBound::Trait(ref trait_ref) => trait_ref.to_tokens(tokens),
+                TyParamBound::Trait(ref trait_ref, modifier) => {
+                    match modifier {
+                        TraitBoundModifier::None => {}
+                        TraitBoundModifier::Maybe => tokens.append("?"),
+                    }
+                    trait_ref.to_tokens(tokens);
+                }
+            }
+        }
+    }
+
+    impl ToTokens for WhereClause {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            if !self.predicates.is_empty() {
+                tokens.append("where");
+                tokens.append_separated(&self.predicates, ",");
             }
         }
     }
diff --git a/src/common.rs b/src/ident.rs
similarity index 71%
rename from src/common.rs
rename to src/ident.rs
index f2db35c3..d5044659 100644
--- a/src/common.rs
+++ b/src/ident.rs
@@ -1,6 +1,6 @@
 use std::fmt::{self, Display};
 
-#[derive(Debug, Clone, Eq, PartialEq)]
+#[derive(Debug, Clone, Eq, Hash)]
 pub struct Ident(String);
 
 impl Ident {
@@ -33,10 +33,10 @@ impl Display for Ident {
     }
 }
 
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub enum Visibility {
-    Public,
-    Inherited,
+impl<T: ?Sized> PartialEq<T> for Ident where T: AsRef<str> {
+    fn eq(&self, other: &T) -> bool {
+        self.0 == other.as_ref()
+    }
 }
 
 #[cfg(feature = "parsing")]
@@ -48,20 +48,10 @@ pub mod parsing {
         ch.is_alphanumeric() || ch == '_'
     }
 
-    named!(pub word<&str, Ident>, preceded!(
+    named!(pub ident<&str, Ident>, preceded!(
         option!(multispace),
         map!(take_while1_s!(ident_ch), Into::into)
     ));
-
-    named!(pub visibility<&str, Visibility>, alt_complete!(
-        do_parse!(
-            punct!("pub") >>
-            multispace >>
-            (Visibility::Public)
-        )
-        |
-        epsilon!() => { |_| Visibility::Inherited }
-    ));
 }
 
 #[cfg(feature = "printing")]
diff --git a/src/item.rs b/src/item.rs
index d36caae4..df5abe44 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -12,24 +12,33 @@ pub struct Item {
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub enum Body {
     Enum(Vec<Variant>),
-    Struct(Style, Vec<Field>),
+    Struct(VariantData),
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Variant {
     pub ident: Ident,
     pub attrs: Vec<Attribute>,
-    pub style: Style,
-    pub fields: Vec<Field>,
+    pub data: VariantData,
 }
 
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub enum Style {
-    Struct,
-    Tuple,
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub enum VariantData {
+    Struct(Vec<Field>),
+    Tuple(Vec<Field>),
     Unit,
 }
 
+impl VariantData {
+    pub fn fields(&self) -> &[Field] {
+        match *self {
+            VariantData::Struct(ref fields) |
+            VariantData::Tuple(ref fields) => fields,
+            VariantData::Unit => &[],
+        }
+    }
+}
+
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Field {
     pub ident: Option<Ident>,
@@ -38,12 +47,18 @@ pub struct Field {
     pub ty: Ty,
 }
 
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum Visibility {
+    Public,
+    Inherited,
+}
+
 #[cfg(feature = "parsing")]
 pub mod parsing {
     use super::*;
     use attr::parsing::attribute;
-    use common::parsing::{word, visibility};
     use generics::parsing::generics;
+    use ident::parsing::ident;
     use ty::parsing::ty;
     use nom::multispace;
 
@@ -52,60 +67,59 @@ pub mod parsing {
         vis: visibility >>
         which: alt_complete!(punct!("struct") | punct!("enum")) >>
         multispace >>
-        ident: word >>
+        id: ident >>
         generics: generics >>
         item: switch!(value!(which),
             "struct" => map!(struct_body, move |body| Item {
-                ident: ident,
+                ident: id,
                 vis: vis,
                 attrs: attrs,
                 generics: generics,
-                body: body,
+                body: Body::Struct(body),
             })
             |
             "enum" => map!(enum_body, move |body| Item {
-                ident: ident,
+                ident: id,
                 vis: vis,
                 attrs: attrs,
                 generics: generics,
-                body: body,
+                body: Body::Enum(body),
             })
         ) >>
         option!(multispace) >>
         (item)
     ));
 
-    named!(struct_body<&str, Body>, alt_complete!(
-        struct_like_body => { |fields| Body::Struct(Style::Struct, fields) }
+    named!(struct_body<&str, VariantData>, alt_complete!(
+        struct_like_body => { VariantData::Struct }
         |
-        terminated!(tuple_like_body, punct!(";")) => { |fields| Body::Struct(Style::Tuple, fields) }
+        terminated!(tuple_like_body, punct!(";")) => { VariantData::Tuple }
         |
-        punct!(";") => { |_| Body::Struct(Style::Unit, Vec::new()) }
+        punct!(";") => { |_| VariantData::Unit }
     ));
 
-    named!(enum_body<&str, Body>, do_parse!(
+    named!(enum_body<&str, Vec<Variant> >, do_parse!(
         punct!("{") >>
         variants: separated_list!(punct!(","), variant) >>
         option!(punct!(",")) >>
         punct!("}") >>
-        (Body::Enum(variants))
+        (variants)
     ));
 
     named!(variant<&str, Variant>, do_parse!(
         attrs: many0!(attribute) >>
-        ident: word >>
-        body: alt_complete!(
-            struct_like_body => { |fields| (Style::Struct, fields) }
+        id: ident >>
+        data: alt_complete!(
+            struct_like_body => { VariantData::Struct }
             |
-            tuple_like_body => { |fields| (Style::Tuple, fields) }
+            tuple_like_body => { VariantData::Tuple }
             |
-            epsilon!() => { |_| (Style::Unit, Vec::new()) }
+            epsilon!() => { |_| VariantData::Unit }
         ) >>
         (Variant {
-            ident: ident,
+            ident: id,
             attrs: attrs,
-            style: body.0,
-            fields: body.1,
+            data: data,
         })
     ));
 
@@ -128,11 +142,11 @@ pub mod parsing {
     named!(struct_field<&str, Field>, do_parse!(
         attrs: many0!(attribute) >>
         vis: visibility >>
-        ident: word >>
+        id: ident >>
         punct!(":") >>
         ty: ty >>
         (Field {
-            ident: Some(ident),
+            ident: Some(id),
             vis: vis,
             attrs: attrs,
             ty: ty,
@@ -150,12 +164,21 @@ pub mod parsing {
             ty: ty,
         })
     ));
+
+    named!(pub visibility<&str, Visibility>, alt_complete!(
+        do_parse!(
+            punct!("pub") >>
+            multispace >>
+            (Visibility::Public)
+        )
+        |
+        epsilon!() => { |_| Visibility::Inherited }
+    ));
 }
 
 #[cfg(feature = "printing")]
 mod printing {
     use super::*;
-    use common::Visibility;
     use quote::{Tokens, ToTokens};
 
     impl ToTokens for Item {
@@ -168,10 +191,11 @@ mod printing {
             }
             match self.body {
                 Body::Enum(_) => tokens.append("enum"),
-                Body::Struct(_, _) => tokens.append("struct"),
+                Body::Struct(_) => tokens.append("struct"),
             }
             self.ident.to_tokens(tokens);
             self.generics.to_tokens(tokens);
+            self.generics.where_clause.to_tokens(tokens);
             self.body.to_tokens(tokens);
         }
     }
@@ -187,11 +211,12 @@ mod printing {
                     }
                     tokens.append("}");
                 }
-                Body::Struct(style, ref fields) => {
-                    fields_to_tokens(style, fields, tokens);
-                    match style {
-                        Style::Struct => { /* no semicolon */ }
-                        Style::Tuple | Style::Unit => tokens.append(";"),
+                Body::Struct(ref variant_data) => {
+                    variant_data_to_tokens(variant_data, tokens);
+                    match *variant_data {
+                        VariantData::Struct(_) => { /* no semicolon */ }
+                        VariantData::Tuple(_) |
+                        VariantData::Unit => tokens.append(";"),
                     }
                 }
             }
@@ -204,7 +229,7 @@ mod printing {
                 attr.to_tokens(tokens);
             }
             self.ident.to_tokens(tokens);
-            fields_to_tokens(self.style, &self.fields, tokens);
+            variant_data_to_tokens(&self.data, tokens);
         }
     }
 
@@ -224,21 +249,19 @@ mod printing {
         }
     }
 
-    fn fields_to_tokens(style: Style, fields: &[Field], tokens: &mut Tokens) {
-        match style {
-            Style::Struct => {
+    fn variant_data_to_tokens(data: &VariantData, tokens: &mut Tokens) {
+        match *data {
+            VariantData::Struct(ref fields) => {
                 tokens.append("{");
                 tokens.append_separated(fields, ",");
                 tokens.append("}");
             }
-            Style::Tuple => {
+            VariantData::Tuple(ref fields) => {
                 tokens.append("(");
                 tokens.append_separated(fields, ",");
                 tokens.append(")");
             }
-            Style::Unit => {
-                assert!(fields.is_empty(), "unit variant cannot have fields");
-            }
+            VariantData::Unit => {}
         }
     }
 }
diff --git a/src/lib.rs b/src/lib.rs
index a4ebe8b3..adbae5ee 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -17,31 +17,33 @@ pub use attr::{
     MetaItem,
 };
 
-mod common;
-pub use common::{
-    Ident,
-    Visibility,
-};
-
 mod generics;
 pub use generics::{
     Generics,
     Lifetime,
     LifetimeDef,
+    TraitBoundModifier,
     TyParam,
     TyParamBound,
     WhereBoundPredicate,
+    WhereClause,
     WherePredicate,
     WhereRegionPredicate,
 };
 
+mod ident;
+pub use ident::{
+    Ident,
+};
+
 mod item;
 pub use item::{
     Body,
     Field,
     Item,
-    Style,
     Variant,
+    VariantData,
+    Visibility,
 };
 
 mod ty;
@@ -63,32 +65,59 @@ pub use ty::{
     TypeBinding,
 };
 
+#[cfg(feature = "aster")]
+pub mod aster;
+
+#[cfg(feature = "visit")]
+pub mod visit;
+
 #[cfg(feature = "parsing")]
-pub fn parse_item(input: &str) -> Item {
-    return match item::parsing::item(input) {
-        nom::IResult::Done(rest, ast) => {
-            if rest.is_empty() {
-                ast
-            } else {
-                panic!("more than a single input item: {:?}", rest)
-            }
-        }
-        nom::IResult::Error(err) => raise(err),
-        nom::IResult::Incomplete(_) => panic!("incomplete input item"),
-    };
-
-    fn raise(mut err: nom::Err<&str>) -> ! {
-        loop {
-            match err {
-                nom::Err::Code(kind) => {
-                    panic!("failed to parse {:?}", kind)
-                }
-                nom::Err::Position(kind, pos) => {
-                    panic!("failed to parse {:?}: {:?}", kind, pos)
+pub use parsing::*;
+
+#[cfg(feature = "parsing")]
+mod parsing {
+    use super::*;
+    use {generics, item, ty};
+    use nom;
+
+    pub fn parse_item(input: &str) -> Result<Item, String> {
+        unwrap("item", item::parsing::item(input))
+    }
+
+    pub fn parse_path(input: &str) -> Result<Path, String> {
+        unwrap("path", ty::parsing::path(input))
+    }
+
+    pub fn parse_where_clause(input: &str) -> Result<WhereClause, String> {
+        unwrap("where clause", generics::parsing::where_clause(input))
+    }
+
+    fn unwrap<T>(name: &'static str, ires: nom::IResult<&str, T>) -> Result<T, String> {
+        return match ires {
+            nom::IResult::Done(rest, t) => {
+                if rest.is_empty() {
+                    Ok(t)
+                } else {
+                    Err(format!("remaining tokens after {}: {:?}", name, rest))
                 }
-                nom::Err::Node(_, next) |
-                nom::Err::NodePosition(_, _, next) => {
-                    err = *next;
+            }
+            nom::IResult::Error(err) => Err(root_cause(err)),
+            nom::IResult::Incomplete(_) => Err(format!("incomplete {}", name)),
+        };
+
+        fn root_cause(mut err: nom::Err<&str>) -> String {
+            loop {
+                match err {
+                    nom::Err::Code(kind) => {
+                        return format!("failed to parse {:?}", kind);
+                    }
+                    nom::Err::Position(kind, pos) => {
+                        return format!("failed to parse {:?}: {:?}", kind, pos);
+                    }
+                    nom::Err::Node(_, next) |
+                    nom::Err::NodePosition(_, _, next) => {
+                        err = *next;
+                    }
                 }
             }
         }
diff --git a/src/ty.rs b/src/ty.rs
index c4e6c41b..09d71483 100644
--- a/src/ty.rs
+++ b/src/ty.rs
@@ -183,8 +183,8 @@ pub enum FunctionRetTy {
 #[cfg(feature = "parsing")]
 pub mod parsing {
     use super::*;
-    use common::parsing::word;
     use generics::parsing::{lifetime, lifetime_def, ty_param_bound, bound_lifetimes};
+    use ident::parsing::ident;
     use nom::{digit, multispace};
     use std::str;
 
@@ -343,7 +343,7 @@ pub mod parsing {
         epsilon!() => { |_| Mutability::Immutable }
     ));
 
-    named!(path<&str, Path>, do_parse!(
+    named!(pub path<&str, Path>, do_parse!(
         global: option!(punct!("::")) >>
         segments: separated_nonempty_list!(punct!("::"), path_segment) >>
         (Path {
@@ -354,7 +354,7 @@ pub mod parsing {
 
     named!(path_segment<&str, PathSegment>, alt_complete!(
         do_parse!(
-            ident: word >>
+            id: ident >>
             punct!("<") >>
             lifetimes: separated_list!(punct!(","), lifetime) >>
             types: opt_vec!(preceded!(
@@ -370,7 +370,7 @@ pub mod parsing {
             )) >>
             punct!(">") >>
             (PathSegment {
-                ident: ident,
+                ident: id,
                 parameters: PathParameters::AngleBracketed(
                     AngleBracketedParameterData {
                         lifetimes: lifetimes,
@@ -381,15 +381,15 @@ pub mod parsing {
             })
         )
         |
-        map!(word, PathSegment::ident)
+        map!(ident, PathSegment::ident)
     ));
 
     named!(type_binding<&str, TypeBinding>, do_parse!(
-        ident: word >>
+        id: ident >>
         punct!("=") >>
         ty: ty >>
         (TypeBinding {
-            ident: ident,
+            ident: id,
             ty: ty,
         })
     ));
@@ -404,7 +404,7 @@ pub mod parsing {
     ));
 
     named!(fn_arg<&str, FnArg>, do_parse!(
-        pat: option!(terminated!(word, punct!(":"))) >>
+        pat: option!(terminated!(ident, punct!(":"))) >>
         ty: ty >>
         (FnArg {
             pat: pat,
diff --git a/src/visit.rs b/src/visit.rs
new file mode 100644
index 00000000..4834a96b
--- /dev/null
+++ b/src/visit.rs
@@ -0,0 +1,267 @@
+// Adapted from libsyntax.
+
+//! AST walker. Each overridden visit method has full control over what
+//! happens with its node, it can do its own traversal of the node's children,
+//! call `visit::walk_*` to apply the default traversal algorithm, or prevent
+//! deeper traversal by doing nothing.
+//!
+//! Note: it is an important invariant that the default visitor walks the body
+//! of a function in "execution order" (more concretely, reverse post-order
+//! with respect to the CFG implied by the AST), meaning that if AST node A may
+//! execute before AST node B, then A is visited first.  The borrow checker in
+//! particular relies on this property.
+//!
+//! Note: walking an AST before macro expansion is probably a bad idea. For
+//! instance, a walker looking for item names in a module will miss all of
+//! those that are created by the expansion of a macro.
+
+use super::*;
+
+/// Each method of the Visitor trait is a hook to be potentially
+/// overridden.  Each method's default implementation recursively visits
+/// the substructure of the input via the corresponding `walk` method;
+/// e.g. the `visit_mod` method by default calls `visit::walk_mod`.
+///
+/// If you want to ensure that your code handles every variant
+/// explicitly, you need to override each method.  (And you also need
+/// to monitor future changes to `Visitor` in case a new method with a
+/// new default implementation gets introduced.)
+pub trait Visitor: Sized {
+    fn visit_ident(&mut self, _ident: &Ident) {}
+    fn visit_item(&mut self, item: &Item) {
+        walk_item(self, item)
+    }
+    fn visit_ty(&mut self, ty: &Ty) {
+        walk_ty(self, ty)
+    }
+    fn visit_generics(&mut self, generics: &Generics) {
+        walk_generics(self, generics)
+    }
+    fn visit_ty_param_bound(&mut self, bound: &TyParamBound) {
+        walk_ty_param_bound(self, bound)
+    }
+    fn visit_poly_trait_ref(&mut self, trait_ref: &PolyTraitRef, modifier: &TraitBoundModifier) {
+        walk_poly_trait_ref(self, trait_ref, modifier)
+    }
+    fn visit_variant_data(&mut self, data: &VariantData, _ident: &Ident, _generics: &Generics) {
+        walk_variant_data(self, data)
+    }
+    fn visit_field(&mut self, field: &Field) {
+        walk_field(self, field)
+    }
+    fn visit_variant(&mut self, variant: &Variant, generics: &Generics) {
+        walk_variant(self, variant, generics)
+    }
+    fn visit_lifetime(&mut self, _lifetime: &Lifetime) {}
+    fn visit_lifetime_def(&mut self, lifetime: &LifetimeDef) {
+        walk_lifetime_def(self, lifetime)
+    }
+    fn visit_path(&mut self, path: &Path) {
+        walk_path(self, path)
+    }
+    fn visit_path_segment(&mut self, path_segment: &PathSegment) {
+        walk_path_segment(self, path_segment)
+    }
+    fn visit_path_parameters(&mut self, path_parameters: &PathParameters) {
+        walk_path_parameters(self, path_parameters)
+    }
+    fn visit_assoc_type_binding(&mut self, type_binding: &TypeBinding) {
+        walk_assoc_type_binding(self, type_binding)
+    }
+    fn visit_attribute(&mut self, _attr: &Attribute) {}
+    fn visit_fn_ret_ty(&mut self, ret_ty: &FunctionRetTy) {
+        walk_fn_ret_ty(self, ret_ty)
+    }
+}
+
+#[macro_export]
+macro_rules! walk_list {
+    ($visitor: expr, $method: ident, $list: expr) => {
+        for elem in $list {
+            $visitor.$method(elem)
+        }
+    };
+    ($visitor: expr, $method: ident, $list: expr, $($extra_args: expr),*) => {
+        for elem in $list {
+            $visitor.$method(elem, $($extra_args,)*)
+        }
+    }
+}
+
+pub fn walk_opt_ident<V: Visitor>(visitor: &mut V, opt_ident: &Option<Ident>) {
+    if let Some(ref ident) = *opt_ident {
+        visitor.visit_ident(ident);
+    }
+}
+
+pub fn walk_lifetime_def<V: Visitor>(visitor: &mut V, lifetime_def: &LifetimeDef) {
+    visitor.visit_lifetime(&lifetime_def.lifetime);
+    walk_list!(visitor, visit_lifetime, &lifetime_def.bounds);
+}
+
+pub fn walk_poly_trait_ref<V>(visitor: &mut V, trait_ref: &PolyTraitRef, _: &TraitBoundModifier)
+    where V: Visitor,
+{
+    walk_list!(visitor, visit_lifetime_def, &trait_ref.bound_lifetimes);
+    visitor.visit_path(&trait_ref.trait_ref);
+}
+
+pub fn walk_item<V: Visitor>(visitor: &mut V, item: &Item) {
+    visitor.visit_ident(&item.ident);
+    visitor.visit_generics(&item.generics);
+    match item.body {
+        Body::Enum(ref variants) => {
+            walk_list!(visitor, visit_variant, variants, &item.generics);
+        }
+        Body::Struct(ref variant_data) => {
+            visitor.visit_variant_data(variant_data, &item.ident,
+                                     &item.generics);
+        }
+    }
+    walk_list!(visitor, visit_attribute, &item.attrs);
+}
+
+pub fn walk_variant<V>(visitor: &mut V, variant: &Variant, generics: &Generics)
+    where V: Visitor,
+{
+    visitor.visit_ident(&variant.ident);
+    visitor.visit_variant_data(&variant.data, &variant.ident, generics);
+    walk_list!(visitor, visit_attribute, &variant.attrs);
+}
+
+pub fn walk_ty<V: Visitor>(visitor: &mut V, ty: &Ty) {
+    match *ty {
+        Ty::Vec(ref inner) | Ty::Paren(ref inner) => {
+            visitor.visit_ty(inner)
+        }
+        Ty::Ptr(ref mutable_type) => {
+            visitor.visit_ty(&mutable_type.ty)
+        }
+        Ty::Rptr(ref opt_lifetime, ref mutable_type) => {
+            walk_list!(visitor, visit_lifetime, opt_lifetime);
+            visitor.visit_ty(&mutable_type.ty)
+        }
+        Ty::Never => {},
+        Ty::Tup(ref tuple_element_types) => {
+            walk_list!(visitor, visit_ty, tuple_element_types);
+        }
+        Ty::BareFn(ref function_declaration) => {
+            walk_fn_decl(visitor, &function_declaration.decl);
+            walk_list!(visitor, visit_lifetime_def, &function_declaration.lifetimes);
+        }
+        Ty::Path(ref maybe_qself, ref path) => {
+            if let Some(ref qself) = *maybe_qself {
+                visitor.visit_ty(&qself.ty);
+            }
+            visitor.visit_path(path);
+        }
+        Ty::ObjectSum(ref inner, ref bounds) => {
+            visitor.visit_ty(inner);
+            walk_list!(visitor, visit_ty_param_bound, bounds);
+        }
+        Ty::FixedLengthVec(ref inner, _len) => {
+            visitor.visit_ty(inner);
+        }
+        Ty::PolyTraitRef(ref bounds) => {
+            walk_list!(visitor, visit_ty_param_bound, bounds);
+        }
+        Ty::ImplTrait(ref bounds) => {
+            walk_list!(visitor, visit_ty_param_bound, bounds);
+        }
+        Ty::Infer => {}
+    }
+}
+
+pub fn walk_path<V: Visitor>(visitor: &mut V, path: &Path) {
+    for segment in &path.segments {
+        visitor.visit_path_segment(segment);
+    }
+}
+
+pub fn walk_path_segment<V: Visitor>(visitor: &mut V, segment: &PathSegment) {
+    visitor.visit_ident(&segment.ident);
+    visitor.visit_path_parameters(&segment.parameters);
+}
+
+pub fn walk_path_parameters<V>(visitor: &mut V, path_parameters: &PathParameters)
+    where V: Visitor,
+{
+    match *path_parameters {
+        PathParameters::AngleBracketed(ref data) => {
+            walk_list!(visitor, visit_ty, &data.types);
+            walk_list!(visitor, visit_lifetime, &data.lifetimes);
+            walk_list!(visitor, visit_assoc_type_binding, &data.bindings);
+        }
+        PathParameters::Parenthesized(ref data) => {
+            walk_list!(visitor, visit_ty, &data.inputs);
+            walk_list!(visitor, visit_ty, &data.output);
+        }
+    }
+}
+
+pub fn walk_assoc_type_binding<V: Visitor>(visitor: &mut V, type_binding: &TypeBinding) {
+    visitor.visit_ident(&type_binding.ident);
+    visitor.visit_ty(&type_binding.ty);
+}
+
+pub fn walk_ty_param_bound<V: Visitor>(visitor: &mut V, bound: &TyParamBound) {
+    match *bound {
+        TyParamBound::Trait(ref ty, ref modifier) => {
+            visitor.visit_poly_trait_ref(ty, modifier);
+        }
+        TyParamBound::Region(ref lifetime) => {
+            visitor.visit_lifetime(lifetime);
+        }
+    }
+}
+
+pub fn walk_generics<V: Visitor>(visitor: &mut V, generics: &Generics) {
+    for param in &generics.ty_params {
+        visitor.visit_ident(&param.ident);
+        walk_list!(visitor, visit_ty_param_bound, &param.bounds);
+        walk_list!(visitor, visit_ty, &param.default);
+    }
+    walk_list!(visitor, visit_lifetime_def, &generics.lifetimes);
+    for predicate in &generics.where_clause.predicates {
+        match *predicate {
+            WherePredicate::BoundPredicate(WhereBoundPredicate{ref bounded_ty,
+                                                               ref bounds,
+                                                               ref bound_lifetimes,
+                                                               ..}) => {
+                visitor.visit_ty(bounded_ty);
+                walk_list!(visitor, visit_ty_param_bound, bounds);
+                walk_list!(visitor, visit_lifetime_def, bound_lifetimes);
+            }
+            WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime,
+                                                                 ref bounds,
+                                                                 ..}) => {
+                visitor.visit_lifetime(lifetime);
+                walk_list!(visitor, visit_lifetime, bounds);
+            }
+        }
+    }
+}
+
+pub fn walk_fn_ret_ty<V: Visitor>(visitor: &mut V, ret_ty: &FunctionRetTy) {
+    if let FunctionRetTy::Ty(ref output_ty) = *ret_ty {
+        visitor.visit_ty(output_ty)
+    }
+}
+
+pub fn walk_fn_decl<V: Visitor>(visitor: &mut V, function_declaration: &FnDecl) {
+    for argument in &function_declaration.inputs {
+        walk_opt_ident(visitor, &argument.pat);
+        visitor.visit_ty(&argument.ty)
+    }
+    visitor.visit_fn_ret_ty(&function_declaration.output)
+}
+
+pub fn walk_variant_data<V: Visitor>(visitor: &mut V, data: &VariantData) {
+    walk_list!(visitor, visit_field, data.fields());
+}
+
+pub fn walk_field<V: Visitor>(visitor: &mut V, field: &Field) {
+    walk_opt_ident(visitor, &field.ident);
+    visitor.visit_ty(&field.ty);
+    walk_list!(visitor, visit_attribute, &field.attrs);
+}


Test patch:
diff --git a/tests/all.rs b/tests/all.rs
index a8a84e1b..07185770 100644
--- a/tests/all.rs
+++ b/tests/all.rs
@@ -8,9 +8,9 @@ extern crate quote;
 #[test]
 fn test_all() {
     for s in ITEMS {
-        let ast = syn::parse_item(s);
+        let ast = syn::parse_item(s).unwrap();
         let tokens = quote!(#ast).to_string();
-        assert_eq!(ast, syn::parse_item(&tokens));
+        assert_eq!(ast, syn::parse_item(&tokens).unwrap());
     }
 
     static ITEMS: &'static [&'static str] = &[
diff --git a/tests/test.rs b/tests/test.rs
index 6dd25d3a..c82533a6 100644
--- a/tests/test.rs
+++ b/tests/test.rs
@@ -17,10 +17,10 @@ fn test_unit() {
         vis: Visibility::Inherited,
         attrs: Vec::new(),
         generics: Generics::default(),
-        body: Body::Struct(Style::Unit, Vec::new()),
+        body: Body::Struct(VariantData::Unit),
     };
 
-    assert_eq!(expected, parse_item(raw));
+    assert_eq!(expected, parse_item(raw).unwrap());
 }
 
 #[test]
@@ -46,7 +46,7 @@ fn test_struct() {
             },
         ],
         generics: Generics::default(),
-        body: Body::Struct(Style::Struct, vec![
+        body: Body::Struct(VariantData::Struct(vec![
             Field {
                 ident: Some("ident".into()),
                 vis: Visibility::Public,
@@ -73,10 +73,10 @@ fn test_struct() {
                     ],
                 }),
             },
-        ]),
+        ])),
     };
 
-    assert_eq!(expected, parse_item(raw));
+    assert_eq!(expected, parse_item(raw).unwrap());
 }
 
 #[test]
@@ -120,37 +120,37 @@ fn test_enum() {
                     default: None,
                 },
             ],
-            where_clause: Vec::new(),
+            where_clause: WhereClause {
+                predicates: Vec::new(),
+            },
         },
         body: Body::Enum(vec![
             Variant {
                 ident: "Ok".into(),
                 attrs: Vec::new(),
-                style: Style::Tuple,
-                fields: vec![
+                data: VariantData::Tuple(vec![
                     Field {
                         ident: None,
                         vis: Visibility::Inherited,
                         attrs: Vec::new(),
                         ty: simple_ty("T"),
                     },
-                ],
+                ]),
             },
             Variant {
                 ident: "Err".into(),
                 attrs: Vec::new(),
-                style: Style::Tuple,
-                fields: vec![
+                data: VariantData::Tuple(vec![
                     Field {
                         ident: None,
                         vis: Visibility::Inherited,
                         attrs: Vec::new(),
                         ty: simple_ty("E"),
                     },
-                ],
+                ]),
             },
         ]),
     };
 
-    assert_eq!(expected, parse_item(raw));
+    assert_eq!(expected, parse_item(raw).unwrap());
 }