Trait printing
diff --git a/src/expr.rs b/src/expr.rs
index 9c3d2b4..ecdb05f 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -677,10 +677,7 @@
     named!(closure_arg -> FnArg, do_parse!(
         pat: pat >>
         ty: option!(preceded!(punct!(":"), ty)) >>
-        (FnArg {
-            pat: pat,
-            ty: ty.unwrap_or(Ty::Infer),
-        })
+        (FnArg::Captured(pat, ty.unwrap_or(Ty::Infer)))
     ));
 
     named!(expr_while -> Expr, do_parse!(
@@ -1032,7 +1029,7 @@
 #[cfg(feature = "printing")]
 mod printing {
     use super::*;
-    use {FunctionRetTy, Mutability, Ty};
+    use {FnArg, FunctionRetTy, Mutability, Ty};
     use attr::FilterAttrs;
     use quote::{Tokens, ToTokens};
 
@@ -1171,15 +1168,11 @@
                         if i > 0 {
                             tokens.append(",");
                         }
-                        input.pat.to_tokens(tokens);
-                        match input.ty {
-                            Ty::Infer => {
-                                // nothing
+                        match *input {
+                            FnArg::Captured(ref pat, Ty::Infer) => {
+                                pat.to_tokens(tokens);
                             }
-                            _ => {
-                                tokens.append(":");
-                                input.ty.to_tokens(tokens);
-                            }
+                            _ => input.to_tokens(tokens),
                         }
                     }
                     tokens.append("|");
diff --git a/src/item.rs b/src/item.rs
index 0e1e6d6..3379d95 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -219,9 +219,11 @@
 ///
 /// E.g. `bar: usize` as in `fn foo(bar: usize)`
 #[derive(Debug, Clone, Eq, PartialEq)]
-pub struct FnArg {
-    pub pat: Pat,
-    pub ty: Ty,
+pub enum FnArg {
+    SelfRef(Option<Lifetime>, Mutability),
+    SelfValue(Mutability),
+    Captured(Pat, Ty),
+    Ignored(Ty),
 }
 
 #[cfg(feature = "parsing")]
@@ -231,7 +233,7 @@
     use attr::parsing::outer_attr;
     use data::parsing::{struct_like_body, visibility};
     use expr::parsing::{block, expr, pat};
-    use generics::parsing::{generics, ty_param_bound, where_clause};
+    use generics::parsing::{generics, lifetime, ty_param_bound, where_clause};
     use ident::parsing::ident;
     use lit::parsing::quoted_string;
     use mac::parsing::delimited;
@@ -379,14 +381,29 @@
         })
     ));
 
-    named!(fn_arg -> FnArg, do_parse!(
-        pat: pat >>
-        punct!(":") >>
-        ty: ty >>
-        (FnArg {
-            pat: pat,
-            ty: ty,
-        })
+    named!(fn_arg -> FnArg, alt!(
+        do_parse!(
+            punct!("&") >>
+            lt: option!(lifetime) >>
+            mutability: mutability >>
+            keyword!("self") >>
+            (FnArg::SelfRef(lt, mutability))
+        )
+        |
+        do_parse!(
+            mutability: mutability >>
+            keyword!("self") >>
+            (FnArg::SelfValue(mutability))
+        )
+        |
+        do_parse!(
+            pat: pat >>
+            punct!(":") >>
+            ty: ty >>
+            (FnArg::Captured(pat, ty))
+        )
+        |
+        ty => { FnArg::Ignored }
     ));
 
     named!(item_ty -> Item, do_parse!(
@@ -547,6 +564,7 @@
             separated_nonempty_list!(punct!("+"), ty_param_bound)
         )) >>
         default: option!(preceded!(punct!("="), ty)) >>
+        punct!(";") >>
         (TraitItem {
             ident: id,
             attrs: attrs,
@@ -592,9 +610,7 @@
 
     impl ToTokens for Item {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            for attr in self.attrs.outer() {
-                attr.to_tokens(tokens);
-            }
+            tokens.append_all(self.attrs.outer());
             match self.node {
                 ItemKind::ExternCrate(ref original) => {
                     tokens.append("extern");
@@ -693,7 +709,21 @@
                     generics.where_clause.to_tokens(tokens);
                     variant_data.to_tokens(tokens);
                 }
-                ItemKind::Trait(_unsafety, ref _generics, ref _bound, ref _item) => unimplemented!(),
+                ItemKind::Trait(unsafety, ref generics, ref bound, ref items) => {
+                    self.vis.to_tokens(tokens);
+                    unsafety.to_tokens(tokens);
+                    tokens.append("trait");
+                    self.ident.to_tokens(tokens);
+                    if !bound.is_empty() {
+                        tokens.append(":");
+                        tokens.append_separated(bound, "+");
+                    }
+                    generics.to_tokens(tokens);
+                    generics.where_clause.to_tokens(tokens);
+                    tokens.append("{");
+                    tokens.append_all(items);
+                    tokens.append("}");
+                }
                 ItemKind::DefaultImpl(_unsafety, ref _path) => unimplemented!(),
                 ItemKind::Impl(_unsafety,
                                _polarity,
@@ -719,11 +749,82 @@
         }
     }
 
+    impl ToTokens for TraitItem {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            tokens.append_all(self.attrs.outer());
+            match self.node {
+                TraitItemKind::Const(ref ty, ref expr) => {
+                    tokens.append("const");
+                    self.ident.to_tokens(tokens);
+                    tokens.append(":");
+                    ty.to_tokens(tokens);
+                    if let Some(ref expr) = *expr {
+                        tokens.append("=");
+                        expr.to_tokens(tokens);
+                    }
+                    tokens.append(";");
+                }
+                TraitItemKind::Method(ref sig, ref block) => {
+                    sig.unsafety.to_tokens(tokens);
+                    sig.abi.to_tokens(tokens);
+                    tokens.append("fn");
+                    self.ident.to_tokens(tokens);
+                    sig.generics.to_tokens(tokens);
+                    tokens.append("(");
+                    tokens.append_separated(&sig.decl.inputs, ",");
+                    tokens.append(")");
+                    if let FunctionRetTy::Ty(ref ty) = sig.decl.output {
+                        tokens.append("->");
+                        ty.to_tokens(tokens);
+                    }
+                    sig.generics.where_clause.to_tokens(tokens);
+                    match *block {
+                        Some(ref block) => block.to_tokens(tokens),
+                        None => tokens.append(";"),
+                    }
+                }
+                TraitItemKind::Type(ref bound, ref default) => {
+                    tokens.append("type");
+                    self.ident.to_tokens(tokens);
+                    if !bound.is_empty() {
+                        tokens.append(":");
+                        tokens.append_separated(bound, "+");
+                    }
+                    if let Some(ref default) = *default {
+                        tokens.append("=");
+                        default.to_tokens(tokens);
+                    }
+                    tokens.append(";");
+                }
+                TraitItemKind::Macro(ref mac) => {
+                    mac.to_tokens(tokens);
+                }
+            }
+        }
+    }
+
     impl ToTokens for FnArg {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            self.pat.to_tokens(tokens);
-            tokens.append(":");
-            self.ty.to_tokens(tokens);
+            match *self {
+                FnArg::SelfRef(ref lifetime, mutability) => {
+                    tokens.append("&");
+                    lifetime.to_tokens(tokens);
+                    mutability.to_tokens(tokens);
+                    tokens.append("self");
+                }
+                FnArg::SelfValue(mutability) => {
+                    mutability.to_tokens(tokens);
+                    tokens.append("self");
+                }
+                FnArg::Captured(ref pat, ref ty) => {
+                    pat.to_tokens(tokens);
+                    tokens.append(":");
+                    ty.to_tokens(tokens);
+                }
+                FnArg::Ignored(ref ty) => {
+                    ty.to_tokens(tokens);
+                }
+            }
         }
     }