]> git.proxmox.com Git - rustc.git/blobdiff - src/libsyntax/print/pprust.rs
New upstream version 1.20.0+dfsg1
[rustc.git] / src / libsyntax / print / pprust.rs
index 46d196d13fa72f4c9191c872835e0f89ba681dfa..b052b2cdbbb5a74fa31c52371b64432abedf513e 100644 (file)
 
 pub use self::AnnNode::*;
 
-use abi;
-use ast;
-use ast::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
-use ast_util;
+use abi::{self, Abi};
+use ast::{self, BlockCheckMode, PatKind, RangeEnd};
+use ast::{SelfKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
+use ast::Attribute;
+use util::parser::AssocOp;
 use attr;
-use owned_slice::OwnedSlice;
-use attr::{AttrMetaMethods, AttributeMethods};
-use codemap::{self, CodeMap, BytePos};
-use diagnostic;
-use parse::token::{self, BinOpToken, Token, InternedString};
+use codemap::{self, CodeMap};
+use syntax_pos::{self, BytePos};
+use parse::token::{self, BinOpToken, Token};
 use parse::lexer::comments;
-use parse;
-use print::pp::{self, break_offset, word, space, zerobreak, hardbreak};
-use print::pp::{Breaks, eof};
+use parse::{self, ParseSess};
+use print::pp::{self, Breaks};
 use print::pp::Breaks::{Consistent, Inconsistent};
 use ptr::P;
 use std_inject;
+use symbol::{Symbol, keywords};
+use syntax_pos::DUMMY_SP;
+use tokenstream::{self, TokenStream, TokenTree};
 
-use std::{ascii, mem};
+use std::ascii;
 use std::io::{self, Write, Read};
-use std::iter;
+use std::iter::{self, Peekable};
+use std::vec;
 
 pub enum AnnNode<'a> {
     NodeIdent(&'a ast::Ident),
@@ -52,105 +54,77 @@ pub struct NoAnn;
 
 impl PpAnn for NoAnn {}
 
-#[derive(Copy, Clone)]
-pub struct CurrentCommentAndLiteral {
-    cur_cmnt: usize,
-    cur_lit: usize,
-}
-
 pub struct State<'a> {
     pub s: pp::Printer<'a>,
     cm: Option<&'a CodeMap>,
     comments: Option<Vec<comments::Comment> >,
-    literals: Option<Vec<comments::Literal> >,
-    cur_cmnt_and_lit: CurrentCommentAndLiteral,
+    literals: Peekable<vec::IntoIter<comments::Literal>>,
+    cur_cmnt: usize,
     boxes: Vec<pp::Breaks>,
     ann: &'a (PpAnn+'a),
-    encode_idents_with_hygiene: bool,
-}
-
-pub fn rust_printer<'a>(writer: Box<Write+'a>) -> State<'a> {
-    static NO_ANN: NoAnn = NoAnn;
-    rust_printer_annotated(writer, &NO_ANN)
 }
 
-pub fn rust_printer_annotated<'a>(writer: Box<Write+'a>,
-                                  ann: &'a PpAnn) -> State<'a> {
+fn rust_printer<'a>(writer: Box<Write+'a>, ann: &'a PpAnn) -> State<'a> {
     State {
-        s: pp::mk_printer(writer, default_columns),
+        s: pp::mk_printer(writer, DEFAULT_COLUMNS),
         cm: None,
         comments: None,
-        literals: None,
-        cur_cmnt_and_lit: CurrentCommentAndLiteral {
-            cur_cmnt: 0,
-            cur_lit: 0
-        },
+        literals: vec![].into_iter().peekable(),
+        cur_cmnt: 0,
         boxes: Vec::new(),
         ann: ann,
-        encode_idents_with_hygiene: false,
     }
 }
 
-#[allow(non_upper_case_globals)]
-pub const indent_unit: usize = 4;
+pub const INDENT_UNIT: usize = 4;
 
-#[allow(non_upper_case_globals)]
-pub const default_columns: usize = 78;
+pub const DEFAULT_COLUMNS: usize = 78;
 
 /// Requires you to pass an input filename and reader so that
 /// it can scan the input text for comments and literals to
 /// copy forward.
 pub fn print_crate<'a>(cm: &'a CodeMap,
-                       span_diagnostic: &diagnostic::SpanHandler,
+                       sess: &ParseSess,
                        krate: &ast::Crate,
                        filename: String,
                        input: &mut Read,
                        out: Box<Write+'a>,
                        ann: &'a PpAnn,
                        is_expanded: bool) -> io::Result<()> {
-    let mut s = State::new_from_input(cm,
-                                      span_diagnostic,
-                                      filename,
-                                      input,
-                                      out,
-                                      ann,
-                                      is_expanded);
-    if is_expanded && std_inject::use_std(krate) {
+    let mut s = State::new_from_input(cm, sess, filename, input, out, ann, is_expanded);
+
+    if is_expanded && !std_inject::injected_crate_name(krate).is_none() {
         // We need to print `#![no_std]` (and its feature gate) so that
         // compiling pretty-printed source won't inject libstd again.
         // However we don't want these attributes in the AST because
         // of the feature gate, so we fake them up here.
 
-        let no_std_meta = attr::mk_word_item(InternedString::new("no_std"));
-
-        // #![feature(no_std)]
-        let fake_attr = attr::mk_attr_inner(attr::mk_attr_id(),
-                                            attr::mk_list_item(InternedString::new("feature"),
-                                                               vec![no_std_meta.clone()]));
-        try!(s.print_attribute(&fake_attr));
+        // #![feature(prelude_import)]
+        let prelude_import_meta = attr::mk_list_word_item(Symbol::intern("prelude_import"));
+        let list = attr::mk_list_item(Symbol::intern("feature"), vec![prelude_import_meta]);
+        let fake_attr = attr::mk_attr_inner(DUMMY_SP, attr::mk_attr_id(), list);
+        s.print_attribute(&fake_attr)?;
 
         // #![no_std]
-        let fake_attr = attr::mk_attr_inner(attr::mk_attr_id(), no_std_meta);
-        try!(s.print_attribute(&fake_attr));
+        let no_std_meta = attr::mk_word_item(Symbol::intern("no_std"));
+        let fake_attr = attr::mk_attr_inner(DUMMY_SP, attr::mk_attr_id(), no_std_meta);
+        s.print_attribute(&fake_attr)?;
     }
 
-    try!(s.print_mod(&krate.module, &krate.attrs));
-    try!(s.print_remaining_comments());
-    eof(&mut s.s)
+    s.print_mod(&krate.module, &krate.attrs)?;
+    s.print_remaining_comments()?;
+    s.s.eof()
 }
 
 impl<'a> State<'a> {
     pub fn new_from_input(cm: &'a CodeMap,
-                          span_diagnostic: &diagnostic::SpanHandler,
+                          sess: &ParseSess,
                           filename: String,
                           input: &mut Read,
                           out: Box<Write+'a>,
                           ann: &'a PpAnn,
                           is_expanded: bool) -> State<'a> {
-        let (cmnts, lits) = comments::gather_comments_and_literals(
-            span_diagnostic,
-            filename,
-            input);
+        let (cmnts, lits) = comments::gather_comments_and_literals(sess, filename, input);
 
         State::new(
             cm,
@@ -169,17 +143,13 @@ impl<'a> State<'a> {
                comments: Option<Vec<comments::Comment>>,
                literals: Option<Vec<comments::Literal>>) -> State<'a> {
         State {
-            s: pp::mk_printer(out, default_columns),
+            s: pp::mk_printer(out, DEFAULT_COLUMNS),
             cm: Some(cm),
             comments: comments,
-            literals: literals,
-            cur_cmnt_and_lit: CurrentCommentAndLiteral {
-                cur_cmnt: 0,
-                cur_lit: 0
-            },
+            literals: literals.unwrap_or_default().into_iter().peekable(),
+            cur_cmnt: 0,
             boxes: Vec::new(),
             ann: ann,
-            encode_idents_with_hygiene: false,
         }
     }
 }
@@ -187,21 +157,17 @@ impl<'a> State<'a> {
 pub fn to_string<F>(f: F) -> String where
     F: FnOnce(&mut State) -> io::Result<()>,
 {
-    use std::raw::TraitObject;
-    let mut s = rust_printer(box Vec::new());
-    f(&mut s).unwrap();
-    eof(&mut s.s).unwrap();
-    let wr = unsafe {
-        // FIXME(pcwalton): A nasty function to extract the string from an `Write`
-        // that we "know" to be a `Vec<u8>` that works around the lack of checked
-        // downcasts.
-        let obj: &TraitObject = mem::transmute(&s.s.out);
-        mem::transmute::<*mut (), &Vec<u8>>(obj.data)
-    };
-    String::from_utf8(wr.clone()).unwrap()
+    let mut wr = Vec::new();
+    {
+        let ann = NoAnn;
+        let mut printer = rust_printer(Box::new(&mut wr), &ann);
+        f(&mut printer).unwrap();
+        printer.s.eof().unwrap();
+    }
+    String::from_utf8(wr).unwrap()
 }
 
-pub fn binop_to_string(op: BinOpToken) -> &'static str {
+fn binop_to_string(op: BinOpToken) -> &'static str {
     match op {
         token::Plus     => "+",
         token::Minus    => "-",
@@ -250,6 +216,8 @@ pub fn token_to_string(tok: &Token) -> String {
         token::CloseDelim(token::Bracket) => "]".to_string(),
         token::OpenDelim(token::Brace) => "{".to_string(),
         token::CloseDelim(token::Brace) => "}".to_string(),
+        token::OpenDelim(token::NoDelim) |
+        token::CloseDelim(token::NoDelim) => " ".to_string(),
         token::Pound                => "#".to_string(),
         token::Dollar               => "$".to_string(),
         token::Question             => "?".to_string(),
@@ -257,317 +225,683 @@ pub fn token_to_string(tok: &Token) -> String {
         /* Literals */
         token::Literal(lit, suf) => {
             let mut out = match lit {
-                token::Byte(b)           => format!("b'{}'", b.as_str()),
-                token::Char(c)           => format!("'{}'", c.as_str()),
-                token::Float(c)          => c.as_str().to_string(),
-                token::Integer(c)        => c.as_str().to_string(),
-                token::Str_(s)           => format!("\"{}\"", s.as_str()),
+                token::Byte(b)           => format!("b'{}'", b),
+                token::Char(c)           => format!("'{}'", c),
+                token::Float(c)          |
+                token::Integer(c)        => c.to_string(),
+                token::Str_(s)           => format!("\"{}\"", s),
                 token::StrRaw(s, n)      => format!("r{delim}\"{string}\"{delim}",
                                                     delim=repeat("#", n),
-                                                    string=s.as_str()),
-                token::Binary(v)         => format!("b\"{}\"", v.as_str()),
-                token::BinaryRaw(s, n)   => format!("br{delim}\"{string}\"{delim}",
+                                                    string=s),
+                token::ByteStr(v)         => format!("b\"{}\"", v),
+                token::ByteStrRaw(s, n)   => format!("br{delim}\"{string}\"{delim}",
                                                     delim=repeat("#", n),
-                                                    string=s.as_str()),
+                                                    string=s),
             };
 
             if let Some(s) = suf {
-                out.push_str(s.as_str())
+                out.push_str(&s.as_str())
             }
 
             out
         }
 
         /* Name components */
-        token::Ident(s, _)          => token::get_ident(s).to_string(),
-        token::Lifetime(s)          => format!("{}", token::get_ident(s)),
+        token::Ident(s)             => s.to_string(),
+        token::Lifetime(s)          => s.to_string(),
         token::Underscore           => "_".to_string(),
 
         /* Other */
-        token::DocComment(s)        => s.as_str().to_string(),
-        token::SubstNt(s, _)        => format!("${}", s),
-        token::MatchNt(s, t, _, _)  => format!("${}:{}", s, t),
+        token::DocComment(s)        => s.to_string(),
         token::Eof                  => "<eof>".to_string(),
         token::Whitespace           => " ".to_string(),
         token::Comment              => "/* */".to_string(),
-        token::Shebang(s)           => format!("/* shebang: {}*/", s.as_str()),
-
-        token::SpecialVarNt(var)    => format!("${}", var.as_str()),
-
-        token::Interpolated(ref nt) => match *nt {
-            token::NtExpr(ref e)  => expr_to_string(&**e),
-            token::NtMeta(ref e)  => meta_item_to_string(&**e),
-            token::NtTy(ref e)    => ty_to_string(&**e),
-            token::NtPath(ref e)  => path_to_string(&**e),
-            token::NtItem(..)     => "an interpolated item".to_string(),
-            token::NtBlock(..)    => "an interpolated block".to_string(),
-            token::NtStmt(..)     => "an interpolated statement".to_string(),
-            token::NtPat(..)      => "an interpolated pattern".to_string(),
-            token::NtIdent(..)    => "an interpolated identifier".to_string(),
-            token::NtTT(..)       => "an interpolated tt".to_string(),
+        token::Shebang(s)           => format!("/* shebang: {}*/", s),
+
+        token::Interpolated(ref nt) => match nt.0 {
+            token::NtExpr(ref e)        => expr_to_string(e),
+            token::NtMeta(ref e)        => meta_item_to_string(e),
+            token::NtTy(ref e)          => ty_to_string(e),
+            token::NtPath(ref e)        => path_to_string(e),
+            token::NtItem(ref e)        => item_to_string(e),
+            token::NtBlock(ref e)       => block_to_string(e),
+            token::NtStmt(ref e)        => stmt_to_string(e),
+            token::NtPat(ref e)         => pat_to_string(e),
+            token::NtIdent(ref e)       => ident_to_string(e.node),
+            token::NtTT(ref tree)       => tt_to_string(tree.clone()),
+            token::NtArm(ref e)         => arm_to_string(e),
+            token::NtImplItem(ref e)    => impl_item_to_string(e),
+            token::NtTraitItem(ref e)   => trait_item_to_string(e),
+            token::NtGenerics(ref e)    => generics_to_string(e),
+            token::NtWhereClause(ref e) => where_clause_to_string(e),
+            token::NtArg(ref e)         => arg_to_string(e),
+            token::NtVis(ref e)         => vis_to_string(e),
         }
     }
 }
 
-// FIXME (Issue #16472): the thing_to_string_impls macro should go away
-// after we revise the syntax::ext::quote::ToToken impls to go directly
-// to token-trees instead of thing -> string -> token-trees.
-
-macro_rules! thing_to_string_impls {
-    ($to_string:ident) => {
-
 pub fn ty_to_string(ty: &ast::Ty) -> String {
-    $to_string(|s| s.print_type(ty))
+    to_string(|s| s.print_type(ty))
 }
 
 pub fn bounds_to_string(bounds: &[ast::TyParamBound]) -> String {
-    $to_string(|s| s.print_bounds("", bounds))
+    to_string(|s| s.print_bounds("", bounds))
 }
 
 pub fn pat_to_string(pat: &ast::Pat) -> String {
-    $to_string(|s| s.print_pat(pat))
+    to_string(|s| s.print_pat(pat))
 }
 
 pub fn arm_to_string(arm: &ast::Arm) -> String {
-    $to_string(|s| s.print_arm(arm))
+    to_string(|s| s.print_arm(arm))
 }
 
 pub fn expr_to_string(e: &ast::Expr) -> String {
-    $to_string(|s| s.print_expr(e))
+    to_string(|s| s.print_expr(e))
 }
 
 pub fn lifetime_to_string(e: &ast::Lifetime) -> String {
-    $to_string(|s| s.print_lifetime(e))
+    to_string(|s| s.print_lifetime(e))
 }
 
-pub fn tt_to_string(tt: &ast::TokenTree) -> String {
-    $to_string(|s| s.print_tt(tt))
+pub fn tt_to_string(tt: tokenstream::TokenTree) -> String {
+    to_string(|s| s.print_tt(tt))
 }
 
-pub fn tts_to_string(tts: &[ast::TokenTree]) -> String {
-    $to_string(|s| s.print_tts(tts))
+pub fn tts_to_string(tts: &[tokenstream::TokenTree]) -> String {
+    to_string(|s| s.print_tts(tts.iter().cloned().collect()))
+}
+
+pub fn tokens_to_string(tokens: TokenStream) -> String {
+    to_string(|s| s.print_tts(tokens))
 }
 
 pub fn stmt_to_string(stmt: &ast::Stmt) -> String {
-    $to_string(|s| s.print_stmt(stmt))
+    to_string(|s| s.print_stmt(stmt))
+}
+
+pub fn attr_to_string(attr: &ast::Attribute) -> String {
+    to_string(|s| s.print_attribute(attr))
 }
 
 pub fn item_to_string(i: &ast::Item) -> String {
-    $to_string(|s| s.print_item(i))
+    to_string(|s| s.print_item(i))
 }
 
 pub fn impl_item_to_string(i: &ast::ImplItem) -> String {
-    $to_string(|s| s.print_impl_item(i))
+    to_string(|s| s.print_impl_item(i))
 }
 
 pub fn trait_item_to_string(i: &ast::TraitItem) -> String {
-    $to_string(|s| s.print_trait_item(i))
+    to_string(|s| s.print_trait_item(i))
 }
 
 pub fn generics_to_string(generics: &ast::Generics) -> String {
-    $to_string(|s| s.print_generics(generics))
+    to_string(|s| s.print_generics(generics))
 }
 
 pub fn where_clause_to_string(i: &ast::WhereClause) -> String {
-    $to_string(|s| s.print_where_clause(i))
+    to_string(|s| s.print_where_clause(i))
 }
 
 pub fn fn_block_to_string(p: &ast::FnDecl) -> String {
-    $to_string(|s| s.print_fn_block_args(p))
+    to_string(|s| s.print_fn_block_args(p))
 }
 
 pub fn path_to_string(p: &ast::Path) -> String {
-    $to_string(|s| s.print_path(p, false, 0))
+    to_string(|s| s.print_path(p, false, 0, false))
+}
+
+pub fn path_segment_to_string(p: &ast::PathSegment) -> String {
+    to_string(|s| s.print_path_segment(p, false))
+}
+
+pub fn ident_to_string(id: ast::Ident) -> String {
+    to_string(|s| s.print_ident(id))
 }
 
-pub fn ident_to_string(id: &ast::Ident) -> String {
-    $to_string(|s| s.print_ident(*id))
+pub fn vis_to_string(v: &ast::Visibility) -> String {
+    to_string(|s| s.print_visibility(v))
 }
 
-pub fn fun_to_string(decl: &ast::FnDecl, unsafety: ast::Unsafety, name: ast::Ident,
-                  opt_explicit_self: Option<&ast::ExplicitSelf_>,
-                  generics: &ast::Generics) -> String {
-    $to_string(|s| {
-        try!(s.head(""));
-        try!(s.print_fn(decl, unsafety, abi::Rust, Some(name),
-                        generics, opt_explicit_self, ast::Inherited));
-        try!(s.end()); // Close the head box
+pub fn fun_to_string(decl: &ast::FnDecl,
+                     unsafety: ast::Unsafety,
+                     constness: ast::Constness,
+                     name: ast::Ident,
+                     generics: &ast::Generics)
+                     -> String {
+    to_string(|s| {
+        s.head("")?;
+        s.print_fn(decl, unsafety, constness, Abi::Rust, Some(name),
+                   generics, &ast::Visibility::Inherited)?;
+        s.end()?; // Close the head box
         s.end() // Close the outer box
     })
 }
 
 pub fn block_to_string(blk: &ast::Block) -> String {
-    $to_string(|s| {
+    to_string(|s| {
         // containing cbox, will be closed by print-block at }
-        try!(s.cbox(indent_unit));
+        s.cbox(INDENT_UNIT)?;
         // head-ibox, will be closed by print-block after {
-        try!(s.ibox(0));
+        s.ibox(0)?;
         s.print_block(blk)
     })
 }
 
+pub fn meta_list_item_to_string(li: &ast::NestedMetaItem) -> String {
+    to_string(|s| s.print_meta_list_item(li))
+}
+
 pub fn meta_item_to_string(mi: &ast::MetaItem) -> String {
-    $to_string(|s| s.print_meta_item(mi))
+    to_string(|s| s.print_meta_item(mi))
 }
 
 pub fn attribute_to_string(attr: &ast::Attribute) -> String {
-    $to_string(|s| s.print_attribute(attr))
+    to_string(|s| s.print_attribute(attr))
 }
 
 pub fn lit_to_string(l: &ast::Lit) -> String {
-    $to_string(|s| s.print_literal(l))
-}
-
-pub fn explicit_self_to_string(explicit_self: &ast::ExplicitSelf_) -> String {
-    $to_string(|s| s.print_explicit_self(explicit_self, ast::MutImmutable).map(|_| {}))
+    to_string(|s| s.print_literal(l))
 }
 
 pub fn variant_to_string(var: &ast::Variant) -> String {
-    $to_string(|s| s.print_variant(var))
+    to_string(|s| s.print_variant(var))
 }
 
 pub fn arg_to_string(arg: &ast::Arg) -> String {
-    $to_string(|s| s.print_arg(arg))
+    to_string(|s| s.print_arg(arg, false))
 }
 
 pub fn mac_to_string(arg: &ast::Mac) -> String {
-    $to_string(|s| s.print_mac(arg, ::parse::token::Paren))
+    to_string(|s| s.print_mac(arg, ::parse::token::Paren))
 }
 
-} }
+pub fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
+    format!("{}{}", to_string(|s| s.print_visibility(vis)), s)
+}
 
-thing_to_string_impls! { to_string }
+fn needs_parentheses(expr: &ast::Expr) -> bool {
+    match expr.node {
+        ast::ExprKind::Assign(..) | ast::ExprKind::Binary(..) |
+        ast::ExprKind::Closure(..) |
+        ast::ExprKind::AssignOp(..) | ast::ExprKind::Cast(..) |
+        ast::ExprKind::InPlace(..) | ast::ExprKind::Type(..) => true,
+        _ => false,
+    }
+}
 
-// FIXME (Issue #16472): the whole `with_hygiene` mod should go away
-// after we revise the syntax::ext::quote::ToToken impls to go directly
-// to token-trees instea of thing -> string -> token-trees.
+pub trait PrintState<'a> {
+    fn writer(&mut self) -> &mut pp::Printer<'a>;
+    fn boxes(&mut self) -> &mut Vec<pp::Breaks>;
+    fn comments(&mut self) -> &mut Option<Vec<comments::Comment>>;
+    fn cur_cmnt(&mut self) -> &mut usize;
+    fn cur_lit(&mut self) -> Option<&comments::Literal>;
+    fn bump_lit(&mut self) -> Option<comments::Literal>;
 
-pub mod with_hygiene {
-    use abi;
-    use ast;
-    use std::io;
-    use super::indent_unit;
+    fn word_space(&mut self, w: &str) -> io::Result<()> {
+        self.writer().word(w)?;
+        self.writer().space()
+    }
 
-    // This function is the trick that all the rest of the routines
-    // hang on.
-    pub fn to_string_hyg<F>(f: F) -> String where
-        F: FnOnce(&mut super::State) -> io::Result<()>,
+    fn popen(&mut self) -> io::Result<()> { self.writer().word("(") }
+
+    fn pclose(&mut self) -> io::Result<()> { self.writer().word(")") }
+
+    fn is_begin(&mut self) -> bool {
+        match self.writer().last_token() {
+            pp::Token::Begin(_) => true,
+            _ => false,
+        }
+    }
+
+    fn is_end(&mut self) -> bool {
+        match self.writer().last_token() {
+            pp::Token::End => true,
+            _ => false,
+        }
+    }
+
+    // is this the beginning of a line?
+    fn is_bol(&mut self) -> bool {
+        self.writer().last_token().is_eof() || self.writer().last_token().is_hardbreak_tok()
+    }
+
+    fn hardbreak_if_not_bol(&mut self) -> io::Result<()> {
+        if !self.is_bol() {
+            self.writer().hardbreak()?
+        }
+        Ok(())
+    }
+
+    // "raw box"
+    fn rbox(&mut self, u: usize, b: pp::Breaks) -> io::Result<()> {
+        self.boxes().push(b);
+        self.writer().rbox(u, b)
+    }
+
+    fn ibox(&mut self, u: usize) -> io::Result<()> {
+        self.boxes().push(pp::Breaks::Inconsistent);
+        self.writer().ibox(u)
+    }
+
+    fn end(&mut self) -> io::Result<()> {
+        self.boxes().pop().unwrap();
+        self.writer().end()
+    }
+
+    fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], mut op: F) -> io::Result<()>
+        where F: FnMut(&mut Self, &T) -> io::Result<()>,
     {
-        super::to_string(move |s| {
-            s.encode_idents_with_hygiene = true;
-            f(s)
-        })
+        self.rbox(0, b)?;
+        let mut first = true;
+        for elt in elts {
+            if first { first = false; } else { self.word_space(",")?; }
+            op(self, elt)?;
+        }
+        self.end()
     }
 
-    thing_to_string_impls! { to_string_hyg }
-}
+    fn next_lit(&mut self, pos: BytePos) -> Option<comments::Literal> {
+        while let Some(ltrl) = self.cur_lit().cloned() {
+            if ltrl.pos > pos { break; }
+
+            // we don't need the value here since we're forced to clone cur_lit
+            // due to lack of NLL.
+            self.bump_lit();
+            if ltrl.pos == pos {
+                return Some(ltrl);
+            }
+        }
 
-pub fn visibility_qualified(vis: ast::Visibility, s: &str) -> String {
-    match vis {
-        ast::Public => format!("pub {}", s),
-        ast::Inherited => s.to_string()
+        None
     }
-}
 
-fn needs_parentheses(expr: &ast::Expr) -> bool {
-    match expr.node {
-        ast::ExprAssign(..) | ast::ExprBinary(..) |
-        ast::ExprClosure(..) |
-        ast::ExprAssignOp(..) | ast::ExprCast(..) => true,
-        _ => false,
+    fn maybe_print_comment(&mut self, pos: BytePos) -> io::Result<()> {
+        while let Some(ref cmnt) = self.next_comment() {
+            if cmnt.pos < pos {
+                self.print_comment(cmnt)?;
+            } else {
+                break
+            }
+        }
+        Ok(())
     }
-}
 
-impl<'a> State<'a> {
-    pub fn ibox(&mut self, u: usize) -> io::Result<()> {
-        self.boxes.push(pp::Breaks::Inconsistent);
-        pp::ibox(&mut self.s, u)
+    fn print_comment(&mut self,
+                     cmnt: &comments::Comment) -> io::Result<()> {
+        let r = match cmnt.style {
+            comments::Mixed => {
+                assert_eq!(cmnt.lines.len(), 1);
+                self.writer().zerobreak()?;
+                self.writer().word(&cmnt.lines[0])?;
+                self.writer().zerobreak()
+            }
+            comments::Isolated => {
+                self.hardbreak_if_not_bol()?;
+                for line in &cmnt.lines {
+                    // Don't print empty lines because they will end up as trailing
+                    // whitespace
+                    if !line.is_empty() {
+                        self.writer().word(&line[..])?;
+                    }
+                    self.writer().hardbreak()?;
+                }
+                Ok(())
+            }
+            comments::Trailing => {
+                if !self.is_bol() {
+                    self.writer().word(" ")?;
+                }
+                if cmnt.lines.len() == 1 {
+                    self.writer().word(&cmnt.lines[0])?;
+                    self.writer().hardbreak()
+                } else {
+                    self.ibox(0)?;
+                    for line in &cmnt.lines {
+                        if !line.is_empty() {
+                            self.writer().word(&line[..])?;
+                        }
+                        self.writer().hardbreak()?;
+                    }
+                    self.end()
+                }
+            }
+            comments::BlankLine => {
+                // We need to do at least one, possibly two hardbreaks.
+                let is_semi = match self.writer().last_token() {
+                    pp::Token::String(s, _) => ";" == s,
+                    _ => false
+                };
+                if is_semi || self.is_begin() || self.is_end() {
+                    self.writer().hardbreak()?;
+                }
+                self.writer().hardbreak()
+            }
+        };
+        match r {
+            Ok(()) => {
+                *self.cur_cmnt() = *self.cur_cmnt() + 1;
+                Ok(())
+            }
+            Err(e) => Err(e),
+        }
     }
 
-    pub fn end(&mut self) -> io::Result<()> {
-        self.boxes.pop().unwrap();
-        pp::end(&mut self.s)
+    fn next_comment(&mut self) -> Option<comments::Comment> {
+        let cur_cmnt = *self.cur_cmnt();
+        match *self.comments() {
+            Some(ref cmnts) => {
+                if cur_cmnt < cmnts.len() {
+                    Some(cmnts[cur_cmnt].clone())
+                } else {
+                    None
+                }
+            }
+            _ => None
+        }
     }
 
-    pub fn cbox(&mut self, u: usize) -> io::Result<()> {
-        self.boxes.push(pp::Breaks::Consistent);
-        pp::cbox(&mut self.s, u)
+    fn print_literal(&mut self, lit: &ast::Lit) -> io::Result<()> {
+        self.maybe_print_comment(lit.span.lo)?;
+        if let Some(ltrl) = self.next_lit(lit.span.lo) {
+            return self.writer().word(&ltrl.lit);
+        }
+        match lit.node {
+            ast::LitKind::Str(st, style) => self.print_string(&st.as_str(), style),
+            ast::LitKind::Byte(byte) => {
+                let mut res = String::from("b'");
+                res.extend(ascii::escape_default(byte).map(|c| c as char));
+                res.push('\'');
+                self.writer().word(&res[..])
+            }
+            ast::LitKind::Char(ch) => {
+                let mut res = String::from("'");
+                res.extend(ch.escape_default());
+                res.push('\'');
+                self.writer().word(&res[..])
+            }
+            ast::LitKind::Int(i, t) => {
+                match t {
+                    ast::LitIntType::Signed(st) => {
+                        self.writer().word(&st.val_to_string(i as i128))
+                    }
+                    ast::LitIntType::Unsigned(ut) => {
+                        self.writer().word(&ut.val_to_string(i))
+                    }
+                    ast::LitIntType::Unsuffixed => {
+                        self.writer().word(&format!("{}", i))
+                    }
+                }
+            }
+            ast::LitKind::Float(ref f, t) => {
+                self.writer().word(&format!("{}{}", &f, t.ty_to_string()))
+            }
+            ast::LitKind::FloatUnsuffixed(ref f) => self.writer().word(&f.as_str()),
+            ast::LitKind::Bool(val) => {
+                if val { self.writer().word("true") } else { self.writer().word("false") }
+            }
+            ast::LitKind::ByteStr(ref v) => {
+                let mut escaped: String = String::new();
+                for &ch in v.iter() {
+                    escaped.extend(ascii::escape_default(ch)
+                                         .map(|c| c as char));
+                }
+                self.writer().word(&format!("b\"{}\"", escaped))
+            }
+        }
     }
 
-    // "raw box"
-    pub fn rbox(&mut self, u: usize, b: pp::Breaks) -> io::Result<()> {
-        self.boxes.push(b);
-        pp::rbox(&mut self.s, u, b)
+    fn print_string(&mut self, st: &str,
+                    style: ast::StrStyle) -> io::Result<()> {
+        let st = match style {
+            ast::StrStyle::Cooked => {
+                (format!("\"{}\"", parse::escape_default(st)))
+            }
+            ast::StrStyle::Raw(n) => {
+                (format!("r{delim}\"{string}\"{delim}",
+                         delim=repeat("#", n),
+                         string=st))
+            }
+        };
+        self.writer().word(&st[..])
     }
 
-    pub fn nbsp(&mut self) -> io::Result<()> { word(&mut self.s, " ") }
+    fn print_inner_attributes(&mut self,
+                              attrs: &[ast::Attribute]) -> io::Result<()> {
+        self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true)
+    }
 
-    pub fn word_nbsp(&mut self, w: &str) -> io::Result<()> {
-        try!(word(&mut self.s, w));
-        self.nbsp()
+    fn print_inner_attributes_no_trailing_hardbreak(&mut self,
+                                                   attrs: &[ast::Attribute])
+                                                   -> io::Result<()> {
+        self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, false)
+    }
+
+    fn print_outer_attributes(&mut self,
+                              attrs: &[ast::Attribute]) -> io::Result<()> {
+        self.print_either_attributes(attrs, ast::AttrStyle::Outer, false, true)
+    }
+
+    fn print_inner_attributes_inline(&mut self,
+                                     attrs: &[ast::Attribute]) -> io::Result<()> {
+        self.print_either_attributes(attrs, ast::AttrStyle::Inner, true, true)
+    }
+
+    fn print_outer_attributes_inline(&mut self,
+                                     attrs: &[ast::Attribute]) -> io::Result<()> {
+        self.print_either_attributes(attrs, ast::AttrStyle::Outer, true, true)
+    }
+
+    fn print_either_attributes(&mut self,
+                              attrs: &[ast::Attribute],
+                              kind: ast::AttrStyle,
+                              is_inline: bool,
+                              trailing_hardbreak: bool) -> io::Result<()> {
+        let mut count = 0;
+        for attr in attrs {
+            if attr.style == kind {
+                self.print_attribute_inline(attr, is_inline)?;
+                if is_inline {
+                    self.nbsp()?;
+                }
+                count += 1;
+            }
+        }
+        if count > 0 && trailing_hardbreak && !is_inline {
+            self.hardbreak_if_not_bol()?;
+        }
+        Ok(())
+    }
+
+    fn print_attribute(&mut self, attr: &ast::Attribute) -> io::Result<()> {
+        self.print_attribute_inline(attr, false)
+    }
+
+    fn print_attribute_inline(&mut self, attr: &ast::Attribute,
+                              is_inline: bool) -> io::Result<()> {
+        if !is_inline {
+            self.hardbreak_if_not_bol()?;
+        }
+        self.maybe_print_comment(attr.span.lo)?;
+        if attr.is_sugared_doc {
+            self.writer().word(&attr.value_str().unwrap().as_str())?;
+            self.writer().hardbreak()
+        } else {
+            match attr.style {
+                ast::AttrStyle::Inner => self.writer().word("#![")?,
+                ast::AttrStyle::Outer => self.writer().word("#[")?,
+            }
+            if let Some(mi) = attr.meta() {
+                self.print_meta_item(&mi)?
+            } else {
+                for (i, segment) in attr.path.segments.iter().enumerate() {
+                    if i > 0 {
+                        self.writer().word("::")?
+                    }
+                    if segment.identifier.name != keywords::CrateRoot.name() &&
+                       segment.identifier.name != keywords::DollarCrate.name() {
+                        self.writer().word(&segment.identifier.name.as_str())?;
+                    }
+                }
+                self.writer().space()?;
+                self.print_tts(attr.tokens.clone())?;
+            }
+            self.writer().word("]")
+        }
+    }
+
+    fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) -> io::Result<()> {
+        match item.node {
+            ast::NestedMetaItemKind::MetaItem(ref mi) => {
+                self.print_meta_item(mi)
+            },
+            ast::NestedMetaItemKind::Literal(ref lit) => {
+                self.print_literal(lit)
+            }
+        }
+    }
+
+    fn print_meta_item(&mut self, item: &ast::MetaItem) -> io::Result<()> {
+        self.ibox(INDENT_UNIT)?;
+        match item.node {
+            ast::MetaItemKind::Word => {
+                self.writer().word(&item.name.as_str())?;
+            }
+            ast::MetaItemKind::NameValue(ref value) => {
+                self.word_space(&item.name.as_str())?;
+                self.word_space("=")?;
+                self.print_literal(value)?;
+            }
+            ast::MetaItemKind::List(ref items) => {
+                self.writer().word(&item.name.as_str())?;
+                self.popen()?;
+                self.commasep(Consistent,
+                              &items[..],
+                              |s, i| s.print_meta_list_item(i))?;
+                self.pclose()?;
+            }
+        }
+        self.end()
+    }
+
+    /// This doesn't deserve to be called "pretty" printing, but it should be
+    /// meaning-preserving. A quick hack that might help would be to look at the
+    /// spans embedded in the TTs to decide where to put spaces and newlines.
+    /// But it'd be better to parse these according to the grammar of the
+    /// appropriate macro, transcribe back into the grammar we just parsed from,
+    /// and then pretty-print the resulting AST nodes (so, e.g., we print
+    /// expression arguments as expressions). It can be done! I think.
+    fn print_tt(&mut self, tt: tokenstream::TokenTree) -> io::Result<()> {
+        match tt {
+            TokenTree::Token(_, ref tk) => {
+                self.writer().word(&token_to_string(tk))?;
+                match *tk {
+                    parse::token::DocComment(..) => {
+                        self.writer().hardbreak()
+                    }
+                    _ => Ok(())
+                }
+            }
+            TokenTree::Delimited(_, ref delimed) => {
+                self.writer().word(&token_to_string(&delimed.open_token()))?;
+                self.writer().space()?;
+                self.print_tts(delimed.stream())?;
+                self.writer().space()?;
+                self.writer().word(&token_to_string(&delimed.close_token()))
+            },
+        }
     }
 
-    pub fn word_space(&mut self, w: &str) -> io::Result<()> {
-        try!(word(&mut self.s, w));
-        space(&mut self.s)
+    fn print_tts(&mut self, tts: tokenstream::TokenStream) -> io::Result<()> {
+        self.ibox(0)?;
+        for (i, tt) in tts.into_trees().enumerate() {
+            if i != 0 {
+                self.writer().space()?;
+            }
+            self.print_tt(tt)?;
+        }
+        self.end()
     }
 
-    pub fn popen(&mut self) -> io::Result<()> { word(&mut self.s, "(") }
+    fn space_if_not_bol(&mut self) -> io::Result<()> {
+        if !self.is_bol() { self.writer().space()?; }
+        Ok(())
+    }
 
-    pub fn pclose(&mut self) -> io::Result<()> { word(&mut self.s, ")") }
+    fn nbsp(&mut self) -> io::Result<()> { self.writer().word(" ") }
+}
+
+impl<'a> PrintState<'a> for State<'a> {
+    fn writer(&mut self) -> &mut pp::Printer<'a> {
+        &mut self.s
+    }
+
+    fn boxes(&mut self) -> &mut Vec<pp::Breaks> {
+        &mut self.boxes
+    }
+
+    fn comments(&mut self) -> &mut Option<Vec<comments::Comment>> {
+        &mut self.comments
+    }
+
+    fn cur_cmnt(&mut self) -> &mut usize {
+        &mut self.cur_cmnt
+    }
+
+    fn cur_lit(&mut self) -> Option<&comments::Literal> {
+        self.literals.peek()
+    }
+
+    fn bump_lit(&mut self) -> Option<comments::Literal> {
+        self.literals.next()
+    }
+}
+
+impl<'a> State<'a> {
+    pub fn cbox(&mut self, u: usize) -> io::Result<()> {
+        self.boxes.push(pp::Breaks::Consistent);
+        self.s.cbox(u)
+    }
+
+    pub fn word_nbsp(&mut self, w: &str) -> io::Result<()> {
+        self.s.word(w)?;
+        self.nbsp()
+    }
 
     pub fn head(&mut self, w: &str) -> io::Result<()> {
         // outer-box is consistent
-        try!(self.cbox(indent_unit));
+        self.cbox(INDENT_UNIT)?;
         // head-box is inconsistent
-        try!(self.ibox(w.len() + 1));
+        self.ibox(w.len() + 1)?;
         // keyword that starts the head
         if !w.is_empty() {
-            try!(self.word_nbsp(w));
+            self.word_nbsp(w)?;
         }
         Ok(())
     }
 
     pub fn bopen(&mut self) -> io::Result<()> {
-        try!(word(&mut self.s, "{"));
+        self.s.word("{")?;
         self.end() // close the head-box
     }
 
-    pub fn bclose_(&mut self, span: codemap::Span,
+    pub fn bclose_(&mut self, span: syntax_pos::Span,
                    indented: usize) -> io::Result<()> {
         self.bclose_maybe_open(span, indented, true)
     }
-    pub fn bclose_maybe_open (&mut self, span: codemap::Span,
-                              indented: usize, close_box: bool) -> io::Result<()> {
-        try!(self.maybe_print_comment(span.hi));
-        try!(self.break_offset_if_not_bol(1, -(indented as isize)));
-        try!(word(&mut self.s, "}"));
+    pub fn bclose_maybe_open(&mut self, span: syntax_pos::Span,
+                             indented: usize, close_box: bool) -> io::Result<()> {
+        self.maybe_print_comment(span.hi)?;
+        self.break_offset_if_not_bol(1, -(indented as isize))?;
+        self.s.word("}")?;
         if close_box {
-            try!(self.end()); // close the outer-box
+            self.end()?; // close the outer-box
         }
         Ok(())
     }
-    pub fn bclose(&mut self, span: codemap::Span) -> io::Result<()> {
-        self.bclose_(span, indent_unit)
-    }
-
-    pub fn is_begin(&mut self) -> bool {
-        match self.s.last_token() {
-            pp::Token::Begin(_) => true,
-            _ => false,
-        }
-    }
-
-    pub fn is_end(&mut self) -> bool {
-        match self.s.last_token() {
-            pp::Token::End => true,
-            _ => false,
-        }
-    }
-
-    // is this the beginning of a line?
-    pub fn is_bol(&mut self) -> bool {
-        self.s.last_token().is_eof() || self.s.last_token().is_hardbreak_tok()
+    pub fn bclose(&mut self, span: syntax_pos::Span) -> io::Result<()> {
+        self.bclose_(span, INDENT_UNIT)
     }
 
     pub fn in_cbox(&self) -> bool {
@@ -577,26 +911,16 @@ impl<'a> State<'a> {
         }
     }
 
-    pub fn hardbreak_if_not_bol(&mut self) -> io::Result<()> {
-        if !self.is_bol() {
-            try!(hardbreak(&mut self.s))
-        }
-        Ok(())
-    }
-    pub fn space_if_not_bol(&mut self) -> io::Result<()> {
-        if !self.is_bol() { try!(space(&mut self.s)); }
-        Ok(())
-    }
     pub fn break_offset_if_not_bol(&mut self, n: usize,
                                    off: isize) -> io::Result<()> {
         if !self.is_bol() {
-            break_offset(&mut self.s, n, off)
+            self.s.break_offset(n, off)
         } else {
             if off != 0 && self.s.last_token().is_hardbreak_tok() {
                 // We do something pretty sketchy here: tuck the nonzero
                 // offset-adjustment we were going to deposit along with the
                 // break into the previous hardbreak.
-                self.s.replace_last_token(pp::hardbreak_tok_offset(off));
+                self.s.replace_last_token(pp::Printer::hardbreak_tok_offset(off));
             }
             Ok(())
         }
@@ -605,24 +929,13 @@ impl<'a> State<'a> {
     // Synthesizes a comment that was not textually present in the original source
     // file.
     pub fn synth_comment(&mut self, text: String) -> io::Result<()> {
-        try!(word(&mut self.s, "/*"));
-        try!(space(&mut self.s));
-        try!(word(&mut self.s, &text[..]));
-        try!(space(&mut self.s));
-        word(&mut self.s, "*/")
+        self.s.word("/*")?;
+        self.s.space()?;
+        self.s.word(&text[..])?;
+        self.s.space()?;
+        self.s.word("*/")
     }
 
-    pub fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], mut op: F) -> io::Result<()> where
-        F: FnMut(&mut State, &T) -> io::Result<()>,
-    {
-        try!(self.rbox(0, b));
-        let mut first = true;
-        for elt in elts {
-            if first { first = false; } else { try!(self.word_space(",")); }
-            try!(op(self, elt));
-        }
-        self.end()
-    }
 
 
     pub fn commasep_cmnt<T, F, G>(&mut self,
@@ -631,20 +944,20 @@ impl<'a> State<'a> {
                                   mut op: F,
                                   mut get_span: G) -> io::Result<()> where
         F: FnMut(&mut State, &T) -> io::Result<()>,
-        G: FnMut(&T) -> codemap::Span,
+        G: FnMut(&T) -> syntax_pos::Span,
     {
-        try!(self.rbox(0, b));
+        self.rbox(0, b)?;
         let len = elts.len();
         let mut i = 0;
         for elt in elts {
-            try!(self.maybe_print_comment(get_span(elt).hi));
-            try!(op(self, elt));
+            self.maybe_print_comment(get_span(elt).hi)?;
+            op(self, elt)?;
             i += 1;
             if i < len {
-                try!(word(&mut self.s, ","));
-                try!(self.maybe_print_trailing_comment(get_span(elt),
-                                                    Some(get_span(&elts[i]).hi)));
-                try!(self.space_if_not_bol());
+                self.s.word(",")?;
+                self.maybe_print_trailing_comment(get_span(elt),
+                                                  Some(get_span(&elts[i]).hi))?;
+                self.space_if_not_bol()?;
             }
         }
         self.end()
@@ -652,23 +965,23 @@ impl<'a> State<'a> {
 
     pub fn commasep_exprs(&mut self, b: Breaks,
                           exprs: &[P<ast::Expr>]) -> io::Result<()> {
-        self.commasep_cmnt(b, exprs, |s, e| s.print_expr(&**e), |e| e.span)
+        self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span)
     }
 
     pub fn print_mod(&mut self, _mod: &ast::Mod,
                      attrs: &[ast::Attribute]) -> io::Result<()> {
-        try!(self.print_inner_attributes(attrs));
+        self.print_inner_attributes(attrs)?;
         for item in &_mod.items {
-            try!(self.print_item(&**item));
+            self.print_item(item)?;
         }
         Ok(())
     }
 
     pub fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod,
                              attrs: &[ast::Attribute]) -> io::Result<()> {
-        try!(self.print_inner_attributes(attrs));
+        self.print_inner_attributes(attrs)?;
         for item in &nmod.items {
-            try!(self.print_foreign_item(&**item));
+            self.print_foreign_item(item)?;
         }
         Ok(())
     }
@@ -676,91 +989,102 @@ impl<'a> State<'a> {
     pub fn print_opt_lifetime(&mut self,
                               lifetime: &Option<ast::Lifetime>) -> io::Result<()> {
         if let Some(l) = *lifetime {
-            try!(self.print_lifetime(&l));
-            try!(self.nbsp());
+            self.print_lifetime(&l)?;
+            self.nbsp()?;
         }
         Ok(())
     }
 
     pub fn print_type(&mut self, ty: &ast::Ty) -> io::Result<()> {
-        try!(self.maybe_print_comment(ty.span.lo));
-        try!(self.ibox(0));
+        self.maybe_print_comment(ty.span.lo)?;
+        self.ibox(0)?;
         match ty.node {
-            ast::TyVec(ref ty) => {
-                try!(word(&mut self.s, "["));
-                try!(self.print_type(&**ty));
-                try!(word(&mut self.s, "]"));
+            ast::TyKind::Slice(ref ty) => {
+                self.s.word("[")?;
+                self.print_type(ty)?;
+                self.s.word("]")?;
             }
-            ast::TyPtr(ref mt) => {
-                try!(word(&mut self.s, "*"));
+            ast::TyKind::Ptr(ref mt) => {
+                self.s.word("*")?;
                 match mt.mutbl {
-                    ast::MutMutable => try!(self.word_nbsp("mut")),
-                    ast::MutImmutable => try!(self.word_nbsp("const")),
+                    ast::Mutability::Mutable => self.word_nbsp("mut")?,
+                    ast::Mutability::Immutable => self.word_nbsp("const")?,
                 }
-                try!(self.print_type(&*mt.ty));
+                self.print_type(&mt.ty)?;
             }
-            ast::TyRptr(ref lifetime, ref mt) => {
-                try!(word(&mut self.s, "&"));
-                try!(self.print_opt_lifetime(lifetime));
-                try!(self.print_mt(mt));
+            ast::TyKind::Rptr(ref lifetime, ref mt) => {
+                self.s.word("&")?;
+                self.print_opt_lifetime(lifetime)?;
+                self.print_mt(mt)?;
             }
-            ast::TyTup(ref elts) => {
-                try!(self.popen());
-                try!(self.commasep(Inconsistent, &elts[..],
-                                   |s, ty| s.print_type(&**ty)));
+            ast::TyKind::Never => {
+                self.s.word("!")?;
+            },
+            ast::TyKind::Tup(ref elts) => {
+                self.popen()?;
+                self.commasep(Inconsistent, &elts[..],
+                              |s, ty| s.print_type(ty))?;
                 if elts.len() == 1 {
-                    try!(word(&mut self.s, ","));
+                    self.s.word(",")?;
                 }
-                try!(self.pclose());
+                self.pclose()?;
             }
-            ast::TyParen(ref typ) => {
-                try!(self.popen());
-                try!(self.print_type(&**typ));
-                try!(self.pclose());
+            ast::TyKind::Paren(ref typ) => {
+                self.popen()?;
+                self.print_type(typ)?;
+                self.pclose()?;
             }
-            ast::TyBareFn(ref f) => {
+            ast::TyKind::BareFn(ref f) => {
                 let generics = ast::Generics {
                     lifetimes: f.lifetimes.clone(),
-                    ty_params: OwnedSlice::empty(),
+                    ty_params: Vec::new(),
                     where_clause: ast::WhereClause {
                         id: ast::DUMMY_NODE_ID,
                         predicates: Vec::new(),
                     },
+                    span: syntax_pos::DUMMY_SP,
                 };
-                try!(self.print_ty_fn(f.abi,
-                                      f.unsafety,
-                                      &*f.decl,
-                                      None,
-                                      &generics,
-                                      None));
+                self.print_ty_fn(f.abi,
+                                 f.unsafety,
+                                 &f.decl,
+                                 None,
+                                 &generics)?;
+            }
+            ast::TyKind::Path(None, ref path) => {
+                self.print_path(path, false, 0, false)?;
             }
-            ast::TyPath(None, ref path) => {
-                try!(self.print_path(path, false, 0));
+            ast::TyKind::Path(Some(ref qself), ref path) => {
+                self.print_qpath(path, qself, false)?
             }
-            ast::TyPath(Some(ref qself), ref path) => {
-                try!(self.print_qpath(path, qself, false))
+            ast::TyKind::TraitObject(ref bounds) => {
+                self.print_bounds("", &bounds[..])?;
             }
-            ast::TyObjectSum(ref ty, ref bounds) => {
-                try!(self.print_type(&**ty));
-                try!(self.print_bounds("+", &bounds[..]));
+            ast::TyKind::ImplTrait(ref bounds) => {
+                self.print_bounds("impl ", &bounds[..])?;
             }
-            ast::TyPolyTraitRef(ref bounds) => {
-                try!(self.print_bounds("", &bounds[..]));
+            ast::TyKind::Array(ref ty, ref v) => {
+                self.s.word("[")?;
+                self.print_type(ty)?;
+                self.s.word("; ")?;
+                self.print_expr(v)?;
+                self.s.word("]")?;
             }
-            ast::TyFixedLengthVec(ref ty, ref v) => {
-                try!(word(&mut self.s, "["));
-                try!(self.print_type(&**ty));
-                try!(word(&mut self.s, "; "));
-                try!(self.print_expr(&**v));
-                try!(word(&mut self.s, "]"));
+            ast::TyKind::Typeof(ref e) => {
+                self.s.word("typeof(")?;
+                self.print_expr(e)?;
+                self.s.word(")")?;
             }
-            ast::TyTypeof(ref e) => {
-                try!(word(&mut self.s, "typeof("));
-                try!(self.print_expr(&**e));
-                try!(word(&mut self.s, ")"));
+            ast::TyKind::Infer => {
+                self.s.word("_")?;
             }
-            ast::TyInfer => {
-                try!(word(&mut self.s, "_"));
+            ast::TyKind::Err => {
+                self.s.word("?")?;
+            }
+            ast::TyKind::ImplicitSelf => {
+                self.s.word("Self")?;
+            }
+            ast::TyKind::Mac(ref m) => {
+                self.print_mac(m, token::Paren)?;
             }
         }
         self.end()
@@ -768,482 +1092,438 @@ impl<'a> State<'a> {
 
     pub fn print_foreign_item(&mut self,
                               item: &ast::ForeignItem) -> io::Result<()> {
-        try!(self.hardbreak_if_not_bol());
-        try!(self.maybe_print_comment(item.span.lo));
-        try!(self.print_outer_attributes(&item.attrs));
+        self.hardbreak_if_not_bol()?;
+        self.maybe_print_comment(item.span.lo)?;
+        self.print_outer_attributes(&item.attrs)?;
         match item.node {
-            ast::ForeignItemFn(ref decl, ref generics) => {
-                try!(self.head(""));
-                try!(self.print_fn(&**decl, ast::Unsafety::Normal,
-                                   abi::Rust, Some(item.ident),
-                                   generics, None, item.vis));
-                try!(self.end()); // end head-ibox
-                try!(word(&mut self.s, ";"));
+            ast::ForeignItemKind::Fn(ref decl, ref generics) => {
+                self.head("")?;
+                self.print_fn(decl, ast::Unsafety::Normal,
+                              ast::Constness::NotConst,
+                              Abi::Rust, Some(item.ident),
+                              generics, &item.vis)?;
+                self.end()?; // end head-ibox
+                self.s.word(";")?;
                 self.end() // end the outer fn box
             }
-            ast::ForeignItemStatic(ref t, m) => {
-                try!(self.head(&visibility_qualified(item.vis,
-                                                    "static")));
+            ast::ForeignItemKind::Static(ref t, m) => {
+                self.head(&visibility_qualified(&item.vis, "static"))?;
                 if m {
-                    try!(self.word_space("mut"));
+                    self.word_space("mut")?;
                 }
-                try!(self.print_ident(item.ident));
-                try!(self.word_space(":"));
-                try!(self.print_type(&**t));
-                try!(word(&mut self.s, ";"));
-                try!(self.end()); // end the head-ibox
+                self.print_ident(item.ident)?;
+                self.word_space(":")?;
+                self.print_type(t)?;
+                self.s.word(";")?;
+                self.end()?; // end the head-ibox
                 self.end() // end the outer cbox
             }
         }
     }
 
+    fn print_associated_const(&mut self,
+                              ident: ast::Ident,
+                              ty: &ast::Ty,
+                              default: Option<&ast::Expr>,
+                              vis: &ast::Visibility)
+                              -> io::Result<()>
+    {
+        self.s.word(&visibility_qualified(vis, ""))?;
+        self.word_space("const")?;
+        self.print_ident(ident)?;
+        self.word_space(":")?;
+        self.print_type(ty)?;
+        if let Some(expr) = default {
+            self.s.space()?;
+            self.word_space("=")?;
+            self.print_expr(expr)?;
+        }
+        self.s.word(";")
+    }
+
     fn print_associated_type(&mut self,
                              ident: ast::Ident,
                              bounds: Option<&ast::TyParamBounds>,
                              ty: Option<&ast::Ty>)
                              -> io::Result<()> {
-        try!(self.word_space("type"));
-        try!(self.print_ident(ident));
+        self.word_space("type")?;
+        self.print_ident(ident)?;
         if let Some(bounds) = bounds {
-            try!(self.print_bounds(":", bounds));
+            self.print_bounds(":", bounds)?;
         }
         if let Some(ty) = ty {
-            try!(space(&mut self.s));
-            try!(self.word_space("="));
-            try!(self.print_type(ty));
+            self.s.space()?;
+            self.word_space("=")?;
+            self.print_type(ty)?;
         }
-        word(&mut self.s, ";")
+        self.s.word(";")
     }
 
-
     /// Pretty-print an item
     pub fn print_item(&mut self, item: &ast::Item) -> io::Result<()> {
-        try!(self.hardbreak_if_not_bol());
-        try!(self.maybe_print_comment(item.span.lo));
-        try!(self.print_outer_attributes(&item.attrs));
-        try!(self.ann.pre(self, NodeItem(item)));
+        self.hardbreak_if_not_bol()?;
+        self.maybe_print_comment(item.span.lo)?;
+        self.print_outer_attributes(&item.attrs)?;
+        self.ann.pre(self, NodeItem(item))?;
         match item.node {
-            ast::ItemExternCrate(ref optional_path) => {
-                try!(self.head(&visibility_qualified(item.vis,
-                                                     "extern crate")));
+            ast::ItemKind::ExternCrate(ref optional_path) => {
+                self.head(&visibility_qualified(&item.vis, "extern crate"))?;
                 if let Some(p) = *optional_path {
-                    let val = token::get_name(p);
-                    if val.contains("-") {
-                        try!(self.print_string(&val, ast::CookedStr));
+                    let val = p.as_str();
+                    if val.contains('-') {
+                        self.print_string(&val, ast::StrStyle::Cooked)?;
                     } else {
-                        try!(self.print_name(p));
+                        self.print_name(p)?;
                     }
-                    try!(space(&mut self.s));
-                    try!(word(&mut self.s, "as"));
-                    try!(space(&mut self.s));
-                }
-                try!(self.print_ident(item.ident));
-                try!(word(&mut self.s, ";"));
-                try!(self.end()); // end inner head-block
-                try!(self.end()); // end outer head-block
-            }
-            ast::ItemUse(ref vp) => {
-                try!(self.head(&visibility_qualified(item.vis,
-                                                     "use")));
-                try!(self.print_view_path(&**vp));
-                try!(word(&mut self.s, ";"));
-                try!(self.end()); // end inner head-block
-                try!(self.end()); // end outer head-block
-            }
-            ast::ItemStatic(ref ty, m, ref expr) => {
-                try!(self.head(&visibility_qualified(item.vis,
-                                                    "static")));
-                if m == ast::MutMutable {
-                    try!(self.word_space("mut"));
-                }
-                try!(self.print_ident(item.ident));
-                try!(self.word_space(":"));
-                try!(self.print_type(&**ty));
-                try!(space(&mut self.s));
-                try!(self.end()); // end the head-ibox
-
-                try!(self.word_space("="));
-                try!(self.print_expr(&**expr));
-                try!(word(&mut self.s, ";"));
-                try!(self.end()); // end the outer cbox
-            }
-            ast::ItemConst(ref ty, ref expr) => {
-                try!(self.head(&visibility_qualified(item.vis,
-                                                    "const")));
-                try!(self.print_ident(item.ident));
-                try!(self.word_space(":"));
-                try!(self.print_type(&**ty));
-                try!(space(&mut self.s));
-                try!(self.end()); // end the head-ibox
-
-                try!(self.word_space("="));
-                try!(self.print_expr(&**expr));
-                try!(word(&mut self.s, ";"));
-                try!(self.end()); // end the outer cbox
-            }
-            ast::ItemFn(ref decl, unsafety, abi, ref typarams, ref body) => {
-                try!(self.head(""));
-                try!(self.print_fn(
+                    self.s.space()?;
+                    self.s.word("as")?;
+                    self.s.space()?;
+                }
+                self.print_ident(item.ident)?;
+                self.s.word(";")?;
+                self.end()?; // end inner head-block
+                self.end()?; // end outer head-block
+            }
+            ast::ItemKind::Use(ref vp) => {
+                self.head(&visibility_qualified(&item.vis, "use"))?;
+                self.print_view_path(vp)?;
+                self.s.word(";")?;
+                self.end()?; // end inner head-block
+                self.end()?; // end outer head-block
+            }
+            ast::ItemKind::Static(ref ty, m, ref expr) => {
+                self.head(&visibility_qualified(&item.vis, "static"))?;
+                if m == ast::Mutability::Mutable {
+                    self.word_space("mut")?;
+                }
+                self.print_ident(item.ident)?;
+                self.word_space(":")?;
+                self.print_type(ty)?;
+                self.s.space()?;
+                self.end()?; // end the head-ibox
+
+                self.word_space("=")?;
+                self.print_expr(expr)?;
+                self.s.word(";")?;
+                self.end()?; // end the outer cbox
+            }
+            ast::ItemKind::Const(ref ty, ref expr) => {
+                self.head(&visibility_qualified(&item.vis, "const"))?;
+                self.print_ident(item.ident)?;
+                self.word_space(":")?;
+                self.print_type(ty)?;
+                self.s.space()?;
+                self.end()?; // end the head-ibox
+
+                self.word_space("=")?;
+                self.print_expr(expr)?;
+                self.s.word(";")?;
+                self.end()?; // end the outer cbox
+            }
+            ast::ItemKind::Fn(ref decl, unsafety, constness, abi, ref typarams, ref body) => {
+                self.head("")?;
+                self.print_fn(
                     decl,
                     unsafety,
+                    constness.node,
                     abi,
                     Some(item.ident),
                     typarams,
-                    None,
-                    item.vis
-                ));
-                try!(word(&mut self.s, " "));
-                try!(self.print_block_with_attrs(&**body, &item.attrs));
-            }
-            ast::ItemMod(ref _mod) => {
-                try!(self.head(&visibility_qualified(item.vis,
-                                                    "mod")));
-                try!(self.print_ident(item.ident));
-                try!(self.nbsp());
-                try!(self.bopen());
-                try!(self.print_mod(_mod, &item.attrs));
-                try!(self.bclose(item.span));
-            }
-            ast::ItemForeignMod(ref nmod) => {
-                try!(self.head("extern"));
-                try!(self.word_nbsp(&nmod.abi.to_string()));
-                try!(self.bopen());
-                try!(self.print_foreign_mod(nmod, &item.attrs));
-                try!(self.bclose(item.span));
-            }
-            ast::ItemTy(ref ty, ref params) => {
-                try!(self.ibox(indent_unit));
-                try!(self.ibox(0));
-                try!(self.word_nbsp(&visibility_qualified(item.vis, "type")));
-                try!(self.print_ident(item.ident));
-                try!(self.print_generics(params));
-                try!(self.end()); // end the inner ibox
-
-                try!(space(&mut self.s));
-                try!(self.word_space("="));
-                try!(self.print_type(&**ty));
-                try!(self.print_where_clause(&params.where_clause));
-                try!(word(&mut self.s, ";"));
-                try!(self.end()); // end the outer ibox
-            }
-            ast::ItemEnum(ref enum_definition, ref params) => {
-                try!(self.print_enum_def(
+                    &item.vis
+                )?;
+                self.s.word(" ")?;
+                self.print_block_with_attrs(body, &item.attrs)?;
+            }
+            ast::ItemKind::Mod(ref _mod) => {
+                self.head(&visibility_qualified(&item.vis, "mod"))?;
+                self.print_ident(item.ident)?;
+                self.nbsp()?;
+                self.bopen()?;
+                self.print_mod(_mod, &item.attrs)?;
+                self.bclose(item.span)?;
+            }
+            ast::ItemKind::ForeignMod(ref nmod) => {
+                self.head("extern")?;
+                self.word_nbsp(&nmod.abi.to_string())?;
+                self.bopen()?;
+                self.print_foreign_mod(nmod, &item.attrs)?;
+                self.bclose(item.span)?;
+            }
+            ast::ItemKind::GlobalAsm(ref ga) => {
+                self.head(&visibility_qualified(&item.vis, "global_asm!"))?;
+                self.s.word(&ga.asm.as_str())?;
+                self.end()?;
+            }
+            ast::ItemKind::Ty(ref ty, ref params) => {
+                self.ibox(INDENT_UNIT)?;
+                self.ibox(0)?;
+                self.word_nbsp(&visibility_qualified(&item.vis, "type"))?;
+                self.print_ident(item.ident)?;
+                self.print_generics(params)?;
+                self.end()?; // end the inner ibox
+
+                self.print_where_clause(&params.where_clause)?;
+                self.s.space()?;
+                self.word_space("=")?;
+                self.print_type(ty)?;
+                self.s.word(";")?;
+                self.end()?; // end the outer ibox
+            }
+            ast::ItemKind::Enum(ref enum_definition, ref params) => {
+                self.print_enum_def(
                     enum_definition,
                     params,
                     item.ident,
                     item.span,
-                    item.vis
-                ));
-            }
-            ast::ItemStruct(ref struct_def, ref generics) => {
-                try!(self.head(&visibility_qualified(item.vis,"struct")));
-                try!(self.print_struct(&**struct_def, generics, item.ident, item.span));
-            }
-
-            ast::ItemDefaultImpl(unsafety, ref trait_ref) => {
-                try!(self.head(""));
-                try!(self.print_visibility(item.vis));
-                try!(self.print_unsafety(unsafety));
-                try!(self.word_nbsp("impl"));
-                try!(self.print_trait_ref(trait_ref));
-                try!(space(&mut self.s));
-                try!(self.word_space("for"));
-                try!(self.word_space(".."));
-                try!(self.bopen());
-                try!(self.bclose(item.span));
-            }
-            ast::ItemImpl(unsafety,
+                    &item.vis
+                )?;
+            }
+            ast::ItemKind::Struct(ref struct_def, ref generics) => {
+                self.head(&visibility_qualified(&item.vis, "struct"))?;
+                self.print_struct(struct_def, generics, item.ident, item.span, true)?;
+            }
+            ast::ItemKind::Union(ref struct_def, ref generics) => {
+                self.head(&visibility_qualified(&item.vis, "union"))?;
+                self.print_struct(struct_def, generics, item.ident, item.span, true)?;
+            }
+            ast::ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
+                self.head("")?;
+                self.print_visibility(&item.vis)?;
+                self.print_unsafety(unsafety)?;
+                self.word_nbsp("impl")?;
+                self.print_trait_ref(trait_ref)?;
+                self.s.space()?;
+                self.word_space("for")?;
+                self.word_space("..")?;
+                self.bopen()?;
+                self.bclose(item.span)?;
+            }
+            ast::ItemKind::Impl(unsafety,
                           polarity,
+                          defaultness,
                           ref generics,
                           ref opt_trait,
                           ref ty,
                           ref impl_items) => {
-                try!(self.head(""));
-                try!(self.print_visibility(item.vis));
-                try!(self.print_unsafety(unsafety));
-                try!(self.word_nbsp("impl"));
+                self.head("")?;
+                self.print_visibility(&item.vis)?;
+                self.print_defaultness(defaultness)?;
+                self.print_unsafety(unsafety)?;
+                self.word_nbsp("impl")?;
 
                 if generics.is_parameterized() {
-                    try!(self.print_generics(generics));
-                    try!(space(&mut self.s));
+                    self.print_generics(generics)?;
+                    self.s.space()?;
                 }
 
-                match polarity {
-                    ast::ImplPolarity::Negative => {
-                        try!(word(&mut self.s, "!"));
-                    },
-                    _ => {}
+                if polarity == ast::ImplPolarity::Negative {
+                    self.s.word("!")?;
                 }
 
-                match opt_trait {
-                    &Some(ref t) => {
-                        try!(self.print_trait_ref(t));
-                        try!(space(&mut self.s));
-                        try!(self.word_space("for"));
-                    }
-                    &None => {}
+                if let Some(ref t) = *opt_trait {
+                    self.print_trait_ref(t)?;
+                    self.s.space()?;
+                    self.word_space("for")?;
                 }
 
-                try!(self.print_type(&**ty));
-                try!(self.print_where_clause(&generics.where_clause));
+                self.print_type(ty)?;
+                self.print_where_clause(&generics.where_clause)?;
 
-                try!(space(&mut self.s));
-                try!(self.bopen());
-                try!(self.print_inner_attributes(&item.attrs));
+                self.s.space()?;
+                self.bopen()?;
+                self.print_inner_attributes(&item.attrs)?;
                 for impl_item in impl_items {
-                    try!(self.print_impl_item(impl_item));
+                    self.print_impl_item(impl_item)?;
                 }
-                try!(self.bclose(item.span));
+                self.bclose(item.span)?;
             }
-            ast::ItemTrait(unsafety, ref generics, ref bounds, ref trait_items) => {
-                try!(self.head(""));
-                try!(self.print_visibility(item.vis));
-                try!(self.print_unsafety(unsafety));
-                try!(self.word_nbsp("trait"));
-                try!(self.print_ident(item.ident));
-                try!(self.print_generics(generics));
+            ast::ItemKind::Trait(unsafety, ref generics, ref bounds, ref trait_items) => {
+                self.head("")?;
+                self.print_visibility(&item.vis)?;
+                self.print_unsafety(unsafety)?;
+                self.word_nbsp("trait")?;
+                self.print_ident(item.ident)?;
+                self.print_generics(generics)?;
                 let mut real_bounds = Vec::with_capacity(bounds.len());
                 for b in bounds.iter() {
                     if let TraitTyParamBound(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
-                        try!(space(&mut self.s));
-                        try!(self.word_space("for ?"));
-                        try!(self.print_trait_ref(&ptr.trait_ref));
+                        self.s.space()?;
+                        self.word_space("for ?")?;
+                        self.print_trait_ref(&ptr.trait_ref)?;
                     } else {
                         real_bounds.push(b.clone());
                     }
                 }
-                try!(self.print_bounds(":", &real_bounds[..]));
-                try!(self.print_where_clause(&generics.where_clause));
-                try!(word(&mut self.s, " "));
-                try!(self.bopen());
+                self.print_bounds(":", &real_bounds[..])?;
+                self.print_where_clause(&generics.where_clause)?;
+                self.s.word(" ")?;
+                self.bopen()?;
                 for trait_item in trait_items {
-                    try!(self.print_trait_item(trait_item));
-                }
-                try!(self.bclose(item.span));
-            }
-            // I think it's reasonable to hide the context here:
-            ast::ItemMac(codemap::Spanned { node: ast::MacInvocTT(ref pth, ref tts, _),
-                                            ..}) => {
-                try!(self.print_visibility(item.vis));
-                try!(self.print_path(pth, false, 0));
-                try!(word(&mut self.s, "! "));
-                try!(self.print_ident(item.ident));
-                try!(self.cbox(indent_unit));
-                try!(self.popen());
-                try!(self.print_tts(&tts[..]));
-                try!(self.pclose());
-                try!(word(&mut self.s, ";"));
-                try!(self.end());
+                    self.print_trait_item(trait_item)?;
+                }
+                self.bclose(item.span)?;
+            }
+            ast::ItemKind::Mac(codemap::Spanned { ref node, .. }) => {
+                self.print_path(&node.path, false, 0, false)?;
+                self.s.word("! ")?;
+                self.print_ident(item.ident)?;
+                self.cbox(INDENT_UNIT)?;
+                self.popen()?;
+                self.print_tts(node.stream())?;
+                self.pclose()?;
+                self.s.word(";")?;
+                self.end()?;
+            }
+            ast::ItemKind::MacroDef(ref tts) => {
+                self.s.word("macro_rules! ")?;
+                self.print_ident(item.ident)?;
+                self.cbox(INDENT_UNIT)?;
+                self.popen()?;
+                self.print_tts(tts.stream())?;
+                self.pclose()?;
+                self.s.word(";")?;
+                self.end()?;
             }
         }
         self.ann.post(self, NodeItem(item))
     }
 
     fn print_trait_ref(&mut self, t: &ast::TraitRef) -> io::Result<()> {
-        self.print_path(&t.path, false, 0)
+        self.print_path(&t.path, false, 0, false)
     }
 
     fn print_formal_lifetime_list(&mut self, lifetimes: &[ast::LifetimeDef]) -> io::Result<()> {
         if !lifetimes.is_empty() {
-            try!(word(&mut self.s, "for<"));
+            self.s.word("for<")?;
             let mut comma = false;
             for lifetime_def in lifetimes {
                 if comma {
-                    try!(self.word_space(","))
+                    self.word_space(",")?
                 }
-                try!(self.print_lifetime_def(lifetime_def));
+                self.print_outer_attributes_inline(&lifetime_def.attrs)?;
+                self.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds)?;
                 comma = true;
             }
-            try!(word(&mut self.s, ">"));
+            self.s.word(">")?;
         }
         Ok(())
     }
 
     fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) -> io::Result<()> {
-        try!(self.print_formal_lifetime_list(&t.bound_lifetimes));
+        self.print_formal_lifetime_list(&t.bound_lifetimes)?;
         self.print_trait_ref(&t.trait_ref)
     }
 
     pub fn print_enum_def(&mut self, enum_definition: &ast::EnumDef,
                           generics: &ast::Generics, ident: ast::Ident,
-                          span: codemap::Span,
-                          visibility: ast::Visibility) -> io::Result<()> {
-        try!(self.head(&visibility_qualified(visibility, "enum")));
-        try!(self.print_ident(ident));
-        try!(self.print_generics(generics));
-        try!(self.print_where_clause(&generics.where_clause));
-        try!(space(&mut self.s));
+                          span: syntax_pos::Span,
+                          visibility: &ast::Visibility) -> io::Result<()> {
+        self.head(&visibility_qualified(visibility, "enum"))?;
+        self.print_ident(ident)?;
+        self.print_generics(generics)?;
+        self.print_where_clause(&generics.where_clause)?;
+        self.s.space()?;
         self.print_variants(&enum_definition.variants, span)
     }
 
     pub fn print_variants(&mut self,
-                          variants: &[P<ast::Variant>],
-                          span: codemap::Span) -> io::Result<()> {
-        try!(self.bopen());
+                          variants: &[ast::Variant],
+                          span: syntax_pos::Span) -> io::Result<()> {
+        self.bopen()?;
         for v in variants {
-            try!(self.space_if_not_bol());
-            try!(self.maybe_print_comment(v.span.lo));
-            try!(self.print_outer_attributes(&v.node.attrs));
-            try!(self.ibox(indent_unit));
-            try!(self.print_variant(&**v));
-            try!(word(&mut self.s, ","));
-            try!(self.end());
-            try!(self.maybe_print_trailing_comment(v.span, None));
+            self.space_if_not_bol()?;
+            self.maybe_print_comment(v.span.lo)?;
+            self.print_outer_attributes(&v.node.attrs)?;
+            self.ibox(INDENT_UNIT)?;
+            self.print_variant(v)?;
+            self.s.word(",")?;
+            self.end()?;
+            self.maybe_print_trailing_comment(v.span, None)?;
         }
         self.bclose(span)
     }
 
-    pub fn print_visibility(&mut self, vis: ast::Visibility) -> io::Result<()> {
-        match vis {
-            ast::Public => self.word_nbsp("pub"),
-            ast::Inherited => Ok(())
+    pub fn print_visibility(&mut self, vis: &ast::Visibility) -> io::Result<()> {
+        match *vis {
+            ast::Visibility::Public => self.word_nbsp("pub"),
+            ast::Visibility::Crate(_) => self.word_nbsp("pub(crate)"),
+            ast::Visibility::Restricted { ref path, .. } => {
+                let path = to_string(|s| s.print_path(path, false, 0, true));
+                if path == "self" || path == "super" {
+                    self.word_nbsp(&format!("pub({})", path))
+                } else {
+                    self.word_nbsp(&format!("pub(in {})", path))
+                }
+            }
+            ast::Visibility::Inherited => Ok(())
         }
     }
 
+    pub fn print_defaultness(&mut self, defatulness: ast::Defaultness) -> io::Result<()> {
+        if let ast::Defaultness::Default = defatulness {
+            try!(self.word_nbsp("default"));
+        }
+        Ok(())
+    }
+
     pub fn print_struct(&mut self,
-                        struct_def: &ast::StructDef,
+                        struct_def: &ast::VariantData,
                         generics: &ast::Generics,
                         ident: ast::Ident,
-                        span: codemap::Span) -> io::Result<()> {
-        try!(self.print_ident(ident));
-        try!(self.print_generics(generics));
-        if ast_util::struct_def_is_tuple_like(struct_def) {
-            if !struct_def.fields.is_empty() {
-                try!(self.popen());
-                try!(self.commasep(
-                    Inconsistent, &struct_def.fields,
+                        span: syntax_pos::Span,
+                        print_finalizer: bool) -> io::Result<()> {
+        self.print_ident(ident)?;
+        self.print_generics(generics)?;
+        if !struct_def.is_struct() {
+            if struct_def.is_tuple() {
+                self.popen()?;
+                self.commasep(
+                    Inconsistent, struct_def.fields(),
                     |s, field| {
-                        match field.node.kind {
-                            ast::NamedField(..) => panic!("unexpected named field"),
-                            ast::UnnamedField(vis) => {
-                                try!(s.print_visibility(vis));
-                                try!(s.maybe_print_comment(field.span.lo));
-                                s.print_type(&*field.node.ty)
-                            }
-                        }
+                        s.maybe_print_comment(field.span.lo)?;
+                        s.print_outer_attributes(&field.attrs)?;
+                        s.print_visibility(&field.vis)?;
+                        s.print_type(&field.ty)
                     }
-                ));
-                try!(self.pclose());
+                )?;
+                self.pclose()?;
             }
-            try!(self.print_where_clause(&generics.where_clause));
-            try!(word(&mut self.s, ";"));
-            try!(self.end());
+            self.print_where_clause(&generics.where_clause)?;
+            if print_finalizer {
+                self.s.word(";")?;
+            }
+            self.end()?;
             self.end() // close the outer-box
         } else {
-            try!(self.print_where_clause(&generics.where_clause));
-            try!(self.nbsp());
-            try!(self.bopen());
-            try!(self.hardbreak_if_not_bol());
-
-            for field in &struct_def.fields {
-                match field.node.kind {
-                    ast::UnnamedField(..) => panic!("unexpected unnamed field"),
-                    ast::NamedField(ident, visibility) => {
-                        try!(self.hardbreak_if_not_bol());
-                        try!(self.maybe_print_comment(field.span.lo));
-                        try!(self.print_outer_attributes(&field.node.attrs));
-                        try!(self.print_visibility(visibility));
-                        try!(self.print_ident(ident));
-                        try!(self.word_nbsp(":"));
-                        try!(self.print_type(&*field.node.ty));
-                        try!(word(&mut self.s, ","));
-                    }
-                }
+            self.print_where_clause(&generics.where_clause)?;
+            self.nbsp()?;
+            self.bopen()?;
+            self.hardbreak_if_not_bol()?;
+
+            for field in struct_def.fields() {
+                self.hardbreak_if_not_bol()?;
+                self.maybe_print_comment(field.span.lo)?;
+                self.print_outer_attributes(&field.attrs)?;
+                self.print_visibility(&field.vis)?;
+                self.print_ident(field.ident.unwrap())?;
+                self.word_nbsp(":")?;
+                self.print_type(&field.ty)?;
+                self.s.word(",")?;
             }
 
             self.bclose(span)
         }
     }
 
-    /// This doesn't deserve to be called "pretty" printing, but it should be
-    /// meaning-preserving. A quick hack that might help would be to look at the
-    /// spans embedded in the TTs to decide where to put spaces and newlines.
-    /// But it'd be better to parse these according to the grammar of the
-    /// appropriate macro, transcribe back into the grammar we just parsed from,
-    /// and then pretty-print the resulting AST nodes (so, e.g., we print
-    /// expression arguments as expressions). It can be done! I think.
-    pub fn print_tt(&mut self, tt: &ast::TokenTree) -> io::Result<()> {
-        match *tt {
-            ast::TtToken(_, ref tk) => {
-                try!(word(&mut self.s, &token_to_string(tk)));
-                match *tk {
-                    parse::token::DocComment(..) => {
-                        hardbreak(&mut self.s)
-                    }
-                    _ => Ok(())
-                }
-            }
-            ast::TtDelimited(_, ref delimed) => {
-                try!(word(&mut self.s, &token_to_string(&delimed.open_token())));
-                try!(space(&mut self.s));
-                try!(self.print_tts(&delimed.tts));
-                try!(space(&mut self.s));
-                word(&mut self.s, &token_to_string(&delimed.close_token()))
-            },
-            ast::TtSequence(_, ref seq) => {
-                try!(word(&mut self.s, "$("));
-                for tt_elt in &seq.tts {
-                    try!(self.print_tt(tt_elt));
-                }
-                try!(word(&mut self.s, ")"));
-                match seq.separator {
-                    Some(ref tk) => {
-                        try!(word(&mut self.s, &token_to_string(tk)));
-                    }
-                    None => {},
-                }
-                match seq.op {
-                    ast::ZeroOrMore => word(&mut self.s, "*"),
-                    ast::OneOrMore => word(&mut self.s, "+"),
-                }
-            }
-        }
-    }
-
-    pub fn print_tts(&mut self, tts: &[ast::TokenTree]) -> io::Result<()> {
-        try!(self.ibox(0));
-        let mut suppress_space = false;
-        for (i, tt) in tts.iter().enumerate() {
-            if i != 0 && !suppress_space {
-                try!(space(&mut self.s));
-            }
-            try!(self.print_tt(tt));
-            // There should be no space between the module name and the following `::` in paths,
-            // otherwise imported macros get re-parsed from crate metadata incorrectly (#20701)
-            suppress_space = match tt {
-                &ast::TtToken(_, token::Ident(_, token::ModName)) |
-                &ast::TtToken(_, token::MatchNt(_, _, _, token::ModName)) |
-                &ast::TtToken(_, token::SubstNt(_, token::ModName)) => true,
-                _ => false
-            }
-        }
-        self.end()
-    }
-
     pub fn print_variant(&mut self, v: &ast::Variant) -> io::Result<()> {
-        try!(self.print_visibility(v.node.vis));
-        match v.node.kind {
-            ast::TupleVariantKind(ref args) => {
-                try!(self.print_ident(v.node.name));
-                if !args.is_empty() {
-                    try!(self.popen());
-                    try!(self.commasep(Consistent,
-                                       &args[..],
-                                       |s, arg| s.print_type(&*arg.ty)));
-                    try!(self.pclose());
-                }
-            }
-            ast::StructVariantKind(ref struct_def) => {
-                try!(self.head(""));
-                let generics = ast_util::empty_generics();
-                try!(self.print_struct(&**struct_def, &generics, v.node.name, v.span));
-            }
-        }
+        self.head("")?;
+        let generics = ast::Generics::default();
+        self.print_struct(&v.node.data, &generics, v.node.name, v.span, false)?;
         match v.node.disr_expr {
             Some(ref d) => {
-                try!(space(&mut self.s));
-                try!(self.word_space("="));
-                self.print_expr(&**d)
+                self.s.space()?;
+                self.word_space("=")?;
+                self.print_expr(d)
             }
             _ => Ok(())
         }
@@ -1252,158 +1532,141 @@ impl<'a> State<'a> {
     pub fn print_method_sig(&mut self,
                             ident: ast::Ident,
                             m: &ast::MethodSig,
-                            vis: ast::Visibility)
+                            vis: &ast::Visibility)
                             -> io::Result<()> {
         self.print_fn(&m.decl,
                       m.unsafety,
+                      m.constness.node,
                       m.abi,
-                      Some(ident),
-                      &m.generics,
-                      Some(&m.explicit_self.node),
-                      vis)
-    }
-
-    pub fn print_trait_item(&mut self, ti: &ast::TraitItem)
-                            -> io::Result<()> {
-        try!(self.ann.pre(self, NodeSubItem(ti.id)));
-        try!(self.hardbreak_if_not_bol());
-        try!(self.maybe_print_comment(ti.span.lo));
-        try!(self.print_outer_attributes(&ti.attrs));
-        match ti.node {
-            ast::MethodTraitItem(ref sig, ref body) => {
-                if body.is_some() {
-                    try!(self.head(""));
-                }
-                try!(self.print_method_sig(ti.ident, sig, ast::Inherited));
-                if let Some(ref body) = *body {
-                    try!(self.nbsp());
-                    try!(self.print_block_with_attrs(body, &ti.attrs));
-                } else {
-                    try!(word(&mut self.s, ";"));
-                }
-            }
-            ast::TypeTraitItem(ref bounds, ref default) => {
-                try!(self.print_associated_type(ti.ident, Some(bounds),
-                                                default.as_ref().map(|ty| &**ty)));
-            }
-        }
-        self.ann.post(self, NodeSubItem(ti.id))
-    }
-
-    pub fn print_impl_item(&mut self, ii: &ast::ImplItem) -> io::Result<()> {
-        try!(self.ann.pre(self, NodeSubItem(ii.id)));
-        try!(self.hardbreak_if_not_bol());
-        try!(self.maybe_print_comment(ii.span.lo));
-        try!(self.print_outer_attributes(&ii.attrs));
-        match ii.node {
-            ast::MethodImplItem(ref sig, ref body) => {
-                try!(self.head(""));
-                try!(self.print_method_sig(ii.ident, sig, ii.vis));
-                try!(self.nbsp());
-                try!(self.print_block_with_attrs(body, &ii.attrs));
-            }
-            ast::TypeImplItem(ref ty) => {
-                try!(self.print_associated_type(ii.ident, None, Some(ty)));
-            }
-            ast::MacImplItem(codemap::Spanned { node: ast::MacInvocTT(ref pth, ref tts, _),
-                                                ..}) => {
-                // code copied from ItemMac:
-                try!(self.print_path(pth, false, 0));
-                try!(word(&mut self.s, "! "));
-                try!(self.cbox(indent_unit));
-                try!(self.popen());
-                try!(self.print_tts(&tts[..]));
-                try!(self.pclose());
-                try!(word(&mut self.s, ";"));
-                try!(self.end())
-            }
-        }
-        self.ann.post(self, NodeSubItem(ii.id))
-    }
-
-    pub fn print_outer_attributes(&mut self,
-                                  attrs: &[ast::Attribute]) -> io::Result<()> {
-        let mut count = 0;
-        for attr in attrs {
-            match attr.node.style {
-                ast::AttrOuter => {
-                    try!(self.print_attribute(attr));
-                    count += 1;
-                }
-                _ => {/* fallthrough */ }
-            }
-        }
-        if count > 0 {
-            try!(self.hardbreak_if_not_bol());
-        }
-        Ok(())
+                      Some(ident),
+                      &m.generics,
+                      vis)
     }
 
-    pub fn print_inner_attributes(&mut self,
-                                  attrs: &[ast::Attribute]) -> io::Result<()> {
-        let mut count = 0;
-        for attr in attrs {
-            match attr.node.style {
-                ast::AttrInner => {
-                    try!(self.print_attribute(attr));
-                    count += 1;
+    pub fn print_trait_item(&mut self, ti: &ast::TraitItem)
+                            -> io::Result<()> {
+        self.ann.pre(self, NodeSubItem(ti.id))?;
+        self.hardbreak_if_not_bol()?;
+        self.maybe_print_comment(ti.span.lo)?;
+        self.print_outer_attributes(&ti.attrs)?;
+        match ti.node {
+            ast::TraitItemKind::Const(ref ty, ref default) => {
+                self.print_associated_const(ti.ident, ty,
+                                            default.as_ref().map(|expr| &**expr),
+                                            &ast::Visibility::Inherited)?;
+            }
+            ast::TraitItemKind::Method(ref sig, ref body) => {
+                if body.is_some() {
+                    self.head("")?;
+                }
+                self.print_method_sig(ti.ident, sig, &ast::Visibility::Inherited)?;
+                if let Some(ref body) = *body {
+                    self.nbsp()?;
+                    self.print_block_with_attrs(body, &ti.attrs)?;
+                } else {
+                    self.s.word(";")?;
                 }
-                _ => {/* fallthrough */ }
+            }
+            ast::TraitItemKind::Type(ref bounds, ref default) => {
+                self.print_associated_type(ti.ident, Some(bounds),
+                                           default.as_ref().map(|ty| &**ty))?;
+            }
+            ast::TraitItemKind::Macro(codemap::Spanned { ref node, .. }) => {
+                // code copied from ItemKind::Mac:
+                self.print_path(&node.path, false, 0, false)?;
+                self.s.word("! ")?;
+                self.cbox(INDENT_UNIT)?;
+                self.popen()?;
+                self.print_tts(node.stream())?;
+                self.pclose()?;
+                self.s.word(";")?;
+                self.end()?
             }
         }
-        if count > 0 {
-            try!(self.hardbreak_if_not_bol());
-        }
-        Ok(())
+        self.ann.post(self, NodeSubItem(ti.id))
     }
 
-    pub fn print_attribute(&mut self, attr: &ast::Attribute) -> io::Result<()> {
-        try!(self.hardbreak_if_not_bol());
-        try!(self.maybe_print_comment(attr.span.lo));
-        if attr.node.is_sugared_doc {
-            word(&mut self.s, &attr.value_str().unwrap())
-        } else {
-            match attr.node.style {
-                ast::AttrInner => try!(word(&mut self.s, "#![")),
-                ast::AttrOuter => try!(word(&mut self.s, "#[")),
+    pub fn print_impl_item(&mut self, ii: &ast::ImplItem) -> io::Result<()> {
+        self.ann.pre(self, NodeSubItem(ii.id))?;
+        self.hardbreak_if_not_bol()?;
+        self.maybe_print_comment(ii.span.lo)?;
+        self.print_outer_attributes(&ii.attrs)?;
+        self.print_defaultness(ii.defaultness)?;
+        match ii.node {
+            ast::ImplItemKind::Const(ref ty, ref expr) => {
+                self.print_associated_const(ii.ident, ty, Some(expr), &ii.vis)?;
+            }
+            ast::ImplItemKind::Method(ref sig, ref body) => {
+                self.head("")?;
+                self.print_method_sig(ii.ident, sig, &ii.vis)?;
+                self.nbsp()?;
+                self.print_block_with_attrs(body, &ii.attrs)?;
+            }
+            ast::ImplItemKind::Type(ref ty) => {
+                self.print_associated_type(ii.ident, None, Some(ty))?;
+            }
+            ast::ImplItemKind::Macro(codemap::Spanned { ref node, .. }) => {
+                // code copied from ItemKind::Mac:
+                self.print_path(&node.path, false, 0, false)?;
+                self.s.word("! ")?;
+                self.cbox(INDENT_UNIT)?;
+                self.popen()?;
+                self.print_tts(node.stream())?;
+                self.pclose()?;
+                self.s.word(";")?;
+                self.end()?
             }
-            try!(self.print_meta_item(&*attr.meta()));
-            word(&mut self.s, "]")
         }
+        self.ann.post(self, NodeSubItem(ii.id))
     }
 
-
     pub fn print_stmt(&mut self, st: &ast::Stmt) -> io::Result<()> {
-        try!(self.maybe_print_comment(st.span.lo));
+        self.maybe_print_comment(st.span.lo)?;
         match st.node {
-            ast::StmtDecl(ref decl, _) => {
-                try!(self.print_decl(&**decl));
-            }
-            ast::StmtExpr(ref expr, _) => {
-                try!(self.space_if_not_bol());
-                try!(self.print_expr(&**expr));
-            }
-            ast::StmtSemi(ref expr, _) => {
-                try!(self.space_if_not_bol());
-                try!(self.print_expr(&**expr));
-                try!(word(&mut self.s, ";"));
-            }
-            ast::StmtMac(ref mac, style) => {
-                try!(self.space_if_not_bol());
+            ast::StmtKind::Local(ref loc) => {
+                self.print_outer_attributes(&loc.attrs)?;
+                self.space_if_not_bol()?;
+                self.ibox(INDENT_UNIT)?;
+                self.word_nbsp("let")?;
+
+                self.ibox(INDENT_UNIT)?;
+                self.print_local_decl(loc)?;
+                self.end()?;
+                if let Some(ref init) = loc.init {
+                    self.nbsp()?;
+                    self.word_space("=")?;
+                    self.print_expr(init)?;
+                }
+                self.s.word(";")?;
+                self.end()?;
+            }
+            ast::StmtKind::Item(ref item) => self.print_item(item)?,
+            ast::StmtKind::Expr(ref expr) => {
+                self.space_if_not_bol()?;
+                self.print_expr_outer_attr_style(expr, false)?;
+                if parse::classify::expr_requires_semi_to_be_stmt(expr) {
+                    self.s.word(";")?;
+                }
+            }
+            ast::StmtKind::Semi(ref expr) => {
+                self.space_if_not_bol()?;
+                self.print_expr_outer_attr_style(expr, false)?;
+                self.s.word(";")?;
+            }
+            ast::StmtKind::Mac(ref mac) => {
+                let (ref mac, style, ref attrs) = **mac;
+                self.space_if_not_bol()?;
+                self.print_outer_attributes(attrs)?;
                 let delim = match style {
-                    ast::MacStmtWithBraces => token::Brace,
+                    ast::MacStmtStyle::Braces => token::Brace,
                     _ => token::Paren
                 };
-                try!(self.print_mac(&**mac, delim));
-                match style {
-                    ast::MacStmtWithBraces => {}
-                    _ => try!(word(&mut self.s, ";")),
+                self.print_mac(mac, delim)?;
+                if style == ast::MacStmtStyle::Semicolon {
+                    self.s.word(";")?;
                 }
             }
         }
-        if parse::classify::stmt_ends_with_semi(&st.node) {
-            try!(word(&mut self.s, ";"));
-        }
         self.maybe_print_trailing_comment(st.span, None)
     }
 
@@ -1412,7 +1675,13 @@ impl<'a> State<'a> {
     }
 
     pub fn print_block_unclosed(&mut self, blk: &ast::Block) -> io::Result<()> {
-        self.print_block_unclosed_indent(blk, indent_unit)
+        self.print_block_unclosed_indent(blk, INDENT_UNIT)
+    }
+
+    pub fn print_block_unclosed_with_attrs(&mut self, blk: &ast::Block,
+                                            attrs: &[ast::Attribute])
+                                           -> io::Result<()> {
+        self.print_block_maybe_unclosed(blk, INDENT_UNIT, attrs, false)
     }
 
     pub fn print_block_unclosed_indent(&mut self, blk: &ast::Block,
@@ -1423,7 +1692,7 @@ impl<'a> State<'a> {
     pub fn print_block_with_attrs(&mut self,
                                   blk: &ast::Block,
                                   attrs: &[ast::Attribute]) -> io::Result<()> {
-        self.print_block_maybe_unclosed(blk, indent_unit, attrs, true)
+        self.print_block_maybe_unclosed(blk, INDENT_UNIT, attrs, true)
     }
 
     pub fn print_block_maybe_unclosed(&mut self,
@@ -1432,27 +1701,28 @@ impl<'a> State<'a> {
                                       attrs: &[ast::Attribute],
                                       close_box: bool) -> io::Result<()> {
         match blk.rules {
-            ast::UnsafeBlock(..) => try!(self.word_space("unsafe")),
-            ast::DefaultBlock => ()
+            BlockCheckMode::Unsafe(..) => self.word_space("unsafe")?,
+            BlockCheckMode::Default => ()
         }
-        try!(self.maybe_print_comment(blk.span.lo));
-        try!(self.ann.pre(self, NodeBlock(blk)));
-        try!(self.bopen());
+        self.maybe_print_comment(blk.span.lo)?;
+        self.ann.pre(self, NodeBlock(blk))?;
+        self.bopen()?;
 
-        try!(self.print_inner_attributes(attrs));
+        self.print_inner_attributes(attrs)?;
 
-        for st in &blk.stmts {
-            try!(self.print_stmt(&**st));
-        }
-        match blk.expr {
-            Some(ref expr) => {
-                try!(self.space_if_not_bol());
-                try!(self.print_expr(&**expr));
-                try!(self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi)));
+        for (i, st) in blk.stmts.iter().enumerate() {
+            match st.node {
+                ast::StmtKind::Expr(ref expr) if i == blk.stmts.len() - 1 => {
+                    self.maybe_print_comment(st.span.lo)?;
+                    self.space_if_not_bol()?;
+                    self.print_expr_outer_attr_style(expr, false)?;
+                    self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi))?;
+                }
+                _ => self.print_stmt(st)?,
             }
-            _ => ()
         }
-        try!(self.bclose_maybe_open(blk.span, indented, close_box));
+
+        self.bclose_maybe_open(blk.span, indented, close_box)?;
         self.ann.post(self, NodeBlock(blk))
     }
 
@@ -1461,34 +1731,34 @@ impl<'a> State<'a> {
             Some(_else) => {
                 match _else.node {
                     // "another else-if"
-                    ast::ExprIf(ref i, ref then, ref e) => {
-                        try!(self.cbox(indent_unit - 1));
-                        try!(self.ibox(0));
-                        try!(word(&mut self.s, " else if "));
-                        try!(self.print_expr(&**i));
-                        try!(space(&mut self.s));
-                        try!(self.print_block(&**then));
+                    ast::ExprKind::If(ref i, ref then, ref e) => {
+                        self.cbox(INDENT_UNIT - 1)?;
+                        self.ibox(0)?;
+                        self.s.word(" else if ")?;
+                        self.print_expr(i)?;
+                        self.s.space()?;
+                        self.print_block(then)?;
                         self.print_else(e.as_ref().map(|e| &**e))
                     }
                     // "another else-if-let"
-                    ast::ExprIfLet(ref pat, ref expr, ref then, ref e) => {
-                        try!(self.cbox(indent_unit - 1));
-                        try!(self.ibox(0));
-                        try!(word(&mut self.s, " else if let "));
-                        try!(self.print_pat(&**pat));
-                        try!(space(&mut self.s));
-                        try!(self.word_space("="));
-                        try!(self.print_expr(&**expr));
-                        try!(space(&mut self.s));
-                        try!(self.print_block(&**then));
+                    ast::ExprKind::IfLet(ref pat, ref expr, ref then, ref e) => {
+                        self.cbox(INDENT_UNIT - 1)?;
+                        self.ibox(0)?;
+                        self.s.word(" else if let ")?;
+                        self.print_pat(pat)?;
+                        self.s.space()?;
+                        self.word_space("=")?;
+                        self.print_expr(expr)?;
+                        self.s.space()?;
+                        self.print_block(then)?;
                         self.print_else(e.as_ref().map(|e| &**e))
                     }
                     // "final else"
-                    ast::ExprBlock(ref b) => {
-                        try!(self.cbox(indent_unit - 1));
-                        try!(self.ibox(0));
-                        try!(word(&mut self.s, " else "));
-                        self.print_block(&**b)
+                    ast::ExprKind::Block(ref b) => {
+                        self.cbox(INDENT_UNIT - 1)?;
+                        self.ibox(0)?;
+                        self.s.word(" else ")?;
+                        self.print_block(b)
                     }
                     // BLEAH, constraints would be great here
                     _ => {
@@ -1502,137 +1772,157 @@ impl<'a> State<'a> {
 
     pub fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block,
                     elseopt: Option<&ast::Expr>) -> io::Result<()> {
-        try!(self.head("if"));
-        try!(self.print_expr(test));
-        try!(space(&mut self.s));
-        try!(self.print_block(blk));
+        self.head("if")?;
+        self.print_expr(test)?;
+        self.s.space()?;
+        self.print_block(blk)?;
         self.print_else(elseopt)
     }
 
     pub fn print_if_let(&mut self, pat: &ast::Pat, expr: &ast::Expr, blk: &ast::Block,
                         elseopt: Option<&ast::Expr>) -> io::Result<()> {
-        try!(self.head("if let"));
-        try!(self.print_pat(pat));
-        try!(space(&mut self.s));
-        try!(self.word_space("="));
-        try!(self.print_expr(expr));
-        try!(space(&mut self.s));
-        try!(self.print_block(blk));
+        self.head("if let")?;
+        self.print_pat(pat)?;
+        self.s.space()?;
+        self.word_space("=")?;
+        self.print_expr(expr)?;
+        self.s.space()?;
+        self.print_block(blk)?;
         self.print_else(elseopt)
     }
 
     pub fn print_mac(&mut self, m: &ast::Mac, delim: token::DelimToken)
                      -> io::Result<()> {
-        match m.node {
-            // I think it's reasonable to hide the ctxt here:
-            ast::MacInvocTT(ref pth, ref tts, _) => {
-                try!(self.print_path(pth, false, 0));
-                try!(word(&mut self.s, "!"));
-                match delim {
-                    token::Paren => try!(self.popen()),
-                    token::Bracket => try!(word(&mut self.s, "[")),
-                    token::Brace => try!(self.bopen()),
-                }
-                try!(self.print_tts(tts));
-                match delim {
-                    token::Paren => self.pclose(),
-                    token::Bracket => word(&mut self.s, "]"),
-                    token::Brace => self.bclose(m.span),
-                }
+        self.print_path(&m.node.path, false, 0, false)?;
+        self.s.word("!")?;
+        match delim {
+            token::Paren => self.popen()?,
+            token::Bracket => self.s.word("[")?,
+            token::Brace => {
+                self.head("")?;
+                self.bopen()?;
             }
+            token::NoDelim => {}
+        }
+        self.print_tts(m.node.stream())?;
+        match delim {
+            token::Paren => self.pclose(),
+            token::Bracket => self.s.word("]"),
+            token::Brace => self.bclose(m.span),
+            token::NoDelim => Ok(()),
         }
     }
 
 
     fn print_call_post(&mut self, args: &[P<ast::Expr>]) -> io::Result<()> {
-        try!(self.popen());
-        try!(self.commasep_exprs(Inconsistent, args));
+        self.popen()?;
+        self.commasep_exprs(Inconsistent, args)?;
         self.pclose()
     }
 
+    pub fn check_expr_bin_needs_paren(&mut self, sub_expr: &ast::Expr,
+                                      binop: ast::BinOp) -> bool {
+        match sub_expr.node {
+            ast::ExprKind::Binary(ref sub_op, _, _) => {
+                AssocOp::from_ast_binop(sub_op.node).precedence() <
+                    AssocOp::from_ast_binop(binop.node).precedence()
+            }
+            _ => true
+        }
+    }
+
     pub fn print_expr_maybe_paren(&mut self, expr: &ast::Expr) -> io::Result<()> {
         let needs_par = needs_parentheses(expr);
         if needs_par {
-            try!(self.popen());
+            self.popen()?;
         }
-        try!(self.print_expr(expr));
+        self.print_expr(expr)?;
         if needs_par {
-            try!(self.pclose());
+            self.pclose()?;
         }
         Ok(())
     }
 
-    fn print_expr_box(&mut self,
-                      place: &Option<P<ast::Expr>>,
-                      expr: &ast::Expr) -> io::Result<()> {
-        try!(word(&mut self.s, "box"));
-        try!(word(&mut self.s, "("));
-        try!(place.as_ref().map_or(Ok(()), |e|self.print_expr(&**e)));
-        try!(self.word_space(")"));
-        self.print_expr(expr)
+    fn print_expr_in_place(&mut self,
+                           place: &ast::Expr,
+                           expr: &ast::Expr) -> io::Result<()> {
+        self.print_expr_maybe_paren(place)?;
+        self.s.space()?;
+        self.word_space("<-")?;
+        self.print_expr_maybe_paren(expr)
     }
 
-    fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>]) -> io::Result<()> {
-        try!(self.ibox(indent_unit));
-        try!(word(&mut self.s, "["));
-        try!(self.commasep_exprs(Inconsistent, &exprs[..]));
-        try!(word(&mut self.s, "]"));
+    fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>],
+                      attrs: &[Attribute]) -> io::Result<()> {
+        self.ibox(INDENT_UNIT)?;
+        self.s.word("[")?;
+        self.print_inner_attributes_inline(attrs)?;
+        self.commasep_exprs(Inconsistent, &exprs[..])?;
+        self.s.word("]")?;
         self.end()
     }
 
     fn print_expr_repeat(&mut self,
                          element: &ast::Expr,
-                         count: &ast::Expr) -> io::Result<()> {
-        try!(self.ibox(indent_unit));
-        try!(word(&mut self.s, "["));
-        try!(self.print_expr(element));
-        try!(self.word_space(";"));
-        try!(self.print_expr(count));
-        try!(word(&mut self.s, "]"));
+                         count: &ast::Expr,
+                         attrs: &[Attribute]) -> io::Result<()> {
+        self.ibox(INDENT_UNIT)?;
+        self.s.word("[")?;
+        self.print_inner_attributes_inline(attrs)?;
+        self.print_expr(element)?;
+        self.word_space(";")?;
+        self.print_expr(count)?;
+        self.s.word("]")?;
         self.end()
     }
 
     fn print_expr_struct(&mut self,
                          path: &ast::Path,
                          fields: &[ast::Field],
-                         wth: &Option<P<ast::Expr>>) -> io::Result<()> {
-        try!(self.print_path(path, true, 0));
-        if !(fields.is_empty() && wth.is_none()) {
-            try!(word(&mut self.s, "{"));
-            try!(self.commasep_cmnt(
-                Consistent,
-                &fields[..],
-                |s, field| {
-                    try!(s.ibox(indent_unit));
-                    try!(s.print_ident(field.ident.node));
-                    try!(s.word_space(":"));
-                    try!(s.print_expr(&*field.expr));
-                    s.end()
-                },
-                |f| f.span));
-            match *wth {
-                Some(ref expr) => {
-                    try!(self.ibox(indent_unit));
-                    if !fields.is_empty() {
-                        try!(word(&mut self.s, ","));
-                        try!(space(&mut self.s));
-                    }
-                    try!(word(&mut self.s, ".."));
-                    try!(self.print_expr(&**expr));
-                    try!(self.end());
+                         wth: &Option<P<ast::Expr>>,
+                         attrs: &[Attribute]) -> io::Result<()> {
+        self.print_path(path, true, 0, false)?;
+        self.s.word("{")?;
+        self.print_inner_attributes_inline(attrs)?;
+        self.commasep_cmnt(
+            Consistent,
+            &fields[..],
+            |s, field| {
+                s.ibox(INDENT_UNIT)?;
+                if !field.is_shorthand {
+                    s.print_ident(field.ident.node)?;
+                    s.word_space(":")?;
+                }
+                s.print_expr(&field.expr)?;
+                s.end()
+            },
+            |f| f.span)?;
+        match *wth {
+            Some(ref expr) => {
+                self.ibox(INDENT_UNIT)?;
+                if !fields.is_empty() {
+                    self.s.word(",")?;
+                    self.s.space()?;
                 }
-                _ => try!(word(&mut self.s, ",")),
+                self.s.word("..")?;
+                self.print_expr(expr)?;
+                self.end()?;
+            }
+            _ => if !fields.is_empty() {
+                self.s.word(",")?
             }
-            try!(word(&mut self.s, "}"));
         }
+        self.s.word("}")?;
         Ok(())
     }
 
-    fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>]) -> io::Result<()> {
-        try!(self.popen());
-        try!(self.commasep_exprs(Inconsistent, &exprs[..]));
+    fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>],
+                      attrs: &[Attribute]) -> io::Result<()> {
+        self.popen()?;
+        self.print_inner_attributes_inline(attrs)?;
+        self.commasep_exprs(Inconsistent, &exprs[..])?;
         if exprs.len() == 1 {
-            try!(word(&mut self.s, ","));
+            self.s.word(",")?;
         }
         self.pclose()
     }
@@ -1640,23 +1930,19 @@ impl<'a> State<'a> {
     fn print_expr_call(&mut self,
                        func: &ast::Expr,
                        args: &[P<ast::Expr>]) -> io::Result<()> {
-        try!(self.print_expr_maybe_paren(func));
+        self.print_expr_maybe_paren(func)?;
         self.print_call_post(args)
     }
 
     fn print_expr_method_call(&mut self,
-                              ident: ast::SpannedIdent,
-                              tys: &[P<ast::Ty>],
+                              segment: &ast::PathSegment,
                               args: &[P<ast::Expr>]) -> io::Result<()> {
         let base_args = &args[1..];
-        try!(self.print_expr(&*args[0]));
-        try!(word(&mut self.s, "."));
-        try!(self.print_ident(ident.node));
-        if tys.len() > 0 {
-            try!(word(&mut self.s, "::<"));
-            try!(self.commasep(Inconsistent, tys,
-                               |s, ty| s.print_type(&**ty)));
-            try!(word(&mut self.s, ">"));
+        self.print_expr(&args[0])?;
+        self.s.word(".")?;
+        self.print_ident(segment.identifier)?;
+        if let Some(ref parameters) = segment.parameters {
+            self.print_path_parameters(parameters, true)?;
         }
         self.print_call_post(base_args)
     }
@@ -1665,395 +1951,415 @@ impl<'a> State<'a> {
                          op: ast::BinOp,
                          lhs: &ast::Expr,
                          rhs: &ast::Expr) -> io::Result<()> {
-        try!(self.print_expr(lhs));
-        try!(space(&mut self.s));
-        try!(self.word_space(ast_util::binop_to_string(op.node)));
-        self.print_expr(rhs)
+        if self.check_expr_bin_needs_paren(lhs, op) {
+            self.print_expr_maybe_paren(lhs)?;
+        } else {
+            self.print_expr(lhs)?;
+        }
+        self.s.space()?;
+        self.word_space(op.node.to_string())?;
+        if self.check_expr_bin_needs_paren(rhs, op) {
+            self.print_expr_maybe_paren(rhs)
+        } else {
+            self.print_expr(rhs)
+        }
     }
 
     fn print_expr_unary(&mut self,
                         op: ast::UnOp,
                         expr: &ast::Expr) -> io::Result<()> {
-        try!(word(&mut self.s, ast_util::unop_to_string(op)));
+        self.s.word(ast::UnOp::to_string(op))?;
         self.print_expr_maybe_paren(expr)
     }
 
     fn print_expr_addr_of(&mut self,
                           mutability: ast::Mutability,
                           expr: &ast::Expr) -> io::Result<()> {
-        try!(word(&mut self.s, "&"));
-        try!(self.print_mutability(mutability));
+        self.s.word("&")?;
+        self.print_mutability(mutability)?;
         self.print_expr_maybe_paren(expr)
     }
 
     pub fn print_expr(&mut self, expr: &ast::Expr) -> io::Result<()> {
-        try!(self.maybe_print_comment(expr.span.lo));
-        try!(self.ibox(indent_unit));
-        try!(self.ann.pre(self, NodeExpr(expr)));
+        self.print_expr_outer_attr_style(expr, true)
+    }
+
+    fn print_expr_outer_attr_style(&mut self,
+                                  expr: &ast::Expr,
+                                  is_inline: bool) -> io::Result<()> {
+        self.maybe_print_comment(expr.span.lo)?;
+
+        let attrs = &expr.attrs;
+        if is_inline {
+            self.print_outer_attributes_inline(attrs)?;
+        } else {
+            self.print_outer_attributes(attrs)?;
+        }
+
+        self.ibox(INDENT_UNIT)?;
+        self.ann.pre(self, NodeExpr(expr))?;
         match expr.node {
-            ast::ExprBox(ref place, ref expr) => {
-                try!(self.print_expr_box(place, &**expr));
+            ast::ExprKind::Box(ref expr) => {
+                self.word_space("box")?;
+                self.print_expr(expr)?;
+            }
+            ast::ExprKind::InPlace(ref place, ref expr) => {
+                self.print_expr_in_place(place, expr)?;
             }
-            ast::ExprVec(ref exprs) => {
-                try!(self.print_expr_vec(&exprs[..]));
+            ast::ExprKind::Array(ref exprs) => {
+                self.print_expr_vec(&exprs[..], attrs)?;
             }
-            ast::ExprRepeat(ref element, ref count) => {
-                try!(self.print_expr_repeat(&**element, &**count));
+            ast::ExprKind::Repeat(ref element, ref count) => {
+                self.print_expr_repeat(element, count, attrs)?;
             }
-            ast::ExprStruct(ref path, ref fields, ref wth) => {
-                try!(self.print_expr_struct(path, &fields[..], wth));
+            ast::ExprKind::Struct(ref path, ref fields, ref wth) => {
+                self.print_expr_struct(path, &fields[..], wth, attrs)?;
             }
-            ast::ExprTup(ref exprs) => {
-                try!(self.print_expr_tup(&exprs[..]));
+            ast::ExprKind::Tup(ref exprs) => {
+                self.print_expr_tup(&exprs[..], attrs)?;
             }
-            ast::ExprCall(ref func, ref args) => {
-                try!(self.print_expr_call(&**func, &args[..]));
+            ast::ExprKind::Call(ref func, ref args) => {
+                self.print_expr_call(func, &args[..])?;
             }
-            ast::ExprMethodCall(ident, ref tys, ref args) => {
-                try!(self.print_expr_method_call(ident, &tys[..], &args[..]));
+            ast::ExprKind::MethodCall(ref segment, ref args) => {
+                self.print_expr_method_call(segment, &args[..])?;
             }
-            ast::ExprBinary(op, ref lhs, ref rhs) => {
-                try!(self.print_expr_binary(op, &**lhs, &**rhs));
+            ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
+                self.print_expr_binary(op, lhs, rhs)?;
             }
-            ast::ExprUnary(op, ref expr) => {
-                try!(self.print_expr_unary(op, &**expr));
+            ast::ExprKind::Unary(op, ref expr) => {
+                self.print_expr_unary(op, expr)?;
             }
-            ast::ExprAddrOf(m, ref expr) => {
-                try!(self.print_expr_addr_of(m, &**expr));
+            ast::ExprKind::AddrOf(m, ref expr) => {
+                self.print_expr_addr_of(m, expr)?;
             }
-            ast::ExprLit(ref lit) => {
-                try!(self.print_literal(&**lit));
+            ast::ExprKind::Lit(ref lit) => {
+                self.print_literal(lit)?;
+            }
+            ast::ExprKind::Cast(ref expr, ref ty) => {
+                if let ast::ExprKind::Cast(..) = expr.node {
+                    self.print_expr(expr)?;
+                } else {
+                    self.print_expr_maybe_paren(expr)?;
+                }
+                self.s.space()?;
+                self.word_space("as")?;
+                self.print_type(ty)?;
             }
-            ast::ExprCast(ref expr, ref ty) => {
-                try!(self.print_expr(&**expr));
-                try!(space(&mut self.s));
-                try!(self.word_space("as"));
-                try!(self.print_type(&**ty));
+            ast::ExprKind::Type(ref expr, ref ty) => {
+                self.print_expr(expr)?;
+                self.word_space(":")?;
+                self.print_type(ty)?;
             }
-            ast::ExprIf(ref test, ref blk, ref elseopt) => {
-                try!(self.print_if(&**test, &**blk, elseopt.as_ref().map(|e| &**e)));
+            ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
+                self.print_if(test, blk, elseopt.as_ref().map(|e| &**e))?;
             }
-            ast::ExprIfLet(ref pat, ref expr, ref blk, ref elseopt) => {
-                try!(self.print_if_let(&**pat, &**expr, &** blk, elseopt.as_ref().map(|e| &**e)));
+            ast::ExprKind::IfLet(ref pat, ref expr, ref blk, ref elseopt) => {
+                self.print_if_let(pat, expr, blk, elseopt.as_ref().map(|e| &**e))?;
             }
-            ast::ExprWhile(ref test, ref blk, opt_ident) => {
+            ast::ExprKind::While(ref test, ref blk, opt_ident) => {
                 if let Some(ident) = opt_ident {
-                    try!(self.print_ident(ident));
-                    try!(self.word_space(":"));
+                    self.print_ident(ident.node)?;
+                    self.word_space(":")?;
                 }
-                try!(self.head("while"));
-                try!(self.print_expr(&**test));
-                try!(space(&mut self.s));
-                try!(self.print_block(&**blk));
+                self.head("while")?;
+                self.print_expr(test)?;
+                self.s.space()?;
+                self.print_block_with_attrs(blk, attrs)?;
             }
-            ast::ExprWhileLet(ref pat, ref expr, ref blk, opt_ident) => {
+            ast::ExprKind::WhileLet(ref pat, ref expr, ref blk, opt_ident) => {
                 if let Some(ident) = opt_ident {
-                    try!(self.print_ident(ident));
-                    try!(self.word_space(":"));
-                }
-                try!(self.head("while let"));
-                try!(self.print_pat(&**pat));
-                try!(space(&mut self.s));
-                try!(self.word_space("="));
-                try!(self.print_expr(&**expr));
-                try!(space(&mut self.s));
-                try!(self.print_block(&**blk));
-            }
-            ast::ExprForLoop(ref pat, ref iter, ref blk, opt_ident) => {
+                    self.print_ident(ident.node)?;
+                    self.word_space(":")?;
+                }
+                self.head("while let")?;
+                self.print_pat(pat)?;
+                self.s.space()?;
+                self.word_space("=")?;
+                self.print_expr(expr)?;
+                self.s.space()?;
+                self.print_block_with_attrs(blk, attrs)?;
+            }
+            ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_ident) => {
                 if let Some(ident) = opt_ident {
-                    try!(self.print_ident(ident));
-                    try!(self.word_space(":"));
-                }
-                try!(self.head("for"));
-                try!(self.print_pat(&**pat));
-                try!(space(&mut self.s));
-                try!(self.word_space("in"));
-                try!(self.print_expr(&**iter));
-                try!(space(&mut self.s));
-                try!(self.print_block(&**blk));
-            }
-            ast::ExprLoop(ref blk, opt_ident) => {
+                    self.print_ident(ident.node)?;
+                    self.word_space(":")?;
+                }
+                self.head("for")?;
+                self.print_pat(pat)?;
+                self.s.space()?;
+                self.word_space("in")?;
+                self.print_expr(iter)?;
+                self.s.space()?;
+                self.print_block_with_attrs(blk, attrs)?;
+            }
+            ast::ExprKind::Loop(ref blk, opt_ident) => {
                 if let Some(ident) = opt_ident {
-                    try!(self.print_ident(ident));
-                    try!(self.word_space(":"));
-                }
-                try!(self.head("loop"));
-                try!(space(&mut self.s));
-                try!(self.print_block(&**blk));
-            }
-            ast::ExprMatch(ref expr, ref arms, _) => {
-                try!(self.cbox(indent_unit));
-                try!(self.ibox(4));
-                try!(self.word_nbsp("match"));
-                try!(self.print_expr(&**expr));
-                try!(space(&mut self.s));
-                try!(self.bopen());
+                    self.print_ident(ident.node)?;
+                    self.word_space(":")?;
+                }
+                self.head("loop")?;
+                self.s.space()?;
+                self.print_block_with_attrs(blk, attrs)?;
+            }
+            ast::ExprKind::Match(ref expr, ref arms) => {
+                self.cbox(INDENT_UNIT)?;
+                self.ibox(4)?;
+                self.word_nbsp("match")?;
+                self.print_expr(expr)?;
+                self.s.space()?;
+                self.bopen()?;
+                self.print_inner_attributes_no_trailing_hardbreak(attrs)?;
                 for arm in arms {
-                    try!(self.print_arm(arm));
+                    self.print_arm(arm)?;
                 }
-                try!(self.bclose_(expr.span, indent_unit));
+                self.bclose_(expr.span, INDENT_UNIT)?;
             }
-            ast::ExprClosure(capture_clause, ref decl, ref body) => {
-                try!(self.print_capture_clause(capture_clause));
-
-                try!(self.print_fn_block_args(&**decl));
-                try!(space(&mut self.s));
+            ast::ExprKind::Closure(capture_clause, ref decl, ref body, _) => {
+                self.print_capture_clause(capture_clause)?;
 
-                let default_return = match decl.output {
-                    ast::DefaultReturn(..) => true,
-                    _ => false
-                };
+                self.print_fn_block_args(decl)?;
+                self.s.space()?;
+                self.print_expr(body)?;
+                self.end()?; // need to close a box
 
-                if !default_return || !body.stmts.is_empty() || body.expr.is_none() {
-                    try!(self.print_block_unclosed(&**body));
-                } else {
-                    // we extract the block, so as not to create another set of boxes
-                    match body.expr.as_ref().unwrap().node {
-                        ast::ExprBlock(ref blk) => {
-                            try!(self.print_block_unclosed(&**blk));
-                        }
-                        _ => {
-                            // this is a bare expression
-                            try!(self.print_expr(body.expr.as_ref().map(|e| &**e).unwrap()));
-                            try!(self.end()); // need to close a box
-                        }
-                    }
-                }
                 // a box will be closed by print_expr, but we didn't want an overall
                 // wrapper so we closed the corresponding opening. so create an
                 // empty box to satisfy the close.
-                try!(self.ibox(0));
+                self.ibox(0)?;
             }
-            ast::ExprBlock(ref blk) => {
+            ast::ExprKind::Block(ref blk) => {
                 // containing cbox, will be closed by print-block at }
-                try!(self.cbox(indent_unit));
+                self.cbox(INDENT_UNIT)?;
                 // head-box, will be closed by print-block after {
-                try!(self.ibox(0));
-                try!(self.print_block(&**blk));
-            }
-            ast::ExprAssign(ref lhs, ref rhs) => {
-                try!(self.print_expr(&**lhs));
-                try!(space(&mut self.s));
-                try!(self.word_space("="));
-                try!(self.print_expr(&**rhs));
-            }
-            ast::ExprAssignOp(op, ref lhs, ref rhs) => {
-                try!(self.print_expr(&**lhs));
-                try!(space(&mut self.s));
-                try!(word(&mut self.s, ast_util::binop_to_string(op.node)));
-                try!(self.word_space("="));
-                try!(self.print_expr(&**rhs));
-            }
-            ast::ExprField(ref expr, id) => {
-                try!(self.print_expr(&**expr));
-                try!(word(&mut self.s, "."));
-                try!(self.print_ident(id.node));
-            }
-            ast::ExprTupField(ref expr, id) => {
-                try!(self.print_expr(&**expr));
-                try!(word(&mut self.s, "."));
-                try!(self.print_usize(id.node));
-            }
-            ast::ExprIndex(ref expr, ref index) => {
-                try!(self.print_expr(&**expr));
-                try!(word(&mut self.s, "["));
-                try!(self.print_expr(&**index));
-                try!(word(&mut self.s, "]"));
-            }
-            ast::ExprRange(ref start, ref end) => {
-                if let &Some(ref e) = start {
-                    try!(self.print_expr(&**e));
-                }
-                try!(word(&mut self.s, ".."));
-                if let &Some(ref e) = end {
-                    try!(self.print_expr(&**e));
-                }
-            }
-            ast::ExprPath(None, ref path) => {
-                try!(self.print_path(path, true, 0))
-            }
-            ast::ExprPath(Some(ref qself), ref path) => {
-                try!(self.print_qpath(path, qself, true))
-            }
-            ast::ExprBreak(opt_ident) => {
-                try!(word(&mut self.s, "break"));
-                try!(space(&mut self.s));
-                if let Some(ident) = opt_ident {
-                    try!(self.print_ident(ident));
-                    try!(space(&mut self.s));
+                self.ibox(0)?;
+                self.print_block_with_attrs(blk, attrs)?;
+            }
+            ast::ExprKind::Assign(ref lhs, ref rhs) => {
+                self.print_expr(lhs)?;
+                self.s.space()?;
+                self.word_space("=")?;
+                self.print_expr(rhs)?;
+            }
+            ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
+                self.print_expr(lhs)?;
+                self.s.space()?;
+                self.s.word(op.node.to_string())?;
+                self.word_space("=")?;
+                self.print_expr(rhs)?;
+            }
+            ast::ExprKind::Field(ref expr, id) => {
+                self.print_expr(expr)?;
+                self.s.word(".")?;
+                self.print_ident(id.node)?;
+            }
+            ast::ExprKind::TupField(ref expr, id) => {
+                self.print_expr(expr)?;
+                self.s.word(".")?;
+                self.print_usize(id.node)?;
+            }
+            ast::ExprKind::Index(ref expr, ref index) => {
+                self.print_expr(expr)?;
+                self.s.word("[")?;
+                self.print_expr(index)?;
+                self.s.word("]")?;
+            }
+            ast::ExprKind::Range(ref start, ref end, limits) => {
+                if let Some(ref e) = *start {
+                    self.print_expr(e)?;
+                }
+                if limits == ast::RangeLimits::HalfOpen {
+                    self.s.word("..")?;
+                } else {
+                    self.s.word("...")?;
+                }
+                if let Some(ref e) = *end {
+                    self.print_expr(e)?;
                 }
             }
-            ast::ExprAgain(opt_ident) => {
-                try!(word(&mut self.s, "continue"));
-                try!(space(&mut self.s));
+            ast::ExprKind::Path(None, ref path) => {
+                self.print_path(path, true, 0, false)?
+            }
+            ast::ExprKind::Path(Some(ref qself), ref path) => {
+                self.print_qpath(path, qself, true)?
+            }
+            ast::ExprKind::Break(opt_ident, ref opt_expr) => {
+                self.s.word("break")?;
+                self.s.space()?;
                 if let Some(ident) = opt_ident {
-                    try!(self.print_ident(ident));
-                    try!(space(&mut self.s))
+                    self.print_ident(ident.node)?;
+                    self.s.space()?;
                 }
-            }
-            ast::ExprRet(ref result) => {
-                try!(word(&mut self.s, "return"));
-                match *result {
-                    Some(ref expr) => {
-                        try!(word(&mut self.s, " "));
-                        try!(self.print_expr(&**expr));
-                    }
-                    _ => ()
+                if let Some(ref expr) = *opt_expr {
+                    self.print_expr(expr)?;
+                    self.s.space()?;
                 }
             }
-            ast::ExprInlineAsm(ref a) => {
-                try!(word(&mut self.s, "asm!"));
-                try!(self.popen());
-                try!(self.print_string(&a.asm, a.asm_str_style));
-                try!(self.word_space(":"));
-
-                try!(self.commasep(Inconsistent, &a.outputs,
-                                   |s, &(ref co, ref o, is_rw)| {
-                    match co.slice_shift_char() {
-                        Some(('=', operand)) if is_rw => {
-                            try!(s.print_string(&format!("+{}", operand),
-                                                ast::CookedStr))
+            ast::ExprKind::Continue(opt_ident) => {
+                self.s.word("continue")?;
+                self.s.space()?;
+                if let Some(ident) = opt_ident {
+                    self.print_ident(ident.node)?;
+                    self.s.space()?
+                }
+            }
+            ast::ExprKind::Ret(ref result) => {
+                self.s.word("return")?;
+                if let Some(ref expr) = *result {
+                    self.s.word(" ")?;
+                    self.print_expr(expr)?;
+                }
+            }
+            ast::ExprKind::InlineAsm(ref a) => {
+                self.s.word("asm!")?;
+                self.popen()?;
+                self.print_string(&a.asm.as_str(), a.asm_str_style)?;
+                self.word_space(":")?;
+
+                self.commasep(Inconsistent, &a.outputs, |s, out| {
+                    let constraint = out.constraint.as_str();
+                    let mut ch = constraint.chars();
+                    match ch.next() {
+                        Some('=') if out.is_rw => {
+                            s.print_string(&format!("+{}", ch.as_str()),
+                                           ast::StrStyle::Cooked)?
                         }
-                        _ => try!(s.print_string(&co, ast::CookedStr))
+                        _ => s.print_string(&constraint, ast::StrStyle::Cooked)?
                     }
-                    try!(s.popen());
-                    try!(s.print_expr(&**o));
-                    try!(s.pclose());
+                    s.popen()?;
+                    s.print_expr(&out.expr)?;
+                    s.pclose()?;
                     Ok(())
-                }));
-                try!(space(&mut self.s));
-                try!(self.word_space(":"));
-
-                try!(self.commasep(Inconsistent, &a.inputs,
-                                   |s, &(ref co, ref o)| {
-                    try!(s.print_string(&co, ast::CookedStr));
-                    try!(s.popen());
-                    try!(s.print_expr(&**o));
-                    try!(s.pclose());
+                })?;
+                self.s.space()?;
+                self.word_space(":")?;
+
+                self.commasep(Inconsistent, &a.inputs, |s, &(co, ref o)| {
+                    s.print_string(&co.as_str(), ast::StrStyle::Cooked)?;
+                    s.popen()?;
+                    s.print_expr(o)?;
+                    s.pclose()?;
                     Ok(())
-                }));
-                try!(space(&mut self.s));
-                try!(self.word_space(":"));
+                })?;
+                self.s.space()?;
+                self.word_space(":")?;
 
-                try!(self.commasep(Inconsistent, &a.clobbers,
+                self.commasep(Inconsistent, &a.clobbers,
                                    |s, co| {
-                    try!(s.print_string(&co, ast::CookedStr));
+                    s.print_string(&co.as_str(), ast::StrStyle::Cooked)?;
                     Ok(())
-                }));
+                })?;
 
-                let mut options = vec!();
+                let mut options = vec![];
                 if a.volatile {
                     options.push("volatile");
                 }
                 if a.alignstack {
                     options.push("alignstack");
                 }
-                if a.dialect == ast::AsmDialect::AsmIntel {
+                if a.dialect == ast::AsmDialect::Intel {
                     options.push("intel");
                 }
 
-                if options.len() > 0 {
-                    try!(space(&mut self.s));
-                    try!(self.word_space(":"));
-                    try!(self.commasep(Inconsistent, &*options,
-                                       |s, &co| {
-                        try!(s.print_string(co, ast::CookedStr));
-                        Ok(())
-                    }));
+                if !options.is_empty() {
+                    self.s.space()?;
+                    self.word_space(":")?;
+                    self.commasep(Inconsistent, &options,
+                                  |s, &co| {
+                                      s.print_string(co, ast::StrStyle::Cooked)?;
+                                      Ok(())
+                                  })?;
                 }
 
-                try!(self.pclose());
+                self.pclose()?;
+            }
+            ast::ExprKind::Mac(ref m) => self.print_mac(m, token::Paren)?,
+            ast::ExprKind::Paren(ref e) => {
+                self.popen()?;
+                self.print_inner_attributes_inline(attrs)?;
+                self.print_expr(e)?;
+                self.pclose()?;
+            },
+            ast::ExprKind::Try(ref e) => {
+                self.print_expr(e)?;
+                self.s.word("?")?
             }
-            ast::ExprMac(ref m) => try!(self.print_mac(m, token::Paren)),
-            ast::ExprParen(ref e) => {
-                try!(self.popen());
-                try!(self.print_expr(&**e));
-                try!(self.pclose());
+            ast::ExprKind::Catch(ref blk) => {
+                self.head("do catch")?;
+                self.s.space()?;
+                self.print_block_with_attrs(blk, attrs)?
             }
         }
-        try!(self.ann.post(self, NodeExpr(expr)));
+        self.ann.post(self, NodeExpr(expr))?;
         self.end()
     }
 
     pub fn print_local_decl(&mut self, loc: &ast::Local) -> io::Result<()> {
-        try!(self.print_pat(&*loc.pat));
+        self.print_pat(&loc.pat)?;
         if let Some(ref ty) = loc.ty {
-            try!(self.word_space(":"));
-            try!(self.print_type(&**ty));
+            self.word_space(":")?;
+            self.print_type(ty)?;
         }
         Ok(())
     }
 
-    pub fn print_decl(&mut self, decl: &ast::Decl) -> io::Result<()> {
-        try!(self.maybe_print_comment(decl.span.lo));
-        match decl.node {
-            ast::DeclLocal(ref loc) => {
-                try!(self.space_if_not_bol());
-                try!(self.ibox(indent_unit));
-                try!(self.word_nbsp("let"));
-
-                try!(self.ibox(indent_unit));
-                try!(self.print_local_decl(&**loc));
-                try!(self.end());
-                if let Some(ref init) = loc.init {
-                    try!(self.nbsp());
-                    try!(self.word_space("="));
-                    try!(self.print_expr(&**init));
-                }
-                self.end()
-            }
-            ast::DeclItem(ref item) => self.print_item(&**item)
-        }
-    }
-
     pub fn print_ident(&mut self, ident: ast::Ident) -> io::Result<()> {
-        if self.encode_idents_with_hygiene {
-            let encoded = ident.encode_with_hygiene();
-            try!(word(&mut self.s, &encoded[..]))
-        } else {
-            try!(word(&mut self.s, &token::get_ident(ident)))
-        }
+        self.s.word(&ident.name.as_str())?;
         self.ann.post(self, NodeIdent(&ident))
     }
 
     pub fn print_usize(&mut self, i: usize) -> io::Result<()> {
-        word(&mut self.s, &i.to_string())
+        self.s.word(&i.to_string())
     }
 
     pub fn print_name(&mut self, name: ast::Name) -> io::Result<()> {
-        try!(word(&mut self.s, &token::get_name(name)));
+        self.s.word(&name.as_str())?;
         self.ann.post(self, NodeName(&name))
     }
 
     pub fn print_for_decl(&mut self, loc: &ast::Local,
                           coll: &ast::Expr) -> io::Result<()> {
-        try!(self.print_local_decl(loc));
-        try!(space(&mut self.s));
-        try!(self.word_space("in"));
+        self.print_local_decl(loc)?;
+        self.s.space()?;
+        self.word_space("in")?;
         self.print_expr(coll)
     }
 
     fn print_path(&mut self,
                   path: &ast::Path,
                   colons_before_params: bool,
-                  depth: usize)
+                  depth: usize,
+                  defaults_to_global: bool)
                   -> io::Result<()>
     {
-        try!(self.maybe_print_comment(path.span.lo));
+        self.maybe_print_comment(path.span.lo)?;
 
-        let mut first = !path.global;
-        for segment in &path.segments[..path.segments.len()-depth] {
-            if first {
-                first = false
-            } else {
-                try!(word(&mut self.s, "::"))
+        let mut segments = path.segments[..path.segments.len()-depth].iter();
+        if defaults_to_global && path.is_global() {
+            segments.next();
+        }
+        for (i, segment) in segments.enumerate() {
+            if i > 0 {
+                self.s.word("::")?
             }
+            self.print_path_segment(segment, colons_before_params)?;
+        }
 
-            try!(self.print_ident(segment.identifier));
+        Ok(())
+    }
 
-            try!(self.print_path_parameters(&segment.parameters, colons_before_params));
+    fn print_path_segment(&mut self,
+                          segment: &ast::PathSegment,
+                          colons_before_params: bool)
+                          -> io::Result<()>
+    {
+        if segment.identifier.name != keywords::CrateRoot.name() &&
+           segment.identifier.name != keywords::DollarCrate.name() {
+            self.print_ident(segment.identifier)?;
+            if let Some(ref parameters) = segment.parameters {
+                self.print_path_parameters(parameters, colons_before_params)?;
+            }
         }
-
         Ok(())
     }
 
@@ -2063,19 +2369,22 @@ impl<'a> State<'a> {
                    colons_before_params: bool)
                    -> io::Result<()>
     {
-        try!(word(&mut self.s, "<"));
-        try!(self.print_type(&qself.ty));
+        self.s.word("<")?;
+        self.print_type(&qself.ty)?;
         if qself.position > 0 {
-            try!(space(&mut self.s));
-            try!(self.word_space("as"));
+            self.s.space()?;
+            self.word_space("as")?;
             let depth = path.segments.len() - qself.position;
-            try!(self.print_path(&path, false, depth));
+            self.print_path(path, false, depth, false)?;
         }
-        try!(word(&mut self.s, ">"));
-        try!(word(&mut self.s, "::"));
+        self.s.word(">")?;
+        self.s.word("::")?;
         let item_segment = path.segments.last().unwrap();
-        try!(self.print_ident(item_segment.identifier));
-        self.print_path_parameters(&item_segment.parameters, colons_before_params)
+        self.print_ident(item_segment.identifier)?;
+        match item_segment.parameters {
+            Some(ref parameters) => self.print_path_parameters(parameters, colons_before_params),
+            None => Ok(()),
+        }
     }
 
     fn print_path_parameters(&mut self,
@@ -2083,67 +2392,60 @@ impl<'a> State<'a> {
                              colons_before_params: bool)
                              -> io::Result<()>
     {
-        if parameters.is_empty() {
-            return Ok(());
-        }
-
         if colons_before_params {
-            try!(word(&mut self.s, "::"))
+            self.s.word("::")?
         }
 
         match *parameters {
-            ast::AngleBracketedParameters(ref data) => {
-                try!(word(&mut self.s, "<"));
+            ast::PathParameters::AngleBracketed(ref data) => {
+                self.s.word("<")?;
 
                 let mut comma = false;
                 for lifetime in &data.lifetimes {
                     if comma {
-                        try!(self.word_space(","))
+                        self.word_space(",")?
                     }
-                    try!(self.print_lifetime(lifetime));
+                    self.print_lifetime(lifetime)?;
                     comma = true;
                 }
 
                 if !data.types.is_empty() {
                     if comma {
-                        try!(self.word_space(","))
+                        self.word_space(",")?
                     }
-                    try!(self.commasep(
+                    self.commasep(
                         Inconsistent,
                         &data.types,
-                        |s, ty| s.print_type(&**ty)));
+                        |s, ty| s.print_type(ty))?;
                         comma = true;
                 }
 
-                for binding in &*data.bindings {
+                for binding in data.bindings.iter() {
                     if comma {
-                        try!(self.word_space(","))
+                        self.word_space(",")?
                     }
-                    try!(self.print_ident(binding.ident));
-                    try!(space(&mut self.s));
-                    try!(self.word_space("="));
-                    try!(self.print_type(&*binding.ty));
+                    self.print_ident(binding.ident)?;
+                    self.s.space()?;
+                    self.word_space("=")?;
+                    self.print_type(&binding.ty)?;
                     comma = true;
                 }
 
-                try!(word(&mut self.s, ">"))
+                self.s.word(">")?
             }
 
-            ast::ParenthesizedParameters(ref data) => {
-                try!(word(&mut self.s, "("));
-                try!(self.commasep(
+            ast::PathParameters::Parenthesized(ref data) => {
+                self.s.word("(")?;
+                self.commasep(
                     Inconsistent,
                     &data.inputs,
-                    |s, ty| s.print_type(&**ty)));
-                try!(word(&mut self.s, ")"));
-
-                match data.output {
-                    None => { }
-                    Some(ref ty) => {
-                        try!(self.space_if_not_bol());
-                        try!(self.word_space("->"));
-                        try!(self.print_type(&**ty));
-                    }
+                    |s, ty| s.print_type(ty))?;
+                self.s.word(")")?;
+
+                if let Some(ref ty) = data.output {
+                    self.space_if_not_bol()?;
+                    self.word_space("->")?;
+                    self.print_type(ty)?;
                 }
             }
         }
@@ -2152,120 +2454,136 @@ impl<'a> State<'a> {
     }
 
     pub fn print_pat(&mut self, pat: &ast::Pat) -> io::Result<()> {
-        try!(self.maybe_print_comment(pat.span.lo));
-        try!(self.ann.pre(self, NodePat(pat)));
+        self.maybe_print_comment(pat.span.lo)?;
+        self.ann.pre(self, NodePat(pat))?;
         /* Pat isn't normalized, but the beauty of it
          is that it doesn't matter */
         match pat.node {
-            ast::PatWild(ast::PatWildSingle) => try!(word(&mut self.s, "_")),
-            ast::PatWild(ast::PatWildMulti) => try!(word(&mut self.s, "..")),
-            ast::PatIdent(binding_mode, ref path1, ref sub) => {
+            PatKind::Wild => self.s.word("_")?,
+            PatKind::Ident(binding_mode, ref path1, ref sub) => {
                 match binding_mode {
-                    ast::BindByRef(mutbl) => {
-                        try!(self.word_nbsp("ref"));
-                        try!(self.print_mutability(mutbl));
+                    ast::BindingMode::ByRef(mutbl) => {
+                        self.word_nbsp("ref")?;
+                        self.print_mutability(mutbl)?;
                     }
-                    ast::BindByValue(ast::MutImmutable) => {}
-                    ast::BindByValue(ast::MutMutable) => {
-                        try!(self.word_nbsp("mut"));
+                    ast::BindingMode::ByValue(ast::Mutability::Immutable) => {}
+                    ast::BindingMode::ByValue(ast::Mutability::Mutable) => {
+                        self.word_nbsp("mut")?;
                     }
                 }
-                try!(self.print_ident(path1.node));
-                match *sub {
-                    Some(ref p) => {
-                        try!(word(&mut self.s, "@"));
-                        try!(self.print_pat(&**p));
+                self.print_ident(path1.node)?;
+                if let Some(ref p) = *sub {
+                    self.s.word("@")?;
+                    self.print_pat(p)?;
+                }
+            }
+            PatKind::TupleStruct(ref path, ref elts, ddpos) => {
+                self.print_path(path, true, 0, false)?;
+                self.popen()?;
+                if let Some(ddpos) = ddpos {
+                    self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p))?;
+                    if ddpos != 0 {
+                        self.word_space(",")?;
                     }
-                    None => ()
-                }
-            }
-            ast::PatEnum(ref path, ref args_) => {
-                try!(self.print_path(path, true, 0));
-                match *args_ {
-                    None => try!(word(&mut self.s, "(..)")),
-                    Some(ref args) => {
-                        if !args.is_empty() {
-                            try!(self.popen());
-                            try!(self.commasep(Inconsistent, &args[..],
-                                              |s, p| s.print_pat(&**p)));
-                            try!(self.pclose());
-                        }
+                    self.s.word("..")?;
+                    if ddpos != elts.len() {
+                        self.s.word(",")?;
+                        self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(p))?;
                     }
+                } else {
+                    self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p))?;
                 }
+                self.pclose()?;
+            }
+            PatKind::Path(None, ref path) => {
+                self.print_path(path, true, 0, false)?;
             }
-            ast::PatStruct(ref path, ref fields, etc) => {
-                try!(self.print_path(path, true, 0));
-                try!(self.nbsp());
-                try!(self.word_space("{"));
-                try!(self.commasep_cmnt(
+            PatKind::Path(Some(ref qself), ref path) => {
+                self.print_qpath(path, qself, false)?;
+            }
+            PatKind::Struct(ref path, ref fields, etc) => {
+                self.print_path(path, true, 0, false)?;
+                self.nbsp()?;
+                self.word_space("{")?;
+                self.commasep_cmnt(
                     Consistent, &fields[..],
                     |s, f| {
-                        try!(s.cbox(indent_unit));
+                        s.cbox(INDENT_UNIT)?;
                         if !f.node.is_shorthand {
-                            try!(s.print_ident(f.node.ident));
-                            try!(s.word_nbsp(":"));
+                            s.print_ident(f.node.ident)?;
+                            s.word_nbsp(":")?;
                         }
-                        try!(s.print_pat(&*f.node.pat));
+                        s.print_pat(&f.node.pat)?;
                         s.end()
                     },
-                    |f| f.node.pat.span));
+                    |f| f.node.pat.span)?;
                 if etc {
-                    if fields.len() != 0 { try!(self.word_space(",")); }
-                    try!(word(&mut self.s, ".."));
-                }
-                try!(space(&mut self.s));
-                try!(word(&mut self.s, "}"));
-            }
-            ast::PatTup(ref elts) => {
-                try!(self.popen());
-                try!(self.commasep(Inconsistent,
-                                   &elts[..],
-                                   |s, p| s.print_pat(&**p)));
-                if elts.len() == 1 {
-                    try!(word(&mut self.s, ","));
+                    if !fields.is_empty() { self.word_space(",")?; }
+                    self.s.word("..")?;
+                }
+                self.s.space()?;
+                self.s.word("}")?;
+            }
+            PatKind::Tuple(ref elts, ddpos) => {
+                self.popen()?;
+                if let Some(ddpos) = ddpos {
+                    self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p))?;
+                    if ddpos != 0 {
+                        self.word_space(",")?;
+                    }
+                    self.s.word("..")?;
+                    if ddpos != elts.len() {
+                        self.s.word(",")?;
+                        self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(p))?;
+                    }
+                } else {
+                    self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p))?;
+                    if elts.len() == 1 {
+                        self.s.word(",")?;
+                    }
                 }
-                try!(self.pclose());
+                self.pclose()?;
             }
-            ast::PatBox(ref inner) => {
-                try!(word(&mut self.s, "box "));
-                try!(self.print_pat(&**inner));
+            PatKind::Box(ref inner) => {
+                self.s.word("box ")?;
+                self.print_pat(inner)?;
             }
-            ast::PatRegion(ref inner, mutbl) => {
-                try!(word(&mut self.s, "&"));
-                if mutbl == ast::MutMutable {
-                    try!(word(&mut self.s, "mut "));
+            PatKind::Ref(ref inner, mutbl) => {
+                self.s.word("&")?;
+                if mutbl == ast::Mutability::Mutable {
+                    self.s.word("mut ")?;
                 }
-                try!(self.print_pat(&**inner));
+                self.print_pat(inner)?;
             }
-            ast::PatLit(ref e) => try!(self.print_expr(&**e)),
-            ast::PatRange(ref begin, ref end) => {
-                try!(self.print_expr(&**begin));
-                try!(space(&mut self.s));
-                try!(word(&mut self.s, "..."));
-                try!(self.print_expr(&**end));
+            PatKind::Lit(ref e) => self.print_expr(&**e)?,
+            PatKind::Range(ref begin, ref end, ref end_kind) => {
+                self.print_expr(begin)?;
+                self.s.space()?;
+                match *end_kind {
+                    RangeEnd::Included => self.s.word("...")?,
+                    RangeEnd::Excluded => self.s.word("..")?,
+                }
+                self.print_expr(end)?;
             }
-            ast::PatVec(ref before, ref slice, ref after) => {
-                try!(word(&mut self.s, "["));
-                try!(self.commasep(Inconsistent,
+            PatKind::Slice(ref before, ref slice, ref after) => {
+                self.s.word("[")?;
+                self.commasep(Inconsistent,
                                    &before[..],
-                                   |s, p| s.print_pat(&**p)));
+                                   |s, p| s.print_pat(p))?;
                 if let Some(ref p) = *slice {
-                    if !before.is_empty() { try!(self.word_space(",")); }
-                    try!(self.print_pat(&**p));
-                    match **p {
-                        ast::Pat { node: ast::PatWild(ast::PatWildMulti), .. } => {
-                            // this case is handled by print_pat
-                        }
-                        _ => try!(word(&mut self.s, "..")),
+                    if !before.is_empty() { self.word_space(",")?; }
+                    if p.node != PatKind::Wild {
+                        self.print_pat(p)?;
                     }
-                    if !after.is_empty() { try!(self.word_space(",")); }
+                    self.s.word("..")?;
+                    if !after.is_empty() { self.word_space(",")?; }
                 }
-                try!(self.commasep(Inconsistent,
+                self.commasep(Inconsistent,
                                    &after[..],
-                                   |s, p| s.print_pat(&**p)));
-                try!(word(&mut self.s, "]"));
+                                   |s, p| s.print_pat(p))?;
+                self.s.word("]")?;
             }
-            ast::PatMac(ref m) => try!(self.print_mac(m, token::Paren)),
+            PatKind::Mac(ref m) => self.print_mac(m, token::Paren)?,
         }
         self.ann.post(self, NodePat(pat))
     }
@@ -2274,134 +2592,97 @@ impl<'a> State<'a> {
         // I have no idea why this check is necessary, but here it
         // is :(
         if arm.attrs.is_empty() {
-            try!(space(&mut self.s));
+            self.s.space()?;
         }
-        try!(self.cbox(indent_unit));
-        try!(self.ibox(0));
-        try!(self.print_outer_attributes(&arm.attrs));
+        self.cbox(INDENT_UNIT)?;
+        self.ibox(0)?;
+        self.maybe_print_comment(arm.pats[0].span.lo)?;
+        self.print_outer_attributes(&arm.attrs)?;
         let mut first = true;
         for p in &arm.pats {
             if first {
                 first = false;
             } else {
-                try!(space(&mut self.s));
-                try!(self.word_space("|"));
+                self.s.space()?;
+                self.word_space("|")?;
             }
-            try!(self.print_pat(&**p));
+            self.print_pat(p)?;
         }
-        try!(space(&mut self.s));
+        self.s.space()?;
         if let Some(ref e) = arm.guard {
-            try!(self.word_space("if"));
-            try!(self.print_expr(&**e));
-            try!(space(&mut self.s));
+            self.word_space("if")?;
+            self.print_expr(e)?;
+            self.s.space()?;
         }
-        try!(self.word_space("=>"));
+        self.word_space("=>")?;
 
         match arm.body.node {
-            ast::ExprBlock(ref blk) => {
+            ast::ExprKind::Block(ref blk) => {
                 // the block will close the pattern's ibox
-                try!(self.print_block_unclosed_indent(&**blk, indent_unit));
+                self.print_block_unclosed_indent(blk, INDENT_UNIT)?;
 
                 // If it is a user-provided unsafe block, print a comma after it
-                if let ast::UnsafeBlock(ast::UserProvided) = blk.rules {
-                    try!(word(&mut self.s, ","));
+                if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
+                    self.s.word(",")?;
                 }
             }
             _ => {
-                try!(self.end()); // close the ibox for the pattern
-                try!(self.print_expr(&*arm.body));
-                try!(word(&mut self.s, ","));
+                self.end()?; // close the ibox for the pattern
+                self.print_expr(&arm.body)?;
+                self.s.word(",")?;
             }
         }
         self.end() // close enclosing cbox
     }
 
-    // Returns whether it printed anything
-    fn print_explicit_self(&mut self,
-                           explicit_self: &ast::ExplicitSelf_,
-                           mutbl: ast::Mutability) -> io::Result<bool> {
-        try!(self.print_mutability(mutbl));
-        match *explicit_self {
-            ast::SelfStatic => { return Ok(false); }
-            ast::SelfValue(_) => {
-                try!(word(&mut self.s, "self"));
+    fn print_explicit_self(&mut self, explicit_self: &ast::ExplicitSelf) -> io::Result<()> {
+        match explicit_self.node {
+            SelfKind::Value(m) => {
+                self.print_mutability(m)?;
+                self.s.word("self")
             }
-            ast::SelfRegion(ref lt, m, _) => {
-                try!(word(&mut self.s, "&"));
-                try!(self.print_opt_lifetime(lt));
-                try!(self.print_mutability(m));
-                try!(word(&mut self.s, "self"));
+            SelfKind::Region(ref lt, m) => {
+                self.s.word("&")?;
+                self.print_opt_lifetime(lt)?;
+                self.print_mutability(m)?;
+                self.s.word("self")
             }
-            ast::SelfExplicit(ref typ, _) => {
-                try!(word(&mut self.s, "self"));
-                try!(self.word_space(":"));
-                try!(self.print_type(&**typ));
+            SelfKind::Explicit(ref typ, m) => {
+                self.print_mutability(m)?;
+                self.s.word("self")?;
+                self.word_space(":")?;
+                self.print_type(typ)
             }
         }
-        return Ok(true);
     }
 
     pub fn print_fn(&mut self,
                     decl: &ast::FnDecl,
                     unsafety: ast::Unsafety,
+                    constness: ast::Constness,
                     abi: abi::Abi,
                     name: Option<ast::Ident>,
                     generics: &ast::Generics,
-                    opt_explicit_self: Option<&ast::ExplicitSelf_>,
-                    vis: ast::Visibility) -> io::Result<()> {
-        try!(self.print_fn_header_info(unsafety, abi, vis));
+                    vis: &ast::Visibility) -> io::Result<()> {
+        self.print_fn_header_info(unsafety, constness, abi, vis)?;
 
         if let Some(name) = name {
-            try!(self.nbsp());
-            try!(self.print_ident(name));
+            self.nbsp()?;
+            self.print_ident(name)?;
         }
-        try!(self.print_generics(generics));
-        try!(self.print_fn_args_and_ret(decl, opt_explicit_self));
+        self.print_generics(generics)?;
+        self.print_fn_args_and_ret(decl)?;
         self.print_where_clause(&generics.where_clause)
     }
 
-    pub fn print_fn_args(&mut self, decl: &ast::FnDecl,
-                         opt_explicit_self: Option<&ast::ExplicitSelf_>)
-        -> io::Result<()> {
-        // It is unfortunate to duplicate the commasep logic, but we want the
-        // self type and the args all in the same box.
-        try!(self.rbox(0, Inconsistent));
-        let mut first = true;
-        if let Some(explicit_self) = opt_explicit_self {
-            let m = match explicit_self {
-                &ast::SelfStatic => ast::MutImmutable,
-                _ => match decl.inputs[0].pat.node {
-                    ast::PatIdent(ast::BindByValue(m), _, _) => m,
-                    _ => ast::MutImmutable
-                }
-            };
-            first = !try!(self.print_explicit_self(explicit_self, m));
-        }
-
-        // HACK(eddyb) ignore the separately printed self argument.
-        let args = if first {
-            &decl.inputs[..]
-        } else {
-            &decl.inputs[1..]
-        };
-
-        for arg in args {
-            if first { first = false; } else { try!(self.word_space(",")); }
-            try!(self.print_arg(arg));
-        }
-
-        self.end()
-    }
-
-    pub fn print_fn_args_and_ret(&mut self, decl: &ast::FnDecl,
-                                 opt_explicit_self: Option<&ast::ExplicitSelf_>)
+    pub fn print_fn_args_and_ret(&mut self, decl: &ast::FnDecl)
         -> io::Result<()> {
-        try!(self.popen());
-        try!(self.print_fn_args(decl, opt_explicit_self));
+        self.popen()?;
+        self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, false))?;
         if decl.variadic {
-            try!(word(&mut self.s, ", ..."));
+            self.s.word(", ...")?;
         }
-        try!(self.pclose());
+        self.pclose()?;
 
         self.print_fn_output(decl)
     }
@@ -2410,34 +2691,30 @@ impl<'a> State<'a> {
             &mut self,
             decl: &ast::FnDecl)
             -> io::Result<()> {
-        try!(word(&mut self.s, "|"));
-        try!(self.print_fn_args(decl, None));
-        try!(word(&mut self.s, "|"));
+        self.s.word("|")?;
+        self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, true))?;
+        self.s.word("|")?;
 
-        if let ast::DefaultReturn(..) = decl.output {
+        if let ast::FunctionRetTy::Default(..) = decl.output {
             return Ok(());
         }
 
-        try!(self.space_if_not_bol());
-        try!(self.word_space("->"));
+        self.space_if_not_bol()?;
+        self.word_space("->")?;
         match decl.output {
-            ast::Return(ref ty) => {
-                try!(self.print_type(&**ty));
+            ast::FunctionRetTy::Ty(ref ty) => {
+                self.print_type(ty)?;
                 self.maybe_print_comment(ty.span.lo)
             }
-            ast::DefaultReturn(..) => unreachable!(),
-            ast::NoReturn(span) => {
-                try!(self.word_nbsp("!"));
-                self.maybe_print_comment(span.lo)
-            }
+            ast::FunctionRetTy::Default(..) => unreachable!(),
         }
     }
 
-    pub fn print_capture_clause(&mut self, capture_clause: ast::CaptureClause)
+    pub fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy)
                                 -> io::Result<()> {
         match capture_clause {
-            ast::CaptureByValue => self.word_space("move"),
-            ast::CaptureByRef => Ok(()),
+            ast::CaptureBy::Value => self.word_space("move"),
+            ast::CaptureBy::Ref => Ok(()),
         }
     }
 
@@ -2446,28 +2723,28 @@ impl<'a> State<'a> {
                         bounds: &[ast::TyParamBound])
                         -> io::Result<()> {
         if !bounds.is_empty() {
-            try!(word(&mut self.s, prefix));
+            self.s.word(prefix)?;
             let mut first = true;
             for bound in bounds {
-                try!(self.nbsp());
+                self.nbsp()?;
                 if first {
                     first = false;
                 } else {
-                    try!(self.word_space("+"));
+                    self.word_space("+")?;
                 }
 
-                try!(match *bound {
+                (match *bound {
                     TraitTyParamBound(ref tref, TraitBoundModifier::None) => {
                         self.print_poly_trait_ref(tref)
                     }
                     TraitTyParamBound(ref tref, TraitBoundModifier::Maybe) => {
-                        try!(word(&mut self.s, "?"));
+                        self.s.word("?")?;
                         self.print_poly_trait_ref(tref)
                     }
                     RegionTyParamBound(ref lt) => {
                         self.print_lifetime(lt)
                     }
-                })
+                })?
             }
             Ok(())
         } else {
@@ -2479,19 +2756,23 @@ impl<'a> State<'a> {
                           lifetime: &ast::Lifetime)
                           -> io::Result<()>
     {
-        self.print_name(lifetime.name)
+        self.print_name(lifetime.ident.name)
     }
 
-    pub fn print_lifetime_def(&mut self,
-                              lifetime: &ast::LifetimeDef)
-                              -> io::Result<()>
+    pub fn print_lifetime_bounds(&mut self,
+                                 lifetime: &ast::Lifetime,
+                                 bounds: &[ast::Lifetime])
+                                 -> io::Result<()>
     {
-        try!(self.print_lifetime(&lifetime.lifetime));
-        let mut sep = ":";
-        for v in &lifetime.bounds {
-            try!(word(&mut self.s, sep));
-            try!(self.print_lifetime(v));
-            sep = "+";
+        self.print_lifetime(lifetime)?;
+        if !bounds.is_empty() {
+            self.s.word(": ")?;
+            for (i, bound) in bounds.iter().enumerate() {
+                if i != 0 {
+                    self.s.word(" + ")?;
+                }
+                self.print_lifetime(bound)?;
+            }
         }
         Ok(())
     }
@@ -2505,36 +2786,38 @@ impl<'a> State<'a> {
             return Ok(());
         }
 
-        try!(word(&mut self.s, "<"));
+        self.s.word("<")?;
 
         let mut ints = Vec::new();
         for i in 0..total {
             ints.push(i);
         }
 
-        try!(self.commasep(Inconsistent, &ints[..], |s, &idx| {
+        self.commasep(Inconsistent, &ints[..], |s, &idx| {
             if idx < generics.lifetimes.len() {
-                let lifetime = &generics.lifetimes[idx];
-                s.print_lifetime_def(lifetime)
+                let lifetime_def = &generics.lifetimes[idx];
+                s.print_outer_attributes_inline(&lifetime_def.attrs)?;
+                s.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds)
             } else {
                 let idx = idx - generics.lifetimes.len();
                 let param = &generics.ty_params[idx];
                 s.print_ty_param(param)
             }
-        }));
+        })?;
 
-        try!(word(&mut self.s, ">"));
+        self.s.word(">")?;
         Ok(())
     }
 
     pub fn print_ty_param(&mut self, param: &ast::TyParam) -> io::Result<()> {
-        try!(self.print_ident(param.ident));
-        try!(self.print_bounds(":", &param.bounds));
+        self.print_outer_attributes_inline(&param.attrs)?;
+        self.print_ident(param.ident)?;
+        self.print_bounds(":", &param.bounds)?;
         match param.default {
             Some(ref default) => {
-                try!(space(&mut self.s));
-                try!(self.word_space("="));
-                self.print_type(&**default)
+                self.s.space()?;
+                self.word_space("=")?;
+                self.print_type(default)
             }
             _ => Ok(())
         }
@@ -2542,46 +2825,39 @@ impl<'a> State<'a> {
 
     pub fn print_where_clause(&mut self, where_clause: &ast::WhereClause)
                               -> io::Result<()> {
-        if where_clause.predicates.len() == 0 {
+        if where_clause.predicates.is_empty() {
             return Ok(())
         }
 
-        try!(space(&mut self.s));
-        try!(self.word_space("where"));
+        self.s.space()?;
+        self.word_space("where")?;
 
         for (i, predicate) in where_clause.predicates.iter().enumerate() {
             if i != 0 {
-                try!(self.word_space(","));
+                self.word_space(",")?;
             }
 
-            match predicate {
-                &ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ref bound_lifetimes,
-                                                                              ref bounded_ty,
-                                                                              ref bounds,
-                                                                              ..}) => {
-                    try!(self.print_formal_lifetime_list(bound_lifetimes));
-                    try!(self.print_type(&**bounded_ty));
-                    try!(self.print_bounds(":", bounds));
+            match *predicate {
+                ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ref bound_lifetimes,
+                                                                             ref bounded_ty,
+                                                                             ref bounds,
+                                                                             ..}) => {
+                    self.print_formal_lifetime_list(bound_lifetimes)?;
+                    self.print_type(bounded_ty)?;
+                    self.print_bounds(":", bounds)?;
                 }
-                &ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
-                                                                                ref bounds,
-                                                                                ..}) => {
-                    try!(self.print_lifetime(lifetime));
-                    try!(word(&mut self.s, ":"));
-
-                    for (i, bound) in bounds.iter().enumerate() {
-                        try!(self.print_lifetime(bound));
-
-                        if i != 0 {
-                            try!(word(&mut self.s, ":"));
-                        }
-                    }
+                ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
+                                                                               ref bounds,
+                                                                               ..}) => {
+                    self.print_lifetime_bounds(lifetime, bounds)?;
                 }
-                &ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ref path, ref ty, ..}) => {
-                    try!(self.print_path(path, false, 0));
-                    try!(space(&mut self.s));
-                    try!(self.word_space("="));
-                    try!(self.print_type(&**ty));
+                ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ref lhs_ty,
+                                                                       ref rhs_ty,
+                                                                       ..}) => {
+                    self.print_type(lhs_ty)?;
+                    self.s.space()?;
+                    self.word_space("=")?;
+                    self.print_type(rhs_ty)?;
                 }
             }
         }
@@ -2589,68 +2865,43 @@ impl<'a> State<'a> {
         Ok(())
     }
 
-    pub fn print_meta_item(&mut self, item: &ast::MetaItem) -> io::Result<()> {
-        try!(self.ibox(indent_unit));
-        match item.node {
-            ast::MetaWord(ref name) => {
-                try!(word(&mut self.s, &name));
-            }
-            ast::MetaNameValue(ref name, ref value) => {
-                try!(self.word_space(&name[..]));
-                try!(self.word_space("="));
-                try!(self.print_literal(value));
-            }
-            ast::MetaList(ref name, ref items) => {
-                try!(word(&mut self.s, &name));
-                try!(self.popen());
-                try!(self.commasep(Consistent,
-                                   &items[..],
-                                   |s, i| s.print_meta_item(&**i)));
-                try!(self.pclose());
-            }
-        }
-        self.end()
-    }
-
     pub fn print_view_path(&mut self, vp: &ast::ViewPath) -> io::Result<()> {
         match vp.node {
             ast::ViewPathSimple(ident, ref path) => {
-                try!(self.print_path(path, false, 0));
+                self.print_path(path, false, 0, true)?;
 
-                // FIXME(#6993) can't compare identifiers directly here
                 if path.segments.last().unwrap().identifier.name !=
                         ident.name {
-                    try!(space(&mut self.s));
-                    try!(self.word_space("as"));
-                    try!(self.print_ident(ident));
+                    self.s.space()?;
+                    self.word_space("as")?;
+                    self.print_ident(ident)?;
                 }
 
                 Ok(())
             }
 
             ast::ViewPathGlob(ref path) => {
-                try!(self.print_path(path, false, 0));
-                word(&mut self.s, "::*")
+                self.print_path(path, false, 0, true)?;
+                self.s.word("::*")
             }
 
             ast::ViewPathList(ref path, ref idents) => {
                 if path.segments.is_empty() {
-                    try!(word(&mut self.s, "{"));
+                    self.s.word("{")?;
                 } else {
-                    try!(self.print_path(path, false, 0));
-                    try!(word(&mut self.s, "::{"));
-                }
-                try!(self.commasep(Inconsistent, &idents[..], |s, w| {
-                    match w.node {
-                        ast::PathListIdent { name, .. } => {
-                            s.print_ident(name)
-                        },
-                        ast::PathListMod { .. } => {
-                            word(&mut s.s, "self")
-                        }
+                    self.print_path(path, false, 0, true)?;
+                    self.s.word("::{")?;
+                }
+                self.commasep(Inconsistent, &idents[..], |s, w| {
+                    s.print_ident(w.node.name)?;
+                    if let Some(ident) = w.node.rename {
+                        s.s.space()?;
+                        s.word_space("as")?;
+                        s.print_ident(ident)?;
                     }
-                }));
-                word(&mut self.s, "}")
+                    Ok(())
+                })?;
+                self.s.word("}")
             }
         }
     }
@@ -2658,58 +2909,58 @@ impl<'a> State<'a> {
     pub fn print_mutability(&mut self,
                             mutbl: ast::Mutability) -> io::Result<()> {
         match mutbl {
-            ast::MutMutable => self.word_nbsp("mut"),
-            ast::MutImmutable => Ok(()),
+            ast::Mutability::Mutable => self.word_nbsp("mut"),
+            ast::Mutability::Immutable => Ok(()),
         }
     }
 
     pub fn print_mt(&mut self, mt: &ast::MutTy) -> io::Result<()> {
-        try!(self.print_mutability(mt.mutbl));
-        self.print_type(&*mt.ty)
+        self.print_mutability(mt.mutbl)?;
+        self.print_type(&mt.ty)
     }
 
-    pub fn print_arg(&mut self, input: &ast::Arg) -> io::Result<()> {
-        try!(self.ibox(indent_unit));
+    pub fn print_arg(&mut self, input: &ast::Arg, is_closure: bool) -> io::Result<()> {
+        self.ibox(INDENT_UNIT)?;
         match input.ty.node {
-            ast::TyInfer => try!(self.print_pat(&*input.pat)),
+            ast::TyKind::Infer if is_closure => self.print_pat(&input.pat)?,
             _ => {
-                match input.pat.node {
-                    ast::PatIdent(_, ref path1, _) if
-                        path1.node.name ==
-                            parse::token::special_idents::invalid.name => {
-                        // Do nothing.
-                    }
-                    _ => {
-                        try!(self.print_pat(&*input.pat));
-                        try!(word(&mut self.s, ":"));
-                        try!(space(&mut self.s));
+                if let Some(eself) = input.to_self() {
+                    self.print_explicit_self(&eself)?;
+                } else {
+                    let invalid = if let PatKind::Ident(_, ident, _) = input.pat.node {
+                        ident.node.name == keywords::Invalid.name()
+                    } else {
+                        false
+                    };
+                    if !invalid {
+                        self.print_pat(&input.pat)?;
+                        self.s.word(":")?;
+                        self.s.space()?;
                     }
+                    self.print_type(&input.ty)?;
                 }
-                try!(self.print_type(&*input.ty));
             }
         }
         self.end()
     }
 
     pub fn print_fn_output(&mut self, decl: &ast::FnDecl) -> io::Result<()> {
-        if let ast::DefaultReturn(..) = decl.output {
+        if let ast::FunctionRetTy::Default(..) = decl.output {
             return Ok(());
         }
 
-        try!(self.space_if_not_bol());
-        try!(self.ibox(indent_unit));
-        try!(self.word_space("->"));
+        self.space_if_not_bol()?;
+        self.ibox(INDENT_UNIT)?;
+        self.word_space("->")?;
         match decl.output {
-            ast::NoReturn(_) =>
-                try!(self.word_nbsp("!")),
-            ast::DefaultReturn(..) => unreachable!(),
-            ast::Return(ref ty) =>
-                try!(self.print_type(&**ty))
+            ast::FunctionRetTy::Default(..) => unreachable!(),
+            ast::FunctionRetTy::Ty(ref ty) =>
+                self.print_type(ty)?
         }
-        try!(self.end());
+        self.end()?;
 
         match decl.output {
-            ast::Return(ref output) => self.maybe_print_comment(output.span.lo),
+            ast::FunctionRetTy::Ty(ref output) => self.maybe_print_comment(output.span.lo),
             _ => Ok(())
         }
     }
@@ -2719,49 +2970,47 @@ impl<'a> State<'a> {
                        unsafety: ast::Unsafety,
                        decl: &ast::FnDecl,
                        name: Option<ast::Ident>,
-                       generics: &ast::Generics,
-                       opt_explicit_self: Option<&ast::ExplicitSelf_>)
+                       generics: &ast::Generics)
                        -> io::Result<()> {
-        try!(self.ibox(indent_unit));
-        if generics.lifetimes.len() > 0 || generics.ty_params.len() > 0 {
-            try!(word(&mut self.s, "for"));
-            try!(self.print_generics(generics));
+        self.ibox(INDENT_UNIT)?;
+        if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() {
+            self.s.word("for")?;
+            self.print_generics(generics)?;
         }
         let generics = ast::Generics {
             lifetimes: Vec::new(),
-            ty_params: OwnedSlice::empty(),
+            ty_params: Vec::new(),
             where_clause: ast::WhereClause {
                 id: ast::DUMMY_NODE_ID,
                 predicates: Vec::new(),
             },
+            span: syntax_pos::DUMMY_SP,
         };
-        try!(self.print_fn(decl, unsafety, abi, name,
-                           &generics, opt_explicit_self,
-                           ast::Inherited));
+        self.print_fn(decl,
+                      unsafety,
+                      ast::Constness::NotConst,
+                      abi,
+                      name,
+                      &generics,
+                      &ast::Visibility::Inherited)?;
         self.end()
     }
 
-    pub fn maybe_print_trailing_comment(&mut self, span: codemap::Span,
+    pub fn maybe_print_trailing_comment(&mut self, span: syntax_pos::Span,
                                         next_pos: Option<BytePos>)
         -> io::Result<()> {
         let cm = match self.cm {
             Some(cm) => cm,
             _ => return Ok(())
         };
-        match self.next_comment() {
-            Some(ref cmnt) => {
-                if (*cmnt).style != comments::Trailing { return Ok(()) }
-                let span_line = cm.lookup_char_pos(span.hi);
-                let comment_line = cm.lookup_char_pos((*cmnt).pos);
-                let mut next = (*cmnt).pos + BytePos(1);
-                match next_pos { None => (), Some(p) => next = p }
-                if span.hi < (*cmnt).pos && (*cmnt).pos < next &&
-                    span_line.line == comment_line.line {
-                        try!(self.print_comment(cmnt));
-                        self.cur_cmnt_and_lit.cur_cmnt += 1;
-                    }
+        if let Some(ref cmnt) = self.next_comment() {
+            if cmnt.style != comments::Trailing { return Ok(()) }
+            let span_line = cm.lookup_char_pos(span.hi);
+            let comment_line = cm.lookup_char_pos(cmnt.pos);
+            let next = next_pos.unwrap_or(cmnt.pos + BytePos(1));
+            if span.hi < cmnt.pos && cmnt.pos < next && span_line.line == comment_line.line {
+                self.print_comment(cmnt)?;
             }
-            _ => ()
         }
         Ok(())
     }
@@ -2770,202 +3019,21 @@ impl<'a> State<'a> {
         // If there aren't any remaining comments, then we need to manually
         // make sure there is a line break at the end.
         if self.next_comment().is_none() {
-            try!(hardbreak(&mut self.s));
-        }
-        loop {
-            match self.next_comment() {
-                Some(ref cmnt) => {
-                    try!(self.print_comment(cmnt));
-                    self.cur_cmnt_and_lit.cur_cmnt += 1;
-                }
-                _ => break
-            }
-        }
-        Ok(())
-    }
-
-    pub fn print_literal(&mut self, lit: &ast::Lit) -> io::Result<()> {
-        try!(self.maybe_print_comment(lit.span.lo));
-        match self.next_lit(lit.span.lo) {
-            Some(ref ltrl) => {
-                return word(&mut self.s, &(*ltrl).lit);
-            }
-            _ => ()
-        }
-        match lit.node {
-            ast::LitStr(ref st, style) => self.print_string(&st, style),
-            ast::LitByte(byte) => {
-                let mut res = String::from_str("b'");
-                res.extend(ascii::escape_default(byte).map(|c| c as char));
-                res.push('\'');
-                word(&mut self.s, &res[..])
-            }
-            ast::LitChar(ch) => {
-                let mut res = String::from_str("'");
-                res.extend(ch.escape_default());
-                res.push('\'');
-                word(&mut self.s, &res[..])
-            }
-            ast::LitInt(i, t) => {
-                match t {
-                    ast::SignedIntLit(st, ast::Plus) => {
-                        word(&mut self.s,
-                             &ast_util::int_ty_to_string(st, Some(i as i64)))
-                    }
-                    ast::SignedIntLit(st, ast::Minus) => {
-                        let istr = ast_util::int_ty_to_string(st, Some(-(i as i64)));
-                        word(&mut self.s,
-                             &format!("-{}", istr))
-                    }
-                    ast::UnsignedIntLit(ut) => {
-                        word(&mut self.s, &ast_util::uint_ty_to_string(ut, Some(i)))
-                    }
-                    ast::UnsuffixedIntLit(ast::Plus) => {
-                        word(&mut self.s, &format!("{}", i))
-                    }
-                    ast::UnsuffixedIntLit(ast::Minus) => {
-                        word(&mut self.s, &format!("-{}", i))
-                    }
-                }
-            }
-            ast::LitFloat(ref f, t) => {
-                word(&mut self.s,
-                     &format!(
-                         "{}{}",
-                         &f,
-                         &ast_util::float_ty_to_string(t)))
-            }
-            ast::LitFloatUnsuffixed(ref f) => word(&mut self.s, &f[..]),
-            ast::LitBool(val) => {
-                if val { word(&mut self.s, "true") } else { word(&mut self.s, "false") }
-            }
-            ast::LitBinary(ref v) => {
-                let mut escaped: String = String::new();
-                for &ch in &**v {
-                    escaped.extend(ascii::escape_default(ch)
-                                         .map(|c| c as char));
-                }
-                word(&mut self.s, &format!("b\"{}\"", escaped))
-            }
-        }
-    }
-
-    pub fn next_lit(&mut self, pos: BytePos) -> Option<comments::Literal> {
-        match self.literals {
-            Some(ref lits) => {
-                while self.cur_cmnt_and_lit.cur_lit < lits.len() {
-                    let ltrl = (*lits)[self.cur_cmnt_and_lit.cur_lit].clone();
-                    if ltrl.pos > pos { return None; }
-                    self.cur_cmnt_and_lit.cur_lit += 1;
-                    if ltrl.pos == pos { return Some(ltrl); }
-                }
-                None
-            }
-            _ => None
+            self.s.hardbreak()?;
         }
-    }
-
-    pub fn maybe_print_comment(&mut self, pos: BytePos) -> io::Result<()> {
-        loop {
-            match self.next_comment() {
-                Some(ref cmnt) => {
-                    if (*cmnt).pos < pos {
-                        try!(self.print_comment(cmnt));
-                        self.cur_cmnt_and_lit.cur_cmnt += 1;
-                    } else { break; }
-                }
-                _ => break
-            }
+        while let Some(ref cmnt) = self.next_comment() {
+            self.print_comment(cmnt)?;
         }
         Ok(())
     }
 
-    pub fn print_comment(&mut self,
-                         cmnt: &comments::Comment) -> io::Result<()> {
-        match cmnt.style {
-            comments::Mixed => {
-                assert_eq!(cmnt.lines.len(), 1);
-                try!(zerobreak(&mut self.s));
-                try!(word(&mut self.s, &cmnt.lines[0]));
-                zerobreak(&mut self.s)
-            }
-            comments::Isolated => {
-                try!(self.hardbreak_if_not_bol());
-                for line in &cmnt.lines {
-                    // Don't print empty lines because they will end up as trailing
-                    // whitespace
-                    if !line.is_empty() {
-                        try!(word(&mut self.s, &line[..]));
-                    }
-                    try!(hardbreak(&mut self.s));
-                }
-                Ok(())
-            }
-            comments::Trailing => {
-                try!(word(&mut self.s, " "));
-                if cmnt.lines.len() == 1 {
-                    try!(word(&mut self.s, &cmnt.lines[0]));
-                    hardbreak(&mut self.s)
-                } else {
-                    try!(self.ibox(0));
-                    for line in &cmnt.lines {
-                        if !line.is_empty() {
-                            try!(word(&mut self.s, &line[..]));
-                        }
-                        try!(hardbreak(&mut self.s));
-                    }
-                    self.end()
-                }
-            }
-            comments::BlankLine => {
-                // We need to do at least one, possibly two hardbreaks.
-                let is_semi = match self.s.last_token() {
-                    pp::Token::String(s, _) => ";" == s,
-                    _ => false
-                };
-                if is_semi || self.is_begin() || self.is_end() {
-                    try!(hardbreak(&mut self.s));
-                }
-                hardbreak(&mut self.s)
-            }
-        }
-    }
-
-    pub fn print_string(&mut self, st: &str,
-                        style: ast::StrStyle) -> io::Result<()> {
-        let st = match style {
-            ast::CookedStr => {
-                (format!("\"{}\"", st.escape_default()))
-            }
-            ast::RawStr(n) => {
-                (format!("r{delim}\"{string}\"{delim}",
-                         delim=repeat("#", n),
-                         string=st))
-            }
-        };
-        word(&mut self.s, &st[..])
-    }
-
-    pub fn next_comment(&mut self) -> Option<comments::Comment> {
-        match self.comments {
-            Some(ref cmnts) => {
-                if self.cur_cmnt_and_lit.cur_cmnt < cmnts.len() {
-                    Some(cmnts[self.cur_cmnt_and_lit.cur_cmnt].clone())
-                } else {
-                    None
-                }
-            }
-            _ => None
-        }
-    }
-
     pub fn print_opt_abi_and_extern_if_nondefault(&mut self,
-                                                  opt_abi: Option<abi::Abi>)
+                                                  opt_abi: Option<Abi>)
         -> io::Result<()> {
         match opt_abi {
-            Some(abi::Rust) => Ok(()),
+            Some(Abi::Rust) => Ok(()),
             Some(abi) => {
-                try!(self.word_nbsp("extern"));
+                self.word_nbsp("extern")?;
                 self.word_nbsp(&abi.to_string())
             }
             None => Ok(())
@@ -2973,10 +3041,10 @@ impl<'a> State<'a> {
     }
 
     pub fn print_extern_opt_abi(&mut self,
-                                opt_abi: Option<abi::Abi>) -> io::Result<()> {
+                                opt_abi: Option<Abi>) -> io::Result<()> {
         match opt_abi {
             Some(abi) => {
-                try!(self.word_nbsp("extern"));
+                self.word_nbsp("extern")?;
                 self.word_nbsp(&abi.to_string())
             }
             None => Ok(())
@@ -2985,17 +3053,24 @@ impl<'a> State<'a> {
 
     pub fn print_fn_header_info(&mut self,
                                 unsafety: ast::Unsafety,
-                                abi: abi::Abi,
-                                vis: ast::Visibility) -> io::Result<()> {
-        try!(word(&mut self.s, &visibility_qualified(vis, "")));
-        try!(self.print_unsafety(unsafety));
+                                constness: ast::Constness,
+                                abi: Abi,
+                                vis: &ast::Visibility) -> io::Result<()> {
+        self.s.word(&visibility_qualified(vis, ""))?;
+
+        match constness {
+            ast::Constness::NotConst => {}
+            ast::Constness::Const => self.word_nbsp("const")?
+        }
 
-        if abi != abi::Rust {
-            try!(self.word_nbsp("extern"));
-            try!(self.word_nbsp(&abi.to_string()));
+        self.print_unsafety(unsafety)?;
+
+        if abi != Abi::Rust {
+            self.word_nbsp("extern")?;
+            self.word_nbsp(&abi.to_string())?;
         }
 
-        word(&mut self.s, "fn")
+        self.s.word("fn")
     }
 
     pub fn print_unsafety(&mut self, s: ast::Unsafety) -> io::Result<()> {
@@ -3009,52 +3084,42 @@ impl<'a> State<'a> {
 fn repeat(s: &str, n: usize) -> String { iter::repeat(s).take(n).collect() }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::*;
 
     use ast;
-    use ast_util;
     use codemap;
-    use parse::token;
+    use syntax_pos;
 
     #[test]
     fn test_fun_to_string() {
-        let abba_ident = token::str_to_ident("abba");
+        let abba_ident = ast::Ident::from_str("abba");
 
         let decl = ast::FnDecl {
             inputs: Vec::new(),
-            output: ast::DefaultReturn(codemap::DUMMY_SP),
+            output: ast::FunctionRetTy::Default(syntax_pos::DUMMY_SP),
             variadic: false
         };
-        let generics = ast_util::empty_generics();
-        assert_eq!(fun_to_string(&decl, ast::Unsafety::Normal, abba_ident,
-                               None, &generics),
+        let generics = ast::Generics::default();
+        assert_eq!(fun_to_string(&decl, ast::Unsafety::Normal,
+                                 ast::Constness::NotConst,
+                                 abba_ident, &generics),
                    "fn abba()");
     }
 
     #[test]
     fn test_variant_to_string() {
-        let ident = token::str_to_ident("principal_skinner");
+        let ident = ast::Ident::from_str("principal_skinner");
 
-        let var = codemap::respan(codemap::DUMMY_SP, ast::Variant_ {
+        let var = codemap::respan(syntax_pos::DUMMY_SP, ast::Variant_ {
             name: ident,
             attrs: Vec::new(),
             // making this up as I go.... ?
-            kind: ast::TupleVariantKind(Vec::new()),
-            id: 0,
+            data: ast::VariantData::Unit(ast::DUMMY_NODE_ID),
             disr_expr: None,
-            vis: ast::Public,
         });
 
         let varstr = variant_to_string(&var);
-        assert_eq!(varstr, "pub principal_skinner");
-    }
-
-    #[test]
-    fn test_signed_int_to_string() {
-        let pos_int = ast::LitInt(42, ast::SignedIntLit(ast::TyI32, ast::Plus));
-        let neg_int = ast::LitInt((!42 + 1) as u64, ast::SignedIntLit(ast::TyI32, ast::Minus));
-        assert_eq!(format!("-{}", lit_to_string(&codemap::dummy_spanned(pos_int))),
-                   lit_to_string(&codemap::dummy_spanned(neg_int)));
+        assert_eq!(varstr, "principal_skinner");
     }
 }