about summary refs log tree commit diff
path: root/src/librustc
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-04-06 05:04:15 -0700
committerbors <bors@rust-lang.org>2016-04-06 05:04:15 -0700
commit943ec3bdfc9ba28e94b6d00a2b53fb2cd8b21655 (patch)
tree30b2cefa099bea233f2e257116c5ec99589aaa63 /src/librustc
parent772c600d4d6f39daa6d07d1a60ee0df3d3426978 (diff)
parent552af51ffb9f4ae08a7ee3bf27b0e8309006ca6f (diff)
Auto merge of #32767 - Manishearth:breakingbatch, r=eddyb
Batch up all plugin breaking changes

https://github.com/rust-lang/rust/pull/32688 already landed so we should get this into the same nightly.

cc https://github.com/rust-lang/rust/issues/31645
Diffstat (limited to 'src/librustc')
-rw-r--r--src/librustc/Cargo.toml1
-rw-r--r--src/librustc/cfg/construct.rs8
-rw-r--r--src/librustc/cfg/graphviz.rs2
-rw-r--r--src/librustc/cfg/mod.rs2
-rw-r--r--src/librustc/dep_graph/mod.rs6
-rw-r--r--src/librustc/hir/check_attr.rs (renamed from src/librustc/front/check_attr.rs)0
-rw-r--r--src/librustc/hir/def.rs (renamed from src/librustc/middle/def.rs)4
-rw-r--r--src/librustc/hir/def_id.rs (renamed from src/librustc/middle/def_id.rs)0
-rw-r--r--src/librustc/hir/fold.rs1143
-rw-r--r--src/librustc/hir/intravisit.rs1070
-rw-r--r--src/librustc/hir/lowering.rs2148
-rw-r--r--src/librustc/hir/map/blocks.rs (renamed from src/librustc/front/map/blocks.rs)8
-rw-r--r--src/librustc/hir/map/collector.rs (renamed from src/librustc/front/map/collector.rs)12
-rw-r--r--src/librustc/hir/map/definitions.rs (renamed from src/librustc/front/map/definitions.rs)2
-rw-r--r--src/librustc/hir/map/mod.rs (renamed from src/librustc/front/map/mod.rs)248
-rw-r--r--src/librustc/hir/mod.rs1652
-rw-r--r--src/librustc/hir/pat_util.rs (renamed from src/librustc/middle/pat_util.rs)27
-rw-r--r--src/librustc/hir/print.rs2413
-rw-r--r--src/librustc/hir/svh.rs439
-rw-r--r--src/librustc/infer/error_reporting.rs20
-rw-r--r--src/librustc/infer/mod.rs4
-rw-r--r--src/librustc/infer/type_variable.rs2
-rw-r--r--src/librustc/lib.rs17
-rw-r--r--src/librustc/lint/context.rs49
-rw-r--r--src/librustc/lint/mod.rs4
-rw-r--r--src/librustc/middle/astconv_util.rs4
-rw-r--r--src/librustc/middle/const_val.rs2
-rw-r--r--src/librustc/middle/cstore.rs21
-rw-r--r--src/librustc/middle/dataflow.rs7
-rw-r--r--src/librustc/middle/dead.rs12
-rw-r--r--src/librustc/middle/effect.rs8
-rw-r--r--src/librustc/middle/entry.rs8
-rw-r--r--src/librustc/middle/expr_use_visitor.rs14
-rw-r--r--src/librustc/middle/intrinsicck.rs8
-rw-r--r--src/librustc/middle/lang_items.rs8
-rw-r--r--src/librustc/middle/liveness.rs16
-rw-r--r--src/librustc/middle/mem_categorization.rs10
-rw-r--r--src/librustc/middle/reachable.rs12
-rw-r--r--src/librustc/middle/region.rs11
-rw-r--r--src/librustc/middle/resolve_lifetime.rs10
-rw-r--r--src/librustc/middle/stability.rs12
-rw-r--r--src/librustc/middle/weak_lang_items.rs6
-rw-r--r--src/librustc/mir/repr.rs4
-rw-r--r--src/librustc/mir/tcx.rs2
-rw-r--r--src/librustc/mir/visit.rs2
-rw-r--r--src/librustc/traits/coherence.rs2
-rw-r--r--src/librustc/traits/error_reporting.rs2
-rw-r--r--src/librustc/traits/mod.rs2
-rw-r--r--src/librustc/traits/object_safety.rs2
-rw-r--r--src/librustc/traits/project.rs2
-rw-r--r--src/librustc/traits/select.rs4
-rw-r--r--src/librustc/traits/specialize/mod.rs2
-rw-r--r--src/librustc/traits/specialize/specialization_graph.rs2
-rw-r--r--src/librustc/traits/util.rs2
-rw-r--r--src/librustc/ty/adjustment.rs2
-rw-r--r--src/librustc/ty/contents.rs2
-rw-r--r--src/librustc/ty/context.rs10
-rw-r--r--src/librustc/ty/error.rs4
-rw-r--r--src/librustc/ty/fast_reject.rs2
-rw-r--r--src/librustc/ty/item_path.rs9
-rw-r--r--src/librustc/ty/maps.rs2
-rw-r--r--src/librustc/ty/mod.rs73
-rw-r--r--src/librustc/ty/relate.rs4
-rw-r--r--src/librustc/ty/structural_impls.rs2
-rw-r--r--src/librustc/ty/sty.rs4
-rw-r--r--src/librustc/ty/subst.rs2
-rw-r--r--src/librustc/ty/trait_def.rs4
-rw-r--r--src/librustc/ty/util.rs8
-rw-r--r--src/librustc/ty/wf.rs2
-rw-r--r--src/librustc/util/common.rs6
-rw-r--r--src/librustc/util/nodemap.rs2
-rw-r--r--src/librustc/util/ppaux.rs4
72 files changed, 9119 insertions, 501 deletions
diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml
index e7aaaef45a1..d77268219fc 100644
--- a/src/librustc/Cargo.toml
+++ b/src/librustc/Cargo.toml
@@ -19,6 +19,5 @@ rustc_back = { path = "../librustc_back" }
 rustc_bitflags = { path = "../librustc_bitflags" }
 rustc_const_math = { path = "../librustc_const_math" }
 rustc_data_structures = { path = "../librustc_data_structures" }
-rustc_front = { path = "../librustc_front" }
 serialize = { path = "../libserialize" }
 syntax = { path = "../libsyntax" }
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index cd1e3b5f30e..70497491355 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -10,13 +10,13 @@
 
 use rustc_data_structures::graph;
 use cfg::*;
-use middle::def::Def;
-use middle::pat_util;
+use hir::def::Def;
+use hir::pat_util;
 use ty::{self, TyCtxt};
 use syntax::ast;
 use syntax::ptr::P;
 
-use rustc_front::hir::{self, PatKind};
+use hir::{self, PatKind};
 
 struct CFGBuilder<'a, 'tcx: 'a> {
     tcx: &'a TyCtxt<'tcx>,
@@ -257,7 +257,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
                 self.match_(expr.id, &discr, &arms, pred)
             }
 
-            hir::ExprBinary(op, ref l, ref r) if ::rustc_front::util::lazy_binop(op.node) => {
+            hir::ExprBinary(op, ref l, ref r) if op.node.is_lazy() => {
                 //
                 //     [pred]
                 //       |
diff --git a/src/librustc/cfg/graphviz.rs b/src/librustc/cfg/graphviz.rs
index c867ec94b25..c651baae282 100644
--- a/src/librustc/cfg/graphviz.rs
+++ b/src/librustc/cfg/graphviz.rs
@@ -17,7 +17,7 @@ use graphviz::IntoCow;
 
 use syntax::ast;
 
-use front::map as ast_map;
+use hir::map as ast_map;
 use cfg;
 
 pub type Node<'a> = (cfg::CFGIndex, &'a cfg::CFGNode);
diff --git a/src/librustc/cfg/mod.rs b/src/librustc/cfg/mod.rs
index 8df4dc5fce5..e86bf6ebc58 100644
--- a/src/librustc/cfg/mod.rs
+++ b/src/librustc/cfg/mod.rs
@@ -14,7 +14,7 @@
 use rustc_data_structures::graph;
 use ty::TyCtxt;
 use syntax::ast;
-use rustc_front::hir;
+use hir;
 
 mod construct;
 pub mod graphviz;
diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs
index 731c33868df..55ec56a4bbe 100644
--- a/src/librustc/dep_graph/mod.rs
+++ b/src/librustc/dep_graph/mod.rs
@@ -9,11 +9,11 @@
 // except according to those terms.
 
 use self::thread::{DepGraphThreadData, DepMessage};
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use syntax::ast::NodeId;
 use ty::TyCtxt;
-use rustc_front::hir;
-use rustc_front::intravisit::Visitor;
+use hir;
+use hir::intravisit::Visitor;
 use std::rc::Rc;
 
 mod dep_tracking_map;
diff --git a/src/librustc/front/check_attr.rs b/src/librustc/hir/check_attr.rs
index 085acc198d1..085acc198d1 100644
--- a/src/librustc/front/check_attr.rs
+++ b/src/librustc/hir/check_attr.rs
diff --git a/src/librustc/middle/def.rs b/src/librustc/hir/def.rs
index e6ea000936c..c270a4413bf 100644
--- a/src/librustc/middle/def.rs
+++ b/src/librustc/hir/def.rs
@@ -8,11 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use ty::subst::ParamSpace;
 use util::nodemap::NodeMap;
 use syntax::ast;
-use rustc_front::hir;
+use hir;
 
 #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum Def {
diff --git a/src/librustc/middle/def_id.rs b/src/librustc/hir/def_id.rs
index a3b83ec5be4..a3b83ec5be4 100644
--- a/src/librustc/middle/def_id.rs
+++ b/src/librustc/hir/def_id.rs
diff --git a/src/librustc/hir/fold.rs b/src/librustc/hir/fold.rs
new file mode 100644
index 00000000000..a6ff7164885
--- /dev/null
+++ b/src/librustc/hir/fold.rs
@@ -0,0 +1,1143 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! A Folder represents an HIR->HIR fold; it accepts a HIR piece,
+//! and returns a piece of the same type.
+
+use hir::*;
+use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, Attribute, Attribute_, MetaItem};
+use syntax::ast::MetaItemKind;
+use syntax::attr::ThinAttributesExt;
+use hir;
+use syntax::codemap::{respan, Span, Spanned};
+use syntax::ptr::P;
+use syntax::parse::token;
+use syntax::util::move_map::MoveMap;
+
+pub trait Folder : Sized {
+    // Any additions to this trait should happen in form
+    // of a call to a public `noop_*` function that only calls
+    // out to the folder again, not other `noop_*` functions.
+    //
+    // This is a necessary API workaround to the problem of not
+    // being able to call out to the super default method
+    // in an overridden default method.
+
+    fn fold_crate(&mut self, c: Crate) -> Crate {
+        noop_fold_crate(c, self)
+    }
+
+    fn fold_meta_items(&mut self, meta_items: HirVec<P<MetaItem>>) -> HirVec<P<MetaItem>> {
+        noop_fold_meta_items(meta_items, self)
+    }
+
+    fn fold_meta_item(&mut self, meta_item: P<MetaItem>) -> P<MetaItem> {
+        noop_fold_meta_item(meta_item, self)
+    }
+
+    fn fold_view_path(&mut self, view_path: P<ViewPath>) -> P<ViewPath> {
+        noop_fold_view_path(view_path, self)
+    }
+
+    fn fold_foreign_item(&mut self, ni: ForeignItem) -> ForeignItem {
+        noop_fold_foreign_item(ni, self)
+    }
+
+    fn fold_item(&mut self, i: Item) -> Item {
+        noop_fold_item(i, self)
+    }
+
+    fn fold_item_id(&mut self, i: ItemId) -> ItemId {
+        noop_fold_item_id(i, self)
+    }
+
+    fn fold_struct_field(&mut self, sf: StructField) -> StructField {
+        noop_fold_struct_field(sf, self)
+    }
+
+    fn fold_item_underscore(&mut self, i: Item_) -> Item_ {
+        noop_fold_item_underscore(i, self)
+    }
+
+    fn fold_trait_item(&mut self, i: TraitItem) -> TraitItem {
+        noop_fold_trait_item(i, self)
+    }
+
+    fn fold_impl_item(&mut self, i: ImplItem) -> ImplItem {
+        noop_fold_impl_item(i, self)
+    }
+
+    fn fold_fn_decl(&mut self, d: P<FnDecl>) -> P<FnDecl> {
+        noop_fold_fn_decl(d, self)
+    }
+
+    fn fold_block(&mut self, b: P<Block>) -> P<Block> {
+        noop_fold_block(b, self)
+    }
+
+    fn fold_stmt(&mut self, s: Stmt) -> Stmt {
+        noop_fold_stmt(s, self)
+    }
+
+    fn fold_arm(&mut self, a: Arm) -> Arm {
+        noop_fold_arm(a, self)
+    }
+
+    fn fold_pat(&mut self, p: P<Pat>) -> P<Pat> {
+        noop_fold_pat(p, self)
+    }
+
+    fn fold_decl(&mut self, d: P<Decl>) -> P<Decl> {
+        noop_fold_decl(d, self)
+    }
+
+    fn fold_expr(&mut self, e: P<Expr>) -> P<Expr> {
+        e.map(|e| noop_fold_expr(e, self))
+    }
+
+    fn fold_ty(&mut self, t: P<Ty>) -> P<Ty> {
+        noop_fold_ty(t, self)
+    }
+
+    fn fold_ty_binding(&mut self, t: TypeBinding) -> TypeBinding {
+        noop_fold_ty_binding(t, self)
+    }
+
+    fn fold_mod(&mut self, m: Mod) -> Mod {
+        noop_fold_mod(m, self)
+    }
+
+    fn fold_foreign_mod(&mut self, nm: ForeignMod) -> ForeignMod {
+        noop_fold_foreign_mod(nm, self)
+    }
+
+    fn fold_variant(&mut self, v: Variant) -> Variant {
+        noop_fold_variant(v, self)
+    }
+
+    fn fold_name(&mut self, n: Name) -> Name {
+        noop_fold_name(n, self)
+    }
+
+    fn fold_ident(&mut self, i: Ident) -> Ident {
+        noop_fold_ident(i, self)
+    }
+
+    fn fold_usize(&mut self, i: usize) -> usize {
+        noop_fold_usize(i, self)
+    }
+
+    fn fold_path(&mut self, p: Path) -> Path {
+        noop_fold_path(p, self)
+    }
+
+    fn fold_path_parameters(&mut self, p: PathParameters) -> PathParameters {
+        noop_fold_path_parameters(p, self)
+    }
+
+    fn fold_angle_bracketed_parameter_data(&mut self,
+                                           p: AngleBracketedParameterData)
+                                           -> AngleBracketedParameterData {
+        noop_fold_angle_bracketed_parameter_data(p, self)
+    }
+
+    fn fold_parenthesized_parameter_data(&mut self,
+                                         p: ParenthesizedParameterData)
+                                         -> ParenthesizedParameterData {
+        noop_fold_parenthesized_parameter_data(p, self)
+    }
+
+    fn fold_local(&mut self, l: P<Local>) -> P<Local> {
+        noop_fold_local(l, self)
+    }
+
+    fn fold_explicit_self(&mut self, es: ExplicitSelf) -> ExplicitSelf {
+        noop_fold_explicit_self(es, self)
+    }
+
+    fn fold_explicit_self_underscore(&mut self, es: ExplicitSelf_) -> ExplicitSelf_ {
+        noop_fold_explicit_self_underscore(es, self)
+    }
+
+    fn fold_lifetime(&mut self, l: Lifetime) -> Lifetime {
+        noop_fold_lifetime(l, self)
+    }
+
+    fn fold_lifetime_def(&mut self, l: LifetimeDef) -> LifetimeDef {
+        noop_fold_lifetime_def(l, self)
+    }
+
+    fn fold_attribute(&mut self, at: Attribute) -> Option<Attribute> {
+        noop_fold_attribute(at, self)
+    }
+
+    fn fold_arg(&mut self, a: Arg) -> Arg {
+        noop_fold_arg(a, self)
+    }
+
+    fn fold_generics(&mut self, generics: Generics) -> Generics {
+        noop_fold_generics(generics, self)
+    }
+
+    fn fold_trait_ref(&mut self, p: TraitRef) -> TraitRef {
+        noop_fold_trait_ref(p, self)
+    }
+
+    fn fold_poly_trait_ref(&mut self, p: PolyTraitRef) -> PolyTraitRef {
+        noop_fold_poly_trait_ref(p, self)
+    }
+
+    fn fold_variant_data(&mut self, vdata: VariantData) -> VariantData {
+        noop_fold_variant_data(vdata, self)
+    }
+
+    fn fold_lifetimes(&mut self, lts: HirVec<Lifetime>) -> HirVec<Lifetime> {
+        noop_fold_lifetimes(lts, self)
+    }
+
+    fn fold_lifetime_defs(&mut self, lts: HirVec<LifetimeDef>) -> HirVec<LifetimeDef> {
+        noop_fold_lifetime_defs(lts, self)
+    }
+
+    fn fold_ty_param(&mut self, tp: TyParam) -> TyParam {
+        noop_fold_ty_param(tp, self)
+    }
+
+    fn fold_ty_params(&mut self, tps: HirVec<TyParam>) -> HirVec<TyParam> {
+        noop_fold_ty_params(tps, self)
+    }
+
+    fn fold_opt_lifetime(&mut self, o_lt: Option<Lifetime>) -> Option<Lifetime> {
+        noop_fold_opt_lifetime(o_lt, self)
+    }
+
+    fn fold_opt_bounds(&mut self,
+                       b: Option<TyParamBounds>)
+                       -> Option<TyParamBounds> {
+        noop_fold_opt_bounds(b, self)
+    }
+
+    fn fold_bounds(&mut self, b: TyParamBounds) -> TyParamBounds {
+        noop_fold_bounds(b, self)
+    }
+
+    fn fold_ty_param_bound(&mut self, tpb: TyParamBound) -> TyParamBound {
+        noop_fold_ty_param_bound(tpb, self)
+    }
+
+    fn fold_mt(&mut self, mt: MutTy) -> MutTy {
+        noop_fold_mt(mt, self)
+    }
+
+    fn fold_field(&mut self, field: Field) -> Field {
+        noop_fold_field(field, self)
+    }
+
+    fn fold_where_clause(&mut self, where_clause: WhereClause) -> WhereClause {
+        noop_fold_where_clause(where_clause, self)
+    }
+
+    fn fold_where_predicate(&mut self, where_predicate: WherePredicate) -> WherePredicate {
+        noop_fold_where_predicate(where_predicate, self)
+    }
+
+    /// called for the `id` on each declaration
+    fn new_id(&mut self, i: NodeId) -> NodeId {
+        i
+    }
+
+    /// called for ids that are references (e.g., ItemDef)
+    fn map_id(&mut self, i: NodeId) -> NodeId {
+        i
+    }
+
+    fn new_span(&mut self, sp: Span) -> Span {
+        sp
+    }
+}
+
+pub fn noop_fold_meta_items<T: Folder>(meta_items: HirVec<P<MetaItem>>,
+                                       fld: &mut T)
+                                       -> HirVec<P<MetaItem>> {
+    meta_items.move_map(|x| fld.fold_meta_item(x))
+}
+
+pub fn noop_fold_view_path<T: Folder>(view_path: P<ViewPath>, fld: &mut T) -> P<ViewPath> {
+    view_path.map(|Spanned { node, span }| {
+        Spanned {
+            node: match node {
+                ViewPathSimple(name, path) => {
+                    ViewPathSimple(name, fld.fold_path(path))
+                }
+                ViewPathGlob(path) => {
+                    ViewPathGlob(fld.fold_path(path))
+                }
+                ViewPathList(path, path_list_idents) => {
+                    ViewPathList(fld.fold_path(path),
+                                 path_list_idents.move_map(|path_list_ident| {
+                                     Spanned {
+                                         node: match path_list_ident.node {
+                                             PathListIdent { id, name, rename } => PathListIdent {
+                                                 id: fld.new_id(id),
+                                                 name: name,
+                                                 rename: rename,
+                                             },
+                                             PathListMod { id, rename } => PathListMod {
+                                                 id: fld.new_id(id),
+                                                 rename: rename,
+                                             },
+                                         },
+                                         span: fld.new_span(path_list_ident.span),
+                                     }
+                                 }))
+                }
+            },
+            span: fld.new_span(span),
+        }
+    })
+}
+
+pub fn fold_attrs<T: Folder>(attrs: HirVec<Attribute>, fld: &mut T) -> HirVec<Attribute> {
+    attrs.move_flat_map(|x| fld.fold_attribute(x))
+}
+
+pub fn noop_fold_arm<T: Folder>(Arm { attrs, pats, guard, body }: Arm, fld: &mut T) -> Arm {
+    Arm {
+        attrs: fold_attrs(attrs, fld),
+        pats: pats.move_map(|x| fld.fold_pat(x)),
+        guard: guard.map(|x| fld.fold_expr(x)),
+        body: fld.fold_expr(body),
+    }
+}
+
+pub fn noop_fold_decl<T: Folder>(d: P<Decl>, fld: &mut T) -> P<Decl> {
+    d.map(|Spanned { node, span }| {
+        match node {
+            DeclLocal(l) => Spanned {
+                node: DeclLocal(fld.fold_local(l)),
+                span: fld.new_span(span),
+            },
+            DeclItem(it) => Spanned {
+                node: DeclItem(fld.fold_item_id(it)),
+                span: fld.new_span(span),
+            },
+        }
+    })
+}
+
+pub fn noop_fold_ty_binding<T: Folder>(b: TypeBinding, fld: &mut T) -> TypeBinding {
+    TypeBinding {
+        id: fld.new_id(b.id),
+        name: b.name,
+        ty: fld.fold_ty(b.ty),
+        span: fld.new_span(b.span),
+    }
+}
+
+pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
+    t.map(|Ty { id, node, span }| {
+        Ty {
+            id: fld.new_id(id),
+            node: match node {
+                TyInfer => node,
+                TyVec(ty) => TyVec(fld.fold_ty(ty)),
+                TyPtr(mt) => TyPtr(fld.fold_mt(mt)),
+                TyRptr(region, mt) => {
+                    TyRptr(fld.fold_opt_lifetime(region), fld.fold_mt(mt))
+                }
+                TyBareFn(f) => {
+                    TyBareFn(f.map(|BareFnTy { lifetimes, unsafety, abi, decl }| {
+                        BareFnTy {
+                            lifetimes: fld.fold_lifetime_defs(lifetimes),
+                            unsafety: unsafety,
+                            abi: abi,
+                            decl: fld.fold_fn_decl(decl),
+                        }
+                    }))
+                }
+                TyTup(tys) => TyTup(tys.move_map(|ty| fld.fold_ty(ty))),
+                TyPath(qself, path) => {
+                    let qself = qself.map(|QSelf { ty, position }| {
+                        QSelf {
+                            ty: fld.fold_ty(ty),
+                            position: position,
+                        }
+                    });
+                    TyPath(qself, fld.fold_path(path))
+                }
+                TyObjectSum(ty, bounds) => {
+                    TyObjectSum(fld.fold_ty(ty), fld.fold_bounds(bounds))
+                }
+                TyFixedLengthVec(ty, e) => {
+                    TyFixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e))
+                }
+                TyTypeof(expr) => {
+                    TyTypeof(fld.fold_expr(expr))
+                }
+                TyPolyTraitRef(bounds) => {
+                    TyPolyTraitRef(bounds.move_map(|b| fld.fold_ty_param_bound(b)))
+                }
+            },
+            span: fld.new_span(span),
+        }
+    })
+}
+
+pub fn noop_fold_foreign_mod<T: Folder>(ForeignMod { abi, items }: ForeignMod,
+                                        fld: &mut T)
+                                        -> ForeignMod {
+    ForeignMod {
+        abi: abi,
+        items: items.move_map(|x| fld.fold_foreign_item(x)),
+    }
+}
+
+pub fn noop_fold_variant<T: Folder>(v: Variant, fld: &mut T) -> Variant {
+    Spanned {
+        node: Variant_ {
+            name: v.node.name,
+            attrs: fold_attrs(v.node.attrs, fld),
+            data: fld.fold_variant_data(v.node.data),
+            disr_expr: v.node.disr_expr.map(|e| fld.fold_expr(e)),
+        },
+        span: fld.new_span(v.span),
+    }
+}
+
+pub fn noop_fold_name<T: Folder>(n: Name, _: &mut T) -> Name {
+    n
+}
+
+pub fn noop_fold_ident<T: Folder>(i: Ident, _: &mut T) -> Ident {
+    i
+}
+
+pub fn noop_fold_usize<T: Folder>(i: usize, _: &mut T) -> usize {
+    i
+}
+
+pub fn noop_fold_path<T: Folder>(Path { global, segments, span }: Path, fld: &mut T) -> Path {
+    Path {
+        global: global,
+        segments: segments.move_map(|PathSegment { identifier, parameters }| {
+            PathSegment {
+                identifier: fld.fold_ident(identifier),
+                parameters: fld.fold_path_parameters(parameters),
+            }
+        }),
+        span: fld.new_span(span),
+    }
+}
+
+pub fn noop_fold_path_parameters<T: Folder>(path_parameters: PathParameters,
+                                            fld: &mut T)
+                                            -> PathParameters {
+    match path_parameters {
+        AngleBracketedParameters(data) =>
+            AngleBracketedParameters(fld.fold_angle_bracketed_parameter_data(data)),
+        ParenthesizedParameters(data) =>
+            ParenthesizedParameters(fld.fold_parenthesized_parameter_data(data)),
+    }
+}
+
+pub fn noop_fold_angle_bracketed_parameter_data<T: Folder>(data: AngleBracketedParameterData,
+                                                           fld: &mut T)
+                                                           -> AngleBracketedParameterData {
+    let AngleBracketedParameterData { lifetimes, types, bindings } = data;
+    AngleBracketedParameterData {
+        lifetimes: fld.fold_lifetimes(lifetimes),
+        types: types.move_map(|ty| fld.fold_ty(ty)),
+        bindings: bindings.move_map(|b| fld.fold_ty_binding(b)),
+    }
+}
+
+pub fn noop_fold_parenthesized_parameter_data<T: Folder>(data: ParenthesizedParameterData,
+                                                         fld: &mut T)
+                                                         -> ParenthesizedParameterData {
+    let ParenthesizedParameterData { inputs, output, span } = data;
+    ParenthesizedParameterData {
+        inputs: inputs.move_map(|ty| fld.fold_ty(ty)),
+        output: output.map(|ty| fld.fold_ty(ty)),
+        span: fld.new_span(span),
+    }
+}
+
+pub fn noop_fold_local<T: Folder>(l: P<Local>, fld: &mut T) -> P<Local> {
+    l.map(|Local { id, pat, ty, init, span, attrs }| {
+        Local {
+            id: fld.new_id(id),
+            ty: ty.map(|t| fld.fold_ty(t)),
+            pat: fld.fold_pat(pat),
+            init: init.map(|e| fld.fold_expr(e)),
+            span: fld.new_span(span),
+            attrs: attrs.map_thin_attrs(|attrs| fold_attrs(attrs.into(), fld).into()),
+        }
+    })
+}
+
+pub fn noop_fold_attribute<T: Folder>(at: Attribute, fld: &mut T) -> Option<Attribute> {
+    let Spanned {node: Attribute_ {id, style, value, is_sugared_doc}, span} = at;
+    Some(Spanned {
+        node: Attribute_ {
+            id: id,
+            style: style,
+            value: fld.fold_meta_item(value),
+            is_sugared_doc: is_sugared_doc,
+        },
+        span: fld.new_span(span),
+    })
+}
+
+pub fn noop_fold_explicit_self_underscore<T: Folder>(es: ExplicitSelf_,
+                                                     fld: &mut T)
+                                                     -> ExplicitSelf_ {
+    match es {
+        SelfStatic | SelfValue(_) => es,
+        SelfRegion(lifetime, m, name) => {
+            SelfRegion(fld.fold_opt_lifetime(lifetime), m, name)
+        }
+        SelfExplicit(typ, name) => {
+            SelfExplicit(fld.fold_ty(typ), name)
+        }
+    }
+}
+
+pub fn noop_fold_explicit_self<T: Folder>(Spanned { span, node }: ExplicitSelf,
+                                          fld: &mut T)
+                                          -> ExplicitSelf {
+    Spanned {
+        node: fld.fold_explicit_self_underscore(node),
+        span: fld.new_span(span),
+    }
+}
+
+pub fn noop_fold_meta_item<T: Folder>(mi: P<MetaItem>, fld: &mut T) -> P<MetaItem> {
+    mi.map(|Spanned { node, span }| {
+        Spanned {
+            node: match node {
+                MetaItemKind::Word(id) => MetaItemKind::Word(id),
+                MetaItemKind::List(id, mis) => {
+                    MetaItemKind::List(id, mis.move_map(|e| fld.fold_meta_item(e)))
+                }
+                MetaItemKind::NameValue(id, s) => MetaItemKind::NameValue(id, s),
+            },
+            span: fld.new_span(span),
+        }
+    })
+}
+
+pub fn noop_fold_arg<T: Folder>(Arg { id, pat, ty }: Arg, fld: &mut T) -> Arg {
+    Arg {
+        id: fld.new_id(id),
+        pat: fld.fold_pat(pat),
+        ty: fld.fold_ty(ty),
+    }
+}
+
+pub fn noop_fold_fn_decl<T: Folder>(decl: P<FnDecl>, fld: &mut T) -> P<FnDecl> {
+    decl.map(|FnDecl { inputs, output, variadic }| {
+        FnDecl {
+            inputs: inputs.move_map(|x| fld.fold_arg(x)),
+            output: match output {
+                Return(ty) => Return(fld.fold_ty(ty)),
+                DefaultReturn(span) => DefaultReturn(span),
+                NoReturn(span) => NoReturn(span),
+            },
+            variadic: variadic,
+        }
+    })
+}
+
+pub fn noop_fold_ty_param_bound<T>(tpb: TyParamBound, fld: &mut T) -> TyParamBound
+    where T: Folder
+{
+    match tpb {
+        TraitTyParamBound(ty, modifier) => TraitTyParamBound(fld.fold_poly_trait_ref(ty), modifier),
+        RegionTyParamBound(lifetime) => RegionTyParamBound(fld.fold_lifetime(lifetime)),
+    }
+}
+
+pub fn noop_fold_ty_param<T: Folder>(tp: TyParam, fld: &mut T) -> TyParam {
+    let TyParam {id, name, bounds, default, span} = tp;
+    TyParam {
+        id: fld.new_id(id),
+        name: name,
+        bounds: fld.fold_bounds(bounds),
+        default: default.map(|x| fld.fold_ty(x)),
+        span: span,
+    }
+}
+
+pub fn noop_fold_ty_params<T: Folder>(tps: HirVec<TyParam>,
+                                      fld: &mut T)
+                                      -> HirVec<TyParam> {
+    tps.move_map(|tp| fld.fold_ty_param(tp))
+}
+
+pub fn noop_fold_lifetime<T: Folder>(l: Lifetime, fld: &mut T) -> Lifetime {
+    Lifetime {
+        id: fld.new_id(l.id),
+        name: l.name,
+        span: fld.new_span(l.span),
+    }
+}
+
+pub fn noop_fold_lifetime_def<T: Folder>(l: LifetimeDef, fld: &mut T) -> LifetimeDef {
+    LifetimeDef {
+        lifetime: fld.fold_lifetime(l.lifetime),
+        bounds: fld.fold_lifetimes(l.bounds),
+    }
+}
+
+pub fn noop_fold_lifetimes<T: Folder>(lts: HirVec<Lifetime>, fld: &mut T) -> HirVec<Lifetime> {
+    lts.move_map(|l| fld.fold_lifetime(l))
+}
+
+pub fn noop_fold_lifetime_defs<T: Folder>(lts: HirVec<LifetimeDef>,
+                                          fld: &mut T)
+                                          -> HirVec<LifetimeDef> {
+    lts.move_map(|l| fld.fold_lifetime_def(l))
+}
+
+pub fn noop_fold_opt_lifetime<T: Folder>(o_lt: Option<Lifetime>, fld: &mut T) -> Option<Lifetime> {
+    o_lt.map(|lt| fld.fold_lifetime(lt))
+}
+
+pub fn noop_fold_generics<T: Folder>(Generics { ty_params, lifetimes, where_clause }: Generics,
+                                     fld: &mut T)
+                                     -> Generics {
+    Generics {
+        ty_params: fld.fold_ty_params(ty_params),
+        lifetimes: fld.fold_lifetime_defs(lifetimes),
+        where_clause: fld.fold_where_clause(where_clause),
+    }
+}
+
+pub fn noop_fold_where_clause<T: Folder>(WhereClause { id, predicates }: WhereClause,
+                                         fld: &mut T)
+                                         -> WhereClause {
+    WhereClause {
+        id: fld.new_id(id),
+        predicates: predicates.move_map(|predicate| fld.fold_where_predicate(predicate)),
+    }
+}
+
+pub fn noop_fold_where_predicate<T: Folder>(pred: WherePredicate, fld: &mut T) -> WherePredicate {
+    match pred {
+        hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate{bound_lifetimes,
+                                                                     bounded_ty,
+                                                                     bounds,
+                                                                     span}) => {
+            hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
+                bound_lifetimes: fld.fold_lifetime_defs(bound_lifetimes),
+                bounded_ty: fld.fold_ty(bounded_ty),
+                bounds: bounds.move_map(|x| fld.fold_ty_param_bound(x)),
+                span: fld.new_span(span),
+            })
+        }
+        hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate{lifetime,
+                                                                       bounds,
+                                                                       span}) => {
+            hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
+                span: fld.new_span(span),
+                lifetime: fld.fold_lifetime(lifetime),
+                bounds: bounds.move_map(|bound| fld.fold_lifetime(bound)),
+            })
+        }
+        hir::WherePredicate::EqPredicate(hir::WhereEqPredicate{id,
+                                                               path,
+                                                               ty,
+                                                               span}) => {
+            hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
+                id: fld.new_id(id),
+                path: fld.fold_path(path),
+                ty: fld.fold_ty(ty),
+                span: fld.new_span(span),
+            })
+        }
+    }
+}
+
+pub fn noop_fold_variant_data<T: Folder>(vdata: VariantData, fld: &mut T) -> VariantData {
+    match vdata {
+        VariantData::Struct(fields, id) => {
+            VariantData::Struct(fields.move_map(|f| fld.fold_struct_field(f)),
+                                fld.new_id(id))
+        }
+        VariantData::Tuple(fields, id) => {
+            VariantData::Tuple(fields.move_map(|f| fld.fold_struct_field(f)),
+                               fld.new_id(id))
+        }
+        VariantData::Unit(id) => VariantData::Unit(fld.new_id(id)),
+    }
+}
+
+pub fn noop_fold_trait_ref<T: Folder>(p: TraitRef, fld: &mut T) -> TraitRef {
+    let id = fld.new_id(p.ref_id);
+    let TraitRef {
+        path,
+        ref_id: _,
+    } = p;
+    hir::TraitRef {
+        path: fld.fold_path(path),
+        ref_id: id,
+    }
+}
+
+pub fn noop_fold_poly_trait_ref<T: Folder>(p: PolyTraitRef, fld: &mut T) -> PolyTraitRef {
+    hir::PolyTraitRef {
+        bound_lifetimes: fld.fold_lifetime_defs(p.bound_lifetimes),
+        trait_ref: fld.fold_trait_ref(p.trait_ref),
+        span: fld.new_span(p.span),
+    }
+}
+
+pub fn noop_fold_struct_field<T: Folder>(f: StructField, fld: &mut T) -> StructField {
+    StructField {
+        span: fld.new_span(f.span),
+        id: fld.new_id(f.id),
+        name: f.name,
+        vis: f.vis,
+        ty: fld.fold_ty(f.ty),
+        attrs: fold_attrs(f.attrs, fld),
+    }
+}
+
+pub fn noop_fold_field<T: Folder>(Field { name, expr, span }: Field, folder: &mut T) -> Field {
+    Field {
+        name: respan(folder.new_span(name.span), folder.fold_name(name.node)),
+        expr: folder.fold_expr(expr),
+        span: folder.new_span(span),
+    }
+}
+
+pub fn noop_fold_mt<T: Folder>(MutTy { ty, mutbl }: MutTy, folder: &mut T) -> MutTy {
+    MutTy {
+        ty: folder.fold_ty(ty),
+        mutbl: mutbl,
+    }
+}
+
+pub fn noop_fold_opt_bounds<T: Folder>(b: Option<TyParamBounds>,
+                                       folder: &mut T)
+                                       -> Option<TyParamBounds> {
+    b.map(|bounds| folder.fold_bounds(bounds))
+}
+
+fn noop_fold_bounds<T: Folder>(bounds: TyParamBounds, folder: &mut T) -> TyParamBounds {
+    bounds.move_map(|bound| folder.fold_ty_param_bound(bound))
+}
+
+pub fn noop_fold_block<T: Folder>(b: P<Block>, folder: &mut T) -> P<Block> {
+    b.map(|Block { id, stmts, expr, rules, span }| {
+        Block {
+            id: folder.new_id(id),
+            stmts: stmts.move_map(|s| folder.fold_stmt(s)),
+            expr: expr.map(|x| folder.fold_expr(x)),
+            rules: rules,
+            span: folder.new_span(span),
+        }
+    })
+}
+
+pub fn noop_fold_item_underscore<T: Folder>(i: Item_, folder: &mut T) -> Item_ {
+    match i {
+        ItemExternCrate(string) => ItemExternCrate(string),
+        ItemUse(view_path) => {
+            ItemUse(folder.fold_view_path(view_path))
+        }
+        ItemStatic(t, m, e) => {
+            ItemStatic(folder.fold_ty(t), m, folder.fold_expr(e))
+        }
+        ItemConst(t, e) => {
+            ItemConst(folder.fold_ty(t), folder.fold_expr(e))
+        }
+        ItemFn(decl, unsafety, constness, abi, generics, body) => {
+            ItemFn(folder.fold_fn_decl(decl),
+                   unsafety,
+                   constness,
+                   abi,
+                   folder.fold_generics(generics),
+                   folder.fold_block(body))
+        }
+        ItemMod(m) => ItemMod(folder.fold_mod(m)),
+        ItemForeignMod(nm) => ItemForeignMod(folder.fold_foreign_mod(nm)),
+        ItemTy(t, generics) => {
+            ItemTy(folder.fold_ty(t), folder.fold_generics(generics))
+        }
+        ItemEnum(enum_definition, generics) => {
+            ItemEnum(hir::EnumDef {
+                         variants: enum_definition.variants.move_map(|x| folder.fold_variant(x)),
+                     },
+                     folder.fold_generics(generics))
+        }
+        ItemStruct(struct_def, generics) => {
+            let struct_def = folder.fold_variant_data(struct_def);
+            ItemStruct(struct_def, folder.fold_generics(generics))
+        }
+        ItemDefaultImpl(unsafety, ref trait_ref) => {
+            ItemDefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone()))
+        }
+        ItemImpl(unsafety, polarity, generics, ifce, ty, impl_items) => {
+            let new_impl_items = impl_items
+                .move_map(|item| folder.fold_impl_item(item));
+            let ifce = match ifce {
+                None => None,
+                Some(ref trait_ref) => {
+                    Some(folder.fold_trait_ref((*trait_ref).clone()))
+                }
+            };
+            ItemImpl(unsafety,
+                     polarity,
+                     folder.fold_generics(generics),
+                     ifce,
+                     folder.fold_ty(ty),
+                     new_impl_items)
+        }
+        ItemTrait(unsafety, generics, bounds, items) => {
+            let bounds = folder.fold_bounds(bounds);
+            let items = items.move_map(|item| folder.fold_trait_item(item));
+            ItemTrait(unsafety, folder.fold_generics(generics), bounds, items)
+        }
+    }
+}
+
+pub fn noop_fold_trait_item<T: Folder>(i: TraitItem,
+                                       folder: &mut T)
+                                       -> TraitItem {
+    TraitItem {
+        id: folder.new_id(i.id),
+        name: folder.fold_name(i.name),
+        attrs: fold_attrs(i.attrs, folder),
+        node: match i.node {
+            ConstTraitItem(ty, default) => {
+                ConstTraitItem(folder.fold_ty(ty), default.map(|x| folder.fold_expr(x)))
+            }
+            MethodTraitItem(sig, body) => {
+                MethodTraitItem(noop_fold_method_sig(sig, folder),
+                                body.map(|x| folder.fold_block(x)))
+            }
+            TypeTraitItem(bounds, default) => {
+                TypeTraitItem(folder.fold_bounds(bounds),
+                              default.map(|x| folder.fold_ty(x)))
+            }
+        },
+        span: folder.new_span(i.span),
+    }
+}
+
+pub fn noop_fold_impl_item<T: Folder>(i: ImplItem, folder: &mut T) -> ImplItem {
+    ImplItem {
+        id: folder.new_id(i.id),
+        name: folder.fold_name(i.name),
+        attrs: fold_attrs(i.attrs, folder),
+        vis: i.vis,
+        defaultness: i.defaultness,
+        node: match i.node {
+            ImplItemKind::Const(ty, expr) => {
+                ImplItemKind::Const(folder.fold_ty(ty), folder.fold_expr(expr))
+            }
+            ImplItemKind::Method(sig, body) => {
+                ImplItemKind::Method(noop_fold_method_sig(sig, folder), folder.fold_block(body))
+            }
+            ImplItemKind::Type(ty) => ImplItemKind::Type(folder.fold_ty(ty)),
+        },
+        span: folder.new_span(i.span),
+    }
+}
+
+pub fn noop_fold_mod<T: Folder>(Mod { inner, item_ids }: Mod, folder: &mut T) -> Mod {
+    Mod {
+        inner: folder.new_span(inner),
+        item_ids: item_ids.move_map(|x| folder.fold_item_id(x)),
+    }
+}
+
+pub fn noop_fold_crate<T: Folder>(Crate { module, attrs, config, span,
+                                          exported_macros, items }: Crate,
+                                  folder: &mut T)
+                                  -> Crate {
+    let config = folder.fold_meta_items(config);
+
+    let crate_mod = folder.fold_item(hir::Item {
+        name: token::special_idents::invalid.name,
+        attrs: attrs,
+        id: DUMMY_NODE_ID,
+        vis: hir::Public,
+        span: span,
+        node: hir::ItemMod(module),
+    });
+
+    let (module, attrs, span) = match crate_mod {
+        hir::Item { attrs, span, node, .. } => {
+            match node {
+                hir::ItemMod(m) => (m, attrs, span),
+                _ => panic!("fold converted a module to not a module"),
+            }
+        }
+    };
+
+    let items = items.into_iter()
+                     .map(|(id, item)| (id, folder.fold_item(item)))
+                     .collect();
+
+    Crate {
+        module: module,
+        attrs: attrs,
+        config: config,
+        span: span,
+        exported_macros: exported_macros,
+        items: items,
+    }
+}
+
+pub fn noop_fold_item_id<T: Folder>(i: ItemId, folder: &mut T) -> ItemId {
+    let id = folder.map_id(i.id);
+    ItemId { id: id }
+}
+
+// fold one item into one item
+pub fn noop_fold_item<T: Folder>(item: Item, folder: &mut T) -> Item {
+    let Item { id, name, attrs, node, vis, span } = item;
+    let id = folder.new_id(id);
+    let node = folder.fold_item_underscore(node);
+
+    Item {
+        id: id,
+        name: folder.fold_name(name),
+        attrs: fold_attrs(attrs, folder),
+        node: node,
+        vis: vis,
+        span: folder.new_span(span),
+    }
+}
+
+pub fn noop_fold_foreign_item<T: Folder>(ni: ForeignItem, folder: &mut T) -> ForeignItem {
+    ForeignItem {
+        id: folder.new_id(ni.id),
+        name: folder.fold_name(ni.name),
+        attrs: fold_attrs(ni.attrs, folder),
+        node: match ni.node {
+            ForeignItemFn(fdec, generics) => {
+                ForeignItemFn(folder.fold_fn_decl(fdec), folder.fold_generics(generics))
+            }
+            ForeignItemStatic(t, m) => {
+                ForeignItemStatic(folder.fold_ty(t), m)
+            }
+        },
+        vis: ni.vis,
+        span: folder.new_span(ni.span),
+    }
+}
+
+pub fn noop_fold_method_sig<T: Folder>(sig: MethodSig, folder: &mut T) -> MethodSig {
+    MethodSig {
+        generics: folder.fold_generics(sig.generics),
+        abi: sig.abi,
+        explicit_self: folder.fold_explicit_self(sig.explicit_self),
+        unsafety: sig.unsafety,
+        constness: sig.constness,
+        decl: folder.fold_fn_decl(sig.decl),
+    }
+}
+
+pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
+    p.map(|Pat { id, node, span }| {
+        Pat {
+            id: folder.new_id(id),
+            node: match node {
+                PatKind::Wild => PatKind::Wild,
+                PatKind::Ident(binding_mode, pth1, sub) => {
+                    PatKind::Ident(binding_mode,
+                             Spanned {
+                                 span: folder.new_span(pth1.span),
+                                 node: folder.fold_ident(pth1.node),
+                             },
+                             sub.map(|x| folder.fold_pat(x)))
+                }
+                PatKind::Lit(e) => PatKind::Lit(folder.fold_expr(e)),
+                PatKind::TupleStruct(pth, pats) => {
+                    PatKind::TupleStruct(folder.fold_path(pth),
+                            pats.map(|pats| pats.move_map(|x| folder.fold_pat(x))))
+                }
+                PatKind::Path(pth) => {
+                    PatKind::Path(folder.fold_path(pth))
+                }
+                PatKind::QPath(qself, pth) => {
+                    let qself = QSelf { ty: folder.fold_ty(qself.ty), ..qself };
+                    PatKind::QPath(qself, folder.fold_path(pth))
+                }
+                PatKind::Struct(pth, fields, etc) => {
+                    let pth = folder.fold_path(pth);
+                    let fs = fields.move_map(|f| {
+                        Spanned {
+                            span: folder.new_span(f.span),
+                            node: hir::FieldPat {
+                                name: f.node.name,
+                                pat: folder.fold_pat(f.node.pat),
+                                is_shorthand: f.node.is_shorthand,
+                            },
+                        }
+                    });
+                    PatKind::Struct(pth, fs, etc)
+                }
+                PatKind::Tup(elts) => PatKind::Tup(elts.move_map(|x| folder.fold_pat(x))),
+                PatKind::Box(inner) => PatKind::Box(folder.fold_pat(inner)),
+                PatKind::Ref(inner, mutbl) => PatKind::Ref(folder.fold_pat(inner), mutbl),
+                PatKind::Range(e1, e2) => {
+                    PatKind::Range(folder.fold_expr(e1), folder.fold_expr(e2))
+                }
+                PatKind::Vec(before, slice, after) => {
+                    PatKind::Vec(before.move_map(|x| folder.fold_pat(x)),
+                           slice.map(|x| folder.fold_pat(x)),
+                           after.move_map(|x| folder.fold_pat(x)))
+                }
+            },
+            span: folder.new_span(span),
+        }
+    })
+}
+
+pub fn noop_fold_expr<T: Folder>(Expr { id, node, span, attrs }: Expr, folder: &mut T) -> Expr {
+    Expr {
+        id: folder.new_id(id),
+        node: match node {
+            ExprBox(e) => {
+                ExprBox(folder.fold_expr(e))
+            }
+            ExprVec(exprs) => {
+                ExprVec(exprs.move_map(|x| folder.fold_expr(x)))
+            }
+            ExprRepeat(expr, count) => {
+                ExprRepeat(folder.fold_expr(expr), folder.fold_expr(count))
+            }
+            ExprTup(elts) => ExprTup(elts.move_map(|x| folder.fold_expr(x))),
+            ExprCall(f, args) => {
+                ExprCall(folder.fold_expr(f), args.move_map(|x| folder.fold_expr(x)))
+            }
+            ExprMethodCall(name, tps, args) => {
+                ExprMethodCall(respan(folder.new_span(name.span), folder.fold_name(name.node)),
+                               tps.move_map(|x| folder.fold_ty(x)),
+                               args.move_map(|x| folder.fold_expr(x)))
+            }
+            ExprBinary(binop, lhs, rhs) => {
+                ExprBinary(binop, folder.fold_expr(lhs), folder.fold_expr(rhs))
+            }
+            ExprUnary(binop, ohs) => {
+                ExprUnary(binop, folder.fold_expr(ohs))
+            }
+            ExprLit(l) => ExprLit(l),
+            ExprCast(expr, ty) => {
+                ExprCast(folder.fold_expr(expr), folder.fold_ty(ty))
+            }
+            ExprType(expr, ty) => {
+                ExprType(folder.fold_expr(expr), folder.fold_ty(ty))
+            }
+            ExprAddrOf(m, ohs) => ExprAddrOf(m, folder.fold_expr(ohs)),
+            ExprIf(cond, tr, fl) => {
+                ExprIf(folder.fold_expr(cond),
+                       folder.fold_block(tr),
+                       fl.map(|x| folder.fold_expr(x)))
+            }
+            ExprWhile(cond, body, opt_ident) => {
+                ExprWhile(folder.fold_expr(cond),
+                          folder.fold_block(body),
+                          opt_ident.map(|i| folder.fold_ident(i)))
+            }
+            ExprLoop(body, opt_ident) => {
+                ExprLoop(folder.fold_block(body),
+                         opt_ident.map(|i| folder.fold_ident(i)))
+            }
+            ExprMatch(expr, arms, source) => {
+                ExprMatch(folder.fold_expr(expr),
+                          arms.move_map(|x| folder.fold_arm(x)),
+                          source)
+            }
+            ExprClosure(capture_clause, decl, body) => {
+                ExprClosure(capture_clause,
+                            folder.fold_fn_decl(decl),
+                            folder.fold_block(body))
+            }
+            ExprBlock(blk) => ExprBlock(folder.fold_block(blk)),
+            ExprAssign(el, er) => {
+                ExprAssign(folder.fold_expr(el), folder.fold_expr(er))
+            }
+            ExprAssignOp(op, el, er) => {
+                ExprAssignOp(op, folder.fold_expr(el), folder.fold_expr(er))
+            }
+            ExprField(el, name) => {
+                ExprField(folder.fold_expr(el),
+                          respan(folder.new_span(name.span), folder.fold_name(name.node)))
+            }
+            ExprTupField(el, index) => {
+                ExprTupField(folder.fold_expr(el),
+                             respan(folder.new_span(index.span), folder.fold_usize(index.node)))
+            }
+            ExprIndex(el, er) => {
+                ExprIndex(folder.fold_expr(el), folder.fold_expr(er))
+            }
+            ExprPath(qself, path) => {
+                let qself = qself.map(|QSelf { ty, position }| {
+                    QSelf {
+                        ty: folder.fold_ty(ty),
+                        position: position,
+                    }
+                });
+                ExprPath(qself, folder.fold_path(path))
+            }
+            ExprBreak(opt_ident) => ExprBreak(opt_ident.map(|label| {
+                respan(folder.new_span(label.span), folder.fold_ident(label.node))
+            })),
+            ExprAgain(opt_ident) => ExprAgain(opt_ident.map(|label| {
+                respan(folder.new_span(label.span), folder.fold_ident(label.node))
+            })),
+            ExprRet(e) => ExprRet(e.map(|x| folder.fold_expr(x))),
+            ExprInlineAsm(asm, outputs, inputs) => {
+                ExprInlineAsm(asm,
+                              outputs.move_map(|x| folder.fold_expr(x)),
+                              inputs.move_map(|x| folder.fold_expr(x)))
+            }
+            ExprStruct(path, fields, maybe_expr) => {
+                ExprStruct(folder.fold_path(path),
+                           fields.move_map(|x| folder.fold_field(x)),
+                           maybe_expr.map(|x| folder.fold_expr(x)))
+            }
+        },
+        span: folder.new_span(span),
+        attrs: attrs.map_thin_attrs(|attrs| fold_attrs(attrs.into(), folder).into()),
+    }
+}
+
+pub fn noop_fold_stmt<T: Folder>(stmt: Stmt, folder: &mut T) -> Stmt {
+    let span = folder.new_span(stmt.span);
+    match stmt.node {
+        StmtDecl(d, id) => {
+            let id = folder.new_id(id);
+            Spanned {
+                node: StmtDecl(folder.fold_decl(d), id),
+                span: span
+            }
+        }
+        StmtExpr(e, id) => {
+            let id = folder.new_id(id);
+            Spanned {
+                node: StmtExpr(folder.fold_expr(e), id),
+                span: span,
+            }
+        }
+        StmtSemi(e, id) => {
+            let id = folder.new_id(id);
+            Spanned {
+                node: StmtSemi(folder.fold_expr(e), id),
+                span: span,
+            }
+        }
+    }
+}
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
new file mode 100644
index 00000000000..d34d66918ca
--- /dev/null
+++ b/src/librustc/hir/intravisit.rs
@@ -0,0 +1,1070 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! HIR walker. Each overridden visit method has full control over what
+//! happens with its node, it can do its own traversal of the node's children,
+//! call `intravisit::walk_*` to apply the default traversal algorithm, or prevent
+//! deeper traversal by doing nothing.
+//!
+//! When visiting the HIR, the contents of nested items are NOT visited
+//! by default. This is different from the AST visitor, which does a deep walk.
+//! Hence this module is called `intravisit`; see the method `visit_nested_item`
+//! for more details.
+//!
+//! Note: it is an important invariant that the default visitor walks
+//! the body of a function in "execution order" (more concretely,
+//! reverse post-order with respect to the CFG implied by the AST),
+//! meaning that if AST node A may execute before AST node B, then A
+//! is visited first.  The borrow checker in particular relies on this
+//! property.
+
+use syntax::abi::Abi;
+use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute};
+use syntax::attr::ThinAttributesExt;
+use syntax::codemap::Span;
+use hir::*;
+
+use std::cmp;
+use std::u32;
+
+#[derive(Copy, Clone, PartialEq, Eq)]
+pub enum FnKind<'a> {
+    /// fn foo() or extern "Abi" fn foo()
+    ItemFn(Name, &'a Generics, Unsafety, Constness, Abi, Visibility, &'a [Attribute]),
+
+    /// fn foo(&self)
+    Method(Name, &'a MethodSig, Option<Visibility>, &'a [Attribute]),
+
+    /// |x, y| {}
+    Closure(&'a [Attribute]),
+}
+
+impl<'a> FnKind<'a> {
+    pub fn attrs(&self) -> &'a [Attribute] {
+        match *self {
+            FnKind::ItemFn(_, _, _, _, _, _, attrs) => attrs,
+            FnKind::Method(_, _, _, attrs) => attrs,
+            FnKind::Closure(attrs) => attrs,
+        }
+    }
+}
+
+/// Each method of the Visitor trait is a hook to be potentially
+/// overridden.  Each method's default implementation recursively visits
+/// the substructure of the input via the corresponding `walk` method;
+/// e.g. the `visit_mod` method by default calls `intravisit::walk_mod`.
+///
+/// Note that this visitor does NOT visit nested items by default
+/// (this is why the module is called `intravisit`, to distinguish it
+/// from the AST's `visit` module, which acts differently). If you
+/// simply want to visit all items in the crate in some order, you
+/// should call `Crate::visit_all_items`. Otherwise, see the comment
+/// on `visit_nested_item` for details on how to visit nested items.
+///
+/// If you want to ensure that your code handles every variant
+/// explicitly, you need to override each method.  (And you also need
+/// to monitor future changes to `Visitor` in case a new method with a
+/// new default implementation gets introduced.)
+pub trait Visitor<'v> : Sized {
+    ///////////////////////////////////////////////////////////////////////////
+    // Nested items.
+
+    /// Invoked when a nested item is encountered. By default, does
+    /// nothing. If you want a deep walk, you need to override to
+    /// fetch the item contents. But most of the time, it is easier
+    /// (and better) to invoke `Crate::visit_all_items`, which visits
+    /// all items in the crate in some order (but doesn't respect
+    /// nesting).
+    #[allow(unused_variables)]
+    fn visit_nested_item(&mut self, id: ItemId) {
+    }
+
+    /// Visit the top-level item and (optionally) nested items. See
+    /// `visit_nested_item` for details.
+    fn visit_item(&mut self, i: &'v Item) {
+        walk_item(self, i)
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    fn visit_name(&mut self, _span: Span, _name: Name) {
+        // Nothing to do.
+    }
+    fn visit_ident(&mut self, span: Span, ident: Ident) {
+        walk_ident(self, span, ident);
+    }
+    fn visit_mod(&mut self, m: &'v Mod, _s: Span, _n: NodeId) {
+        walk_mod(self, m)
+    }
+    fn visit_foreign_item(&mut self, i: &'v ForeignItem) {
+        walk_foreign_item(self, i)
+    }
+    fn visit_local(&mut self, l: &'v Local) {
+        walk_local(self, l)
+    }
+    fn visit_block(&mut self, b: &'v Block) {
+        walk_block(self, b)
+    }
+    fn visit_stmt(&mut self, s: &'v Stmt) {
+        walk_stmt(self, s)
+    }
+    fn visit_arm(&mut self, a: &'v Arm) {
+        walk_arm(self, a)
+    }
+    fn visit_pat(&mut self, p: &'v Pat) {
+        walk_pat(self, p)
+    }
+    fn visit_decl(&mut self, d: &'v Decl) {
+        walk_decl(self, d)
+    }
+    fn visit_expr(&mut self, ex: &'v Expr) {
+        walk_expr(self, ex)
+    }
+    fn visit_expr_post(&mut self, _ex: &'v Expr) {
+    }
+    fn visit_ty(&mut self, t: &'v Ty) {
+        walk_ty(self, t)
+    }
+    fn visit_generics(&mut self, g: &'v Generics) {
+        walk_generics(self, g)
+    }
+    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, _: NodeId) {
+        walk_fn(self, fk, fd, b, s)
+    }
+    fn visit_trait_item(&mut self, ti: &'v TraitItem) {
+        walk_trait_item(self, ti)
+    }
+    fn visit_impl_item(&mut self, ii: &'v ImplItem) {
+        walk_impl_item(self, ii)
+    }
+    fn visit_trait_ref(&mut self, t: &'v TraitRef) {
+        walk_trait_ref(self, t)
+    }
+    fn visit_ty_param_bound(&mut self, bounds: &'v TyParamBound) {
+        walk_ty_param_bound(self, bounds)
+    }
+    fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: &'v TraitBoundModifier) {
+        walk_poly_trait_ref(self, t, m)
+    }
+    fn visit_variant_data(&mut self,
+                          s: &'v VariantData,
+                          _: Name,
+                          _: &'v Generics,
+                          _: NodeId,
+                          _: Span) {
+        walk_struct_def(self, s)
+    }
+    fn visit_struct_field(&mut self, s: &'v StructField) {
+        walk_struct_field(self, s)
+    }
+    fn visit_enum_def(&mut self,
+                      enum_definition: &'v EnumDef,
+                      generics: &'v Generics,
+                      item_id: NodeId,
+                      _: Span) {
+        walk_enum_def(self, enum_definition, generics, item_id)
+    }
+    fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics, item_id: NodeId) {
+        walk_variant(self, v, g, item_id)
+    }
+    fn visit_lifetime(&mut self, lifetime: &'v Lifetime) {
+        walk_lifetime(self, lifetime)
+    }
+    fn visit_lifetime_def(&mut self, lifetime: &'v LifetimeDef) {
+        walk_lifetime_def(self, lifetime)
+    }
+    fn visit_explicit_self(&mut self, es: &'v ExplicitSelf) {
+        walk_explicit_self(self, es)
+    }
+    fn visit_path(&mut self, path: &'v Path, _id: NodeId) {
+        walk_path(self, path)
+    }
+    fn visit_path_list_item(&mut self, prefix: &'v Path, item: &'v PathListItem) {
+        walk_path_list_item(self, prefix, item)
+    }
+    fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v PathSegment) {
+        walk_path_segment(self, path_span, path_segment)
+    }
+    fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &'v PathParameters) {
+        walk_path_parameters(self, path_span, path_parameters)
+    }
+    fn visit_assoc_type_binding(&mut self, type_binding: &'v TypeBinding) {
+        walk_assoc_type_binding(self, type_binding)
+    }
+    fn visit_attribute(&mut self, _attr: &'v Attribute) {
+    }
+    fn visit_macro_def(&mut self, macro_def: &'v MacroDef) {
+        walk_macro_def(self, macro_def)
+    }
+}
+
+pub fn walk_opt_name<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_name: Option<Name>) {
+    for name in opt_name {
+        visitor.visit_name(span, name);
+    }
+}
+
+pub fn walk_opt_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_ident: Option<Ident>) {
+    for ident in opt_ident {
+        visitor.visit_ident(span, ident);
+    }
+}
+
+pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, ident: Ident) {
+    visitor.visit_name(span, ident.name);
+}
+
+/// Walks the contents of a crate. See also `Crate::visit_all_items`.
+pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) {
+    visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID);
+    walk_list!(visitor, visit_attribute, &krate.attrs);
+    walk_list!(visitor, visit_macro_def, &krate.exported_macros);
+}
+
+pub fn walk_macro_def<'v, V: Visitor<'v>>(visitor: &mut V, macro_def: &'v MacroDef) {
+    visitor.visit_name(macro_def.span, macro_def.name);
+    walk_opt_name(visitor, macro_def.span, macro_def.imported_from);
+    walk_list!(visitor, visit_attribute, &macro_def.attrs);
+}
+
+pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod) {
+    for &item_id in &module.item_ids {
+        visitor.visit_nested_item(item_id);
+    }
+}
+
+pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) {
+    visitor.visit_pat(&local.pat);
+    walk_list!(visitor, visit_ty, &local.ty);
+    walk_list!(visitor, visit_expr, &local.init);
+}
+
+pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
+    visitor.visit_name(lifetime.span, lifetime.name);
+}
+
+pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, lifetime_def: &'v LifetimeDef) {
+    visitor.visit_lifetime(&lifetime_def.lifetime);
+    walk_list!(visitor, visit_lifetime, &lifetime_def.bounds);
+}
+
+pub fn walk_explicit_self<'v, V: Visitor<'v>>(visitor: &mut V, explicit_self: &'v ExplicitSelf) {
+    match explicit_self.node {
+        SelfStatic => {}
+        SelfValue(name) => {
+            visitor.visit_name(explicit_self.span, name)
+        }
+        SelfRegion(ref opt_lifetime, _, name) => {
+            visitor.visit_name(explicit_self.span, name);
+            walk_list!(visitor, visit_lifetime, opt_lifetime);
+        }
+        SelfExplicit(ref typ, name) => {
+            visitor.visit_name(explicit_self.span, name);
+            visitor.visit_ty(typ)
+        }
+    }
+}
+
+pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V,
+                                  trait_ref: &'v PolyTraitRef,
+                                  _modifier: &'v TraitBoundModifier)
+    where V: Visitor<'v>
+{
+    walk_list!(visitor, visit_lifetime_def, &trait_ref.bound_lifetimes);
+    visitor.visit_trait_ref(&trait_ref.trait_ref);
+}
+
+pub fn walk_trait_ref<'v, V>(visitor: &mut V, trait_ref: &'v TraitRef)
+    where V: Visitor<'v>
+{
+    visitor.visit_path(&trait_ref.path, trait_ref.ref_id)
+}
+
+pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
+    visitor.visit_name(item.span, item.name);
+    match item.node {
+        ItemExternCrate(opt_name) => {
+            walk_opt_name(visitor, item.span, opt_name)
+        }
+        ItemUse(ref vp) => {
+            match vp.node {
+                ViewPathSimple(name, ref path) => {
+                    visitor.visit_name(vp.span, name);
+                    visitor.visit_path(path, item.id);
+                }
+                ViewPathGlob(ref path) => {
+                    visitor.visit_path(path, item.id);
+                }
+                ViewPathList(ref prefix, ref list) => {
+                    if !list.is_empty() {
+                        for item in list {
+                            visitor.visit_path_list_item(prefix, item)
+                        }
+                    } else {
+                        visitor.visit_path(prefix, item.id);
+                    }
+                }
+            }
+        }
+        ItemStatic(ref typ, _, ref expr) |
+        ItemConst(ref typ, ref expr) => {
+            visitor.visit_ty(typ);
+            visitor.visit_expr(expr);
+        }
+        ItemFn(ref declaration, unsafety, constness, abi, ref generics, ref body) => {
+            visitor.visit_fn(FnKind::ItemFn(item.name,
+                                            generics,
+                                            unsafety,
+                                            constness,
+                                            abi,
+                                            item.vis,
+                                            &item.attrs),
+                             declaration,
+                             body,
+                             item.span,
+                             item.id)
+        }
+        ItemMod(ref module) => {
+            visitor.visit_mod(module, item.span, item.id)
+        }
+        ItemForeignMod(ref foreign_module) => {
+            walk_list!(visitor, visit_foreign_item, &foreign_module.items);
+        }
+        ItemTy(ref typ, ref type_parameters) => {
+            visitor.visit_ty(typ);
+            visitor.visit_generics(type_parameters)
+        }
+        ItemEnum(ref enum_definition, ref type_parameters) => {
+            visitor.visit_generics(type_parameters);
+            visitor.visit_enum_def(enum_definition, type_parameters, item.id, item.span)
+        }
+        ItemDefaultImpl(_, ref trait_ref) => {
+            visitor.visit_trait_ref(trait_ref)
+        }
+        ItemImpl(_, _, ref type_parameters, ref opt_trait_reference, ref typ, ref impl_items) => {
+            visitor.visit_generics(type_parameters);
+            walk_list!(visitor, visit_trait_ref, opt_trait_reference);
+            visitor.visit_ty(typ);
+            walk_list!(visitor, visit_impl_item, impl_items);
+        }
+        ItemStruct(ref struct_definition, ref generics) => {
+            visitor.visit_generics(generics);
+            visitor.visit_variant_data(struct_definition, item.name, generics, item.id, item.span);
+        }
+        ItemTrait(_, ref generics, ref bounds, ref methods) => {
+            visitor.visit_generics(generics);
+            walk_list!(visitor, visit_ty_param_bound, bounds);
+            walk_list!(visitor, visit_trait_item, methods);
+        }
+    }
+    walk_list!(visitor, visit_attribute, &item.attrs);
+}
+
+pub fn walk_enum_def<'v, V: Visitor<'v>>(visitor: &mut V,
+                                         enum_definition: &'v EnumDef,
+                                         generics: &'v Generics,
+                                         item_id: NodeId) {
+    walk_list!(visitor,
+               visit_variant,
+               &enum_definition.variants,
+               generics,
+               item_id);
+}
+
+pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V,
+                                        variant: &'v Variant,
+                                        generics: &'v Generics,
+                                        item_id: NodeId) {
+    visitor.visit_name(variant.span, variant.node.name);
+    visitor.visit_variant_data(&variant.node.data,
+                               variant.node.name,
+                               generics,
+                               item_id,
+                               variant.span);
+    walk_list!(visitor, visit_expr, &variant.node.disr_expr);
+    walk_list!(visitor, visit_attribute, &variant.node.attrs);
+}
+
+pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
+    match typ.node {
+        TyVec(ref ty) => {
+            visitor.visit_ty(ty)
+        }
+        TyPtr(ref mutable_type) => {
+            visitor.visit_ty(&mutable_type.ty)
+        }
+        TyRptr(ref opt_lifetime, ref mutable_type) => {
+            walk_list!(visitor, visit_lifetime, opt_lifetime);
+            visitor.visit_ty(&mutable_type.ty)
+        }
+        TyTup(ref tuple_element_types) => {
+            walk_list!(visitor, visit_ty, tuple_element_types);
+        }
+        TyBareFn(ref function_declaration) => {
+            walk_fn_decl(visitor, &function_declaration.decl);
+            walk_list!(visitor, visit_lifetime_def, &function_declaration.lifetimes);
+        }
+        TyPath(ref maybe_qself, ref path) => {
+            if let Some(ref qself) = *maybe_qself {
+                visitor.visit_ty(&qself.ty);
+            }
+            visitor.visit_path(path, typ.id);
+        }
+        TyObjectSum(ref ty, ref bounds) => {
+            visitor.visit_ty(ty);
+            walk_list!(visitor, visit_ty_param_bound, bounds);
+        }
+        TyFixedLengthVec(ref ty, ref expression) => {
+            visitor.visit_ty(ty);
+            visitor.visit_expr(expression)
+        }
+        TyPolyTraitRef(ref bounds) => {
+            walk_list!(visitor, visit_ty_param_bound, bounds);
+        }
+        TyTypeof(ref expression) => {
+            visitor.visit_expr(expression)
+        }
+        TyInfer => {}
+    }
+}
+
+pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) {
+    for segment in &path.segments {
+        visitor.visit_path_segment(path.span, segment);
+    }
+}
+
+pub fn walk_path_list_item<'v, V: Visitor<'v>>(visitor: &mut V,
+                                               prefix: &'v Path,
+                                               item: &'v PathListItem) {
+    for segment in &prefix.segments {
+        visitor.visit_path_segment(prefix.span, segment);
+    }
+
+    walk_opt_name(visitor, item.span, item.node.name());
+    walk_opt_name(visitor, item.span, item.node.rename());
+}
+
+pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V,
+                                             path_span: Span,
+                                             segment: &'v PathSegment) {
+    visitor.visit_ident(path_span, segment.identifier);
+    visitor.visit_path_parameters(path_span, &segment.parameters);
+}
+
+pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V,
+                                                _path_span: Span,
+                                                path_parameters: &'v PathParameters) {
+    match *path_parameters {
+        AngleBracketedParameters(ref data) => {
+            walk_list!(visitor, visit_ty, &data.types);
+            walk_list!(visitor, visit_lifetime, &data.lifetimes);
+            walk_list!(visitor, visit_assoc_type_binding, &data.bindings);
+        }
+        ParenthesizedParameters(ref data) => {
+            walk_list!(visitor, visit_ty, &data.inputs);
+            walk_list!(visitor, visit_ty, &data.output);
+        }
+    }
+}
+
+pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V,
+                                                   type_binding: &'v TypeBinding) {
+    visitor.visit_name(type_binding.span, type_binding.name);
+    visitor.visit_ty(&type_binding.ty);
+}
+
+pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
+    match pattern.node {
+        PatKind::TupleStruct(ref path, ref opt_children) => {
+            visitor.visit_path(path, pattern.id);
+            if let Some(ref children) = *opt_children {
+                walk_list!(visitor, visit_pat, children);
+            }
+        }
+        PatKind::Path(ref path) => {
+            visitor.visit_path(path, pattern.id);
+        }
+        PatKind::QPath(ref qself, ref path) => {
+            visitor.visit_ty(&qself.ty);
+            visitor.visit_path(path, pattern.id)
+        }
+        PatKind::Struct(ref path, ref fields, _) => {
+            visitor.visit_path(path, pattern.id);
+            for field in fields {
+                visitor.visit_name(field.span, field.node.name);
+                visitor.visit_pat(&field.node.pat)
+            }
+        }
+        PatKind::Tup(ref tuple_elements) => {
+            walk_list!(visitor, visit_pat, tuple_elements);
+        }
+        PatKind::Box(ref subpattern) |
+        PatKind::Ref(ref subpattern, _) => {
+            visitor.visit_pat(subpattern)
+        }
+        PatKind::Ident(_, ref pth1, ref optional_subpattern) => {
+            visitor.visit_ident(pth1.span, pth1.node);
+            walk_list!(visitor, visit_pat, optional_subpattern);
+        }
+        PatKind::Lit(ref expression) => visitor.visit_expr(expression),
+        PatKind::Range(ref lower_bound, ref upper_bound) => {
+            visitor.visit_expr(lower_bound);
+            visitor.visit_expr(upper_bound)
+        }
+        PatKind::Wild => (),
+        PatKind::Vec(ref prepatterns, ref slice_pattern, ref postpatterns) => {
+            walk_list!(visitor, visit_pat, prepatterns);
+            walk_list!(visitor, visit_pat, slice_pattern);
+            walk_list!(visitor, visit_pat, postpatterns);
+        }
+    }
+}
+
+pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v ForeignItem) {
+    visitor.visit_name(foreign_item.span, foreign_item.name);
+
+    match foreign_item.node {
+        ForeignItemFn(ref function_declaration, ref generics) => {
+            walk_fn_decl(visitor, function_declaration);
+            visitor.visit_generics(generics)
+        }
+        ForeignItemStatic(ref typ, _) => visitor.visit_ty(typ),
+    }
+
+    walk_list!(visitor, visit_attribute, &foreign_item.attrs);
+}
+
+pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v TyParamBound) {
+    match *bound {
+        TraitTyParamBound(ref typ, ref modifier) => {
+            visitor.visit_poly_trait_ref(typ, modifier);
+        }
+        RegionTyParamBound(ref lifetime) => {
+            visitor.visit_lifetime(lifetime);
+        }
+    }
+}
+
+pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) {
+    for param in &generics.ty_params {
+        visitor.visit_name(param.span, param.name);
+        walk_list!(visitor, visit_ty_param_bound, &param.bounds);
+        walk_list!(visitor, visit_ty, &param.default);
+    }
+    walk_list!(visitor, visit_lifetime_def, &generics.lifetimes);
+    for predicate in &generics.where_clause.predicates {
+        match predicate {
+            &WherePredicate::BoundPredicate(WhereBoundPredicate{ref bounded_ty,
+                                                                          ref bounds,
+                                                                          ref bound_lifetimes,
+                                                                          ..}) => {
+                visitor.visit_ty(bounded_ty);
+                walk_list!(visitor, visit_ty_param_bound, bounds);
+                walk_list!(visitor, visit_lifetime_def, bound_lifetimes);
+            }
+            &WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime,
+                                                                            ref bounds,
+                                                                            ..}) => {
+                visitor.visit_lifetime(lifetime);
+                walk_list!(visitor, visit_lifetime, bounds);
+            }
+            &WherePredicate::EqPredicate(WhereEqPredicate{id,
+                                                                    ref path,
+                                                                    ref ty,
+                                                                    ..}) => {
+                visitor.visit_path(path, id);
+                visitor.visit_ty(ty);
+            }
+        }
+    }
+}
+
+pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FunctionRetTy) {
+    if let Return(ref output_ty) = *ret_ty {
+        visitor.visit_ty(output_ty)
+    }
+}
+
+pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) {
+    for argument in &function_declaration.inputs {
+        visitor.visit_pat(&argument.pat);
+        visitor.visit_ty(&argument.ty)
+    }
+    walk_fn_ret_ty(visitor, &function_declaration.output)
+}
+
+pub fn walk_fn_decl_nopat<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) {
+    for argument in &function_declaration.inputs {
+        visitor.visit_ty(&argument.ty)
+    }
+    walk_fn_ret_ty(visitor, &function_declaration.output)
+}
+
+pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'v>) {
+    match function_kind {
+        FnKind::ItemFn(_, generics, _, _, _, _, _) => {
+            visitor.visit_generics(generics);
+        }
+        FnKind::Method(_, sig, _, _) => {
+            visitor.visit_generics(&sig.generics);
+            visitor.visit_explicit_self(&sig.explicit_self);
+        }
+        FnKind::Closure(_) => {}
+    }
+}
+
+pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V,
+                                   function_kind: FnKind<'v>,
+                                   function_declaration: &'v FnDecl,
+                                   function_body: &'v Block,
+                                   _span: Span) {
+    walk_fn_decl(visitor, function_declaration);
+    walk_fn_kind(visitor, function_kind);
+    visitor.visit_block(function_body)
+}
+
+pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem) {
+    visitor.visit_name(trait_item.span, trait_item.name);
+    walk_list!(visitor, visit_attribute, &trait_item.attrs);
+    match trait_item.node {
+        ConstTraitItem(ref ty, ref default) => {
+            visitor.visit_ty(ty);
+            walk_list!(visitor, visit_expr, default);
+        }
+        MethodTraitItem(ref sig, None) => {
+            visitor.visit_explicit_self(&sig.explicit_self);
+            visitor.visit_generics(&sig.generics);
+            walk_fn_decl(visitor, &sig.decl);
+        }
+        MethodTraitItem(ref sig, Some(ref body)) => {
+            visitor.visit_fn(FnKind::Method(trait_item.name,
+                                            sig,
+                                            None,
+                                            &trait_item.attrs),
+                             &sig.decl,
+                             body,
+                             trait_item.span,
+                             trait_item.id);
+        }
+        TypeTraitItem(ref bounds, ref default) => {
+            walk_list!(visitor, visit_ty_param_bound, bounds);
+            walk_list!(visitor, visit_ty, default);
+        }
+    }
+}
+
+pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem) {
+    visitor.visit_name(impl_item.span, impl_item.name);
+    walk_list!(visitor, visit_attribute, &impl_item.attrs);
+    match impl_item.node {
+        ImplItemKind::Const(ref ty, ref expr) => {
+            visitor.visit_ty(ty);
+            visitor.visit_expr(expr);
+        }
+        ImplItemKind::Method(ref sig, ref body) => {
+            visitor.visit_fn(FnKind::Method(impl_item.name,
+                                            sig,
+                                            Some(impl_item.vis),
+                                            &impl_item.attrs),
+                             &sig.decl,
+                             body,
+                             impl_item.span,
+                             impl_item.id);
+        }
+        ImplItemKind::Type(ref ty) => {
+            visitor.visit_ty(ty);
+        }
+    }
+}
+
+pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v VariantData) {
+    walk_list!(visitor, visit_struct_field, struct_definition.fields());
+}
+
+pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, struct_field: &'v StructField) {
+    visitor.visit_name(struct_field.span, struct_field.name);
+    visitor.visit_ty(&struct_field.ty);
+    walk_list!(visitor, visit_attribute, &struct_field.attrs);
+}
+
+pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block) {
+    walk_list!(visitor, visit_stmt, &block.stmts);
+    walk_list!(visitor, visit_expr, &block.expr);
+}
+
+pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt) {
+    match statement.node {
+        StmtDecl(ref declaration, _) => visitor.visit_decl(declaration),
+        StmtExpr(ref expression, _) | StmtSemi(ref expression, _) => {
+            visitor.visit_expr(expression)
+        }
+    }
+}
+
+pub fn walk_decl<'v, V: Visitor<'v>>(visitor: &mut V, declaration: &'v Decl) {
+    match declaration.node {
+        DeclLocal(ref local) => visitor.visit_local(local),
+        DeclItem(item) => visitor.visit_nested_item(item),
+    }
+}
+
+pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
+    match expression.node {
+        ExprBox(ref subexpression) => {
+            visitor.visit_expr(subexpression)
+        }
+        ExprVec(ref subexpressions) => {
+            walk_list!(visitor, visit_expr, subexpressions);
+        }
+        ExprRepeat(ref element, ref count) => {
+            visitor.visit_expr(element);
+            visitor.visit_expr(count)
+        }
+        ExprStruct(ref path, ref fields, ref optional_base) => {
+            visitor.visit_path(path, expression.id);
+            for field in fields {
+                visitor.visit_name(field.name.span, field.name.node);
+                visitor.visit_expr(&field.expr)
+            }
+            walk_list!(visitor, visit_expr, optional_base);
+        }
+        ExprTup(ref subexpressions) => {
+            walk_list!(visitor, visit_expr, subexpressions);
+        }
+        ExprCall(ref callee_expression, ref arguments) => {
+            walk_list!(visitor, visit_expr, arguments);
+            visitor.visit_expr(callee_expression)
+        }
+        ExprMethodCall(ref name, ref types, ref arguments) => {
+            visitor.visit_name(name.span, name.node);
+            walk_list!(visitor, visit_expr, arguments);
+            walk_list!(visitor, visit_ty, types);
+        }
+        ExprBinary(_, ref left_expression, ref right_expression) => {
+            visitor.visit_expr(left_expression);
+            visitor.visit_expr(right_expression)
+        }
+        ExprAddrOf(_, ref subexpression) | ExprUnary(_, ref subexpression) => {
+            visitor.visit_expr(subexpression)
+        }
+        ExprLit(_) => {}
+        ExprCast(ref subexpression, ref typ) | ExprType(ref subexpression, ref typ) => {
+            visitor.visit_expr(subexpression);
+            visitor.visit_ty(typ)
+        }
+        ExprIf(ref head_expression, ref if_block, ref optional_else) => {
+            visitor.visit_expr(head_expression);
+            visitor.visit_block(if_block);
+            walk_list!(visitor, visit_expr, optional_else);
+        }
+        ExprWhile(ref subexpression, ref block, opt_ident) => {
+            visitor.visit_expr(subexpression);
+            visitor.visit_block(block);
+            walk_opt_ident(visitor, expression.span, opt_ident)
+        }
+        ExprLoop(ref block, opt_ident) => {
+            visitor.visit_block(block);
+            walk_opt_ident(visitor, expression.span, opt_ident)
+        }
+        ExprMatch(ref subexpression, ref arms, _) => {
+            visitor.visit_expr(subexpression);
+            walk_list!(visitor, visit_arm, arms);
+        }
+        ExprClosure(_, ref function_declaration, ref body) => {
+            visitor.visit_fn(FnKind::Closure(expression.attrs.as_attr_slice()),
+                             function_declaration,
+                             body,
+                             expression.span,
+                             expression.id)
+        }
+        ExprBlock(ref block) => visitor.visit_block(block),
+        ExprAssign(ref left_hand_expression, ref right_hand_expression) => {
+            visitor.visit_expr(right_hand_expression);
+            visitor.visit_expr(left_hand_expression)
+        }
+        ExprAssignOp(_, ref left_expression, ref right_expression) => {
+            visitor.visit_expr(right_expression);
+            visitor.visit_expr(left_expression)
+        }
+        ExprField(ref subexpression, ref name) => {
+            visitor.visit_expr(subexpression);
+            visitor.visit_name(name.span, name.node);
+        }
+        ExprTupField(ref subexpression, _) => {
+            visitor.visit_expr(subexpression);
+        }
+        ExprIndex(ref main_expression, ref index_expression) => {
+            visitor.visit_expr(main_expression);
+            visitor.visit_expr(index_expression)
+        }
+        ExprPath(ref maybe_qself, ref path) => {
+            if let Some(ref qself) = *maybe_qself {
+                visitor.visit_ty(&qself.ty);
+            }
+            visitor.visit_path(path, expression.id)
+        }
+        ExprBreak(ref opt_sp_ident) | ExprAgain(ref opt_sp_ident) => {
+            for sp_ident in opt_sp_ident {
+                visitor.visit_ident(sp_ident.span, sp_ident.node);
+            }
+        }
+        ExprRet(ref optional_expression) => {
+            walk_list!(visitor, visit_expr, optional_expression);
+        }
+        ExprInlineAsm(_, ref outputs, ref inputs) => {
+            for output in outputs {
+                visitor.visit_expr(output)
+            }
+            for input in inputs {
+                visitor.visit_expr(input)
+            }
+        }
+    }
+
+    visitor.visit_expr_post(expression)
+}
+
+pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) {
+    walk_list!(visitor, visit_pat, &arm.pats);
+    walk_list!(visitor, visit_expr, &arm.guard);
+    visitor.visit_expr(&arm.body);
+    walk_list!(visitor, visit_attribute, &arm.attrs);
+}
+
+#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)]
+pub struct IdRange {
+    pub min: NodeId,
+    pub max: NodeId,
+}
+
+impl IdRange {
+    pub fn max() -> IdRange {
+        IdRange {
+            min: u32::MAX,
+            max: u32::MIN,
+        }
+    }
+
+    pub fn empty(&self) -> bool {
+        self.min >= self.max
+    }
+
+    pub fn add(&mut self, id: NodeId) {
+        self.min = cmp::min(self.min, id);
+        self.max = cmp::max(self.max, id + 1);
+    }
+}
+
+pub trait IdVisitingOperation {
+    fn visit_id(&mut self, node_id: NodeId);
+}
+
+pub struct IdRangeComputingVisitor {
+    pub result: IdRange,
+}
+
+impl IdRangeComputingVisitor {
+    pub fn new() -> IdRangeComputingVisitor {
+        IdRangeComputingVisitor { result: IdRange::max() }
+    }
+
+    pub fn result(&self) -> IdRange {
+        self.result
+    }
+}
+
+impl IdVisitingOperation for IdRangeComputingVisitor {
+    fn visit_id(&mut self, id: NodeId) {
+        self.result.add(id);
+    }
+}
+
+pub struct IdVisitor<'a, O: 'a> {
+    operation: &'a mut O,
+
+    // In general, the id visitor visits the contents of an item, but
+    // not including nested trait/impl items, nor other nested items.
+    // The base visitor itself always skips nested items, but not
+    // trait/impl items. This means in particular that if you start by
+    // visiting a trait or an impl, you should not visit the
+    // trait/impl items respectively.  This is handled by setting
+    // `skip_members` to true when `visit_item` is on the stack. This
+    // way, if the user begins by calling `visit_trait_item`, we will
+    // visit the trait item, but if they begin with `visit_item`, we
+    // won't visit the (nested) trait items.
+    skip_members: bool,
+}
+
+impl<'a, O: IdVisitingOperation> IdVisitor<'a, O> {
+    pub fn new(operation: &'a mut O) -> IdVisitor<'a, O> {
+        IdVisitor { operation: operation, skip_members: false }
+    }
+
+    fn visit_generics_helper(&mut self, generics: &Generics) {
+        for type_parameter in generics.ty_params.iter() {
+            self.operation.visit_id(type_parameter.id)
+        }
+        for lifetime in &generics.lifetimes {
+            self.operation.visit_id(lifetime.lifetime.id)
+        }
+    }
+}
+
+impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> {
+    fn visit_mod(&mut self, module: &Mod, _: Span, node_id: NodeId) {
+        self.operation.visit_id(node_id);
+        walk_mod(self, module)
+    }
+
+    fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
+        self.operation.visit_id(foreign_item.id);
+        walk_foreign_item(self, foreign_item)
+    }
+
+    fn visit_item(&mut self, item: &Item) {
+        assert!(!self.skip_members);
+        self.skip_members = true;
+
+        self.operation.visit_id(item.id);
+        match item.node {
+            ItemUse(ref view_path) => {
+                match view_path.node {
+                    ViewPathSimple(_, _) |
+                    ViewPathGlob(_) => {}
+                    ViewPathList(_, ref paths) => {
+                        for path in paths {
+                            self.operation.visit_id(path.node.id())
+                        }
+                    }
+                }
+            }
+            _ => {}
+        }
+        walk_item(self, item);
+
+        self.skip_members = false;
+    }
+
+    fn visit_local(&mut self, local: &Local) {
+        self.operation.visit_id(local.id);
+        walk_local(self, local)
+    }
+
+    fn visit_block(&mut self, block: &Block) {
+        self.operation.visit_id(block.id);
+        walk_block(self, block)
+    }
+
+    fn visit_stmt(&mut self, statement: &Stmt) {
+        self.operation.visit_id(statement.node.id());
+        walk_stmt(self, statement)
+    }
+
+    fn visit_pat(&mut self, pattern: &Pat) {
+        self.operation.visit_id(pattern.id);
+        walk_pat(self, pattern)
+    }
+
+    fn visit_expr(&mut self, expression: &Expr) {
+        self.operation.visit_id(expression.id);
+        walk_expr(self, expression)
+    }
+
+    fn visit_ty(&mut self, typ: &Ty) {
+        self.operation.visit_id(typ.id);
+        walk_ty(self, typ)
+    }
+
+    fn visit_generics(&mut self, generics: &Generics) {
+        self.visit_generics_helper(generics);
+        walk_generics(self, generics)
+    }
+
+    fn visit_fn(&mut self,
+                function_kind: FnKind<'v>,
+                function_declaration: &'v FnDecl,
+                block: &'v Block,
+                span: Span,
+                node_id: NodeId) {
+        self.operation.visit_id(node_id);
+
+        match function_kind {
+            FnKind::ItemFn(_, generics, _, _, _, _, _) => {
+                self.visit_generics_helper(generics)
+            }
+            FnKind::Method(_, sig, _, _) => {
+                self.visit_generics_helper(&sig.generics)
+            }
+            FnKind::Closure(_) => {}
+        }
+
+        for argument in &function_declaration.inputs {
+            self.operation.visit_id(argument.id)
+        }
+
+        walk_fn(self, function_kind, function_declaration, block, span);
+    }
+
+    fn visit_struct_field(&mut self, struct_field: &StructField) {
+        self.operation.visit_id(struct_field.id);
+        walk_struct_field(self, struct_field)
+    }
+
+    fn visit_variant_data(&mut self,
+                          struct_def: &VariantData,
+                          _: Name,
+                          _: &Generics,
+                          _: NodeId,
+                          _: Span) {
+        self.operation.visit_id(struct_def.id());
+        walk_struct_def(self, struct_def);
+    }
+
+    fn visit_trait_item(&mut self, ti: &TraitItem) {
+        if !self.skip_members {
+            self.operation.visit_id(ti.id);
+            walk_trait_item(self, ti);
+        }
+    }
+
+    fn visit_impl_item(&mut self, ii: &ImplItem) {
+        if !self.skip_members {
+            self.operation.visit_id(ii.id);
+            walk_impl_item(self, ii);
+        }
+    }
+
+    fn visit_lifetime(&mut self, lifetime: &Lifetime) {
+        self.operation.visit_id(lifetime.id);
+    }
+
+    fn visit_lifetime_def(&mut self, def: &LifetimeDef) {
+        self.visit_lifetime(&def.lifetime);
+    }
+
+    fn visit_trait_ref(&mut self, trait_ref: &TraitRef) {
+        self.operation.visit_id(trait_ref.ref_id);
+        walk_trait_ref(self, trait_ref);
+    }
+}
+
+/// Computes the id range for a single fn body, ignoring nested items.
+pub fn compute_id_range_for_fn_body(fk: FnKind,
+                                    decl: &FnDecl,
+                                    body: &Block,
+                                    sp: Span,
+                                    id: NodeId)
+                                    -> IdRange {
+    let mut visitor = IdRangeComputingVisitor { result: IdRange::max() };
+    let mut id_visitor = IdVisitor::new(&mut visitor);
+    id_visitor.visit_fn(fk, decl, body, sp, id);
+    id_visitor.operation.result
+}
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
new file mode 100644
index 00000000000..738a04dea58
--- /dev/null
+++ b/src/librustc/hir/lowering.rs
@@ -0,0 +1,2148 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Lowers the AST to the HIR.
+//
+// Since the AST and HIR are fairly similar, this is mostly a simple procedure,
+// much like a fold. Where lowering involves a bit more work things get more
+// interesting and there are some invariants you should know about. These mostly
+// concern spans and ids.
+//
+// Spans are assigned to AST nodes during parsing and then are modified during
+// expansion to indicate the origin of a node and the process it went through
+// being expanded. Ids are assigned to AST nodes just before lowering.
+//
+// For the simpler lowering steps, ids and spans should be preserved. Unlike
+// expansion we do not preserve the process of lowering in the spans, so spans
+// should not be modified here. When creating a new node (as opposed to
+// 'folding' an existing one), then you create a new id using `next_id()`.
+//
+// You must ensure that ids are unique. That means that you should only use the
+// id from an AST node in a single HIR node (you can assume that AST node ids
+// are unique). Every new node must have a unique id. Avoid cloning HIR nodes.
+// If you do, you must then set the new node's id to a fresh one.
+//
+// Lowering must be reproducable (the compiler only lowers once, but tools and
+// custom lints may lower an AST node to a HIR node to interact with the
+// compiler). The most interesting bit of this is ids - if you lower an AST node
+// and create new HIR nodes with fresh ids, when re-lowering the same node, you
+// must ensure you get the same ids! To do this, we keep track of the next id
+// when we translate a node which requires new ids. By checking this cache and
+// using node ids starting with the cached id, we ensure ids are reproducible.
+// To use this system, you just need to hold on to a CachedIdSetter object
+// whilst lowering. This is an RAII object that takes care of setting and
+// restoring the cached id, etc.
+//
+// This whole system relies on node ids being incremented one at a time and
+// all increments being for lowering. This means that you should not call any
+// non-lowering function which will use new node ids.
+//
+// We must also cache gensym'ed Idents to ensure that we get the same Ident
+// every time we lower a node with gensym'ed names. One consequence of this is
+// that you can only gensym a name once in a lowering (you don't need to worry
+// about nested lowering though). That's because we cache based on the name and
+// the currently cached node id, which is unique per lowered node.
+//
+// Spans are used for error messages and for tools to map semantics back to
+// source code. It is therefore not as important with spans as ids to be strict
+// about use (you can't break the compiler by screwing up a span). Obviously, a
+// HIR node can only have a single span. But multiple nodes can have the same
+// span and spans don't need to be kept in order, etc. Where code is preserved
+// by lowering, it should have the same span as in the AST. Where HIR nodes are
+// new it is probably best to give a span for the whole AST node being lowered.
+// All nodes should have real spans, don't use dummy spans. Tools are likely to
+// get confused if the spans from leaf AST nodes occur in multiple places
+// in the HIR, especially for multiple identifiers.
+
+use hir;
+
+use std::collections::BTreeMap;
+use std::collections::HashMap;
+use std::iter;
+use syntax::ast::*;
+use syntax::attr::{ThinAttributes, ThinAttributesExt};
+use syntax::errors::Handler;
+use syntax::ext::mtwt;
+use syntax::ptr::P;
+use syntax::codemap::{respan, Spanned, Span};
+use syntax::parse::token;
+use syntax::std_inject;
+use syntax::visit::{self, Visitor};
+
+use std::cell::{Cell, RefCell};
+
+pub struct LoweringContext<'a> {
+    crate_root: Option<&'static str>,
+    // Map AST ids to ids used for expanded nodes.
+    id_cache: RefCell<HashMap<NodeId, NodeId>>,
+    // Use if there are no cached ids for the current node.
+    id_assigner: &'a NodeIdAssigner,
+    // 0 == no cached id. Must be incremented to align with previous id
+    // incrementing.
+    cached_id: Cell<u32>,
+    // Keep track of gensym'ed idents.
+    gensym_cache: RefCell<HashMap<(NodeId, &'static str), hir::Ident>>,
+    // A copy of cached_id, but is also set to an id while a node is lowered for
+    // the first time.
+    gensym_key: Cell<u32>,
+}
+
+impl<'a, 'hir> LoweringContext<'a> {
+    pub fn new(id_assigner: &'a NodeIdAssigner, c: Option<&Crate>) -> LoweringContext<'a> {
+        let crate_root = c.and_then(|c| {
+            if std_inject::no_core(c) {
+                None
+            } else if std_inject::no_std(c) {
+                Some("core")
+            } else {
+                Some("std")
+            }
+        });
+
+        LoweringContext {
+            crate_root: crate_root,
+            id_cache: RefCell::new(HashMap::new()),
+            id_assigner: id_assigner,
+            cached_id: Cell::new(0),
+            gensym_cache: RefCell::new(HashMap::new()),
+            gensym_key: Cell::new(0),
+        }
+    }
+
+    fn next_id(&self) -> NodeId {
+        let cached_id = self.cached_id.get();
+        if cached_id == 0 {
+            return self.id_assigner.next_node_id();
+        }
+
+        self.cached_id.set(cached_id + 1);
+        cached_id
+    }
+
+    fn str_to_ident(&self, s: &'static str) -> hir::Ident {
+        let gensym_key = self.gensym_key.get();
+        if gensym_key == 0 {
+            return hir::Ident::from_name(token::gensym(s));
+        }
+
+        let cached = self.gensym_cache.borrow().contains_key(&(gensym_key, s));
+        if cached {
+            self.gensym_cache.borrow()[&(gensym_key, s)]
+        } else {
+            let result = hir::Ident::from_name(token::gensym(s));
+            self.gensym_cache.borrow_mut().insert((gensym_key, s), result);
+            result
+        }
+    }
+
+    // Panics if this LoweringContext's NodeIdAssigner is not able to emit diagnostics.
+    fn diagnostic(&self) -> &Handler {
+        self.id_assigner.diagnostic()
+    }
+}
+
+// Utility fn for setting and unsetting the cached id.
+fn cache_ids<'a, OP, R>(lctx: &LoweringContext, expr_id: NodeId, op: OP) -> R
+    where OP: FnOnce(&LoweringContext) -> R
+{
+    // Only reset the id if it was previously 0, i.e., was not cached.
+    // If it was cached, we are in a nested node, but our id count will
+    // still count towards the parent's count.
+    let reset_cached_id = lctx.cached_id.get() == 0;
+    // We always reset gensym_key so that if we use the same name in a nested
+    // node and after that node, they get different values.
+    let old_gensym_key = lctx.gensym_key.get();
+
+    {
+        let id_cache: &mut HashMap<_, _> = &mut lctx.id_cache.borrow_mut();
+
+        if id_cache.contains_key(&expr_id) {
+            let cached_id = lctx.cached_id.get();
+            if cached_id == 0 {
+                // We're entering a node where we need to track ids, but are not
+                // yet tracking.
+                lctx.cached_id.set(id_cache[&expr_id]);
+            } else {
+                // We're already tracking - check that the tracked id is the same
+                // as the expected id.
+                assert!(cached_id == id_cache[&expr_id], "id mismatch");
+            }
+            lctx.gensym_key.set(id_cache[&expr_id]);
+        } else {
+            // We've never lowered this node before, remember it for next time.
+            let next_id = lctx.id_assigner.peek_node_id();
+            id_cache.insert(expr_id, next_id);
+            lctx.gensym_key.set(next_id);
+            // self.cached_id is not set when we lower a node for the first time,
+            // only on re-lowering.
+        }
+    }
+
+    let result = op(lctx);
+
+    if reset_cached_id {
+        lctx.cached_id.set(0);
+    }
+    lctx.gensym_key.set(old_gensym_key);
+
+    result
+}
+
+pub fn lower_ident(_lctx: &LoweringContext, ident: Ident) -> hir::Ident {
+    hir::Ident {
+        name: mtwt::resolve(ident),
+        unhygienic_name: ident.name,
+    }
+}
+
+pub fn lower_attrs(_lctx: &LoweringContext, attrs: &Vec<Attribute>) -> hir::HirVec<Attribute> {
+    attrs.clone().into()
+}
+
+pub fn lower_view_path(lctx: &LoweringContext, view_path: &ViewPath) -> P<hir::ViewPath> {
+    P(Spanned {
+        node: match view_path.node {
+            ViewPathSimple(ident, ref path) => {
+                hir::ViewPathSimple(ident.name, lower_path(lctx, path))
+            }
+            ViewPathGlob(ref path) => {
+                hir::ViewPathGlob(lower_path(lctx, path))
+            }
+            ViewPathList(ref path, ref path_list_idents) => {
+                hir::ViewPathList(lower_path(lctx, path),
+                                  path_list_idents.iter()
+                                                  .map(lower_path_list_item)
+                                                  .collect())
+            }
+        },
+        span: view_path.span,
+    })
+}
+
+fn lower_path_list_item(path_list_ident: &PathListItem) -> hir::PathListItem {
+    Spanned {
+        node: match path_list_ident.node {
+            PathListItemKind::Ident { id, name, rename } => hir::PathListIdent {
+                id: id,
+                name: name.name,
+                rename: rename.map(|x| x.name),
+            },
+            PathListItemKind::Mod { id, rename } => hir::PathListMod {
+                id: id,
+                rename: rename.map(|x| x.name),
+            },
+        },
+        span: path_list_ident.span,
+    }
+}
+
+pub fn lower_arm(lctx: &LoweringContext, arm: &Arm) -> hir::Arm {
+    hir::Arm {
+        attrs: lower_attrs(lctx, &arm.attrs),
+        pats: arm.pats.iter().map(|x| lower_pat(lctx, x)).collect(),
+        guard: arm.guard.as_ref().map(|ref x| lower_expr(lctx, x)),
+        body: lower_expr(lctx, &arm.body),
+    }
+}
+
+pub fn lower_decl(lctx: &LoweringContext, d: &Decl) -> P<hir::Decl> {
+    match d.node {
+        DeclKind::Local(ref l) => P(Spanned {
+            node: hir::DeclLocal(lower_local(lctx, l)),
+            span: d.span,
+        }),
+        DeclKind::Item(ref it) => P(Spanned {
+            node: hir::DeclItem(lower_item_id(lctx, it)),
+            span: d.span,
+        }),
+    }
+}
+
+pub fn lower_ty_binding(lctx: &LoweringContext, b: &TypeBinding) -> hir::TypeBinding {
+    hir::TypeBinding {
+        id: b.id,
+        name: b.ident.name,
+        ty: lower_ty(lctx, &b.ty),
+        span: b.span,
+    }
+}
+
+pub fn lower_ty(lctx: &LoweringContext, t: &Ty) -> P<hir::Ty> {
+    use syntax::ast::TyKind::*;
+    P(hir::Ty {
+        id: t.id,
+        node: match t.node {
+            Infer => hir::TyInfer,
+            Vec(ref ty) => hir::TyVec(lower_ty(lctx, ty)),
+            Ptr(ref mt) => hir::TyPtr(lower_mt(lctx, mt)),
+            Rptr(ref region, ref mt) => {
+                hir::TyRptr(lower_opt_lifetime(lctx, region), lower_mt(lctx, mt))
+            }
+            BareFn(ref f) => {
+                hir::TyBareFn(P(hir::BareFnTy {
+                    lifetimes: lower_lifetime_defs(lctx, &f.lifetimes),
+                    unsafety: lower_unsafety(lctx, f.unsafety),
+                    abi: f.abi,
+                    decl: lower_fn_decl(lctx, &f.decl),
+                }))
+            }
+            Tup(ref tys) => hir::TyTup(tys.iter().map(|ty| lower_ty(lctx, ty)).collect()),
+            Paren(ref ty) => {
+                return lower_ty(lctx, ty);
+            }
+            Path(ref qself, ref path) => {
+                let qself = qself.as_ref().map(|&QSelf { ref ty, position }| {
+                    hir::QSelf {
+                        ty: lower_ty(lctx, ty),
+                        position: position,
+                    }
+                });
+                hir::TyPath(qself, lower_path(lctx, path))
+            }
+            ObjectSum(ref ty, ref bounds) => {
+                hir::TyObjectSum(lower_ty(lctx, ty), lower_bounds(lctx, bounds))
+            }
+            FixedLengthVec(ref ty, ref e) => {
+                hir::TyFixedLengthVec(lower_ty(lctx, ty), lower_expr(lctx, e))
+            }
+            Typeof(ref expr) => {
+                hir::TyTypeof(lower_expr(lctx, expr))
+            }
+            PolyTraitRef(ref bounds) => {
+                hir::TyPolyTraitRef(bounds.iter().map(|b| lower_ty_param_bound(lctx, b)).collect())
+            }
+            Mac(_) => panic!("TyMac should have been expanded by now."),
+        },
+        span: t.span,
+    })
+}
+
+pub fn lower_foreign_mod(lctx: &LoweringContext, fm: &ForeignMod) -> hir::ForeignMod {
+    hir::ForeignMod {
+        abi: fm.abi,
+        items: fm.items.iter().map(|x| lower_foreign_item(lctx, x)).collect(),
+    }
+}
+
+pub fn lower_variant(lctx: &LoweringContext, v: &Variant) -> hir::Variant {
+    Spanned {
+        node: hir::Variant_ {
+            name: v.node.name.name,
+            attrs: lower_attrs(lctx, &v.node.attrs),
+            data: lower_variant_data(lctx, &v.node.data),
+            disr_expr: v.node.disr_expr.as_ref().map(|e| lower_expr(lctx, e)),
+        },
+        span: v.span,
+    }
+}
+
+// Path segments are usually unhygienic, hygienic path segments can occur only in
+// identifier-like paths originating from `ExprPath`.
+// Make life simpler for rustc_resolve by renaming only such segments.
+pub fn lower_path_full(lctx: &LoweringContext, p: &Path, maybe_hygienic: bool) -> hir::Path {
+    let maybe_hygienic = maybe_hygienic && !p.global && p.segments.len() == 1;
+    hir::Path {
+        global: p.global,
+        segments: p.segments
+                   .iter()
+                   .map(|&PathSegment { identifier, ref parameters }| {
+                       hir::PathSegment {
+                           identifier: if maybe_hygienic {
+                               lower_ident(lctx, identifier)
+                           } else {
+                               hir::Ident::from_name(identifier.name)
+                           },
+                           parameters: lower_path_parameters(lctx, parameters),
+                       }
+                   })
+                   .collect(),
+        span: p.span,
+    }
+}
+
+pub fn lower_path(lctx: &LoweringContext, p: &Path) -> hir::Path {
+    lower_path_full(lctx, p, false)
+}
+
+pub fn lower_path_parameters(lctx: &LoweringContext,
+                             path_parameters: &PathParameters)
+                             -> hir::PathParameters {
+    match *path_parameters {
+        PathParameters::AngleBracketed(ref data) =>
+            hir::AngleBracketedParameters(lower_angle_bracketed_parameter_data(lctx, data)),
+        PathParameters::Parenthesized(ref data) =>
+            hir::ParenthesizedParameters(lower_parenthesized_parameter_data(lctx, data)),
+    }
+}
+
+pub fn lower_angle_bracketed_parameter_data(lctx: &LoweringContext,
+                                            data: &AngleBracketedParameterData)
+                                            -> hir::AngleBracketedParameterData {
+    let &AngleBracketedParameterData { ref lifetimes, ref types, ref bindings } = data;
+    hir::AngleBracketedParameterData {
+        lifetimes: lower_lifetimes(lctx, lifetimes),
+        types: types.iter().map(|ty| lower_ty(lctx, ty)).collect(),
+        bindings: bindings.iter().map(|b| lower_ty_binding(lctx, b)).collect(),
+    }
+}
+
+pub fn lower_parenthesized_parameter_data(lctx: &LoweringContext,
+                                          data: &ParenthesizedParameterData)
+                                          -> hir::ParenthesizedParameterData {
+    let &ParenthesizedParameterData { ref inputs, ref output, span } = data;
+    hir::ParenthesizedParameterData {
+        inputs: inputs.iter().map(|ty| lower_ty(lctx, ty)).collect(),
+        output: output.as_ref().map(|ty| lower_ty(lctx, ty)),
+        span: span,
+    }
+}
+
+pub fn lower_local(lctx: &LoweringContext, l: &Local) -> P<hir::Local> {
+    P(hir::Local {
+        id: l.id,
+        ty: l.ty.as_ref().map(|t| lower_ty(lctx, t)),
+        pat: lower_pat(lctx, &l.pat),
+        init: l.init.as_ref().map(|e| lower_expr(lctx, e)),
+        span: l.span,
+        attrs: l.attrs.clone(),
+    })
+}
+
+pub fn lower_explicit_self_underscore(lctx: &LoweringContext,
+                                      es: &SelfKind)
+                                      -> hir::ExplicitSelf_ {
+    match *es {
+        SelfKind::Static => hir::SelfStatic,
+        SelfKind::Value(v) => hir::SelfValue(v.name),
+        SelfKind::Region(ref lifetime, m, ident) => {
+            hir::SelfRegion(lower_opt_lifetime(lctx, lifetime),
+                            lower_mutability(lctx, m),
+                            ident.name)
+        }
+        SelfKind::Explicit(ref typ, ident) => {
+            hir::SelfExplicit(lower_ty(lctx, typ), ident.name)
+        }
+    }
+}
+
+pub fn lower_mutability(_lctx: &LoweringContext, m: Mutability) -> hir::Mutability {
+    match m {
+        Mutability::Mutable => hir::MutMutable,
+        Mutability::Immutable => hir::MutImmutable,
+    }
+}
+
+pub fn lower_explicit_self(lctx: &LoweringContext, s: &ExplicitSelf) -> hir::ExplicitSelf {
+    Spanned {
+        node: lower_explicit_self_underscore(lctx, &s.node),
+        span: s.span,
+    }
+}
+
+pub fn lower_arg(lctx: &LoweringContext, arg: &Arg) -> hir::Arg {
+    hir::Arg {
+        id: arg.id,
+        pat: lower_pat(lctx, &arg.pat),
+        ty: lower_ty(lctx, &arg.ty),
+    }
+}
+
+pub fn lower_fn_decl(lctx: &LoweringContext, decl: &FnDecl) -> P<hir::FnDecl> {
+    P(hir::FnDecl {
+        inputs: decl.inputs.iter().map(|x| lower_arg(lctx, x)).collect(),
+        output: match decl.output {
+            FunctionRetTy::Ty(ref ty) => hir::Return(lower_ty(lctx, ty)),
+            FunctionRetTy::Default(span) => hir::DefaultReturn(span),
+            FunctionRetTy::None(span) => hir::NoReturn(span),
+        },
+        variadic: decl.variadic,
+    })
+}
+
+pub fn lower_ty_param_bound(lctx: &LoweringContext, tpb: &TyParamBound) -> hir::TyParamBound {
+    match *tpb {
+        TraitTyParamBound(ref ty, modifier) => {
+            hir::TraitTyParamBound(lower_poly_trait_ref(lctx, ty),
+                                   lower_trait_bound_modifier(lctx, modifier))
+        }
+        RegionTyParamBound(ref lifetime) => {
+            hir::RegionTyParamBound(lower_lifetime(lctx, lifetime))
+        }
+    }
+}
+
+pub fn lower_ty_param(lctx: &LoweringContext, tp: &TyParam) -> hir::TyParam {
+    hir::TyParam {
+        id: tp.id,
+        name: tp.ident.name,
+        bounds: lower_bounds(lctx, &tp.bounds),
+        default: tp.default.as_ref().map(|x| lower_ty(lctx, x)),
+        span: tp.span,
+    }
+}
+
+pub fn lower_ty_params(lctx: &LoweringContext,
+                       tps: &P<[TyParam]>)
+                       -> hir::HirVec<hir::TyParam> {
+    tps.iter().map(|tp| lower_ty_param(lctx, tp)).collect()
+}
+
+pub fn lower_lifetime(_lctx: &LoweringContext, l: &Lifetime) -> hir::Lifetime {
+    hir::Lifetime {
+        id: l.id,
+        name: l.name,
+        span: l.span,
+    }
+}
+
+pub fn lower_lifetime_def(lctx: &LoweringContext, l: &LifetimeDef) -> hir::LifetimeDef {
+    hir::LifetimeDef {
+        lifetime: lower_lifetime(lctx, &l.lifetime),
+        bounds: lower_lifetimes(lctx, &l.bounds),
+    }
+}
+
+pub fn lower_lifetimes(lctx: &LoweringContext, lts: &Vec<Lifetime>) -> hir::HirVec<hir::Lifetime> {
+    lts.iter().map(|l| lower_lifetime(lctx, l)).collect()
+}
+
+pub fn lower_lifetime_defs(lctx: &LoweringContext,
+                           lts: &Vec<LifetimeDef>)
+                           -> hir::HirVec<hir::LifetimeDef> {
+    lts.iter().map(|l| lower_lifetime_def(lctx, l)).collect()
+}
+
+pub fn lower_opt_lifetime(lctx: &LoweringContext,
+                          o_lt: &Option<Lifetime>)
+                          -> Option<hir::Lifetime> {
+    o_lt.as_ref().map(|lt| lower_lifetime(lctx, lt))
+}
+
+pub fn lower_generics(lctx: &LoweringContext, g: &Generics) -> hir::Generics {
+    hir::Generics {
+        ty_params: lower_ty_params(lctx, &g.ty_params),
+        lifetimes: lower_lifetime_defs(lctx, &g.lifetimes),
+        where_clause: lower_where_clause(lctx, &g.where_clause),
+    }
+}
+
+pub fn lower_where_clause(lctx: &LoweringContext, wc: &WhereClause) -> hir::WhereClause {
+    hir::WhereClause {
+        id: wc.id,
+        predicates: wc.predicates
+                      .iter()
+                      .map(|predicate| lower_where_predicate(lctx, predicate))
+                      .collect(),
+    }
+}
+
+pub fn lower_where_predicate(lctx: &LoweringContext,
+                             pred: &WherePredicate)
+                             -> hir::WherePredicate {
+    match *pred {
+        WherePredicate::BoundPredicate(WhereBoundPredicate{ ref bound_lifetimes,
+                                                            ref bounded_ty,
+                                                            ref bounds,
+                                                            span}) => {
+            hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
+                bound_lifetimes: lower_lifetime_defs(lctx, bound_lifetimes),
+                bounded_ty: lower_ty(lctx, bounded_ty),
+                bounds: bounds.iter().map(|x| lower_ty_param_bound(lctx, x)).collect(),
+                span: span,
+            })
+        }
+        WherePredicate::RegionPredicate(WhereRegionPredicate{ ref lifetime,
+                                                              ref bounds,
+                                                              span}) => {
+            hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
+                span: span,
+                lifetime: lower_lifetime(lctx, lifetime),
+                bounds: bounds.iter().map(|bound| lower_lifetime(lctx, bound)).collect(),
+            })
+        }
+        WherePredicate::EqPredicate(WhereEqPredicate{ id,
+                                                      ref path,
+                                                      ref ty,
+                                                      span}) => {
+            hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
+                id: id,
+                path: lower_path(lctx, path),
+                ty: lower_ty(lctx, ty),
+                span: span,
+            })
+        }
+    }
+}
+
+pub fn lower_variant_data(lctx: &LoweringContext, vdata: &VariantData) -> hir::VariantData {
+    match *vdata {
+        VariantData::Struct(ref fields, id) => {
+            hir::VariantData::Struct(fields.iter()
+                                           .enumerate()
+                                           .map(|f| lower_struct_field(lctx, f))
+                                           .collect(),
+                                     id)
+        }
+        VariantData::Tuple(ref fields, id) => {
+            hir::VariantData::Tuple(fields.iter()
+                                          .enumerate()
+                                          .map(|f| lower_struct_field(lctx, f))
+                                          .collect(),
+                                    id)
+        }
+        VariantData::Unit(id) => hir::VariantData::Unit(id),
+    }
+}
+
+pub fn lower_trait_ref(lctx: &LoweringContext, p: &TraitRef) -> hir::TraitRef {
+    hir::TraitRef {
+        path: lower_path(lctx, &p.path),
+        ref_id: p.ref_id,
+    }
+}
+
+pub fn lower_poly_trait_ref(lctx: &LoweringContext, p: &PolyTraitRef) -> hir::PolyTraitRef {
+    hir::PolyTraitRef {
+        bound_lifetimes: lower_lifetime_defs(lctx, &p.bound_lifetimes),
+        trait_ref: lower_trait_ref(lctx, &p.trait_ref),
+        span: p.span,
+    }
+}
+
+pub fn lower_struct_field(lctx: &LoweringContext,
+                          (index, f): (usize, &StructField))
+                          -> hir::StructField {
+    hir::StructField {
+        span: f.span,
+        id: f.id,
+        name: f.ident.map(|ident| ident.name).unwrap_or(token::intern(&index.to_string())),
+        vis: lower_visibility(lctx, &f.vis),
+        ty: lower_ty(lctx, &f.ty),
+        attrs: lower_attrs(lctx, &f.attrs),
+    }
+}
+
+pub fn lower_field(lctx: &LoweringContext, f: &Field) -> hir::Field {
+    hir::Field {
+        name: respan(f.ident.span, f.ident.node.name),
+        expr: lower_expr(lctx, &f.expr),
+        span: f.span,
+    }
+}
+
+pub fn lower_mt(lctx: &LoweringContext, mt: &MutTy) -> hir::MutTy {
+    hir::MutTy {
+        ty: lower_ty(lctx, &mt.ty),
+        mutbl: lower_mutability(lctx, mt.mutbl),
+    }
+}
+
+pub fn lower_opt_bounds(lctx: &LoweringContext,
+                        b: &Option<TyParamBounds>)
+                        -> Option<hir::TyParamBounds> {
+    b.as_ref().map(|ref bounds| lower_bounds(lctx, bounds))
+}
+
+fn lower_bounds(lctx: &LoweringContext, bounds: &TyParamBounds) -> hir::TyParamBounds {
+    bounds.iter().map(|bound| lower_ty_param_bound(lctx, bound)).collect()
+}
+
+pub fn lower_block(lctx: &LoweringContext, b: &Block) -> P<hir::Block> {
+    P(hir::Block {
+        id: b.id,
+        stmts: b.stmts.iter().map(|s| lower_stmt(lctx, s)).collect(),
+        expr: b.expr.as_ref().map(|ref x| lower_expr(lctx, x)),
+        rules: lower_block_check_mode(lctx, &b.rules),
+        span: b.span,
+    })
+}
+
+pub fn lower_item_kind(lctx: &LoweringContext, i: &ItemKind) -> hir::Item_ {
+    match *i {
+        ItemKind::ExternCrate(string) => hir::ItemExternCrate(string),
+        ItemKind::Use(ref view_path) => {
+            hir::ItemUse(lower_view_path(lctx, view_path))
+        }
+        ItemKind::Static(ref t, m, ref e) => {
+            hir::ItemStatic(lower_ty(lctx, t),
+                            lower_mutability(lctx, m),
+                            lower_expr(lctx, e))
+        }
+        ItemKind::Const(ref t, ref e) => {
+            hir::ItemConst(lower_ty(lctx, t), lower_expr(lctx, e))
+        }
+        ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
+            hir::ItemFn(lower_fn_decl(lctx, decl),
+                        lower_unsafety(lctx, unsafety),
+                        lower_constness(lctx, constness),
+                        abi,
+                        lower_generics(lctx, generics),
+                        lower_block(lctx, body))
+        }
+        ItemKind::Mod(ref m) => hir::ItemMod(lower_mod(lctx, m)),
+        ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(lower_foreign_mod(lctx, nm)),
+        ItemKind::Ty(ref t, ref generics) => {
+            hir::ItemTy(lower_ty(lctx, t), lower_generics(lctx, generics))
+        }
+        ItemKind::Enum(ref enum_definition, ref generics) => {
+            hir::ItemEnum(hir::EnumDef {
+                              variants: enum_definition.variants
+                                                       .iter()
+                                                       .map(|x| lower_variant(lctx, x))
+                                                       .collect(),
+                          },
+                          lower_generics(lctx, generics))
+        }
+        ItemKind::Struct(ref struct_def, ref generics) => {
+            let struct_def = lower_variant_data(lctx, struct_def);
+            hir::ItemStruct(struct_def, lower_generics(lctx, generics))
+        }
+        ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
+            hir::ItemDefaultImpl(lower_unsafety(lctx, unsafety),
+                                 lower_trait_ref(lctx, trait_ref))
+        }
+        ItemKind::Impl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => {
+            let new_impl_items = impl_items.iter()
+                                           .map(|item| lower_impl_item(lctx, item))
+                                           .collect();
+            let ifce = ifce.as_ref().map(|trait_ref| lower_trait_ref(lctx, trait_ref));
+            hir::ItemImpl(lower_unsafety(lctx, unsafety),
+                          lower_impl_polarity(lctx, polarity),
+                          lower_generics(lctx, generics),
+                          ifce,
+                          lower_ty(lctx, ty),
+                          new_impl_items)
+        }
+        ItemKind::Trait(unsafety, ref generics, ref bounds, ref items) => {
+            let bounds = lower_bounds(lctx, bounds);
+            let items = items.iter().map(|item| lower_trait_item(lctx, item)).collect();
+            hir::ItemTrait(lower_unsafety(lctx, unsafety),
+                           lower_generics(lctx, generics),
+                           bounds,
+                           items)
+        }
+        ItemKind::Mac(_) => panic!("Shouldn't still be around"),
+    }
+}
+
+pub fn lower_trait_item(lctx: &LoweringContext, i: &TraitItem) -> hir::TraitItem {
+    hir::TraitItem {
+        id: i.id,
+        name: i.ident.name,
+        attrs: lower_attrs(lctx, &i.attrs),
+        node: match i.node {
+            TraitItemKind::Const(ref ty, ref default) => {
+                hir::ConstTraitItem(lower_ty(lctx, ty),
+                                    default.as_ref().map(|x| lower_expr(lctx, x)))
+            }
+            TraitItemKind::Method(ref sig, ref body) => {
+                hir::MethodTraitItem(lower_method_sig(lctx, sig),
+                                     body.as_ref().map(|x| lower_block(lctx, x)))
+            }
+            TraitItemKind::Type(ref bounds, ref default) => {
+                hir::TypeTraitItem(lower_bounds(lctx, bounds),
+                                   default.as_ref().map(|x| lower_ty(lctx, x)))
+            }
+        },
+        span: i.span,
+    }
+}
+
+pub fn lower_impl_item(lctx: &LoweringContext, i: &ImplItem) -> hir::ImplItem {
+    hir::ImplItem {
+        id: i.id,
+        name: i.ident.name,
+        attrs: lower_attrs(lctx, &i.attrs),
+        vis: lower_visibility(lctx, &i.vis),
+        defaultness: lower_defaultness(lctx, i.defaultness),
+        node: match i.node {
+            ImplItemKind::Const(ref ty, ref expr) => {
+                hir::ImplItemKind::Const(lower_ty(lctx, ty), lower_expr(lctx, expr))
+            }
+            ImplItemKind::Method(ref sig, ref body) => {
+                hir::ImplItemKind::Method(lower_method_sig(lctx, sig), lower_block(lctx, body))
+            }
+            ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(lower_ty(lctx, ty)),
+            ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
+        },
+        span: i.span,
+    }
+}
+
+pub fn lower_mod(lctx: &LoweringContext, m: &Mod) -> hir::Mod {
+    hir::Mod {
+        inner: m.inner,
+        item_ids: m.items.iter().map(|x| lower_item_id(lctx, x)).collect(),
+    }
+}
+
+struct ItemLowerer<'lcx, 'interner: 'lcx> {
+    items: BTreeMap<NodeId, hir::Item>,
+    lctx: &'lcx LoweringContext<'interner>,
+}
+
+impl<'lcx, 'interner> Visitor<'lcx> for ItemLowerer<'lcx, 'interner> {
+    fn visit_item(&mut self, item: &'lcx Item) {
+        self.items.insert(item.id, lower_item(self.lctx, item));
+        visit::walk_item(self, item);
+    }
+}
+
+pub fn lower_crate(lctx: &LoweringContext, c: &Crate) -> hir::Crate {
+    let items = {
+        let mut item_lowerer = ItemLowerer { items: BTreeMap::new(), lctx: lctx };
+        visit::walk_crate(&mut item_lowerer, c);
+        item_lowerer.items
+    };
+
+    hir::Crate {
+        module: lower_mod(lctx, &c.module),
+        attrs: lower_attrs(lctx, &c.attrs),
+        config: c.config.clone().into(),
+        span: c.span,
+        exported_macros: c.exported_macros.iter().map(|m| lower_macro_def(lctx, m)).collect(),
+        items: items,
+    }
+}
+
+pub fn lower_macro_def(lctx: &LoweringContext, m: &MacroDef) -> hir::MacroDef {
+    hir::MacroDef {
+        name: m.ident.name,
+        attrs: lower_attrs(lctx, &m.attrs),
+        id: m.id,
+        span: m.span,
+        imported_from: m.imported_from.map(|x| x.name),
+        export: m.export,
+        use_locally: m.use_locally,
+        allow_internal_unstable: m.allow_internal_unstable,
+        body: m.body.clone().into(),
+    }
+}
+
+pub fn lower_item_id(_lctx: &LoweringContext, i: &Item) -> hir::ItemId {
+    hir::ItemId { id: i.id }
+}
+
+pub fn lower_item(lctx: &LoweringContext, i: &Item) -> hir::Item {
+    let node = lower_item_kind(lctx, &i.node);
+
+    hir::Item {
+        id: i.id,
+        name: i.ident.name,
+        attrs: lower_attrs(lctx, &i.attrs),
+        node: node,
+        vis: lower_visibility(lctx, &i.vis),
+        span: i.span,
+    }
+}
+
+pub fn lower_foreign_item(lctx: &LoweringContext, i: &ForeignItem) -> hir::ForeignItem {
+    hir::ForeignItem {
+        id: i.id,
+        name: i.ident.name,
+        attrs: lower_attrs(lctx, &i.attrs),
+        node: match i.node {
+            ForeignItemKind::Fn(ref fdec, ref generics) => {
+                hir::ForeignItemFn(lower_fn_decl(lctx, fdec), lower_generics(lctx, generics))
+            }
+            ForeignItemKind::Static(ref t, m) => {
+                hir::ForeignItemStatic(lower_ty(lctx, t), m)
+            }
+        },
+        vis: lower_visibility(lctx, &i.vis),
+        span: i.span,
+    }
+}
+
+pub fn lower_method_sig(lctx: &LoweringContext, sig: &MethodSig) -> hir::MethodSig {
+    hir::MethodSig {
+        generics: lower_generics(lctx, &sig.generics),
+        abi: sig.abi,
+        explicit_self: lower_explicit_self(lctx, &sig.explicit_self),
+        unsafety: lower_unsafety(lctx, sig.unsafety),
+        constness: lower_constness(lctx, sig.constness),
+        decl: lower_fn_decl(lctx, &sig.decl),
+    }
+}
+
+pub fn lower_unsafety(_lctx: &LoweringContext, u: Unsafety) -> hir::Unsafety {
+    match u {
+        Unsafety::Unsafe => hir::Unsafety::Unsafe,
+        Unsafety::Normal => hir::Unsafety::Normal,
+    }
+}
+
+pub fn lower_constness(_lctx: &LoweringContext, c: Constness) -> hir::Constness {
+    match c {
+        Constness::Const => hir::Constness::Const,
+        Constness::NotConst => hir::Constness::NotConst,
+    }
+}
+
+pub fn lower_unop(_lctx: &LoweringContext, u: UnOp) -> hir::UnOp {
+    match u {
+        UnOp::Deref => hir::UnDeref,
+        UnOp::Not => hir::UnNot,
+        UnOp::Neg => hir::UnNeg,
+    }
+}
+
+pub fn lower_binop(_lctx: &LoweringContext, b: BinOp) -> hir::BinOp {
+    Spanned {
+        node: match b.node {
+            BinOpKind::Add => hir::BiAdd,
+            BinOpKind::Sub => hir::BiSub,
+            BinOpKind::Mul => hir::BiMul,
+            BinOpKind::Div => hir::BiDiv,
+            BinOpKind::Rem => hir::BiRem,
+            BinOpKind::And => hir::BiAnd,
+            BinOpKind::Or => hir::BiOr,
+            BinOpKind::BitXor => hir::BiBitXor,
+            BinOpKind::BitAnd => hir::BiBitAnd,
+            BinOpKind::BitOr => hir::BiBitOr,
+            BinOpKind::Shl => hir::BiShl,
+            BinOpKind::Shr => hir::BiShr,
+            BinOpKind::Eq => hir::BiEq,
+            BinOpKind::Lt => hir::BiLt,
+            BinOpKind::Le => hir::BiLe,
+            BinOpKind::Ne => hir::BiNe,
+            BinOpKind::Ge => hir::BiGe,
+            BinOpKind::Gt => hir::BiGt,
+        },
+        span: b.span,
+    }
+}
+
+pub fn lower_pat(lctx: &LoweringContext, p: &Pat) -> P<hir::Pat> {
+    P(hir::Pat {
+        id: p.id,
+        node: match p.node {
+            PatKind::Wild => hir::PatKind::Wild,
+            PatKind::Ident(ref binding_mode, pth1, ref sub) => {
+                hir::PatKind::Ident(lower_binding_mode(lctx, binding_mode),
+                              respan(pth1.span, lower_ident(lctx, pth1.node)),
+                              sub.as_ref().map(|x| lower_pat(lctx, x)))
+            }
+            PatKind::Lit(ref e) => hir::PatKind::Lit(lower_expr(lctx, e)),
+            PatKind::TupleStruct(ref pth, ref pats) => {
+                hir::PatKind::TupleStruct(lower_path(lctx, pth),
+                             pats.as_ref()
+                                 .map(|pats| pats.iter().map(|x| lower_pat(lctx, x)).collect()))
+            }
+            PatKind::Path(ref pth) => {
+                hir::PatKind::Path(lower_path(lctx, pth))
+            }
+            PatKind::QPath(ref qself, ref pth) => {
+                let qself = hir::QSelf {
+                    ty: lower_ty(lctx, &qself.ty),
+                    position: qself.position,
+                };
+                hir::PatKind::QPath(qself, lower_path(lctx, pth))
+            }
+            PatKind::Struct(ref pth, ref fields, etc) => {
+                let pth = lower_path(lctx, pth);
+                let fs = fields.iter()
+                               .map(|f| {
+                                   Spanned {
+                                       span: f.span,
+                                       node: hir::FieldPat {
+                                           name: f.node.ident.name,
+                                           pat: lower_pat(lctx, &f.node.pat),
+                                           is_shorthand: f.node.is_shorthand,
+                                       },
+                                   }
+                               })
+                               .collect();
+                hir::PatKind::Struct(pth, fs, etc)
+            }
+            PatKind::Tup(ref elts) => {
+                hir::PatKind::Tup(elts.iter().map(|x| lower_pat(lctx, x)).collect())
+            }
+            PatKind::Box(ref inner) => hir::PatKind::Box(lower_pat(lctx, inner)),
+            PatKind::Ref(ref inner, mutbl) => {
+                hir::PatKind::Ref(lower_pat(lctx, inner), lower_mutability(lctx, mutbl))
+            }
+            PatKind::Range(ref e1, ref e2) => {
+                hir::PatKind::Range(lower_expr(lctx, e1), lower_expr(lctx, e2))
+            }
+            PatKind::Vec(ref before, ref slice, ref after) => {
+                hir::PatKind::Vec(before.iter().map(|x| lower_pat(lctx, x)).collect(),
+                            slice.as_ref().map(|x| lower_pat(lctx, x)),
+                            after.iter().map(|x| lower_pat(lctx, x)).collect())
+            }
+            PatKind::Mac(_) => panic!("Shouldn't exist here"),
+        },
+        span: p.span,
+    })
+}
+
+pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
+    P(hir::Expr {
+        id: e.id,
+        node: match e.node {
+            // Issue #22181:
+            // Eventually a desugaring for `box EXPR`
+            // (similar to the desugaring above for `in PLACE BLOCK`)
+            // should go here, desugaring
+            //
+            // to:
+            //
+            // let mut place = BoxPlace::make_place();
+            // let raw_place = Place::pointer(&mut place);
+            // let value = $value;
+            // unsafe {
+            //     ::std::ptr::write(raw_place, value);
+            //     Boxed::finalize(place)
+            // }
+            //
+            // But for now there are type-inference issues doing that.
+            ExprKind::Box(ref e) => {
+                hir::ExprBox(lower_expr(lctx, e))
+            }
+
+            // Desugar ExprBox: `in (PLACE) EXPR`
+            ExprKind::InPlace(ref placer, ref value_expr) => {
+                // to:
+                //
+                // let p = PLACE;
+                // let mut place = Placer::make_place(p);
+                // let raw_place = Place::pointer(&mut place);
+                // push_unsafe!({
+                //     std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR ));
+                //     InPlace::finalize(place)
+                // })
+                return cache_ids(lctx, e.id, |lctx| {
+                    let placer_expr = lower_expr(lctx, placer);
+                    let value_expr = lower_expr(lctx, value_expr);
+
+                    let placer_ident = lctx.str_to_ident("placer");
+                    let place_ident = lctx.str_to_ident("place");
+                    let p_ptr_ident = lctx.str_to_ident("p_ptr");
+
+                    let make_place = ["ops", "Placer", "make_place"];
+                    let place_pointer = ["ops", "Place", "pointer"];
+                    let move_val_init = ["intrinsics", "move_val_init"];
+                    let inplace_finalize = ["ops", "InPlace", "finalize"];
+
+                    let make_call = |lctx: &LoweringContext, p, args| {
+                        let path = core_path(lctx, e.span, p);
+                        let path = expr_path(lctx, path, None);
+                        expr_call(lctx, e.span, path, args, None)
+                    };
+
+                    let mk_stmt_let = |lctx: &LoweringContext, bind, expr| {
+                        stmt_let(lctx, e.span, false, bind, expr, None)
+                    };
+
+                    let mk_stmt_let_mut = |lctx: &LoweringContext, bind, expr| {
+                        stmt_let(lctx, e.span, true, bind, expr, None)
+                    };
+
+                    // let placer = <placer_expr> ;
+                    let s1 = {
+                        let placer_expr = signal_block_expr(lctx,
+                                                            hir_vec![],
+                                                            placer_expr,
+                                                            e.span,
+                                                            hir::PopUnstableBlock,
+                                                            None);
+                        mk_stmt_let(lctx, placer_ident, placer_expr)
+                    };
+
+                    // let mut place = Placer::make_place(placer);
+                    let s2 = {
+                        let placer = expr_ident(lctx, e.span, placer_ident, None);
+                        let call = make_call(lctx, &make_place, hir_vec![placer]);
+                        mk_stmt_let_mut(lctx, place_ident, call)
+                    };
+
+                    // let p_ptr = Place::pointer(&mut place);
+                    let s3 = {
+                        let agent = expr_ident(lctx, e.span, place_ident, None);
+                        let args = hir_vec![expr_mut_addr_of(lctx, e.span, agent, None)];
+                        let call = make_call(lctx, &place_pointer, args);
+                        mk_stmt_let(lctx, p_ptr_ident, call)
+                    };
+
+                    // pop_unsafe!(EXPR));
+                    let pop_unsafe_expr = {
+                        let value_expr = signal_block_expr(lctx,
+                                                           hir_vec![],
+                                                           value_expr,
+                                                           e.span,
+                                                           hir::PopUnstableBlock,
+                                                           None);
+                        signal_block_expr(lctx,
+                                          hir_vec![],
+                                          value_expr,
+                                          e.span,
+                                          hir::PopUnsafeBlock(hir::CompilerGenerated), None)
+                    };
+
+                    // push_unsafe!({
+                    //     std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR ));
+                    //     InPlace::finalize(place)
+                    // })
+                    let expr = {
+                        let ptr = expr_ident(lctx, e.span, p_ptr_ident, None);
+                        let call_move_val_init =
+                            hir::StmtSemi(
+                                make_call(lctx, &move_val_init, hir_vec![ptr, pop_unsafe_expr]),
+                                lctx.next_id());
+                        let call_move_val_init = respan(e.span, call_move_val_init);
+
+                        let place = expr_ident(lctx, e.span, place_ident, None);
+                        let call = make_call(lctx, &inplace_finalize, hir_vec![place]);
+                        signal_block_expr(lctx,
+                                          hir_vec![call_move_val_init],
+                                          call,
+                                          e.span,
+                                          hir::PushUnsafeBlock(hir::CompilerGenerated), None)
+                    };
+
+                    signal_block_expr(lctx,
+                                      hir_vec![s1, s2, s3],
+                                      expr,
+                                      e.span,
+                                      hir::PushUnstableBlock,
+                                      e.attrs.clone())
+                });
+            }
+
+            ExprKind::Vec(ref exprs) => {
+                hir::ExprVec(exprs.iter().map(|x| lower_expr(lctx, x)).collect())
+            }
+            ExprKind::Repeat(ref expr, ref count) => {
+                let expr = lower_expr(lctx, expr);
+                let count = lower_expr(lctx, count);
+                hir::ExprRepeat(expr, count)
+            }
+            ExprKind::Tup(ref elts) => {
+                hir::ExprTup(elts.iter().map(|x| lower_expr(lctx, x)).collect())
+            }
+            ExprKind::Call(ref f, ref args) => {
+                let f = lower_expr(lctx, f);
+                hir::ExprCall(f, args.iter().map(|x| lower_expr(lctx, x)).collect())
+            }
+            ExprKind::MethodCall(i, ref tps, ref args) => {
+                let tps = tps.iter().map(|x| lower_ty(lctx, x)).collect();
+                let args = args.iter().map(|x| lower_expr(lctx, x)).collect();
+                hir::ExprMethodCall(respan(i.span, i.node.name), tps, args)
+            }
+            ExprKind::Binary(binop, ref lhs, ref rhs) => {
+                let binop = lower_binop(lctx, binop);
+                let lhs = lower_expr(lctx, lhs);
+                let rhs = lower_expr(lctx, rhs);
+                hir::ExprBinary(binop, lhs, rhs)
+            }
+            ExprKind::Unary(op, ref ohs) => {
+                let op = lower_unop(lctx, op);
+                let ohs = lower_expr(lctx, ohs);
+                hir::ExprUnary(op, ohs)
+            }
+            ExprKind::Lit(ref l) => hir::ExprLit(P((**l).clone())),
+            ExprKind::Cast(ref expr, ref ty) => {
+                let expr = lower_expr(lctx, expr);
+                hir::ExprCast(expr, lower_ty(lctx, ty))
+            }
+            ExprKind::Type(ref expr, ref ty) => {
+                let expr = lower_expr(lctx, expr);
+                hir::ExprType(expr, lower_ty(lctx, ty))
+            }
+            ExprKind::AddrOf(m, ref ohs) => {
+                let m = lower_mutability(lctx, m);
+                let ohs = lower_expr(lctx, ohs);
+                hir::ExprAddrOf(m, ohs)
+            }
+            // More complicated than you might expect because the else branch
+            // might be `if let`.
+            ExprKind::If(ref cond, ref blk, ref else_opt) => {
+                let else_opt = else_opt.as_ref().map(|els| {
+                    match els.node {
+                        ExprKind::IfLet(..) => {
+                            cache_ids(lctx, e.id, |lctx| {
+                                // wrap the if-let expr in a block
+                                let span = els.span;
+                                let els = lower_expr(lctx, els);
+                                let id = lctx.next_id();
+                                let blk = P(hir::Block {
+                                    stmts: hir_vec![],
+                                    expr: Some(els),
+                                    id: id,
+                                    rules: hir::DefaultBlock,
+                                    span: span,
+                                });
+                                expr_block(lctx, blk, None)
+                            })
+                        }
+                        _ => lower_expr(lctx, els),
+                    }
+                });
+
+                hir::ExprIf(lower_expr(lctx, cond), lower_block(lctx, blk), else_opt)
+            }
+            ExprKind::While(ref cond, ref body, opt_ident) => {
+                hir::ExprWhile(lower_expr(lctx, cond), lower_block(lctx, body),
+                               opt_ident.map(|ident| lower_ident(lctx, ident)))
+            }
+            ExprKind::Loop(ref body, opt_ident) => {
+                hir::ExprLoop(lower_block(lctx, body),
+                              opt_ident.map(|ident| lower_ident(lctx, ident)))
+            }
+            ExprKind::Match(ref expr, ref arms) => {
+                hir::ExprMatch(lower_expr(lctx, expr),
+                               arms.iter().map(|x| lower_arm(lctx, x)).collect(),
+                               hir::MatchSource::Normal)
+            }
+            ExprKind::Closure(capture_clause, ref decl, ref body) => {
+                hir::ExprClosure(lower_capture_clause(lctx, capture_clause),
+                                 lower_fn_decl(lctx, decl),
+                                 lower_block(lctx, body))
+            }
+            ExprKind::Block(ref blk) => hir::ExprBlock(lower_block(lctx, blk)),
+            ExprKind::Assign(ref el, ref er) => {
+                hir::ExprAssign(lower_expr(lctx, el), lower_expr(lctx, er))
+            }
+            ExprKind::AssignOp(op, ref el, ref er) => {
+                hir::ExprAssignOp(lower_binop(lctx, op),
+                                  lower_expr(lctx, el),
+                                  lower_expr(lctx, er))
+            }
+            ExprKind::Field(ref el, ident) => {
+                hir::ExprField(lower_expr(lctx, el), respan(ident.span, ident.node.name))
+            }
+            ExprKind::TupField(ref el, ident) => {
+                hir::ExprTupField(lower_expr(lctx, el), ident)
+            }
+            ExprKind::Index(ref el, ref er) => {
+                hir::ExprIndex(lower_expr(lctx, el), lower_expr(lctx, er))
+            }
+            ExprKind::Range(ref e1, ref e2, lims) => {
+                fn make_struct(lctx: &LoweringContext,
+                               ast_expr: &Expr,
+                               path: &[&str],
+                               fields: &[(&str, &P<Expr>)]) -> P<hir::Expr> {
+                    let strs = std_path(lctx, &iter::once(&"ops")
+                                                    .chain(path)
+                                                    .map(|s| *s)
+                                                    .collect::<Vec<_>>());
+
+                    let structpath = path_global(ast_expr.span, strs);
+
+                    let hir_expr = if fields.len() == 0 {
+                        expr_path(lctx,
+                                  structpath,
+                                  ast_expr.attrs.clone())
+                    } else {
+                        expr_struct(lctx,
+                                    ast_expr.span,
+                                    structpath,
+                                    fields.into_iter().map(|&(s, e)| {
+                                        field(token::intern(s),
+                                              signal_block_expr(lctx,
+                                                                hir_vec![],
+                                                                lower_expr(lctx, &**e),
+                                                                e.span,
+                                                                hir::PopUnstableBlock,
+                                                                None),
+                                              ast_expr.span)
+                                    }).collect(),
+                                    None,
+                                    ast_expr.attrs.clone())
+                    };
+
+                    signal_block_expr(lctx,
+                                      hir_vec![],
+                                      hir_expr,
+                                      ast_expr.span,
+                                      hir::PushUnstableBlock,
+                                      None)
+                }
+
+                return cache_ids(lctx, e.id, |lctx| {
+                    use syntax::ast::RangeLimits::*;
+
+                    match (e1, e2, lims) {
+                        (&None,         &None,         HalfOpen) =>
+                            make_struct(lctx, e, &["RangeFull"],
+                                                 &[]),
+
+                        (&Some(ref e1), &None,         HalfOpen) =>
+                            make_struct(lctx, e, &["RangeFrom"],
+                                                 &[("start", e1)]),
+
+                        (&None,         &Some(ref e2), HalfOpen) =>
+                            make_struct(lctx, e, &["RangeTo"],
+                                                 &[("end", e2)]),
+
+                        (&Some(ref e1), &Some(ref e2), HalfOpen) =>
+                            make_struct(lctx, e, &["Range"],
+                                                 &[("start", e1), ("end", e2)]),
+
+                        (&None,         &Some(ref e2), Closed)   =>
+                            make_struct(lctx, e, &["RangeToInclusive"],
+                                                 &[("end", e2)]),
+
+                        (&Some(ref e1), &Some(ref e2), Closed)   =>
+                            make_struct(lctx, e, &["RangeInclusive", "NonEmpty"],
+                                                 &[("start", e1), ("end", e2)]),
+
+                        _ => panic!(lctx.diagnostic().span_fatal(e.span,
+                                                                 "inclusive range with no end"))
+                    }
+                });
+            }
+            ExprKind::Path(ref qself, ref path) => {
+                let hir_qself = qself.as_ref().map(|&QSelf { ref ty, position }| {
+                    hir::QSelf {
+                        ty: lower_ty(lctx, ty),
+                        position: position,
+                    }
+                });
+                hir::ExprPath(hir_qself, lower_path_full(lctx, path, qself.is_none()))
+            }
+            ExprKind::Break(opt_ident) => hir::ExprBreak(opt_ident.map(|sp_ident| {
+                respan(sp_ident.span, lower_ident(lctx, sp_ident.node))
+            })),
+            ExprKind::Again(opt_ident) => hir::ExprAgain(opt_ident.map(|sp_ident| {
+                respan(sp_ident.span, lower_ident(lctx, sp_ident.node))
+            })),
+            ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| lower_expr(lctx, x))),
+            ExprKind::InlineAsm(InlineAsm {
+                    ref inputs,
+                    ref outputs,
+                    ref asm,
+                    asm_str_style,
+                    ref clobbers,
+                    volatile,
+                    alignstack,
+                    dialect,
+                    expn_id,
+                }) => hir::ExprInlineAsm(hir::InlineAsm {
+                inputs: inputs.iter().map(|&(ref c, _)| c.clone()).collect(),
+                outputs: outputs.iter()
+                                .map(|out| {
+                                    hir::InlineAsmOutput {
+                                        constraint: out.constraint.clone(),
+                                        is_rw: out.is_rw,
+                                        is_indirect: out.is_indirect,
+                                    }
+                                })
+                                .collect(),
+                asm: asm.clone(),
+                asm_str_style: asm_str_style,
+                clobbers: clobbers.clone().into(),
+                volatile: volatile,
+                alignstack: alignstack,
+                dialect: dialect,
+                expn_id: expn_id,
+            }, outputs.iter().map(|out| lower_expr(lctx, &out.expr)).collect(),
+               inputs.iter().map(|&(_, ref input)| lower_expr(lctx, input)).collect()),
+            ExprKind::Struct(ref path, ref fields, ref maybe_expr) => {
+                hir::ExprStruct(lower_path(lctx, path),
+                                fields.iter().map(|x| lower_field(lctx, x)).collect(),
+                                maybe_expr.as_ref().map(|x| lower_expr(lctx, x)))
+            }
+            ExprKind::Paren(ref ex) => {
+                // merge attributes into the inner expression.
+                return lower_expr(lctx, ex).map(|mut ex| {
+                    ex.attrs.update(|attrs| {
+                        attrs.prepend(e.attrs.clone())
+                    });
+                    ex
+                });
+            }
+
+            // Desugar ExprIfLet
+            // From: `if let <pat> = <sub_expr> <body> [<else_opt>]`
+            ExprKind::IfLet(ref pat, ref sub_expr, ref body, ref else_opt) => {
+                // to:
+                //
+                //   match <sub_expr> {
+                //     <pat> => <body>,
+                //     [_ if <else_opt_if_cond> => <else_opt_if_body>,]
+                //     _ => [<else_opt> | ()]
+                //   }
+
+                return cache_ids(lctx, e.id, |lctx| {
+                    // `<pat> => <body>`
+                    let pat_arm = {
+                        let body = lower_block(lctx, body);
+                        let body_expr = expr_block(lctx, body, None);
+                        arm(hir_vec![lower_pat(lctx, pat)], body_expr)
+                    };
+
+                    // `[_ if <else_opt_if_cond> => <else_opt_if_body>,]`
+                    let mut else_opt = else_opt.as_ref().map(|e| lower_expr(lctx, e));
+                    let else_if_arms = {
+                        let mut arms = vec![];
+                        loop {
+                            let else_opt_continue = else_opt.and_then(|els| {
+                                els.and_then(|els| {
+                                    match els.node {
+                                        // else if
+                                        hir::ExprIf(cond, then, else_opt) => {
+                                            let pat_under = pat_wild(lctx, e.span);
+                                            arms.push(hir::Arm {
+                                                attrs: hir_vec![],
+                                                pats: hir_vec![pat_under],
+                                                guard: Some(cond),
+                                                body: expr_block(lctx, then, None),
+                                            });
+                                            else_opt.map(|else_opt| (else_opt, true))
+                                        }
+                                        _ => Some((P(els), false)),
+                                    }
+                                })
+                            });
+                            match else_opt_continue {
+                                Some((e, true)) => {
+                                    else_opt = Some(e);
+                                }
+                                Some((e, false)) => {
+                                    else_opt = Some(e);
+                                    break;
+                                }
+                                None => {
+                                    else_opt = None;
+                                    break;
+                                }
+                            }
+                        }
+                        arms
+                    };
+
+                    let contains_else_clause = else_opt.is_some();
+
+                    // `_ => [<else_opt> | ()]`
+                    let else_arm = {
+                        let pat_under = pat_wild(lctx, e.span);
+                        let else_expr =
+                            else_opt.unwrap_or_else(
+                                || expr_tuple(lctx, e.span, hir_vec![], None));
+                        arm(hir_vec![pat_under], else_expr)
+                    };
+
+                    let mut arms = Vec::with_capacity(else_if_arms.len() + 2);
+                    arms.push(pat_arm);
+                    arms.extend(else_if_arms);
+                    arms.push(else_arm);
+
+                    let sub_expr = lower_expr(lctx, sub_expr);
+                    // add attributes to the outer returned expr node
+                    expr(lctx,
+                         e.span,
+                         hir::ExprMatch(sub_expr,
+                                        arms.into(),
+                                        hir::MatchSource::IfLetDesugar {
+                                            contains_else_clause: contains_else_clause,
+                                        }),
+                         e.attrs.clone())
+                });
+            }
+
+            // Desugar ExprWhileLet
+            // From: `[opt_ident]: while let <pat> = <sub_expr> <body>`
+            ExprKind::WhileLet(ref pat, ref sub_expr, ref body, opt_ident) => {
+                // to:
+                //
+                //   [opt_ident]: loop {
+                //     match <sub_expr> {
+                //       <pat> => <body>,
+                //       _ => break
+                //     }
+                //   }
+
+                return cache_ids(lctx, e.id, |lctx| {
+                    // `<pat> => <body>`
+                    let pat_arm = {
+                        let body = lower_block(lctx, body);
+                        let body_expr = expr_block(lctx, body, None);
+                        arm(hir_vec![lower_pat(lctx, pat)], body_expr)
+                    };
+
+                    // `_ => break`
+                    let break_arm = {
+                        let pat_under = pat_wild(lctx, e.span);
+                        let break_expr = expr_break(lctx, e.span, None);
+                        arm(hir_vec![pat_under], break_expr)
+                    };
+
+                    // `match <sub_expr> { ... }`
+                    let arms = hir_vec![pat_arm, break_arm];
+                    let sub_expr = lower_expr(lctx, sub_expr);
+                    let match_expr = expr(lctx,
+                                          e.span,
+                                          hir::ExprMatch(sub_expr,
+                                                         arms,
+                                                         hir::MatchSource::WhileLetDesugar),
+                                          None);
+
+                    // `[opt_ident]: loop { ... }`
+                    let loop_block = block_expr(lctx, match_expr);
+                    let loop_expr = hir::ExprLoop(loop_block,
+                                                  opt_ident.map(|ident| lower_ident(lctx, ident)));
+                    // add attributes to the outer returned expr node
+                    expr(lctx, e.span, loop_expr, e.attrs.clone())
+                });
+            }
+
+            // Desugar ExprForLoop
+            // From: `[opt_ident]: for <pat> in <head> <body>`
+            ExprKind::ForLoop(ref pat, ref head, ref body, opt_ident) => {
+                // to:
+                //
+                //   {
+                //     let result = match ::std::iter::IntoIterator::into_iter(<head>) {
+                //       mut iter => {
+                //         [opt_ident]: loop {
+                //           match ::std::iter::Iterator::next(&mut iter) {
+                //             ::std::option::Option::Some(<pat>) => <body>,
+                //             ::std::option::Option::None => break
+                //           }
+                //         }
+                //       }
+                //     };
+                //     result
+                //   }
+
+                return cache_ids(lctx, e.id, |lctx| {
+                    // expand <head>
+                    let head = lower_expr(lctx, head);
+
+                    let iter = lctx.str_to_ident("iter");
+
+                    // `::std::option::Option::Some(<pat>) => <body>`
+                    let pat_arm = {
+                        let body_block = lower_block(lctx, body);
+                        let body_span = body_block.span;
+                        let body_expr = P(hir::Expr {
+                            id: lctx.next_id(),
+                            node: hir::ExprBlock(body_block),
+                            span: body_span,
+                            attrs: None,
+                        });
+                        let pat = lower_pat(lctx, pat);
+                        let some_pat = pat_some(lctx, e.span, pat);
+
+                        arm(hir_vec![some_pat], body_expr)
+                    };
+
+                    // `::std::option::Option::None => break`
+                    let break_arm = {
+                        let break_expr = expr_break(lctx, e.span, None);
+
+                        arm(hir_vec![pat_none(lctx, e.span)], break_expr)
+                    };
+
+                    // `match ::std::iter::Iterator::next(&mut iter) { ... }`
+                    let match_expr = {
+                        let next_path = {
+                            let strs = std_path(lctx, &["iter", "Iterator", "next"]);
+
+                            path_global(e.span, strs)
+                        };
+                        let iter = expr_ident(lctx, e.span, iter, None);
+                        let ref_mut_iter = expr_mut_addr_of(lctx, e.span, iter, None);
+                        let next_path = expr_path(lctx, next_path, None);
+                        let next_expr = expr_call(lctx,
+                                                  e.span,
+                                                  next_path,
+                                                  hir_vec![ref_mut_iter],
+                                                  None);
+                        let arms = hir_vec![pat_arm, break_arm];
+
+                        expr(lctx,
+                             e.span,
+                             hir::ExprMatch(next_expr, arms, hir::MatchSource::ForLoopDesugar),
+                             None)
+                    };
+
+                    // `[opt_ident]: loop { ... }`
+                    let loop_block = block_expr(lctx, match_expr);
+                    let loop_expr = hir::ExprLoop(loop_block,
+                                                  opt_ident.map(|ident| lower_ident(lctx, ident)));
+                    let loop_expr = expr(lctx, e.span, loop_expr, None);
+
+                    // `mut iter => { ... }`
+                    let iter_arm = {
+                        let iter_pat = pat_ident_binding_mode(lctx,
+                                                              e.span,
+                                                              iter,
+                                                              hir::BindByValue(hir::MutMutable));
+                        arm(hir_vec![iter_pat], loop_expr)
+                    };
+
+                    // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
+                    let into_iter_expr = {
+                        let into_iter_path = {
+                            let strs = std_path(lctx, &["iter", "IntoIterator", "into_iter"]);
+
+                            path_global(e.span, strs)
+                        };
+
+                        let into_iter = expr_path(lctx, into_iter_path, None);
+                        expr_call(lctx, e.span, into_iter, hir_vec![head], None)
+                    };
+
+                    let match_expr = expr_match(lctx,
+                                                e.span,
+                                                into_iter_expr,
+                                                hir_vec![iter_arm],
+                                                hir::MatchSource::ForLoopDesugar,
+                                                None);
+
+                    // `{ let _result = ...; _result }`
+                    // underscore prevents an unused_variables lint if the head diverges
+                    let result_ident = lctx.str_to_ident("_result");
+                    let let_stmt = stmt_let(lctx, e.span, false, result_ident, match_expr, None);
+                    let result = expr_ident(lctx, e.span, result_ident, None);
+                    let block = block_all(lctx, e.span, hir_vec![let_stmt], Some(result));
+                    // add the attributes to the outer returned expr node
+                    expr_block(lctx, block, e.attrs.clone())
+                });
+            }
+
+            // Desugar ExprKind::Try
+            // From: `<expr>?`
+            ExprKind::Try(ref sub_expr) => {
+                // to:
+                //
+                // {
+                //     match <expr> {
+                //         Ok(val) => val,
+                //         Err(err) => {
+                //             return Err(From::from(err))
+                //         }
+                //     }
+                // }
+
+                return cache_ids(lctx, e.id, |lctx| {
+                    // expand <expr>
+                    let sub_expr = lower_expr(lctx, sub_expr);
+
+                    // Ok(val) => val
+                    let ok_arm = {
+                        let val_ident = lctx.str_to_ident("val");
+                        let val_pat = pat_ident(lctx, e.span, val_ident);
+                        let val_expr = expr_ident(lctx, e.span, val_ident, None);
+                        let ok_pat = pat_ok(lctx, e.span, val_pat);
+
+                        arm(hir_vec![ok_pat], val_expr)
+                    };
+
+                    // Err(err) => return Err(From::from(err))
+                    let err_arm = {
+                        let err_ident = lctx.str_to_ident("err");
+                        let from_expr = {
+                            let path = std_path(lctx, &["convert", "From", "from"]);
+                            let path = path_global(e.span, path);
+                            let from = expr_path(lctx, path, None);
+                            let err_expr = expr_ident(lctx, e.span, err_ident, None);
+
+                            expr_call(lctx, e.span, from, hir_vec![err_expr], None)
+                        };
+                        let err_expr = {
+                            let path = std_path(lctx, &["result", "Result", "Err"]);
+                            let path = path_global(e.span, path);
+                            let err_ctor = expr_path(lctx, path, None);
+                            expr_call(lctx, e.span, err_ctor, hir_vec![from_expr], None)
+                        };
+                        let err_pat = pat_err(lctx, e.span, pat_ident(lctx, e.span, err_ident));
+                        let ret_expr = expr(lctx, e.span,
+                                            hir::Expr_::ExprRet(Some(err_expr)), None);
+
+                        arm(hir_vec![err_pat], ret_expr)
+                    };
+
+                    expr_match(lctx, e.span, sub_expr, hir_vec![err_arm, ok_arm],
+                               hir::MatchSource::TryDesugar, None)
+                })
+            }
+
+            ExprKind::Mac(_) => panic!("Shouldn't exist here"),
+        },
+        span: e.span,
+        attrs: e.attrs.clone(),
+    })
+}
+
+pub fn lower_stmt(lctx: &LoweringContext, s: &Stmt) -> hir::Stmt {
+    match s.node {
+        StmtKind::Decl(ref d, id) => {
+            Spanned {
+                node: hir::StmtDecl(lower_decl(lctx, d), id),
+                span: s.span,
+            }
+        }
+        StmtKind::Expr(ref e, id) => {
+            Spanned {
+                node: hir::StmtExpr(lower_expr(lctx, e), id),
+                span: s.span,
+            }
+        }
+        StmtKind::Semi(ref e, id) => {
+            Spanned {
+                node: hir::StmtSemi(lower_expr(lctx, e), id),
+                span: s.span,
+            }
+        }
+        StmtKind::Mac(..) => panic!("Shouldn't exist here"),
+    }
+}
+
+pub fn lower_capture_clause(_lctx: &LoweringContext, c: CaptureBy) -> hir::CaptureClause {
+    match c {
+        CaptureBy::Value => hir::CaptureByValue,
+        CaptureBy::Ref => hir::CaptureByRef,
+    }
+}
+
+pub fn lower_visibility(lctx: &LoweringContext, v: &Visibility) -> hir::Visibility {
+    match *v {
+        Visibility::Public => hir::Public,
+        Visibility::Inherited => hir::Inherited,
+        _ => panic!(lctx.diagnostic().fatal("pub(restricted) is not implemented yet!"))
+    }
+}
+
+pub fn lower_defaultness(_lctx: &LoweringContext, d: Defaultness) -> hir::Defaultness {
+    match d {
+        Defaultness::Default => hir::Defaultness::Default,
+        Defaultness::Final => hir::Defaultness::Final,
+    }
+}
+
+pub fn lower_block_check_mode(lctx: &LoweringContext, b: &BlockCheckMode) -> hir::BlockCheckMode {
+    match *b {
+        BlockCheckMode::Default => hir::DefaultBlock,
+        BlockCheckMode::Unsafe(u) => hir::UnsafeBlock(lower_unsafe_source(lctx, u)),
+    }
+}
+
+pub fn lower_binding_mode(lctx: &LoweringContext, b: &BindingMode) -> hir::BindingMode {
+    match *b {
+        BindingMode::ByRef(m) => hir::BindByRef(lower_mutability(lctx, m)),
+        BindingMode::ByValue(m) => hir::BindByValue(lower_mutability(lctx, m)),
+    }
+}
+
+pub fn lower_unsafe_source(_lctx: &LoweringContext, u: UnsafeSource) -> hir::UnsafeSource {
+    match u {
+        CompilerGenerated => hir::CompilerGenerated,
+        UserProvided => hir::UserProvided,
+    }
+}
+
+pub fn lower_impl_polarity(_lctx: &LoweringContext, i: ImplPolarity) -> hir::ImplPolarity {
+    match i {
+        ImplPolarity::Positive => hir::ImplPolarity::Positive,
+        ImplPolarity::Negative => hir::ImplPolarity::Negative,
+    }
+}
+
+pub fn lower_trait_bound_modifier(_lctx: &LoweringContext,
+                                  f: TraitBoundModifier)
+                                  -> hir::TraitBoundModifier {
+    match f {
+        TraitBoundModifier::None => hir::TraitBoundModifier::None,
+        TraitBoundModifier::Maybe => hir::TraitBoundModifier::Maybe,
+    }
+}
+
+// Helper methods for building HIR.
+
+fn arm(pats: hir::HirVec<P<hir::Pat>>, expr: P<hir::Expr>) -> hir::Arm {
+    hir::Arm {
+        attrs: hir_vec![],
+        pats: pats,
+        guard: None,
+        body: expr,
+    }
+}
+
+fn field(name: Name, expr: P<hir::Expr>, span: Span) -> hir::Field {
+    hir::Field {
+        name: Spanned {
+            node: name,
+            span: span,
+        },
+        span: span,
+        expr: expr,
+    }
+}
+
+fn expr_break(lctx: &LoweringContext, span: Span,
+              attrs: ThinAttributes) -> P<hir::Expr> {
+    expr(lctx, span, hir::ExprBreak(None), attrs)
+}
+
+fn expr_call(lctx: &LoweringContext,
+             span: Span,
+             e: P<hir::Expr>,
+             args: hir::HirVec<P<hir::Expr>>,
+             attrs: ThinAttributes)
+             -> P<hir::Expr> {
+    expr(lctx, span, hir::ExprCall(e, args), attrs)
+}
+
+fn expr_ident(lctx: &LoweringContext, span: Span, id: hir::Ident,
+              attrs: ThinAttributes) -> P<hir::Expr> {
+    expr_path(lctx, path_ident(span, id), attrs)
+}
+
+fn expr_mut_addr_of(lctx: &LoweringContext, span: Span, e: P<hir::Expr>,
+                    attrs: ThinAttributes) -> P<hir::Expr> {
+    expr(lctx, span, hir::ExprAddrOf(hir::MutMutable, e), attrs)
+}
+
+fn expr_path(lctx: &LoweringContext, path: hir::Path,
+             attrs: ThinAttributes) -> P<hir::Expr> {
+    expr(lctx, path.span, hir::ExprPath(None, path), attrs)
+}
+
+fn expr_match(lctx: &LoweringContext,
+              span: Span,
+              arg: P<hir::Expr>,
+              arms: hir::HirVec<hir::Arm>,
+              source: hir::MatchSource,
+              attrs: ThinAttributes)
+              -> P<hir::Expr> {
+    expr(lctx, span, hir::ExprMatch(arg, arms, source), attrs)
+}
+
+fn expr_block(lctx: &LoweringContext, b: P<hir::Block>,
+              attrs: ThinAttributes) -> P<hir::Expr> {
+    expr(lctx, b.span, hir::ExprBlock(b), attrs)
+}
+
+fn expr_tuple(lctx: &LoweringContext, sp: Span, exprs: hir::HirVec<P<hir::Expr>>,
+              attrs: ThinAttributes) -> P<hir::Expr> {
+    expr(lctx, sp, hir::ExprTup(exprs), attrs)
+}
+
+fn expr_struct(lctx: &LoweringContext,
+               sp: Span,
+               path: hir::Path,
+               fields: hir::HirVec<hir::Field>,
+               e: Option<P<hir::Expr>>,
+               attrs: ThinAttributes) -> P<hir::Expr> {
+    expr(lctx, sp, hir::ExprStruct(path, fields, e), attrs)
+}
+
+fn expr(lctx: &LoweringContext, span: Span, node: hir::Expr_,
+        attrs: ThinAttributes) -> P<hir::Expr> {
+    P(hir::Expr {
+        id: lctx.next_id(),
+        node: node,
+        span: span,
+        attrs: attrs,
+    })
+}
+
+fn stmt_let(lctx: &LoweringContext,
+            sp: Span,
+            mutbl: bool,
+            ident: hir::Ident,
+            ex: P<hir::Expr>,
+            attrs: ThinAttributes)
+            -> hir::Stmt {
+    let pat = if mutbl {
+        pat_ident_binding_mode(lctx, sp, ident, hir::BindByValue(hir::MutMutable))
+    } else {
+        pat_ident(lctx, sp, ident)
+    };
+    let local = P(hir::Local {
+        pat: pat,
+        ty: None,
+        init: Some(ex),
+        id: lctx.next_id(),
+        span: sp,
+        attrs: attrs,
+    });
+    let decl = respan(sp, hir::DeclLocal(local));
+    respan(sp, hir::StmtDecl(P(decl), lctx.next_id()))
+}
+
+fn block_expr(lctx: &LoweringContext, expr: P<hir::Expr>) -> P<hir::Block> {
+    block_all(lctx, expr.span, hir::HirVec::new(), Some(expr))
+}
+
+fn block_all(lctx: &LoweringContext,
+             span: Span,
+             stmts: hir::HirVec<hir::Stmt>,
+             expr: Option<P<hir::Expr>>)
+             -> P<hir::Block> {
+    P(hir::Block {
+        stmts: stmts,
+        expr: expr,
+        id: lctx.next_id(),
+        rules: hir::DefaultBlock,
+        span: span,
+    })
+}
+
+fn pat_ok(lctx: &LoweringContext, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
+    let ok = std_path(lctx, &["result", "Result", "Ok"]);
+    let path = path_global(span, ok);
+    pat_enum(lctx, span, path, hir_vec![pat])
+}
+
+fn pat_err(lctx: &LoweringContext, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
+    let err = std_path(lctx, &["result", "Result", "Err"]);
+    let path = path_global(span, err);
+    pat_enum(lctx, span, path, hir_vec![pat])
+}
+
+fn pat_some(lctx: &LoweringContext, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
+    let some = std_path(lctx, &["option", "Option", "Some"]);
+    let path = path_global(span, some);
+    pat_enum(lctx, span, path, hir_vec![pat])
+}
+
+fn pat_none(lctx: &LoweringContext, span: Span) -> P<hir::Pat> {
+    let none = std_path(lctx, &["option", "Option", "None"]);
+    let path = path_global(span, none);
+    pat_enum(lctx, span, path, hir_vec![])
+}
+
+fn pat_enum(lctx: &LoweringContext,
+            span: Span,
+            path: hir::Path,
+            subpats: hir::HirVec<P<hir::Pat>>)
+            -> P<hir::Pat> {
+    let pt = if subpats.is_empty() {
+        hir::PatKind::Path(path)
+    } else {
+        hir::PatKind::TupleStruct(path, Some(subpats))
+    };
+    pat(lctx, span, pt)
+}
+
+fn pat_ident(lctx: &LoweringContext, span: Span, ident: hir::Ident) -> P<hir::Pat> {
+    pat_ident_binding_mode(lctx, span, ident, hir::BindByValue(hir::MutImmutable))
+}
+
+fn pat_ident_binding_mode(lctx: &LoweringContext,
+                          span: Span,
+                          ident: hir::Ident,
+                          bm: hir::BindingMode)
+                          -> P<hir::Pat> {
+    let pat_ident = hir::PatKind::Ident(bm,
+                                  Spanned {
+                                      span: span,
+                                      node: ident,
+                                  },
+                                  None);
+    pat(lctx, span, pat_ident)
+}
+
+fn pat_wild(lctx: &LoweringContext, span: Span) -> P<hir::Pat> {
+    pat(lctx, span, hir::PatKind::Wild)
+}
+
+fn pat(lctx: &LoweringContext, span: Span, pat: hir::PatKind) -> P<hir::Pat> {
+    P(hir::Pat {
+        id: lctx.next_id(),
+        node: pat,
+        span: span,
+    })
+}
+
+fn path_ident(span: Span, id: hir::Ident) -> hir::Path {
+    path(span, vec![id])
+}
+
+fn path(span: Span, strs: Vec<hir::Ident>) -> hir::Path {
+    path_all(span, false, strs, hir::HirVec::new(), hir::HirVec::new(), hir::HirVec::new())
+}
+
+fn path_global(span: Span, strs: Vec<hir::Ident>) -> hir::Path {
+    path_all(span, true, strs, hir::HirVec::new(), hir::HirVec::new(), hir::HirVec::new())
+}
+
+fn path_all(sp: Span,
+            global: bool,
+            mut idents: Vec<hir::Ident>,
+            lifetimes: hir::HirVec<hir::Lifetime>,
+            types: hir::HirVec<P<hir::Ty>>,
+            bindings: hir::HirVec<hir::TypeBinding>)
+            -> hir::Path {
+    let last_identifier = idents.pop().unwrap();
+    let mut segments: Vec<hir::PathSegment> = idents.into_iter()
+                                                    .map(|ident| {
+                                                        hir::PathSegment {
+                                                            identifier: ident,
+                                                            parameters: hir::PathParameters::none(),
+                                                        }
+                                                    })
+                                                    .collect();
+    segments.push(hir::PathSegment {
+        identifier: last_identifier,
+        parameters: hir::AngleBracketedParameters(hir::AngleBracketedParameterData {
+            lifetimes: lifetimes,
+            types: types,
+            bindings: bindings,
+        }),
+    });
+    hir::Path {
+        span: sp,
+        global: global,
+        segments: segments.into(),
+    }
+}
+
+fn std_path(lctx: &LoweringContext, components: &[&str]) -> Vec<hir::Ident> {
+    let mut v = Vec::new();
+    if let Some(s) = lctx.crate_root {
+        v.push(hir::Ident::from_name(token::intern(s)));
+    }
+    v.extend(components.iter().map(|s| hir::Ident::from_name(token::intern(s))));
+    return v;
+}
+
+// Given suffix ["b","c","d"], returns path `::std::b::c::d` when
+// `fld.cx.use_std`, and `::core::b::c::d` otherwise.
+fn core_path(lctx: &LoweringContext, span: Span, components: &[&str]) -> hir::Path {
+    let idents = std_path(lctx, components);
+    path_global(span, idents)
+}
+
+fn signal_block_expr(lctx: &LoweringContext,
+                     stmts: hir::HirVec<hir::Stmt>,
+                     expr: P<hir::Expr>,
+                     span: Span,
+                     rule: hir::BlockCheckMode,
+                     attrs: ThinAttributes)
+                     -> P<hir::Expr> {
+    let id = lctx.next_id();
+    expr_block(lctx,
+               P(hir::Block {
+                   rules: rule,
+                   span: span,
+                   id: id,
+                   stmts: stmts,
+                   expr: Some(expr),
+               }),
+               attrs)
+}
+
+
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use syntax::ast::{self, NodeId, NodeIdAssigner};
+    use syntax::{parse, codemap};
+    use syntax::fold::Folder;
+    use std::cell::Cell;
+
+    struct MockAssigner {
+        next_id: Cell<NodeId>,
+    }
+
+    impl MockAssigner {
+        fn new() -> MockAssigner {
+            MockAssigner { next_id: Cell::new(0) }
+        }
+    }
+
+    trait FakeExtCtxt {
+        fn call_site(&self) -> codemap::Span;
+        fn cfg(&self) -> ast::CrateConfig;
+        fn ident_of(&self, st: &str) -> ast::Ident;
+        fn name_of(&self, st: &str) -> ast::Name;
+        fn parse_sess(&self) -> &parse::ParseSess;
+    }
+
+    impl FakeExtCtxt for parse::ParseSess {
+        fn call_site(&self) -> codemap::Span {
+            codemap::Span {
+                lo: codemap::BytePos(0),
+                hi: codemap::BytePos(0),
+                expn_id: codemap::NO_EXPANSION,
+            }
+        }
+        fn cfg(&self) -> ast::CrateConfig {
+            Vec::new()
+        }
+        fn ident_of(&self, st: &str) -> ast::Ident {
+            parse::token::str_to_ident(st)
+        }
+        fn name_of(&self, st: &str) -> ast::Name {
+            parse::token::intern(st)
+        }
+        fn parse_sess(&self) -> &parse::ParseSess {
+            self
+        }
+    }
+
+    impl NodeIdAssigner for MockAssigner {
+        fn next_node_id(&self) -> NodeId {
+            let result = self.next_id.get();
+            self.next_id.set(result + 1);
+            result
+        }
+
+        fn peek_node_id(&self) -> NodeId {
+            self.next_id.get()
+        }
+    }
+
+    impl Folder for MockAssigner {
+        fn new_id(&mut self, old_id: NodeId) -> NodeId {
+            assert_eq!(old_id, ast::DUMMY_NODE_ID);
+            self.next_node_id()
+        }
+    }
+
+    #[test]
+    fn test_preserves_ids() {
+        let cx = parse::ParseSess::new();
+        let mut assigner = MockAssigner::new();
+
+        let ast_if_let = quote_expr!(&cx,
+                                     if let Some(foo) = baz {
+                                         bar(foo);
+                                     });
+        let ast_if_let = assigner.fold_expr(ast_if_let);
+        let ast_while_let = quote_expr!(&cx,
+                                        while let Some(foo) = baz {
+                                            bar(foo);
+                                        });
+        let ast_while_let = assigner.fold_expr(ast_while_let);
+        let ast_for = quote_expr!(&cx,
+                                  for i in 0..10 {
+                                      for j in 0..10 {
+                                          foo(i, j);
+                                      }
+                                  });
+        let ast_for = assigner.fold_expr(ast_for);
+        let ast_in = quote_expr!(&cx, in HEAP { foo() });
+        let ast_in = assigner.fold_expr(ast_in);
+
+        let lctx = LoweringContext::new(&assigner, None);
+        let hir1 = lower_expr(&lctx, &ast_if_let);
+        let hir2 = lower_expr(&lctx, &ast_if_let);
+        assert!(hir1 == hir2);
+
+        let hir1 = lower_expr(&lctx, &ast_while_let);
+        let hir2 = lower_expr(&lctx, &ast_while_let);
+        assert!(hir1 == hir2);
+
+        let hir1 = lower_expr(&lctx, &ast_for);
+        let hir2 = lower_expr(&lctx, &ast_for);
+        assert!(hir1 == hir2);
+
+        let hir1 = lower_expr(&lctx, &ast_in);
+        let hir2 = lower_expr(&lctx, &ast_in);
+        assert!(hir1 == hir2);
+    }
+}
diff --git a/src/librustc/front/map/blocks.rs b/src/librustc/hir/map/blocks.rs
index 2eb3d56bb5e..7b1c692d54b 100644
--- a/src/librustc/front/map/blocks.rs
+++ b/src/librustc/hir/map/blocks.rs
@@ -23,14 +23,14 @@
 
 pub use self::Code::*;
 
-use front::map::{self, Node};
+use hir::map::{self, Node};
 use syntax::abi;
-use rustc_front::hir::{Block, FnDecl};
+use hir::{Block, FnDecl};
 use syntax::ast::{Attribute, Name, NodeId};
 use syntax::attr::ThinAttributesExt;
-use rustc_front::hir as ast;
+use hir as ast;
 use syntax::codemap::Span;
-use rustc_front::intravisit::FnKind;
+use hir::intravisit::FnKind;
 
 /// An FnLikeNode is a Node that is like a fn, in that it has a decl
 /// and a body (as well as a NodeId, a span, etc).
diff --git a/src/librustc/front/map/collector.rs b/src/librustc/hir/map/collector.rs
index 4ae03b1b9d7..94fa393ae3d 100644
--- a/src/librustc/front/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -11,10 +11,10 @@
 use super::*;
 use super::MapEntry::*;
 
-use rustc_front::hir::*;
-use rustc_front::util;
-use rustc_front::intravisit::{self, Visitor};
-use middle::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
+use hir::*;
+use hir::intravisit::Visitor;
+use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
+use middle::cstore::InlinedItem;
 use std::iter::repeat;
 use syntax::ast::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID};
 use syntax::codemap::Span;
@@ -47,7 +47,7 @@ impl<'ast> NodeCollector<'ast> {
     }
 
     pub fn extend(krate: &'ast Crate,
-                  parent: &'ast InlinedParent,
+                  parent: &'ast InlinedItem,
                   parent_node: NodeId,
                   parent_def_path: DefPath,
                   parent_def_id: DefId,
@@ -305,7 +305,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
     }
 
     fn visit_stmt(&mut self, stmt: &'ast Stmt) {
-        let id = util::stmt_id(stmt);
+        let id = stmt.node.id();
         self.insert(id, NodeStmt(stmt));
         let parent_node = self.parent_node;
         self.parent_node = id;
diff --git a/src/librustc/front/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index 82574b85229..d045313cb1e 100644
--- a/src/librustc/front/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use middle::cstore::LOCAL_CRATE;
-use middle::def_id::{DefId, DefIndex};
+use hir::def_id::{DefId, DefIndex};
 use rustc_data_structures::fnv::FnvHashMap;
 use syntax::ast;
 use syntax::parse::token::InternedString;
diff --git a/src/librustc/front/map/mod.rs b/src/librustc/hir/map/mod.rs
index 817bec58407..e1b7afda58b 100644
--- a/src/librustc/front/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 pub use self::Node::*;
-pub use self::PathElem::*;
 use self::MapEntry::*;
 use self::collector::NodeCollector;
 pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData,
@@ -19,100 +18,26 @@ use dep_graph::{DepGraph, DepNode};
 
 use middle::cstore::InlinedItem;
 use middle::cstore::InlinedItem as II;
-use middle::def_id::{CRATE_DEF_INDEX, DefId};
+use hir::def_id::{CRATE_DEF_INDEX, DefId};
 
 use syntax::abi::Abi;
 use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID};
 use syntax::attr::ThinAttributesExt;
 use syntax::codemap::{Span, Spanned};
-use syntax::parse::token;
 
-use rustc_front::hir::*;
-use rustc_front::fold::Folder;
-use rustc_front::intravisit;
-use rustc_front::print::pprust;
+use hir::*;
+use hir::fold::Folder;
+use hir::print as pprust;
 
 use arena::TypedArena;
 use std::cell::RefCell;
-use std::fmt;
 use std::io;
-use std::iter;
 use std::mem;
-use std::slice;
 
 pub mod blocks;
 mod collector;
 pub mod definitions;
 
-#[derive(Clone, Copy, PartialEq, Debug)]
-pub enum PathElem {
-    PathMod(Name),
-    PathName(Name)
-}
-
-impl PathElem {
-    pub fn name(&self) -> Name {
-        match *self {
-            PathMod(name) | PathName(name) => name
-        }
-    }
-}
-
-impl fmt::Display for PathElem {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", self.name())
-    }
-}
-
-#[derive(Clone)]
-pub struct LinkedPathNode<'a> {
-    node: PathElem,
-    next: LinkedPath<'a>,
-}
-
-#[derive(Copy, Clone)]
-pub struct LinkedPath<'a>(Option<&'a LinkedPathNode<'a>>);
-
-impl<'a> LinkedPath<'a> {
-    pub fn empty() -> LinkedPath<'a> {
-        LinkedPath(None)
-    }
-
-    pub fn from(node: &'a LinkedPathNode) -> LinkedPath<'a> {
-        LinkedPath(Some(node))
-    }
-}
-
-impl<'a> Iterator for LinkedPath<'a> {
-    type Item = PathElem;
-
-    fn next(&mut self) -> Option<PathElem> {
-        match self.0 {
-            Some(node) => {
-                *self = node.next;
-                Some(node.node)
-            }
-            None => None
-        }
-    }
-}
-
-/// The type of the iterator used by with_path.
-pub type PathElems<'a, 'b> = iter::Chain<iter::Cloned<slice::Iter<'a, PathElem>>, LinkedPath<'b>>;
-
-pub fn path_to_string<PI: Iterator<Item=PathElem>>(path: PI) -> String {
-    let itr = token::get_ident_interner();
-
-    path.fold(String::new(), |mut s, e| {
-        let e = itr.get(e.name());
-        if !s.is_empty() {
-            s.push_str("::");
-        }
-        s.push_str(&e[..]);
-        s
-    })
-}
-
 #[derive(Copy, Clone, Debug)]
 pub enum Node<'ast> {
     NodeItem(&'ast Item),
@@ -157,7 +82,7 @@ pub enum MapEntry<'ast> {
 
     /// Roots for node trees.
     RootCrate,
-    RootInlinedParent(&'ast InlinedParent)
+    RootInlinedParent(&'ast InlinedItem)
 }
 
 impl<'ast> Clone for MapEntry<'ast> {
@@ -166,12 +91,6 @@ impl<'ast> Clone for MapEntry<'ast> {
     }
 }
 
-#[derive(Debug)]
-pub struct InlinedParent {
-    path: Vec<PathElem>,
-    ii: InlinedItem
-}
-
 impl<'ast> MapEntry<'ast> {
     fn from_node(p: NodeId, node: Node<'ast>) -> MapEntry<'ast> {
         match node {
@@ -234,7 +153,7 @@ impl<'ast> MapEntry<'ast> {
 pub struct Forest {
     krate: Crate,
     pub dep_graph: DepGraph,
-    inlined_items: TypedArena<InlinedParent>
+    inlined_items: TypedArena<InlinedItem>
 }
 
 impl Forest {
@@ -352,8 +271,10 @@ impl<'ast> Map<'ast> {
         self.definitions.borrow().def_key(def_id.index)
     }
 
-    pub fn def_path_from_id(&self, id: NodeId) -> DefPath {
-        self.def_path(self.local_def_id(id))
+    pub fn def_path_from_id(&self, id: NodeId) -> Option<DefPath> {
+        self.opt_local_def_id(id).map(|def_id| {
+            self.def_path(def_id)
+        })
     }
 
     pub fn def_path(&self, def_id: DefId) -> DefPath {
@@ -552,8 +473,8 @@ impl<'ast> Map<'ast> {
     pub fn get_parent_did(&self, id: NodeId) -> DefId {
         let parent = self.get_parent(id);
         match self.find_entry(parent) {
-            Some(RootInlinedParent(&InlinedParent {ii: II::TraitItem(did, _), ..})) => did,
-            Some(RootInlinedParent(&InlinedParent {ii: II::ImplItem(did, _), ..})) => did,
+            Some(RootInlinedParent(&II::TraitItem(did, _))) |
+            Some(RootInlinedParent(&II::ImplItem(did, _))) => did,
             _ => self.local_def_id(parent)
         }
     }
@@ -635,80 +556,21 @@ impl<'ast> Map<'ast> {
         }
     }
 
-    /// returns the name associated with the given NodeId's AST
-    pub fn get_path_elem(&self, id: NodeId) -> PathElem {
-        let node = self.get(id);
-        match node {
-            NodeItem(item) => {
-                match item.node {
-                    ItemMod(_) | ItemForeignMod(_) => {
-                        PathMod(item.name)
-                    }
-                    _ => PathName(item.name)
-                }
-            }
-            NodeForeignItem(i) => PathName(i.name),
-            NodeImplItem(ii) => PathName(ii.name),
-            NodeTraitItem(ti) => PathName(ti.name),
-            NodeVariant(v) => PathName(v.node.name),
-            NodeLifetime(lt) => PathName(lt.name),
-            NodeTyParam(tp) => PathName(tp.name),
+    /// Returns the name associated with the given NodeId's AST.
+    pub fn name(&self, id: NodeId) -> Name {
+        match self.get(id) {
+            NodeItem(i) => i.name,
+            NodeForeignItem(i) => i.name,
+            NodeImplItem(ii) => ii.name,
+            NodeTraitItem(ti) => ti.name,
+            NodeVariant(v) => v.node.name,
+            NodeLifetime(lt) => lt.name,
+            NodeTyParam(tp) => tp.name,
             NodeLocal(&Pat { node: PatKind::Ident(_,l,_), .. }) => {
-                PathName(l.node.name)
+                l.node.name
             },
-            _ => bug!("no path elem for {:?}", node)
-        }
-    }
-
-    pub fn with_path<T, F>(&self, id: NodeId, f: F) -> T where
-        F: FnOnce(PathElems) -> T,
-    {
-        self.with_path_next(id, LinkedPath::empty(), f)
-    }
-
-    pub fn path_to_string(&self, id: NodeId) -> String {
-        self.with_path(id, |path| path_to_string(path))
-    }
-
-    fn path_to_str_with_name(&self, id: NodeId, name: Name) -> String {
-        self.with_path(id, |path| {
-            path_to_string(path.chain(Some(PathName(name))))
-        })
-    }
-
-    fn with_path_next<T, F>(&self, id: NodeId, next: LinkedPath, f: F) -> T where
-        F: FnOnce(PathElems) -> T,
-    {
-        // This function reveals the name of the item and hence is a
-        // kind of read. This is inefficient, since it walks ancestors
-        // and we are walking them anyhow, but whatever.
-        self.read(id);
-
-        let parent = self.get_parent(id);
-        let parent = match self.find_entry(id) {
-            Some(EntryForeignItem(..)) => {
-                // Anonymous extern items go in the parent scope.
-                self.get_parent(parent)
-            }
-            // But tuple struct ctors don't have names, so use the path of its
-            // parent, the struct item. Similarly with closure expressions.
-            Some(EntryStructCtor(..)) | Some(EntryExpr(..)) => {
-                return self.with_path_next(parent, next, f);
-            }
-            _ => parent
-        };
-        if parent == id {
-            match self.find_entry(id) {
-                Some(RootInlinedParent(data)) => {
-                    f(data.path.iter().cloned().chain(next))
-                }
-                _ => f([].iter().cloned().chain(next))
-            }
-        } else {
-            self.with_path_next(parent, LinkedPath::from(&LinkedPathNode {
-                node: self.get_path_elem(id),
-                next: next
-            }), f)
+            NodeStructCtor(_) => self.name(self.get_parent(id)),
+            _ => bug!("no name for {}", self.node_to_string(id))
         }
     }
 
@@ -959,7 +821,6 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest) -> Map<'ast> {
 /// Used for items loaded from external crate that are being inlined into this
 /// crate.
 pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
-                                          parent_path: Vec<PathElem>,
                                           parent_def_path: DefPath,
                                           parent_def_id: DefId,
                                           ii: InlinedItem,
@@ -979,27 +840,24 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
         II::Foreign(i) => II::Foreign(i.map(|i| fld.fold_foreign_item(i)))
     };
 
-    let ii_parent = map.forest.inlined_items.alloc(InlinedParent {
-        path: parent_path,
-        ii: ii
-    });
+    let ii = map.forest.inlined_items.alloc(ii);
 
     let ii_parent_id = fld.new_id(DUMMY_NODE_ID);
     let mut collector =
         NodeCollector::extend(
             map.krate(),
-            ii_parent,
+            ii,
             ii_parent_id,
             parent_def_path,
             parent_def_id,
             mem::replace(&mut *map.map.borrow_mut(), vec![]),
             mem::replace(&mut *map.definitions.borrow_mut(), Definitions::new()));
-    ii_parent.ii.visit(&mut collector);
+    ii.visit(&mut collector);
 
     *map.map.borrow_mut() = collector.map;
     *map.definitions.borrow_mut() = collector.definitions;
 
-    &ii_parent.ii
+    ii
 }
 
 pub trait NodePrinter {
@@ -1033,9 +891,24 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
     let id_str = format!(" (id={})", id);
     let id_str = if include_id { &id_str[..] } else { "" };
 
+    let path_str = || {
+        // This functionality is used for debugging, try to use TyCtxt to get
+        // the user-friendly path, otherwise fall back to stringifying DefPath.
+        ::ty::tls::with_opt(|tcx| {
+            if let Some(tcx) = tcx {
+                tcx.node_path_str(id)
+            } else if let Some(path) = map.def_path_from_id(id) {
+                path.data.into_iter().map(|elem| {
+                    elem.data.to_string()
+                }).collect::<Vec<_>>().join("::")
+            } else {
+                String::from("<missing path>")
+            }
+        })
+    };
+
     match map.find(id) {
         Some(NodeItem(item)) => {
-            let path_str = map.path_to_str_with_name(id, item.name);
             let item_str = match item.node {
                 ItemExternCrate(..) => "extern crate",
                 ItemUse(..) => "use",
@@ -1051,30 +924,21 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
                 ItemImpl(..) => "impl",
                 ItemDefaultImpl(..) => "default impl",
             };
-            format!("{} {}{}", item_str, path_str, id_str)
+            format!("{} {}{}", item_str, path_str(), id_str)
         }
-        Some(NodeForeignItem(item)) => {
-            let path_str = map.path_to_str_with_name(id, item.name);
-            format!("foreign item {}{}", path_str, id_str)
+        Some(NodeForeignItem(_)) => {
+            format!("foreign item {}{}", path_str(), id_str)
         }
         Some(NodeImplItem(ii)) => {
             match ii.node {
                 ImplItemKind::Const(..) => {
-                    format!("assoc const {} in {}{}",
-                            ii.name,
-                            map.path_to_string(id),
-                            id_str)
+                    format!("assoc const {} in {}{}", ii.name, path_str(), id_str)
                 }
                 ImplItemKind::Method(..) => {
-                    format!("method {} in {}{}",
-                            ii.name,
-                            map.path_to_string(id), id_str)
+                    format!("method {} in {}{}", ii.name, path_str(), id_str)
                 }
                 ImplItemKind::Type(_) => {
-                    format!("assoc type {} in {}{}",
-                            ii.name,
-                            map.path_to_string(id),
-                            id_str)
+                    format!("assoc type {} in {}{}", ii.name, path_str(), id_str)
                 }
             }
         }
@@ -1085,16 +949,12 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
                 TypeTraitItem(..) => "assoc type",
             };
 
-            format!("{} {} in {}{}",
-                    kind,
-                    ti.name,
-                    map.path_to_string(id),
-                    id_str)
+            format!("{} {} in {}{}", kind, ti.name, path_str(), id_str)
         }
         Some(NodeVariant(ref variant)) => {
             format!("variant {} in {}{}",
                     variant.node.name,
-                    map.path_to_string(id), id_str)
+                    path_str(), id_str)
         }
         Some(NodeExpr(ref expr)) => {
             format!("expr {}{}", pprust::expr_to_string(&expr), id_str)
@@ -1112,7 +972,7 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
             format!("block {}{}", pprust::block_to_string(&block), id_str)
         }
         Some(NodeStructCtor(_)) => {
-            format!("struct_ctor {}{}", map.path_to_string(id), id_str)
+            format!("struct_ctor {}{}", path_str(), id_str)
         }
         Some(NodeLifetime(ref l)) => {
             format!("lifetime {}{}",
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
new file mode 100644
index 00000000000..edb9b783527
--- /dev/null
+++ b/src/librustc/hir/mod.rs
@@ -0,0 +1,1652 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// The Rust HIR.
+
+pub use self::BindingMode::*;
+pub use self::BinOp_::*;
+pub use self::BlockCheckMode::*;
+pub use self::CaptureClause::*;
+pub use self::Decl_::*;
+pub use self::ExplicitSelf_::*;
+pub use self::Expr_::*;
+pub use self::FunctionRetTy::*;
+pub use self::ForeignItem_::*;
+pub use self::Item_::*;
+pub use self::Mutability::*;
+pub use self::PathListItem_::*;
+pub use self::PrimTy::*;
+pub use self::Stmt_::*;
+pub use self::TraitItem_::*;
+pub use self::Ty_::*;
+pub use self::TyParamBound::*;
+pub use self::UnOp::*;
+pub use self::UnsafeSource::*;
+pub use self::ViewPath_::*;
+pub use self::Visibility::*;
+pub use self::PathParameters::*;
+
+use hir::def::Def;
+use hir::def_id::DefId;
+use util::nodemap::{NodeMap, FnvHashSet};
+
+use syntax::codemap::{self, Span, Spanned, DUMMY_SP, ExpnId};
+use syntax::abi::Abi;
+use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, TokenTree, AsmDialect};
+use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem};
+use syntax::attr::{ThinAttributes, ThinAttributesExt};
+use syntax::parse::token::InternedString;
+use syntax::ptr::P;
+
+use std::collections::BTreeMap;
+use std::fmt;
+use std::hash::{Hash, Hasher};
+use serialize::{Encodable, Decodable, Encoder, Decoder};
+
+/// HIR doesn't commit to a concrete storage type and have its own alias for a vector.
+/// It can be `Vec`, `P<[T]>` or potentially `Box<[T]>`, or some other container with similar
+/// behavior. Unlike AST, HIR is mostly a static structure, so we can use an owned slice instead
+/// of `Vec` to avoid keeping extra capacity.
+pub type HirVec<T> = P<[T]>;
+
+macro_rules! hir_vec {
+    ($elem:expr; $n:expr) => (
+        $crate::hir::HirVec::from(vec![$elem; $n])
+    );
+    ($($x:expr),*) => (
+        $crate::hir::HirVec::from(vec![$($x),*])
+    );
+    ($($x:expr,)*) => (hir_vec![$($x),*])
+}
+
+pub mod check_attr;
+pub mod def;
+pub mod def_id;
+pub mod fold;
+pub mod intravisit;
+pub mod lowering;
+pub mod map;
+pub mod pat_util;
+pub mod print;
+pub mod svh;
+
+/// Identifier in HIR
+#[derive(Clone, Copy, Eq)]
+pub struct Ident {
+    /// Hygienic name (renamed), should be used by default
+    pub name: Name,
+    /// Unhygienic name (original, not renamed), needed in few places in name resolution
+    pub unhygienic_name: Name,
+}
+
+impl Ident {
+    /// Creates a HIR identifier with both `name` and `unhygienic_name` initialized with
+    /// the argument. Hygiene properties of the created identifier depend entirely on this
+    /// argument. If the argument is a plain interned string `intern("iter")`, then the result
+    /// is unhygienic and can interfere with other entities named "iter". If the argument is
+    /// a "fresh" name created with `gensym("iter")`, then the result is hygienic and can't
+    /// interfere with other entities having the same string as a name.
+    pub fn from_name(name: Name) -> Ident {
+        Ident { name: name, unhygienic_name: name }
+    }
+}
+
+impl PartialEq for Ident {
+    fn eq(&self, other: &Ident) -> bool {
+        self.name == other.name
+    }
+}
+
+impl Hash for Ident {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        self.name.hash(state)
+    }
+}
+
+impl fmt::Debug for Ident {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(&self.name, f)
+    }
+}
+
+impl fmt::Display for Ident {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(&self.name, f)
+    }
+}
+
+impl Encodable for Ident {
+    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+        self.name.encode(s)
+    }
+}
+
+impl Decodable for Ident {
+    fn decode<D: Decoder>(d: &mut D) -> Result<Ident, D::Error> {
+        Ok(Ident::from_name(Name::decode(d)?))
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
+pub struct Lifetime {
+    pub id: NodeId,
+    pub span: Span,
+    pub name: Name,
+}
+
+impl fmt::Debug for Lifetime {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f,
+               "lifetime({}: {})",
+               self.id,
+               print::lifetime_to_string(self))
+    }
+}
+
+/// A lifetime definition, eg `'a: 'b+'c+'d`
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct LifetimeDef {
+    pub lifetime: Lifetime,
+    pub bounds: HirVec<Lifetime>,
+}
+
+/// A "Path" is essentially Rust's notion of a name; for instance:
+/// std::cmp::PartialEq  .  It's represented as a sequence of identifiers,
+/// along with a bunch of supporting information.
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
+pub struct Path {
+    pub span: Span,
+    /// A `::foo` path, is relative to the crate root rather than current
+    /// module (like paths in an import).
+    pub global: bool,
+    /// The segments in the path: the things separated by `::`.
+    pub segments: HirVec<PathSegment>,
+}
+
+impl fmt::Debug for Path {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "path({})", print::path_to_string(self))
+    }
+}
+
+impl fmt::Display for Path {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", print::path_to_string(self))
+    }
+}
+
+impl Path {
+    /// Convert a span and an identifier to the corresponding
+    /// 1-segment path.
+    pub fn from_ident(s: Span, ident: Ident) -> Path {
+        Path {
+            span: s,
+            global: false,
+            segments: hir_vec![PathSegment {
+                identifier: ident,
+                parameters: PathParameters::none()
+            }],
+        }
+    }
+}
+
+/// A segment of a path: an identifier, an optional lifetime, and a set of
+/// types.
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct PathSegment {
+    /// The identifier portion of this path segment.
+    ///
+    /// Hygiene properties of this identifier are worth noting.
+    /// Most path segments are not hygienic and they are not renamed during
+    /// lowering from AST to HIR (see comments to `fn lower_path`). However segments from
+    /// unqualified paths with one segment originating from `ExprPath` (local-variable-like paths)
+    /// can be hygienic, so they are renamed. You should not normally care about this peculiarity
+    /// and just use `identifier.name` unless you modify identifier resolution code
+    /// (`fn resolve_identifier` and other functions called by it in `rustc_resolve`).
+    pub identifier: Ident,
+
+    /// Type/lifetime parameters attached to this path. They come in
+    /// two flavors: `Path<A,B,C>` and `Path(A,B) -> C`. Note that
+    /// this is more than just simple syntactic sugar; the use of
+    /// parens affects the region binding rules, so we preserve the
+    /// distinction.
+    pub parameters: PathParameters,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum PathParameters {
+    /// The `<'a, A,B,C>` in `foo::bar::baz::<'a, A,B,C>`
+    AngleBracketedParameters(AngleBracketedParameterData),
+    /// The `(A,B)` and `C` in `Foo(A,B) -> C`
+    ParenthesizedParameters(ParenthesizedParameterData),
+}
+
+impl PathParameters {
+    pub fn none() -> PathParameters {
+        AngleBracketedParameters(AngleBracketedParameterData {
+            lifetimes: HirVec::new(),
+            types: HirVec::new(),
+            bindings: HirVec::new(),
+        })
+    }
+
+    pub fn is_empty(&self) -> bool {
+        match *self {
+            AngleBracketedParameters(ref data) => data.is_empty(),
+
+            // Even if the user supplied no types, something like
+            // `X()` is equivalent to `X<(),()>`.
+            ParenthesizedParameters(..) => false,
+        }
+    }
+
+    pub fn has_lifetimes(&self) -> bool {
+        match *self {
+            AngleBracketedParameters(ref data) => !data.lifetimes.is_empty(),
+            ParenthesizedParameters(_) => false,
+        }
+    }
+
+    pub fn has_types(&self) -> bool {
+        match *self {
+            AngleBracketedParameters(ref data) => !data.types.is_empty(),
+            ParenthesizedParameters(..) => true,
+        }
+    }
+
+    /// Returns the types that the user wrote. Note that these do not necessarily map to the type
+    /// parameters in the parenthesized case.
+    pub fn types(&self) -> HirVec<&P<Ty>> {
+        match *self {
+            AngleBracketedParameters(ref data) => {
+                data.types.iter().collect()
+            }
+            ParenthesizedParameters(ref data) => {
+                data.inputs
+                    .iter()
+                    .chain(data.output.iter())
+                    .collect()
+            }
+        }
+    }
+
+    pub fn lifetimes(&self) -> HirVec<&Lifetime> {
+        match *self {
+            AngleBracketedParameters(ref data) => {
+                data.lifetimes.iter().collect()
+            }
+            ParenthesizedParameters(_) => {
+                HirVec::new()
+            }
+        }
+    }
+
+    pub fn bindings(&self) -> HirVec<&TypeBinding> {
+        match *self {
+            AngleBracketedParameters(ref data) => {
+                data.bindings.iter().collect()
+            }
+            ParenthesizedParameters(_) => {
+                HirVec::new()
+            }
+        }
+    }
+}
+
+/// A path like `Foo<'a, T>`
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct AngleBracketedParameterData {
+    /// The lifetime parameters for this path segment.
+    pub lifetimes: HirVec<Lifetime>,
+    /// The type parameters for this path segment, if present.
+    pub types: HirVec<P<Ty>>,
+    /// Bindings (equality constraints) on associated types, if present.
+    /// E.g., `Foo<A=Bar>`.
+    pub bindings: HirVec<TypeBinding>,
+}
+
+impl AngleBracketedParameterData {
+    fn is_empty(&self) -> bool {
+        self.lifetimes.is_empty() && self.types.is_empty() && self.bindings.is_empty()
+    }
+}
+
+/// A path like `Foo(A,B) -> C`
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct ParenthesizedParameterData {
+    /// Overall span
+    pub span: Span,
+
+    /// `(A,B)`
+    pub inputs: HirVec<P<Ty>>,
+
+    /// `C`
+    pub output: Option<P<Ty>>,
+}
+
+/// The AST represents all type param bounds as types.
+/// typeck::collect::compute_bounds matches these against
+/// the "special" built-in traits (see middle::lang_items) and
+/// detects Copy, Send and Sync.
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum TyParamBound {
+    TraitTyParamBound(PolyTraitRef, TraitBoundModifier),
+    RegionTyParamBound(Lifetime),
+}
+
+/// A modifier on a bound, currently this is only used for `?Sized`, where the
+/// modifier is `Maybe`. Negative bounds should also be handled here.
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum TraitBoundModifier {
+    None,
+    Maybe,
+}
+
+pub type TyParamBounds = HirVec<TyParamBound>;
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct TyParam {
+    pub name: Name,
+    pub id: NodeId,
+    pub bounds: TyParamBounds,
+    pub default: Option<P<Ty>>,
+    pub span: Span,
+}
+
+/// Represents lifetimes and type parameters attached to a declaration
+/// of a function, enum, trait, etc.
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct Generics {
+    pub lifetimes: HirVec<LifetimeDef>,
+    pub ty_params: HirVec<TyParam>,
+    pub where_clause: WhereClause,
+}
+
+impl Generics {
+    pub fn empty() -> Generics {
+        Generics {
+            lifetimes: HirVec::new(),
+            ty_params: HirVec::new(),
+            where_clause: WhereClause {
+                id: DUMMY_NODE_ID,
+                predicates: HirVec::new(),
+            },
+        }
+    }
+
+    pub fn is_lt_parameterized(&self) -> bool {
+        !self.lifetimes.is_empty()
+    }
+
+    pub fn is_type_parameterized(&self) -> bool {
+        !self.ty_params.is_empty()
+    }
+
+    pub fn is_parameterized(&self) -> bool {
+        self.is_lt_parameterized() || self.is_type_parameterized()
+    }
+}
+
+/// A `where` clause in a definition
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct WhereClause {
+    pub id: NodeId,
+    pub predicates: HirVec<WherePredicate>,
+}
+
+/// A single predicate in a `where` clause
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum WherePredicate {
+    /// A type binding, eg `for<'c> Foo: Send+Clone+'c`
+    BoundPredicate(WhereBoundPredicate),
+    /// A lifetime predicate, e.g. `'a: 'b+'c`
+    RegionPredicate(WhereRegionPredicate),
+    /// An equality predicate (unsupported)
+    EqPredicate(WhereEqPredicate),
+}
+
+/// A type bound, eg `for<'c> Foo: Send+Clone+'c`
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct WhereBoundPredicate {
+    pub span: Span,
+    /// Any lifetimes from a `for` binding
+    pub bound_lifetimes: HirVec<LifetimeDef>,
+    /// The type being bounded
+    pub bounded_ty: P<Ty>,
+    /// Trait and lifetime bounds (`Clone+Send+'static`)
+    pub bounds: TyParamBounds,
+}
+
+/// A lifetime predicate, e.g. `'a: 'b+'c`
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct WhereRegionPredicate {
+    pub span: Span,
+    pub lifetime: Lifetime,
+    pub bounds: HirVec<Lifetime>,
+}
+
+/// An equality predicate (unsupported), e.g. `T=int`
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct WhereEqPredicate {
+    pub id: NodeId,
+    pub span: Span,
+    pub path: Path,
+    pub ty: P<Ty>,
+}
+
+pub type CrateConfig = HirVec<P<MetaItem>>;
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
+pub struct Crate {
+    pub module: Mod,
+    pub attrs: HirVec<Attribute>,
+    pub config: CrateConfig,
+    pub span: Span,
+    pub exported_macros: HirVec<MacroDef>,
+
+    // NB: We use a BTreeMap here so that `visit_all_items` iterates
+    // over the ids in increasing order. In principle it should not
+    // matter what order we visit things in, but in *practice* it
+    // does, because it can affect the order in which errors are
+    // detected, which in turn can make compile-fail tests yield
+    // slightly different results.
+    pub items: BTreeMap<NodeId, Item>,
+}
+
+impl Crate {
+    pub fn item(&self, id: NodeId) -> &Item {
+        &self.items[&id]
+    }
+
+    /// Visits all items in the crate in some determinstic (but
+    /// unspecified) order. If you just need to process every item,
+    /// but don't care about nesting, this method is the best choice.
+    ///
+    /// If you do care about nesting -- usually because your algorithm
+    /// follows lexical scoping rules -- then you want a different
+    /// approach. You should override `visit_nested_item` in your
+    /// visitor and then call `intravisit::walk_crate` instead.
+    pub fn visit_all_items<'hir, V>(&'hir self, visitor: &mut V)
+        where V: intravisit::Visitor<'hir>
+    {
+        for (_, item) in &self.items {
+            visitor.visit_item(item);
+        }
+    }
+}
+
+/// A macro definition, in this crate or imported from another.
+///
+/// Not parsed directly, but created on macro import or `macro_rules!` expansion.
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct MacroDef {
+    pub name: Name,
+    pub attrs: HirVec<Attribute>,
+    pub id: NodeId,
+    pub span: Span,
+    pub imported_from: Option<Name>,
+    pub export: bool,
+    pub use_locally: bool,
+    pub allow_internal_unstable: bool,
+    pub body: HirVec<TokenTree>,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct Block {
+    /// Statements in a block
+    pub stmts: HirVec<Stmt>,
+    /// An expression at the end of the block
+    /// without a semicolon, if any
+    pub expr: Option<P<Expr>>,
+    pub id: NodeId,
+    /// Distinguishes between `unsafe { ... }` and `{ ... }`
+    pub rules: BlockCheckMode,
+    pub span: Span,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
+pub struct Pat {
+    pub id: NodeId,
+    pub node: PatKind,
+    pub span: Span,
+}
+
+impl fmt::Debug for Pat {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "pat({}: {})", self.id, print::pat_to_string(self))
+    }
+}
+
+impl Pat {
+    // FIXME(#19596) this is a workaround, but there should be a better way
+    fn walk_<G>(&self, it: &mut G) -> bool
+        where G: FnMut(&Pat) -> bool
+    {
+        if !it(self) {
+            return false;
+        }
+
+        match self.node {
+            PatKind::Ident(_, _, Some(ref p)) => p.walk_(it),
+            PatKind::Struct(_, ref fields, _) => {
+                fields.iter().all(|field| field.node.pat.walk_(it))
+            }
+            PatKind::TupleStruct(_, Some(ref s)) | PatKind::Tup(ref s) => {
+                s.iter().all(|p| p.walk_(it))
+            }
+            PatKind::Box(ref s) | PatKind::Ref(ref s, _) => {
+                s.walk_(it)
+            }
+            PatKind::Vec(ref before, ref slice, ref after) => {
+                before.iter().all(|p| p.walk_(it)) &&
+                slice.iter().all(|p| p.walk_(it)) &&
+                after.iter().all(|p| p.walk_(it))
+            }
+            PatKind::Wild |
+            PatKind::Lit(_) |
+            PatKind::Range(_, _) |
+            PatKind::Ident(_, _, _) |
+            PatKind::TupleStruct(..) |
+            PatKind::Path(..) |
+            PatKind::QPath(_, _) => {
+                true
+            }
+        }
+    }
+
+    pub fn walk<F>(&self, mut it: F) -> bool
+        where F: FnMut(&Pat) -> bool
+    {
+        self.walk_(&mut it)
+    }
+}
+
+/// A single field in a struct pattern
+///
+/// Patterns like the fields of Foo `{ x, ref y, ref mut z }`
+/// are treated the same as` x: x, y: ref y, z: ref mut z`,
+/// except is_shorthand is true
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct FieldPat {
+    /// The identifier for the field
+    pub name: Name,
+    /// The pattern the field is destructured to
+    pub pat: P<Pat>,
+    pub is_shorthand: bool,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+pub enum BindingMode {
+    BindByRef(Mutability),
+    BindByValue(Mutability),
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum PatKind {
+    /// Represents a wildcard pattern (`_`)
+    Wild,
+
+    /// A `PatKind::Ident` may either be a new bound variable,
+    /// or a unit struct/variant pattern, or a const pattern (in the last two cases
+    /// the third field must be `None`).
+    ///
+    /// In the unit or const pattern case, the parser can't determine
+    /// which it is. The resolver determines this, and
+    /// records this pattern's `NodeId` in an auxiliary
+    /// set (of "PatIdents that refer to unit patterns or constants").
+    Ident(BindingMode, Spanned<Ident>, Option<P<Pat>>),
+
+    /// A struct or struct variant pattern, e.g. `Variant {x, y, ..}`.
+    /// The `bool` is `true` in the presence of a `..`.
+    Struct(Path, HirVec<Spanned<FieldPat>>, bool),
+
+    /// A tuple struct/variant pattern `Variant(x, y, z)`.
+    /// "None" means a `Variant(..)` pattern where we don't bind the fields to names.
+    TupleStruct(Path, Option<HirVec<P<Pat>>>),
+
+    /// A path pattern.
+    /// Such pattern can be resolved to a unit struct/variant or a constant.
+    Path(Path),
+
+    /// An associated const named using the qualified path `<T>::CONST` or
+    /// `<T as Trait>::CONST`. Associated consts from inherent impls can be
+    /// referred to as simply `T::CONST`, in which case they will end up as
+    /// PatKind::Path, and the resolver will have to sort that out.
+    QPath(QSelf, Path),
+
+    /// A tuple pattern `(a, b)`
+    Tup(HirVec<P<Pat>>),
+    /// A `box` pattern
+    Box(P<Pat>),
+    /// A reference pattern, e.g. `&mut (a, b)`
+    Ref(P<Pat>, Mutability),
+    /// A literal
+    Lit(P<Expr>),
+    /// A range pattern, e.g. `1...2`
+    Range(P<Expr>, P<Expr>),
+    /// `[a, b, ..i, y, z]` is represented as:
+    ///     `PatKind::Vec(box [a, b], Some(i), box [y, z])`
+    Vec(HirVec<P<Pat>>, Option<P<Pat>>, HirVec<P<Pat>>),
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+pub enum Mutability {
+    MutMutable,
+    MutImmutable,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+pub enum BinOp_ {
+    /// The `+` operator (addition)
+    BiAdd,
+    /// The `-` operator (subtraction)
+    BiSub,
+    /// The `*` operator (multiplication)
+    BiMul,
+    /// The `/` operator (division)
+    BiDiv,
+    /// The `%` operator (modulus)
+    BiRem,
+    /// The `&&` operator (logical and)
+    BiAnd,
+    /// The `||` operator (logical or)
+    BiOr,
+    /// The `^` operator (bitwise xor)
+    BiBitXor,
+    /// The `&` operator (bitwise and)
+    BiBitAnd,
+    /// The `|` operator (bitwise or)
+    BiBitOr,
+    /// The `<<` operator (shift left)
+    BiShl,
+    /// The `>>` operator (shift right)
+    BiShr,
+    /// The `==` operator (equality)
+    BiEq,
+    /// The `<` operator (less than)
+    BiLt,
+    /// The `<=` operator (less than or equal to)
+    BiLe,
+    /// The `!=` operator (not equal to)
+    BiNe,
+    /// The `>=` operator (greater than or equal to)
+    BiGe,
+    /// The `>` operator (greater than)
+    BiGt,
+}
+
+impl BinOp_ {
+    pub fn as_str(self) -> &'static str {
+        match self {
+            BiAdd => "+",
+            BiSub => "-",
+            BiMul => "*",
+            BiDiv => "/",
+            BiRem => "%",
+            BiAnd => "&&",
+            BiOr => "||",
+            BiBitXor => "^",
+            BiBitAnd => "&",
+            BiBitOr => "|",
+            BiShl => "<<",
+            BiShr => ">>",
+            BiEq => "==",
+            BiLt => "<",
+            BiLe => "<=",
+            BiNe => "!=",
+            BiGe => ">=",
+            BiGt => ">",
+        }
+    }
+
+    pub fn is_lazy(self) -> bool {
+        match self {
+            BiAnd | BiOr => true,
+            _ => false,
+        }
+    }
+
+    pub fn is_shift(self) -> bool {
+        match self {
+            BiShl | BiShr => true,
+            _ => false,
+        }
+    }
+
+    pub fn is_comparison(self) -> bool {
+        match self {
+            BiEq | BiLt | BiLe | BiNe | BiGt | BiGe => true,
+            BiAnd |
+            BiOr |
+            BiAdd |
+            BiSub |
+            BiMul |
+            BiDiv |
+            BiRem |
+            BiBitXor |
+            BiBitAnd |
+            BiBitOr |
+            BiShl |
+            BiShr => false,
+        }
+    }
+
+    /// Returns `true` if the binary operator takes its arguments by value
+    pub fn is_by_value(self) -> bool {
+        !self.is_comparison()
+    }
+}
+
+pub type BinOp = Spanned<BinOp_>;
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+pub enum UnOp {
+    /// The `*` operator for dereferencing
+    UnDeref,
+    /// The `!` operator for logical inversion
+    UnNot,
+    /// The `-` operator for negation
+    UnNeg,
+}
+
+impl UnOp {
+    pub fn as_str(self) -> &'static str {
+        match self {
+            UnDeref => "*",
+            UnNot => "!",
+            UnNeg => "-",
+        }
+    }
+
+    /// Returns `true` if the unary operator takes its argument by value
+    pub fn is_by_value(self) -> bool {
+        match self {
+            UnNeg | UnNot => true,
+            _ => false,
+        }
+    }
+}
+
+/// A statement
+pub type Stmt = Spanned<Stmt_>;
+
+impl fmt::Debug for Stmt_ {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        // Sadness.
+        let spanned = codemap::dummy_spanned(self.clone());
+        write!(f,
+               "stmt({}: {})",
+               spanned.node.id(),
+               print::stmt_to_string(&spanned))
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
+pub enum Stmt_ {
+    /// Could be an item or a local (let) binding:
+    StmtDecl(P<Decl>, NodeId),
+
+    /// Expr without trailing semi-colon (must have unit type):
+    StmtExpr(P<Expr>, NodeId),
+
+    /// Expr with trailing semi-colon (may have any type):
+    StmtSemi(P<Expr>, NodeId),
+}
+
+impl Stmt_ {
+    pub fn attrs(&self) -> &[Attribute] {
+        match *self {
+            StmtDecl(ref d, _) => d.node.attrs(),
+            StmtExpr(ref e, _) |
+            StmtSemi(ref e, _) => e.attrs.as_attr_slice(),
+        }
+    }
+
+    pub fn id(&self) -> NodeId {
+        match *self {
+            StmtDecl(_, id) => id,
+            StmtExpr(_, id) => id,
+            StmtSemi(_, id) => id,
+        }
+    }
+}
+
+// FIXME (pending discussion of #1697, #2178...): local should really be
+// a refinement on pat.
+/// Local represents a `let` statement, e.g., `let <pat>:<ty> = <expr>;`
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct Local {
+    pub pat: P<Pat>,
+    pub ty: Option<P<Ty>>,
+    /// Initializer expression to set the value, if any
+    pub init: Option<P<Expr>>,
+    pub id: NodeId,
+    pub span: Span,
+    pub attrs: ThinAttributes,
+}
+
+pub type Decl = Spanned<Decl_>;
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum Decl_ {
+    /// A local (let) binding:
+    DeclLocal(P<Local>),
+    /// An item binding:
+    DeclItem(ItemId),
+}
+
+impl Decl_ {
+    pub fn attrs(&self) -> &[Attribute] {
+        match *self {
+            DeclLocal(ref l) => l.attrs.as_attr_slice(),
+            DeclItem(_) => &[]
+        }
+    }
+}
+
+/// represents one arm of a 'match'
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct Arm {
+    pub attrs: HirVec<Attribute>,
+    pub pats: HirVec<P<Pat>>,
+    pub guard: Option<P<Expr>>,
+    pub body: P<Expr>,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct Field {
+    pub name: Spanned<Name>,
+    pub expr: P<Expr>,
+    pub span: Span,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+pub enum BlockCheckMode {
+    DefaultBlock,
+    UnsafeBlock(UnsafeSource),
+    PushUnsafeBlock(UnsafeSource),
+    PopUnsafeBlock(UnsafeSource),
+    // Within this block (but outside a PopUnstableBlock), we suspend checking of stability.
+    PushUnstableBlock,
+    PopUnstableBlock,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+pub enum UnsafeSource {
+    CompilerGenerated,
+    UserProvided,
+}
+
+/// An expression
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
+pub struct Expr {
+    pub id: NodeId,
+    pub node: Expr_,
+    pub span: Span,
+    pub attrs: ThinAttributes,
+}
+
+impl fmt::Debug for Expr {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "expr({}: {})", self.id, print::expr_to_string(self))
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum Expr_ {
+    /// A `box x` expression.
+    ExprBox(P<Expr>),
+    /// An array (`[a, b, c, d]`)
+    ExprVec(HirVec<P<Expr>>),
+    /// A function call
+    ///
+    /// The first field resolves to the function itself,
+    /// and the second field is the list of arguments
+    ExprCall(P<Expr>, HirVec<P<Expr>>),
+    /// A method call (`x.foo::<Bar, Baz>(a, b, c, d)`)
+    ///
+    /// The `Spanned<Name>` is the identifier for the method name.
+    /// The vector of `Ty`s are the ascripted type parameters for the method
+    /// (within the angle brackets).
+    ///
+    /// The first element of the vector of `Expr`s is the expression that evaluates
+    /// to the object on which the method is being called on (the receiver),
+    /// and the remaining elements are the rest of the arguments.
+    ///
+    /// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
+    /// `ExprMethodCall(foo, [Bar, Baz], [x, a, b, c, d])`.
+    ExprMethodCall(Spanned<Name>, HirVec<P<Ty>>, HirVec<P<Expr>>),
+    /// A tuple (`(a, b, c ,d)`)
+    ExprTup(HirVec<P<Expr>>),
+    /// A binary operation (For example: `a + b`, `a * b`)
+    ExprBinary(BinOp, P<Expr>, P<Expr>),
+    /// A unary operation (For example: `!x`, `*x`)
+    ExprUnary(UnOp, P<Expr>),
+    /// A literal (For example: `1`, `"foo"`)
+    ExprLit(P<Lit>),
+    /// A cast (`foo as f64`)
+    ExprCast(P<Expr>, P<Ty>),
+    ExprType(P<Expr>, P<Ty>),
+    /// An `if` block, with an optional else block
+    ///
+    /// `if expr { block } else { expr }`
+    ExprIf(P<Expr>, P<Block>, Option<P<Expr>>),
+    /// A while loop, with an optional label
+    ///
+    /// `'label: while expr { block }`
+    ExprWhile(P<Expr>, P<Block>, Option<Ident>),
+    /// Conditionless loop (can be exited with break, continue, or return)
+    ///
+    /// `'label: loop { block }`
+    ExprLoop(P<Block>, Option<Ident>),
+    /// A `match` block, with a source that indicates whether or not it is
+    /// the result of a desugaring, and if so, which kind.
+    ExprMatch(P<Expr>, HirVec<Arm>, MatchSource),
+    /// A closure (for example, `move |a, b, c| {a + b + c}`)
+    ExprClosure(CaptureClause, P<FnDecl>, P<Block>),
+    /// A block (`{ ... }`)
+    ExprBlock(P<Block>),
+
+    /// An assignment (`a = foo()`)
+    ExprAssign(P<Expr>, P<Expr>),
+    /// An assignment with an operator
+    ///
+    /// For example, `a += 1`.
+    ExprAssignOp(BinOp, P<Expr>, P<Expr>),
+    /// Access of a named struct field (`obj.foo`)
+    ExprField(P<Expr>, Spanned<Name>),
+    /// Access of an unnamed field of a struct or tuple-struct
+    ///
+    /// For example, `foo.0`.
+    ExprTupField(P<Expr>, Spanned<usize>),
+    /// An indexing operation (`foo[2]`)
+    ExprIndex(P<Expr>, P<Expr>),
+
+    /// Variable reference, possibly containing `::` and/or type
+    /// parameters, e.g. foo::bar::<baz>.
+    ///
+    /// Optionally "qualified",
+    /// e.g. `<HirVec<T> as SomeTrait>::SomeType`.
+    ExprPath(Option<QSelf>, Path),
+
+    /// A referencing operation (`&a` or `&mut a`)
+    ExprAddrOf(Mutability, P<Expr>),
+    /// A `break`, with an optional label to break
+    ExprBreak(Option<Spanned<Ident>>),
+    /// A `continue`, with an optional label
+    ExprAgain(Option<Spanned<Ident>>),
+    /// A `return`, with an optional value to be returned
+    ExprRet(Option<P<Expr>>),
+
+    /// Inline assembly (from `asm!`), with its outputs and inputs.
+    ExprInlineAsm(InlineAsm, Vec<P<Expr>>, Vec<P<Expr>>),
+
+    /// A struct literal expression.
+    ///
+    /// For example, `Foo {x: 1, y: 2}`, or
+    /// `Foo {x: 1, .. base}`, where `base` is the `Option<Expr>`.
+    ExprStruct(Path, HirVec<Field>, Option<P<Expr>>),
+
+    /// A vector literal constructed from one repeated element.
+    ///
+    /// For example, `[1; 5]`. The first expression is the element
+    /// to be repeated; the second is the number of times to repeat it.
+    ExprRepeat(P<Expr>, P<Expr>),
+}
+
+/// The explicit Self type in a "qualified path". The actual
+/// path, including the trait and the associated item, is stored
+/// separately. `position` represents the index of the associated
+/// item qualified with this Self type.
+///
+///     <HirVec<T> as a::b::Trait>::AssociatedItem
+///      ^~~~~     ~~~~~~~~~~~~~~^
+///      ty        position = 3
+///
+///     <HirVec<T>>::AssociatedItem
+///      ^~~~~    ^
+///      ty       position = 0
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct QSelf {
+    pub ty: P<Ty>,
+    pub position: usize,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+pub enum MatchSource {
+    Normal,
+    IfLetDesugar {
+        contains_else_clause: bool,
+    },
+    WhileLetDesugar,
+    ForLoopDesugar,
+    TryDesugar,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+pub enum CaptureClause {
+    CaptureByValue,
+    CaptureByRef,
+}
+
+// NB: If you change this, you'll probably want to change the corresponding
+// type structure in middle/ty.rs as well.
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct MutTy {
+    pub ty: P<Ty>,
+    pub mutbl: Mutability,
+}
+
+/// Represents a method's signature in a trait declaration,
+/// or in an implementation.
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct MethodSig {
+    pub unsafety: Unsafety,
+    pub constness: Constness,
+    pub abi: Abi,
+    pub decl: P<FnDecl>,
+    pub generics: Generics,
+    pub explicit_self: ExplicitSelf,
+}
+
+/// Represents an item declaration within a trait declaration,
+/// possibly including a default implementation. A trait item is
+/// either required (meaning it doesn't have an implementation, just a
+/// signature) or provided (meaning it has a default implementation).
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct TraitItem {
+    pub id: NodeId,
+    pub name: Name,
+    pub attrs: HirVec<Attribute>,
+    pub node: TraitItem_,
+    pub span: Span,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum TraitItem_ {
+    ConstTraitItem(P<Ty>, Option<P<Expr>>),
+    MethodTraitItem(MethodSig, Option<P<Block>>),
+    TypeTraitItem(TyParamBounds, Option<P<Ty>>),
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct ImplItem {
+    pub id: NodeId,
+    pub name: Name,
+    pub vis: Visibility,
+    pub defaultness: Defaultness,
+    pub attrs: HirVec<Attribute>,
+    pub node: ImplItemKind,
+    pub span: Span,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum ImplItemKind {
+    Const(P<Ty>, P<Expr>),
+    Method(MethodSig, P<Block>),
+    Type(P<Ty>),
+}
+
+// Bind a type to an associated type: `A=Foo`.
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct TypeBinding {
+    pub id: NodeId,
+    pub name: Name,
+    pub ty: P<Ty>,
+    pub span: Span,
+}
+
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
+pub struct Ty {
+    pub id: NodeId,
+    pub node: Ty_,
+    pub span: Span,
+}
+
+impl fmt::Debug for Ty {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "type({})", print::ty_to_string(self))
+    }
+}
+
+/// Not represented directly in the AST, referred to by name through a ty_path.
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+pub enum PrimTy {
+    TyInt(IntTy),
+    TyUint(UintTy),
+    TyFloat(FloatTy),
+    TyStr,
+    TyBool,
+    TyChar,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct BareFnTy {
+    pub unsafety: Unsafety,
+    pub abi: Abi,
+    pub lifetimes: HirVec<LifetimeDef>,
+    pub decl: P<FnDecl>,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+/// The different kinds of types recognized by the compiler
+pub enum Ty_ {
+    TyVec(P<Ty>),
+    /// A fixed length array (`[T; n]`)
+    TyFixedLengthVec(P<Ty>, P<Expr>),
+    /// A raw pointer (`*const T` or `*mut T`)
+    TyPtr(MutTy),
+    /// A reference (`&'a T` or `&'a mut T`)
+    TyRptr(Option<Lifetime>, MutTy),
+    /// A bare function (e.g. `fn(usize) -> bool`)
+    TyBareFn(P<BareFnTy>),
+    /// A tuple (`(A, B, C, D,...)`)
+    TyTup(HirVec<P<Ty>>),
+    /// A path (`module::module::...::Type`), optionally
+    /// "qualified", e.g. `<HirVec<T> as SomeTrait>::SomeType`.
+    ///
+    /// Type parameters are stored in the Path itself
+    TyPath(Option<QSelf>, Path),
+    /// Something like `A+B`. Note that `B` must always be a path.
+    TyObjectSum(P<Ty>, TyParamBounds),
+    /// A type like `for<'a> Foo<&'a Bar>`
+    TyPolyTraitRef(TyParamBounds),
+    /// Unused for now
+    TyTypeof(P<Expr>),
+    /// TyInfer means the type should be inferred instead of it having been
+    /// specified. This can appear anywhere in a type.
+    TyInfer,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct InlineAsmOutput {
+    pub constraint: InternedString,
+    pub is_rw: bool,
+    pub is_indirect: bool,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct InlineAsm {
+    pub asm: InternedString,
+    pub asm_str_style: StrStyle,
+    pub outputs: HirVec<InlineAsmOutput>,
+    pub inputs: HirVec<InternedString>,
+    pub clobbers: HirVec<InternedString>,
+    pub volatile: bool,
+    pub alignstack: bool,
+    pub dialect: AsmDialect,
+    pub expn_id: ExpnId,
+}
+
+/// represents an argument in a function header
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct Arg {
+    pub ty: P<Ty>,
+    pub pat: P<Pat>,
+    pub id: NodeId,
+}
+
+impl Arg {
+    pub fn new_self(span: Span, mutability: Mutability, self_ident: Ident) -> Arg {
+        let path = Spanned {
+            span: span,
+            node: self_ident,
+        };
+        Arg {
+            // HACK(eddyb) fake type for the self argument.
+            ty: P(Ty {
+                id: DUMMY_NODE_ID,
+                node: TyInfer,
+                span: DUMMY_SP,
+            }),
+            pat: P(Pat {
+                id: DUMMY_NODE_ID,
+                node: PatKind::Ident(BindByValue(mutability), path, None),
+                span: span,
+            }),
+            id: DUMMY_NODE_ID,
+        }
+    }
+}
+
+/// Represents the header (not the body) of a function declaration
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct FnDecl {
+    pub inputs: HirVec<Arg>,
+    pub output: FunctionRetTy,
+    pub variadic: bool,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum Unsafety {
+    Unsafe,
+    Normal,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum Constness {
+    Const,
+    NotConst,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum Defaultness {
+    Default,
+    Final,
+}
+
+impl Defaultness {
+    pub fn is_final(&self) -> bool {
+        *self == Defaultness::Final
+    }
+
+    pub fn is_default(&self) -> bool {
+        *self == Defaultness::Default
+    }
+}
+
+impl fmt::Display for Unsafety {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(match *self {
+                              Unsafety::Normal => "normal",
+                              Unsafety::Unsafe => "unsafe",
+                          },
+                          f)
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
+pub enum ImplPolarity {
+    /// `impl Trait for Type`
+    Positive,
+    /// `impl !Trait for Type`
+    Negative,
+}
+
+impl fmt::Debug for ImplPolarity {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            ImplPolarity::Positive => "positive".fmt(f),
+            ImplPolarity::Negative => "negative".fmt(f),
+        }
+    }
+}
+
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum FunctionRetTy {
+    /// Functions with return type `!`that always
+    /// raise an error or exit (i.e. never return to the caller)
+    NoReturn(Span),
+    /// Return type is not specified.
+    ///
+    /// Functions default to `()` and
+    /// closures default to inference. Span points to where return
+    /// type would be inserted.
+    DefaultReturn(Span),
+    /// Everything else
+    Return(P<Ty>),
+}
+
+impl FunctionRetTy {
+    pub fn span(&self) -> Span {
+        match *self {
+            NoReturn(span) => span,
+            DefaultReturn(span) => span,
+            Return(ref ty) => ty.span,
+        }
+    }
+}
+
+/// Represents the kind of 'self' associated with a method
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum ExplicitSelf_ {
+    /// No self
+    SelfStatic,
+    /// `self`
+    SelfValue(Name),
+    /// `&'lt self`, `&'lt mut self`
+    SelfRegion(Option<Lifetime>, Mutability, Name),
+    /// `self: TYPE`
+    SelfExplicit(P<Ty>, Name),
+}
+
+pub type ExplicitSelf = Spanned<ExplicitSelf_>;
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct Mod {
+    /// A span from the first token past `{` to the last token until `}`.
+    /// For `mod foo;`, the inner span ranges from the first token
+    /// to the last token in the external file.
+    pub inner: Span,
+    pub item_ids: HirVec<ItemId>,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct ForeignMod {
+    pub abi: Abi,
+    pub items: HirVec<ForeignItem>,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct EnumDef {
+    pub variants: HirVec<Variant>,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct Variant_ {
+    pub name: Name,
+    pub attrs: HirVec<Attribute>,
+    pub data: VariantData,
+    /// Explicit discriminant, eg `Foo = 1`
+    pub disr_expr: Option<P<Expr>>,
+}
+
+pub type Variant = Spanned<Variant_>;
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+pub enum PathListItem_ {
+    PathListIdent {
+        name: Name,
+        /// renamed in list, eg `use foo::{bar as baz};`
+        rename: Option<Name>,
+        id: NodeId,
+    },
+    PathListMod {
+        /// renamed in list, eg `use foo::{self as baz};`
+        rename: Option<Name>,
+        id: NodeId,
+    },
+}
+
+impl PathListItem_ {
+    pub fn id(&self) -> NodeId {
+        match *self {
+            PathListIdent { id, .. } | PathListMod { id, .. } => id,
+        }
+    }
+
+    pub fn name(&self) -> Option<Name> {
+        match *self {
+            PathListIdent { name, .. } => Some(name),
+            PathListMod { .. } => None,
+        }
+    }
+
+    pub fn rename(&self) -> Option<Name> {
+        match *self {
+            PathListIdent { rename, .. } | PathListMod { rename, .. } => rename,
+        }
+    }
+}
+
+pub type PathListItem = Spanned<PathListItem_>;
+
+pub type ViewPath = Spanned<ViewPath_>;
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum ViewPath_ {
+    /// `foo::bar::baz as quux`
+    ///
+    /// or just
+    ///
+    /// `foo::bar::baz` (with `as baz` implicitly on the right)
+    ViewPathSimple(Name, Path),
+
+    /// `foo::bar::*`
+    ViewPathGlob(Path),
+
+    /// `foo::bar::{a,b,c}`
+    ViewPathList(Path, HirVec<PathListItem>),
+}
+
+/// TraitRef's appear in impls.
+///
+/// resolve maps each TraitRef's ref_id to its defining trait; that's all
+/// that the ref_id is for. The impl_id maps to the "self type" of this impl.
+/// If this impl is an ItemImpl, the impl_id is redundant (it could be the
+/// same as the impl's node id).
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct TraitRef {
+    pub path: Path,
+    pub ref_id: NodeId,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct PolyTraitRef {
+    /// The `'a` in `<'a> Foo<&'a T>`
+    pub bound_lifetimes: HirVec<LifetimeDef>,
+
+    /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`
+    pub trait_ref: TraitRef,
+
+    pub span: Span,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+pub enum Visibility {
+    Public,
+    Inherited,
+}
+
+impl Visibility {
+    pub fn inherit_from(&self, parent_visibility: Visibility) -> Visibility {
+        match self {
+            &Inherited => parent_visibility,
+            &Public => *self,
+        }
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct StructField {
+    pub span: Span,
+    pub name: Name,
+    pub vis: Visibility,
+    pub id: NodeId,
+    pub ty: P<Ty>,
+    pub attrs: HirVec<Attribute>,
+}
+
+impl StructField {
+    // Still necessary in couple of places
+    pub fn is_positional(&self) -> bool {
+        let first = self.name.as_str().as_bytes()[0];
+        first >= b'0' && first <= b'9'
+    }
+}
+
+/// Fields and Ids of enum variants and structs
+///
+/// For enum variants: `NodeId` represents both an Id of the variant itself (relevant for all
+/// variant kinds) and an Id of the variant's constructor (not relevant for `Struct`-variants).
+/// One shared Id can be successfully used for these two purposes.
+/// Id of the whole enum lives in `Item`.
+///
+/// For structs: `NodeId` represents an Id of the structure's constructor, so it is not actually
+/// used for `Struct`-structs (but still presents). Structures don't have an analogue of "Id of
+/// the variant itself" from enum variants.
+/// Id of the whole struct lives in `Item`.
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum VariantData {
+    Struct(HirVec<StructField>, NodeId),
+    Tuple(HirVec<StructField>, NodeId),
+    Unit(NodeId),
+}
+
+impl VariantData {
+    pub fn fields(&self) -> &[StructField] {
+        match *self {
+            VariantData::Struct(ref fields, _) | VariantData::Tuple(ref fields, _) => fields,
+            _ => &[],
+        }
+    }
+    pub fn id(&self) -> NodeId {
+        match *self {
+            VariantData::Struct(_, id) | VariantData::Tuple(_, id) | VariantData::Unit(id) => id,
+        }
+    }
+    pub fn is_struct(&self) -> bool {
+        if let VariantData::Struct(..) = *self {
+            true
+        } else {
+            false
+        }
+    }
+    pub fn is_tuple(&self) -> bool {
+        if let VariantData::Tuple(..) = *self {
+            true
+        } else {
+            false
+        }
+    }
+    pub fn is_unit(&self) -> bool {
+        if let VariantData::Unit(..) = *self {
+            true
+        } else {
+            false
+        }
+    }
+}
+
+// The bodies for items are stored "out of line", in a separate
+// hashmap in the `Crate`. Here we just record the node-id of the item
+// so it can fetched later.
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct ItemId {
+    pub id: NodeId,
+}
+
+//  FIXME (#3300): Should allow items to be anonymous. Right now
+//  we just use dummy names for anon items.
+/// An item
+///
+/// The name might be a dummy name in case of anonymous items
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct Item {
+    pub name: Name,
+    pub attrs: HirVec<Attribute>,
+    pub id: NodeId,
+    pub node: Item_,
+    pub vis: Visibility,
+    pub span: Span,
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum Item_ {
+    /// An`extern crate` item, with optional original crate name,
+    ///
+    /// e.g. `extern crate foo` or `extern crate foo_bar as foo`
+    ItemExternCrate(Option<Name>),
+    /// A `use` or `pub use` item
+    ItemUse(P<ViewPath>),
+
+    /// A `static` item
+    ItemStatic(P<Ty>, Mutability, P<Expr>),
+    /// A `const` item
+    ItemConst(P<Ty>, P<Expr>),
+    /// A function declaration
+    ItemFn(P<FnDecl>, Unsafety, Constness, Abi, Generics, P<Block>),
+    /// A module
+    ItemMod(Mod),
+    /// An external module
+    ItemForeignMod(ForeignMod),
+    /// A type alias, e.g. `type Foo = Bar<u8>`
+    ItemTy(P<Ty>, Generics),
+    /// An enum definition, e.g. `enum Foo<A, B> {C<A>, D<B>}`
+    ItemEnum(EnumDef, Generics),
+    /// A struct definition, e.g. `struct Foo<A> {x: A}`
+    ItemStruct(VariantData, Generics),
+    /// Represents a Trait Declaration
+    ItemTrait(Unsafety, Generics, TyParamBounds, HirVec<TraitItem>),
+
+    // Default trait implementations
+    ///
+    /// `impl Trait for .. {}`
+    ItemDefaultImpl(Unsafety, TraitRef),
+    /// An implementation, eg `impl<A> Trait for Foo { .. }`
+    ItemImpl(Unsafety,
+             ImplPolarity,
+             Generics,
+             Option<TraitRef>, // (optional) trait this impl implements
+             P<Ty>, // self
+             HirVec<ImplItem>),
+}
+
+impl Item_ {
+    pub fn descriptive_variant(&self) -> &str {
+        match *self {
+            ItemExternCrate(..) => "extern crate",
+            ItemUse(..) => "use",
+            ItemStatic(..) => "static item",
+            ItemConst(..) => "constant item",
+            ItemFn(..) => "function",
+            ItemMod(..) => "module",
+            ItemForeignMod(..) => "foreign module",
+            ItemTy(..) => "type alias",
+            ItemEnum(..) => "enum",
+            ItemStruct(..) => "struct",
+            ItemTrait(..) => "trait",
+            ItemImpl(..) |
+            ItemDefaultImpl(..) => "item",
+        }
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct ForeignItem {
+    pub name: Name,
+    pub attrs: HirVec<Attribute>,
+    pub node: ForeignItem_,
+    pub id: NodeId,
+    pub span: Span,
+    pub vis: Visibility,
+}
+
+/// An item within an `extern` block
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum ForeignItem_ {
+    /// A foreign function
+    ForeignItemFn(P<FnDecl>, Generics),
+    /// A foreign static item (`static ext: u8`), with optional mutability
+    /// (the boolean is true when mutable)
+    ForeignItemStatic(P<Ty>, bool),
+}
+
+impl ForeignItem_ {
+    pub fn descriptive_variant(&self) -> &str {
+        match *self {
+            ForeignItemFn(..) => "foreign function",
+            ForeignItemStatic(..) => "foreign static item",
+        }
+    }
+}
+
+/// A free variable referred to in a function.
+#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
+pub struct Freevar {
+    /// The variable being accessed free.
+    pub def: Def,
+
+    // First span where it is accessed (there can be multiple).
+    pub span: Span
+}
+
+pub type FreevarMap = NodeMap<Vec<Freevar>>;
+
+pub type CaptureModeMap = NodeMap<CaptureClause>;
+
+// Trait method resolution
+pub type TraitMap = NodeMap<Vec<DefId>>;
+
+// Map from the NodeId of a glob import to a list of items which are actually
+// imported.
+pub type GlobMap = NodeMap<FnvHashSet<Name>>;
diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/hir/pat_util.rs
index b2b1344c4bb..6cc5a29062f 100644
--- a/src/librustc/middle/pat_util.rs
+++ b/src/librustc/hir/pat_util.rs
@@ -8,14 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use middle::def::*;
-use middle::def_id::DefId;
+use hir::def::*;
+use hir::def_id::DefId;
 use ty::TyCtxt;
 use util::nodemap::FnvHashMap;
 
 use syntax::ast;
-use rustc_front::hir::{self, PatKind};
-use rustc_front::util::walk_pat;
+use hir::{self, PatKind};
 use syntax::codemap::{respan, Span, Spanned, DUMMY_SP};
 
 use std::cell::RefCell;
@@ -115,7 +114,7 @@ pub fn pat_is_binding_or_wild(dm: &DefMap, pat: &hir::Pat) -> bool {
 pub fn pat_bindings<I>(dm: &RefCell<DefMap>, pat: &hir::Pat, mut it: I) where
     I: FnMut(hir::BindingMode, ast::NodeId, Span, &Spanned<ast::Name>),
 {
-    walk_pat(pat, |p| {
+    pat.walk(|p| {
         match p.node {
           PatKind::Ident(binding_mode, ref pth, _) if pat_is_binding(&dm.borrow(), p) => {
             it(binding_mode, p.id, p.span, &respan(pth.span, pth.node.name));
@@ -128,7 +127,7 @@ pub fn pat_bindings<I>(dm: &RefCell<DefMap>, pat: &hir::Pat, mut it: I) where
 pub fn pat_bindings_ident<I>(dm: &RefCell<DefMap>, pat: &hir::Pat, mut it: I) where
     I: FnMut(hir::BindingMode, ast::NodeId, Span, &Spanned<hir::Ident>),
 {
-    walk_pat(pat, |p| {
+    pat.walk(|p| {
         match p.node {
           PatKind::Ident(binding_mode, ref pth, _) if pat_is_binding(&dm.borrow(), p) => {
             it(binding_mode, p.id, p.span, &respan(pth.span, pth.node));
@@ -143,7 +142,7 @@ pub fn pat_bindings_ident<I>(dm: &RefCell<DefMap>, pat: &hir::Pat, mut it: I) wh
 /// an ident, e.g. `foo`, or `Foo(foo)` or `foo @ Bar(..)`.
 pub fn pat_contains_bindings(dm: &DefMap, pat: &hir::Pat) -> bool {
     let mut contains_bindings = false;
-    walk_pat(pat, |p| {
+    pat.walk(|p| {
         if pat_is_binding(dm, p) {
             contains_bindings = true;
             false // there's at least one binding, can short circuit now.
@@ -188,7 +187,7 @@ pub fn arm_contains_ref_binding(dm: &RefCell<DefMap>, arm: &hir::Arm) -> Option<
 /// an ident or wildcard, e.g. `foo`, or `Foo(_)`, `foo @ Bar(..)`,
 pub fn pat_contains_bindings_or_wild(dm: &DefMap, pat: &hir::Pat) -> bool {
     let mut contains_bindings = false;
-    walk_pat(pat, |p| {
+    pat.walk(|p| {
         if pat_is_binding_or_wild(dm, p) {
             contains_bindings = true;
             false // there's at least one binding/wildcard, can short circuit now.
@@ -211,20 +210,14 @@ pub fn simple_name<'a>(pat: &'a hir::Pat) -> Option<ast::Name> {
 }
 
 pub fn def_to_path(tcx: &TyCtxt, id: DefId) -> hir::Path {
-    tcx.with_path(id, |path| hir::Path {
-        global: false,
-        segments: path.last().map(|elem| hir::PathSegment {
-            identifier: hir::Ident::from_name(elem.name()),
-            parameters: hir::PathParameters::none(),
-        }).into_iter().collect(),
-        span: DUMMY_SP,
-    })
+    let name = tcx.item_name(id);
+    hir::Path::from_ident(DUMMY_SP, hir::Ident::from_name(name))
 }
 
 /// Return variants that are necessary to exist for the pattern to match.
 pub fn necessary_variants(dm: &DefMap, pat: &hir::Pat) -> Vec<DefId> {
     let mut variants = vec![];
-    walk_pat(pat, |p| {
+    pat.walk(|p| {
         match p.node {
             PatKind::TupleStruct(..) |
             PatKind::Path(..) |
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
new file mode 100644
index 00000000000..cd2dfd44639
--- /dev/null
+++ b/src/librustc/hir/print.rs
@@ -0,0 +1,2413 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub use self::AnnNode::*;
+
+use syntax::abi::Abi;
+use syntax::ast;
+use syntax::codemap::{self, CodeMap, BytePos, Spanned};
+use syntax::errors;
+use syntax::parse::token::{self, BinOpToken};
+use syntax::parse::lexer::comments;
+use syntax::parse;
+use syntax::print::pp::{self, break_offset, word, space, hardbreak};
+use syntax::print::pp::{Breaks, eof};
+use syntax::print::pp::Breaks::{Consistent, Inconsistent};
+use syntax::print::pprust::{self as ast_pp, PrintState};
+use syntax::ptr::P;
+
+use hir;
+use hir::{Crate, PatKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
+
+use std::io::{self, Write, Read};
+
+pub enum AnnNode<'a> {
+    NodeName(&'a ast::Name),
+    NodeBlock(&'a hir::Block),
+    NodeItem(&'a hir::Item),
+    NodeSubItem(ast::NodeId),
+    NodeExpr(&'a hir::Expr),
+    NodePat(&'a hir::Pat),
+}
+
+pub trait PpAnn {
+    fn pre(&self, _state: &mut State, _node: AnnNode) -> io::Result<()> {
+        Ok(())
+    }
+    fn post(&self, _state: &mut State, _node: AnnNode) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+#[derive(Copy, Clone)]
+pub struct NoAnn;
+
+impl PpAnn for NoAnn {}
+
+
+pub struct State<'a> {
+    krate: Option<&'a Crate>,
+    pub s: pp::Printer<'a>,
+    cm: Option<&'a CodeMap>,
+    comments: Option<Vec<comments::Comment>>,
+    literals: Option<Vec<comments::Literal>>,
+    cur_cmnt_and_lit: ast_pp::CurrentCommentAndLiteral,
+    boxes: Vec<pp::Breaks>,
+    ann: &'a (PpAnn + 'a),
+}
+
+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_and_lit(&mut self) -> &mut ast_pp::CurrentCommentAndLiteral {
+        &mut self.cur_cmnt_and_lit
+    }
+
+    fn literals(&self) -> &Option<Vec<comments::Literal>> {
+        &self.literals
+    }
+}
+
+pub fn rust_printer<'a>(writer: Box<Write + 'a>, krate: Option<&'a Crate>) -> State<'a> {
+    static NO_ANN: NoAnn = NoAnn;
+    rust_printer_annotated(writer, &NO_ANN, krate)
+}
+
+pub fn rust_printer_annotated<'a>(writer: Box<Write + 'a>,
+                                  ann: &'a PpAnn,
+                                  krate: Option<&'a Crate>)
+                                  -> State<'a> {
+    State {
+        krate: krate,
+        s: pp::mk_printer(writer, default_columns),
+        cm: None,
+        comments: None,
+        literals: None,
+        cur_cmnt_and_lit: ast_pp::CurrentCommentAndLiteral {
+            cur_cmnt: 0,
+            cur_lit: 0,
+        },
+        boxes: Vec::new(),
+        ann: ann,
+    }
+}
+
+#[allow(non_upper_case_globals)]
+pub const indent_unit: usize = 4;
+
+#[allow(non_upper_case_globals)]
+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: &errors::Handler,
+                       krate: &hir::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, Some(krate));
+
+    // When printing the AST, we sometimes need to inject `#[no_std]` here.
+    // Since you can't compile the HIR, it's not necessary.
+
+    s.print_mod(&krate.module, &krate.attrs)?;
+    s.print_remaining_comments()?;
+    eof(&mut s.s)
+}
+
+impl<'a> State<'a> {
+    pub fn new_from_input(cm: &'a CodeMap,
+                          span_diagnostic: &errors::Handler,
+                          filename: String,
+                          input: &mut Read,
+                          out: Box<Write + 'a>,
+                          ann: &'a PpAnn,
+                          is_expanded: bool,
+                          krate: Option<&'a Crate>)
+                          -> State<'a> {
+        let (cmnts, lits) = comments::gather_comments_and_literals(span_diagnostic,
+                                                                   filename,
+                                                                   input);
+
+        State::new(cm,
+                   out,
+                   ann,
+                   Some(cmnts),
+                   // If the code is post expansion, don't use the table of
+                   // literals, since it doesn't correspond with the literals
+                   // in the AST anymore.
+                   if is_expanded {
+                       None
+                   } else {
+                       Some(lits)
+                   },
+                   krate)
+    }
+
+    pub fn new(cm: &'a CodeMap,
+               out: Box<Write + 'a>,
+               ann: &'a PpAnn,
+               comments: Option<Vec<comments::Comment>>,
+               literals: Option<Vec<comments::Literal>>,
+               krate: Option<&'a Crate>)
+               -> State<'a> {
+        State {
+            krate: krate,
+            s: pp::mk_printer(out, default_columns),
+            cm: Some(cm),
+            comments: comments.clone(),
+            literals: literals.clone(),
+            cur_cmnt_and_lit: ast_pp::CurrentCommentAndLiteral {
+                cur_cmnt: 0,
+                cur_lit: 0,
+            },
+            boxes: Vec::new(),
+            ann: ann,
+        }
+    }
+}
+
+pub fn to_string<F>(f: F) -> String
+    where F: FnOnce(&mut State) -> io::Result<()>
+{
+    let mut wr = Vec::new();
+    {
+        let mut printer = rust_printer(Box::new(&mut wr), None);
+        f(&mut printer).unwrap();
+        eof(&mut printer.s).unwrap();
+    }
+    String::from_utf8(wr).unwrap()
+}
+
+pub fn binop_to_string(op: BinOpToken) -> &'static str {
+    match op {
+        token::Plus => "+",
+        token::Minus => "-",
+        token::Star => "*",
+        token::Slash => "/",
+        token::Percent => "%",
+        token::Caret => "^",
+        token::And => "&",
+        token::Or => "|",
+        token::Shl => "<<",
+        token::Shr => ">>",
+    }
+}
+
+pub fn ty_to_string(ty: &hir::Ty) -> String {
+    to_string(|s| s.print_type(ty))
+}
+
+pub fn bounds_to_string(bounds: &[hir::TyParamBound]) -> String {
+    to_string(|s| s.print_bounds("", bounds))
+}
+
+pub fn pat_to_string(pat: &hir::Pat) -> String {
+    to_string(|s| s.print_pat(pat))
+}
+
+pub fn arm_to_string(arm: &hir::Arm) -> String {
+    to_string(|s| s.print_arm(arm))
+}
+
+pub fn expr_to_string(e: &hir::Expr) -> String {
+    to_string(|s| s.print_expr(e))
+}
+
+pub fn lifetime_to_string(e: &hir::Lifetime) -> String {
+    to_string(|s| s.print_lifetime(e))
+}
+
+pub fn stmt_to_string(stmt: &hir::Stmt) -> String {
+    to_string(|s| s.print_stmt(stmt))
+}
+
+pub fn item_to_string(i: &hir::Item) -> String {
+    to_string(|s| s.print_item(i))
+}
+
+pub fn impl_item_to_string(i: &hir::ImplItem) -> String {
+    to_string(|s| s.print_impl_item(i))
+}
+
+pub fn trait_item_to_string(i: &hir::TraitItem) -> String {
+    to_string(|s| s.print_trait_item(i))
+}
+
+pub fn generics_to_string(generics: &hir::Generics) -> String {
+    to_string(|s| s.print_generics(generics))
+}
+
+pub fn where_clause_to_string(i: &hir::WhereClause) -> String {
+    to_string(|s| s.print_where_clause(i))
+}
+
+pub fn fn_block_to_string(p: &hir::FnDecl) -> String {
+    to_string(|s| s.print_fn_block_args(p))
+}
+
+pub fn path_to_string(p: &hir::Path) -> String {
+    to_string(|s| s.print_path(p, false, 0))
+}
+
+pub fn name_to_string(name: ast::Name) -> String {
+    to_string(|s| s.print_name(name))
+}
+
+pub fn fun_to_string(decl: &hir::FnDecl,
+                     unsafety: hir::Unsafety,
+                     constness: hir::Constness,
+                     name: ast::Name,
+                     opt_explicit_self: Option<&hir::ExplicitSelf_>,
+                     generics: &hir::Generics)
+                     -> String {
+    to_string(|s| {
+        s.head("")?;
+        s.print_fn(decl,
+                   unsafety,
+                   constness,
+                   Abi::Rust,
+                   Some(name),
+                   generics,
+                   opt_explicit_self,
+                   hir::Inherited)?;
+        s.end()?; // Close the head box
+        s.end() // Close the outer box
+    })
+}
+
+pub fn block_to_string(blk: &hir::Block) -> String {
+    to_string(|s| {
+        // containing cbox, will be closed by print-block at }
+        s.cbox(indent_unit)?;
+        // head-ibox, will be closed by print-block after {
+        s.ibox(0)?;
+        s.print_block(blk)
+    })
+}
+
+pub fn explicit_self_to_string(explicit_self: &hir::ExplicitSelf_) -> String {
+    to_string(|s| s.print_explicit_self(explicit_self, hir::MutImmutable).map(|_| {}))
+}
+
+pub fn variant_to_string(var: &hir::Variant) -> String {
+    to_string(|s| s.print_variant(var))
+}
+
+pub fn arg_to_string(arg: &hir::Arg) -> String {
+    to_string(|s| s.print_arg(arg, false))
+}
+
+pub fn visibility_qualified(vis: hir::Visibility, s: &str) -> String {
+    match vis {
+        hir::Public => format!("pub {}", s),
+        hir::Inherited => s.to_string(),
+    }
+}
+
+fn needs_parentheses(expr: &hir::Expr) -> bool {
+    match expr.node {
+        hir::ExprAssign(..) |
+        hir::ExprBinary(..) |
+        hir::ExprClosure(..) |
+        hir::ExprAssignOp(..) |
+        hir::ExprCast(..) |
+        hir::ExprType(..) => true,
+        _ => false,
+    }
+}
+
+impl<'a> State<'a> {
+    pub fn cbox(&mut self, u: usize) -> io::Result<()> {
+        self.boxes.push(pp::Breaks::Consistent);
+        pp::cbox(&mut self.s, u)
+    }
+
+    pub fn nbsp(&mut self) -> io::Result<()> {
+        word(&mut self.s, " ")
+    }
+
+    pub fn word_nbsp(&mut self, w: &str) -> io::Result<()> {
+        word(&mut self.s, w)?;
+        self.nbsp()
+    }
+
+    pub fn head(&mut self, w: &str) -> io::Result<()> {
+        // outer-box is consistent
+        self.cbox(indent_unit)?;
+        // head-box is inconsistent
+        self.ibox(w.len() + 1)?;
+        // keyword that starts the head
+        if !w.is_empty() {
+            self.word_nbsp(w)?;
+        }
+        Ok(())
+    }
+
+    pub fn bopen(&mut self) -> io::Result<()> {
+        word(&mut self.s, "{")?;
+        self.end() // close the head-box
+    }
+
+    pub fn bclose_(&mut self, span: codemap::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<()> {
+        self.maybe_print_comment(span.hi)?;
+        self.break_offset_if_not_bol(1, -(indented as isize))?;
+        word(&mut self.s, "}")?;
+        if close_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 in_cbox(&self) -> bool {
+        match self.boxes.last() {
+            Some(&last_box) => last_box == pp::Breaks::Consistent,
+            None => false,
+        }
+    }
+    pub fn space_if_not_bol(&mut self) -> io::Result<()> {
+        if !self.is_bol() {
+            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)
+        } 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));
+            }
+            Ok(())
+        }
+    }
+
+    // Synthesizes a comment that was not textually present in the original source
+    // file.
+    pub fn synth_comment(&mut self, text: String) -> io::Result<()> {
+        word(&mut self.s, "/*")?;
+        space(&mut self.s)?;
+        word(&mut self.s, &text[..])?;
+        space(&mut self.s)?;
+        word(&mut self.s, "*/")
+    }
+
+
+    pub fn commasep_cmnt<T, F, G>(&mut self,
+                                  b: Breaks,
+                                  elts: &[T],
+                                  mut op: F,
+                                  mut get_span: G)
+                                  -> io::Result<()>
+        where F: FnMut(&mut State, &T) -> io::Result<()>,
+              G: FnMut(&T) -> codemap::Span
+    {
+        self.rbox(0, b)?;
+        let len = elts.len();
+        let mut i = 0;
+        for elt in elts {
+            self.maybe_print_comment(get_span(elt).hi)?;
+            op(self, elt)?;
+            i += 1;
+            if i < len {
+                word(&mut self.s, ",")?;
+                self.maybe_print_trailing_comment(get_span(elt), Some(get_span(&elts[i]).hi))?;
+                self.space_if_not_bol()?;
+            }
+        }
+        self.end()
+    }
+
+    pub fn commasep_exprs(&mut self, b: Breaks, exprs: &[P<hir::Expr>]) -> io::Result<()> {
+        self.commasep_cmnt(b, exprs, |s, e| s.print_expr(&e), |e| e.span)
+    }
+
+    pub fn print_mod(&mut self, _mod: &hir::Mod, attrs: &[ast::Attribute]) -> io::Result<()> {
+        self.print_inner_attributes(attrs)?;
+        for item_id in &_mod.item_ids {
+            self.print_item_id(item_id)?;
+        }
+        Ok(())
+    }
+
+    pub fn print_foreign_mod(&mut self,
+                             nmod: &hir::ForeignMod,
+                             attrs: &[ast::Attribute])
+                             -> io::Result<()> {
+        self.print_inner_attributes(attrs)?;
+        for item in &nmod.items {
+            self.print_foreign_item(item)?;
+        }
+        Ok(())
+    }
+
+    pub fn print_opt_lifetime(&mut self, lifetime: &Option<hir::Lifetime>) -> io::Result<()> {
+        if let Some(l) = *lifetime {
+            self.print_lifetime(&l)?;
+            self.nbsp()?;
+        }
+        Ok(())
+    }
+
+    pub fn print_type(&mut self, ty: &hir::Ty) -> io::Result<()> {
+        self.maybe_print_comment(ty.span.lo)?;
+        self.ibox(0)?;
+        match ty.node {
+            hir::TyVec(ref ty) => {
+                word(&mut self.s, "[")?;
+                self.print_type(&ty)?;
+                word(&mut self.s, "]")?;
+            }
+            hir::TyPtr(ref mt) => {
+                word(&mut self.s, "*")?;
+                match mt.mutbl {
+                    hir::MutMutable => self.word_nbsp("mut")?,
+                    hir::MutImmutable => self.word_nbsp("const")?,
+                }
+                self.print_type(&mt.ty)?;
+            }
+            hir::TyRptr(ref lifetime, ref mt) => {
+                word(&mut self.s, "&")?;
+                self.print_opt_lifetime(lifetime)?;
+                self.print_mt(mt)?;
+            }
+            hir::TyTup(ref elts) => {
+                self.popen()?;
+                self.commasep(Inconsistent, &elts[..], |s, ty| s.print_type(&ty))?;
+                if elts.len() == 1 {
+                    word(&mut self.s, ",")?;
+                }
+                self.pclose()?;
+            }
+            hir::TyBareFn(ref f) => {
+                let generics = hir::Generics {
+                    lifetimes: f.lifetimes.clone(),
+                    ty_params: hir::HirVec::new(),
+                    where_clause: hir::WhereClause {
+                        id: ast::DUMMY_NODE_ID,
+                        predicates: hir::HirVec::new(),
+                    },
+                };
+                self.print_ty_fn(f.abi, f.unsafety, &f.decl, None, &generics, None)?;
+            }
+            hir::TyPath(None, ref path) => {
+                self.print_path(path, false, 0)?;
+            }
+            hir::TyPath(Some(ref qself), ref path) => {
+                self.print_qpath(path, qself, false)?
+            }
+            hir::TyObjectSum(ref ty, ref bounds) => {
+                self.print_type(&ty)?;
+                self.print_bounds("+", &bounds[..])?;
+            }
+            hir::TyPolyTraitRef(ref bounds) => {
+                self.print_bounds("", &bounds[..])?;
+            }
+            hir::TyFixedLengthVec(ref ty, ref v) => {
+                word(&mut self.s, "[")?;
+                self.print_type(&ty)?;
+                word(&mut self.s, "; ")?;
+                self.print_expr(&v)?;
+                word(&mut self.s, "]")?;
+            }
+            hir::TyTypeof(ref e) => {
+                word(&mut self.s, "typeof(")?;
+                self.print_expr(&e)?;
+                word(&mut self.s, ")")?;
+            }
+            hir::TyInfer => {
+                word(&mut self.s, "_")?;
+            }
+        }
+        self.end()
+    }
+
+    pub fn print_foreign_item(&mut self, item: &hir::ForeignItem) -> io::Result<()> {
+        self.hardbreak_if_not_bol()?;
+        self.maybe_print_comment(item.span.lo)?;
+        self.print_outer_attributes(&item.attrs)?;
+        match item.node {
+            hir::ForeignItemFn(ref decl, ref generics) => {
+                self.head("")?;
+                self.print_fn(decl,
+                              hir::Unsafety::Normal,
+                              hir::Constness::NotConst,
+                              Abi::Rust,
+                              Some(item.name),
+                              generics,
+                              None,
+                              item.vis)?;
+                self.end()?; // end head-ibox
+                word(&mut self.s, ";")?;
+                self.end() // end the outer fn box
+            }
+            hir::ForeignItemStatic(ref t, m) => {
+                self.head(&visibility_qualified(item.vis, "static"))?;
+                if m {
+                    self.word_space("mut")?;
+                }
+                self.print_name(item.name)?;
+                self.word_space(":")?;
+                self.print_type(&t)?;
+                word(&mut self.s, ";")?;
+                self.end()?; // end the head-ibox
+                self.end() // end the outer cbox
+            }
+        }
+    }
+
+    fn print_associated_const(&mut self,
+                              name: ast::Name,
+                              ty: &hir::Ty,
+                              default: Option<&hir::Expr>,
+                              vis: hir::Visibility)
+                              -> io::Result<()> {
+        word(&mut self.s, &visibility_qualified(vis, ""))?;
+        self.word_space("const")?;
+        self.print_name(name)?;
+        self.word_space(":")?;
+        self.print_type(ty)?;
+        if let Some(expr) = default {
+            space(&mut self.s)?;
+            self.word_space("=")?;
+            self.print_expr(expr)?;
+        }
+        word(&mut self.s, ";")
+    }
+
+    fn print_associated_type(&mut self,
+                             name: ast::Name,
+                             bounds: Option<&hir::TyParamBounds>,
+                             ty: Option<&hir::Ty>)
+                             -> io::Result<()> {
+        self.word_space("type")?;
+        self.print_name(name)?;
+        if let Some(bounds) = bounds {
+            self.print_bounds(":", bounds)?;
+        }
+        if let Some(ty) = ty {
+            space(&mut self.s)?;
+            self.word_space("=")?;
+            self.print_type(ty)?;
+        }
+        word(&mut self.s, ";")
+    }
+
+    pub fn print_item_id(&mut self, item_id: &hir::ItemId) -> io::Result<()> {
+        if let Some(krate) = self.krate {
+            // skip nested items if krate context was not provided
+            let item = &krate.items[&item_id.id];
+            self.print_item(item)
+        } else {
+            Ok(())
+        }
+    }
+
+    /// Pretty-print an item
+    pub fn print_item(&mut self, item: &hir::Item) -> io::Result<()> {
+        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 {
+            hir::ItemExternCrate(ref optional_path) => {
+                self.head(&visibility_qualified(item.vis, "extern crate"))?;
+                if let Some(p) = *optional_path {
+                    let val = p.as_str();
+                    if val.contains("-") {
+                        self.print_string(&val, ast::StrStyle::Cooked)?;
+                    } else {
+                        self.print_name(p)?;
+                    }
+                    space(&mut self.s)?;
+                    word(&mut self.s, "as")?;
+                    space(&mut self.s)?;
+                }
+                self.print_name(item.name)?;
+                word(&mut self.s, ";")?;
+                self.end()?; // end inner head-block
+                self.end()?; // end outer head-block
+            }
+            hir::ItemUse(ref vp) => {
+                self.head(&visibility_qualified(item.vis, "use"))?;
+                self.print_view_path(&vp)?;
+                word(&mut self.s, ";")?;
+                self.end()?; // end inner head-block
+                self.end()?; // end outer head-block
+            }
+            hir::ItemStatic(ref ty, m, ref expr) => {
+                self.head(&visibility_qualified(item.vis, "static"))?;
+                if m == hir::MutMutable {
+                    self.word_space("mut")?;
+                }
+                self.print_name(item.name)?;
+                self.word_space(":")?;
+                self.print_type(&ty)?;
+                space(&mut self.s)?;
+                self.end()?; // end the head-ibox
+
+                self.word_space("=")?;
+                self.print_expr(&expr)?;
+                word(&mut self.s, ";")?;
+                self.end()?; // end the outer cbox
+            }
+            hir::ItemConst(ref ty, ref expr) => {
+                self.head(&visibility_qualified(item.vis, "const"))?;
+                self.print_name(item.name)?;
+                self.word_space(":")?;
+                self.print_type(&ty)?;
+                space(&mut self.s)?;
+                self.end()?; // end the head-ibox
+
+                self.word_space("=")?;
+                self.print_expr(&expr)?;
+                word(&mut self.s, ";")?;
+                self.end()?; // end the outer cbox
+            }
+            hir::ItemFn(ref decl, unsafety, constness, abi, ref typarams, ref body) => {
+                self.head("")?;
+                self.print_fn(decl,
+                              unsafety,
+                              constness,
+                              abi,
+                              Some(item.name),
+                              typarams,
+                              None,
+                              item.vis)?;
+                word(&mut self.s, " ")?;
+                self.print_block_with_attrs(&body, &item.attrs)?;
+            }
+            hir::ItemMod(ref _mod) => {
+                self.head(&visibility_qualified(item.vis, "mod"))?;
+                self.print_name(item.name)?;
+                self.nbsp()?;
+                self.bopen()?;
+                self.print_mod(_mod, &item.attrs)?;
+                self.bclose(item.span)?;
+            }
+            hir::ItemForeignMod(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)?;
+            }
+            hir::ItemTy(ref ty, ref params) => {
+                self.ibox(indent_unit)?;
+                self.ibox(0)?;
+                self.word_nbsp(&visibility_qualified(item.vis, "type"))?;
+                self.print_name(item.name)?;
+                self.print_generics(params)?;
+                self.end()?; // end the inner ibox
+
+                self.print_where_clause(&params.where_clause)?;
+                space(&mut self.s)?;
+                self.word_space("=")?;
+                self.print_type(&ty)?;
+                word(&mut self.s, ";")?;
+                self.end()?; // end the outer ibox
+            }
+            hir::ItemEnum(ref enum_definition, ref params) => {
+                self.print_enum_def(enum_definition, params, item.name, item.span, item.vis)?;
+            }
+            hir::ItemStruct(ref struct_def, ref generics) => {
+                self.head(&visibility_qualified(item.vis, "struct"))?;
+                self.print_struct(struct_def, generics, item.name, item.span, true)?;
+            }
+
+            hir::ItemDefaultImpl(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)?;
+                space(&mut self.s)?;
+                self.word_space("for")?;
+                self.word_space("..")?;
+                self.bopen()?;
+                self.bclose(item.span)?;
+            }
+            hir::ItemImpl(unsafety,
+                          polarity,
+                          ref generics,
+                          ref opt_trait,
+                          ref ty,
+                          ref impl_items) => {
+                self.head("")?;
+                self.print_visibility(item.vis)?;
+                self.print_unsafety(unsafety)?;
+                self.word_nbsp("impl")?;
+
+                if generics.is_parameterized() {
+                    self.print_generics(generics)?;
+                    space(&mut self.s)?;
+                }
+
+                match polarity {
+                    hir::ImplPolarity::Negative => {
+                        word(&mut self.s, "!")?;
+                    }
+                    _ => {}
+                }
+
+                match opt_trait {
+                    &Some(ref t) => {
+                        self.print_trait_ref(t)?;
+                        space(&mut self.s)?;
+                        self.word_space("for")?;
+                    }
+                    &None => {}
+                }
+
+                self.print_type(&ty)?;
+                self.print_where_clause(&generics.where_clause)?;
+
+                space(&mut self.s)?;
+                self.bopen()?;
+                self.print_inner_attributes(&item.attrs)?;
+                for impl_item in impl_items {
+                    self.print_impl_item(impl_item)?;
+                }
+                self.bclose(item.span)?;
+            }
+            hir::ItemTrait(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_name(item.name)?;
+                self.print_generics(generics)?;
+                let mut real_bounds = Vec::with_capacity(bounds.len());
+                for b in bounds.iter() {
+                    if let TraitTyParamBound(ref ptr, hir::TraitBoundModifier::Maybe) = *b {
+                        space(&mut self.s)?;
+                        self.word_space("for ?")?;
+                        self.print_trait_ref(&ptr.trait_ref)?;
+                    } else {
+                        real_bounds.push(b.clone());
+                    }
+                }
+                self.print_bounds(":", &real_bounds[..])?;
+                self.print_where_clause(&generics.where_clause)?;
+                word(&mut self.s, " ")?;
+                self.bopen()?;
+                for trait_item in trait_items {
+                    self.print_trait_item(trait_item)?;
+                }
+                self.bclose(item.span)?;
+            }
+        }
+        self.ann.post(self, NodeItem(item))
+    }
+
+    fn print_trait_ref(&mut self, t: &hir::TraitRef) -> io::Result<()> {
+        self.print_path(&t.path, false, 0)
+    }
+
+    fn print_formal_lifetime_list(&mut self, lifetimes: &[hir::LifetimeDef]) -> io::Result<()> {
+        if !lifetimes.is_empty() {
+            word(&mut self.s, "for<")?;
+            let mut comma = false;
+            for lifetime_def in lifetimes {
+                if comma {
+                    self.word_space(",")?
+                }
+                self.print_lifetime_def(lifetime_def)?;
+                comma = true;
+            }
+            word(&mut self.s, ">")?;
+        }
+        Ok(())
+    }
+
+    fn print_poly_trait_ref(&mut self, t: &hir::PolyTraitRef) -> io::Result<()> {
+        self.print_formal_lifetime_list(&t.bound_lifetimes)?;
+        self.print_trait_ref(&t.trait_ref)
+    }
+
+    pub fn print_enum_def(&mut self,
+                          enum_definition: &hir::EnumDef,
+                          generics: &hir::Generics,
+                          name: ast::Name,
+                          span: codemap::Span,
+                          visibility: hir::Visibility)
+                          -> io::Result<()> {
+        self.head(&visibility_qualified(visibility, "enum"))?;
+        self.print_name(name)?;
+        self.print_generics(generics)?;
+        self.print_where_clause(&generics.where_clause)?;
+        space(&mut self.s)?;
+        self.print_variants(&enum_definition.variants, span)
+    }
+
+    pub fn print_variants(&mut self,
+                          variants: &[hir::Variant],
+                          span: codemap::Span)
+                          -> io::Result<()> {
+        self.bopen()?;
+        for v in variants {
+            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)?;
+            word(&mut self.s, ",")?;
+            self.end()?;
+            self.maybe_print_trailing_comment(v.span, None)?;
+        }
+        self.bclose(span)
+    }
+
+    pub fn print_visibility(&mut self, vis: hir::Visibility) -> io::Result<()> {
+        match vis {
+            hir::Public => self.word_nbsp("pub"),
+            hir::Inherited => Ok(()),
+        }
+    }
+
+    pub fn print_struct(&mut self,
+                        struct_def: &hir::VariantData,
+                        generics: &hir::Generics,
+                        name: ast::Name,
+                        span: codemap::Span,
+                        print_finalizer: bool)
+                        -> io::Result<()> {
+        self.print_name(name)?;
+        self.print_generics(generics)?;
+        if !struct_def.is_struct() {
+            if struct_def.is_tuple() {
+                self.popen()?;
+                self.commasep(Inconsistent, struct_def.fields(), |s, field| {
+                    s.print_visibility(field.vis)?;
+                    s.maybe_print_comment(field.span.lo)?;
+                    s.print_type(&field.ty)
+                })?;
+                self.pclose()?;
+            }
+            self.print_where_clause(&generics.where_clause)?;
+            if print_finalizer {
+                word(&mut self.s, ";")?;
+            }
+            self.end()?;
+            self.end() // close the outer-box
+        } else {
+            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_name(field.name)?;
+                self.word_nbsp(":")?;
+                self.print_type(&field.ty)?;
+                word(&mut self.s, ",")?;
+            }
+
+            self.bclose(span)
+        }
+    }
+
+    pub fn print_variant(&mut self, v: &hir::Variant) -> io::Result<()> {
+        self.head("")?;
+        let generics = hir::Generics::empty();
+        self.print_struct(&v.node.data, &generics, v.node.name, v.span, false)?;
+        match v.node.disr_expr {
+            Some(ref d) => {
+                space(&mut self.s)?;
+                self.word_space("=")?;
+                self.print_expr(&d)
+            }
+            _ => Ok(()),
+        }
+    }
+    pub fn print_method_sig(&mut self,
+                            name: ast::Name,
+                            m: &hir::MethodSig,
+                            vis: hir::Visibility)
+                            -> io::Result<()> {
+        self.print_fn(&m.decl,
+                      m.unsafety,
+                      m.constness,
+                      m.abi,
+                      Some(name),
+                      &m.generics,
+                      Some(&m.explicit_self.node),
+                      vis)
+    }
+
+    pub fn print_trait_item(&mut self, ti: &hir::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 {
+            hir::ConstTraitItem(ref ty, ref default) => {
+                self.print_associated_const(ti.name,
+                                            &ty,
+                                            default.as_ref().map(|expr| &**expr),
+                                            hir::Inherited)?;
+            }
+            hir::MethodTraitItem(ref sig, ref body) => {
+                if body.is_some() {
+                    self.head("")?;
+                }
+                self.print_method_sig(ti.name, sig, hir::Inherited)?;
+                if let Some(ref body) = *body {
+                    self.nbsp()?;
+                    self.print_block_with_attrs(body, &ti.attrs)?;
+                } else {
+                    word(&mut self.s, ";")?;
+                }
+            }
+            hir::TypeTraitItem(ref bounds, ref default) => {
+                self.print_associated_type(ti.name,
+                                           Some(bounds),
+                                           default.as_ref().map(|ty| &**ty))?;
+            }
+        }
+        self.ann.post(self, NodeSubItem(ti.id))
+    }
+
+    pub fn print_impl_item(&mut self, ii: &hir::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)?;
+
+        if let hir::Defaultness::Default = ii.defaultness {
+            self.word_nbsp("default")?;
+        }
+
+        match ii.node {
+            hir::ImplItemKind::Const(ref ty, ref expr) => {
+                self.print_associated_const(ii.name, &ty, Some(&expr), ii.vis)?;
+            }
+            hir::ImplItemKind::Method(ref sig, ref body) => {
+                self.head("")?;
+                self.print_method_sig(ii.name, sig, ii.vis)?;
+                self.nbsp()?;
+                self.print_block_with_attrs(body, &ii.attrs)?;
+            }
+            hir::ImplItemKind::Type(ref ty) => {
+                self.print_associated_type(ii.name, None, Some(ty))?;
+            }
+        }
+        self.ann.post(self, NodeSubItem(ii.id))
+    }
+
+    pub fn print_stmt(&mut self, st: &hir::Stmt) -> io::Result<()> {
+        self.maybe_print_comment(st.span.lo)?;
+        match st.node {
+            hir::StmtDecl(ref decl, _) => {
+                self.print_decl(&decl)?;
+            }
+            hir::StmtExpr(ref expr, _) => {
+                self.space_if_not_bol()?;
+                self.print_expr(&expr)?;
+            }
+            hir::StmtSemi(ref expr, _) => {
+                self.space_if_not_bol()?;
+                self.print_expr(&expr)?;
+                word(&mut self.s, ";")?;
+            }
+        }
+        if stmt_ends_with_semi(&st.node) {
+            word(&mut self.s, ";")?;
+        }
+        self.maybe_print_trailing_comment(st.span, None)
+    }
+
+    pub fn print_block(&mut self, blk: &hir::Block) -> io::Result<()> {
+        self.print_block_with_attrs(blk, &[])
+    }
+
+    pub fn print_block_unclosed(&mut self, blk: &hir::Block) -> io::Result<()> {
+        self.print_block_unclosed_indent(blk, indent_unit)
+    }
+
+    pub fn print_block_unclosed_indent(&mut self,
+                                       blk: &hir::Block,
+                                       indented: usize)
+                                       -> io::Result<()> {
+        self.print_block_maybe_unclosed(blk, indented, &[], false)
+    }
+
+    pub fn print_block_with_attrs(&mut self,
+                                  blk: &hir::Block,
+                                  attrs: &[ast::Attribute])
+                                  -> io::Result<()> {
+        self.print_block_maybe_unclosed(blk, indent_unit, attrs, true)
+    }
+
+    pub fn print_block_maybe_unclosed(&mut self,
+                                      blk: &hir::Block,
+                                      indented: usize,
+                                      attrs: &[ast::Attribute],
+                                      close_box: bool)
+                                      -> io::Result<()> {
+        match blk.rules {
+            hir::UnsafeBlock(..) => self.word_space("unsafe")?,
+            hir::PushUnsafeBlock(..) => self.word_space("push_unsafe")?,
+            hir::PopUnsafeBlock(..) => self.word_space("pop_unsafe")?,
+            hir::PushUnstableBlock => self.word_space("push_unstable")?,
+            hir::PopUnstableBlock => self.word_space("pop_unstable")?,
+            hir::DefaultBlock => (),
+        }
+        self.maybe_print_comment(blk.span.lo)?;
+        self.ann.pre(self, NodeBlock(blk))?;
+        self.bopen()?;
+
+        self.print_inner_attributes(attrs)?;
+
+        for st in &blk.stmts {
+            self.print_stmt(st)?;
+        }
+        match blk.expr {
+            Some(ref expr) => {
+                self.space_if_not_bol()?;
+                self.print_expr(&expr)?;
+                self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi))?;
+            }
+            _ => (),
+        }
+        self.bclose_maybe_open(blk.span, indented, close_box)?;
+        self.ann.post(self, NodeBlock(blk))
+    }
+
+    fn print_else(&mut self, els: Option<&hir::Expr>) -> io::Result<()> {
+        match els {
+            Some(_else) => {
+                match _else.node {
+                    // "another else-if"
+                    hir::ExprIf(ref i, ref then, ref e) => {
+                        self.cbox(indent_unit - 1)?;
+                        self.ibox(0)?;
+                        word(&mut self.s, " else if ")?;
+                        self.print_expr(&i)?;
+                        space(&mut self.s)?;
+                        self.print_block(&then)?;
+                        self.print_else(e.as_ref().map(|e| &**e))
+                    }
+                    // "final else"
+                    hir::ExprBlock(ref b) => {
+                        self.cbox(indent_unit - 1)?;
+                        self.ibox(0)?;
+                        word(&mut self.s, " else ")?;
+                        self.print_block(&b)
+                    }
+                    // BLEAH, constraints would be great here
+                    _ => {
+                        panic!("print_if saw if with weird alternative");
+                    }
+                }
+            }
+            _ => Ok(()),
+        }
+    }
+
+    pub fn print_if(&mut self,
+                    test: &hir::Expr,
+                    blk: &hir::Block,
+                    elseopt: Option<&hir::Expr>)
+                    -> io::Result<()> {
+        self.head("if")?;
+        self.print_expr(test)?;
+        space(&mut self.s)?;
+        self.print_block(blk)?;
+        self.print_else(elseopt)
+    }
+
+    pub fn print_if_let(&mut self,
+                        pat: &hir::Pat,
+                        expr: &hir::Expr,
+                        blk: &hir::Block,
+                        elseopt: Option<&hir::Expr>)
+                        -> io::Result<()> {
+        self.head("if let")?;
+        self.print_pat(pat)?;
+        space(&mut self.s)?;
+        self.word_space("=")?;
+        self.print_expr(expr)?;
+        space(&mut self.s)?;
+        self.print_block(blk)?;
+        self.print_else(elseopt)
+    }
+
+
+    fn print_call_post(&mut self, args: &[P<hir::Expr>]) -> io::Result<()> {
+        self.popen()?;
+        self.commasep_exprs(Inconsistent, args)?;
+        self.pclose()
+    }
+
+    pub fn print_expr_maybe_paren(&mut self, expr: &hir::Expr) -> io::Result<()> {
+        let needs_par = needs_parentheses(expr);
+        if needs_par {
+            self.popen()?;
+        }
+        self.print_expr(expr)?;
+        if needs_par {
+            self.pclose()?;
+        }
+        Ok(())
+    }
+
+    fn print_expr_vec(&mut self, exprs: &[P<hir::Expr>]) -> io::Result<()> {
+        self.ibox(indent_unit)?;
+        word(&mut self.s, "[")?;
+        self.commasep_exprs(Inconsistent, &exprs[..])?;
+        word(&mut self.s, "]")?;
+        self.end()
+    }
+
+    fn print_expr_repeat(&mut self, element: &hir::Expr, count: &hir::Expr) -> io::Result<()> {
+        self.ibox(indent_unit)?;
+        word(&mut self.s, "[")?;
+        self.print_expr(element)?;
+        self.word_space(";")?;
+        self.print_expr(count)?;
+        word(&mut self.s, "]")?;
+        self.end()
+    }
+
+    fn print_expr_struct(&mut self,
+                         path: &hir::Path,
+                         fields: &[hir::Field],
+                         wth: &Option<P<hir::Expr>>)
+                         -> io::Result<()> {
+        self.print_path(path, true, 0)?;
+        word(&mut self.s, "{")?;
+        self.commasep_cmnt(Consistent,
+                           &fields[..],
+                           |s, field| {
+                               s.ibox(indent_unit)?;
+                               s.print_name(field.name.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() {
+                    word(&mut self.s, ",")?;
+                    space(&mut self.s)?;
+                }
+                word(&mut self.s, "..")?;
+                self.print_expr(&expr)?;
+                self.end()?;
+            }
+            _ => if !fields.is_empty() {
+                word(&mut self.s, ",")?
+            },
+        }
+        word(&mut self.s, "}")?;
+        Ok(())
+    }
+
+    fn print_expr_tup(&mut self, exprs: &[P<hir::Expr>]) -> io::Result<()> {
+        self.popen()?;
+        self.commasep_exprs(Inconsistent, &exprs[..])?;
+        if exprs.len() == 1 {
+            word(&mut self.s, ",")?;
+        }
+        self.pclose()
+    }
+
+    fn print_expr_call(&mut self, func: &hir::Expr, args: &[P<hir::Expr>]) -> io::Result<()> {
+        self.print_expr_maybe_paren(func)?;
+        self.print_call_post(args)
+    }
+
+    fn print_expr_method_call(&mut self,
+                              name: Spanned<ast::Name>,
+                              tys: &[P<hir::Ty>],
+                              args: &[P<hir::Expr>])
+                              -> io::Result<()> {
+        let base_args = &args[1..];
+        self.print_expr(&args[0])?;
+        word(&mut self.s, ".")?;
+        self.print_name(name.node)?;
+        if !tys.is_empty() {
+            word(&mut self.s, "::<")?;
+            self.commasep(Inconsistent, tys, |s, ty| s.print_type(&ty))?;
+            word(&mut self.s, ">")?;
+        }
+        self.print_call_post(base_args)
+    }
+
+    fn print_expr_binary(&mut self,
+                         op: hir::BinOp,
+                         lhs: &hir::Expr,
+                         rhs: &hir::Expr)
+                         -> io::Result<()> {
+        self.print_expr(lhs)?;
+        space(&mut self.s)?;
+        self.word_space(op.node.as_str())?;
+        self.print_expr(rhs)
+    }
+
+    fn print_expr_unary(&mut self, op: hir::UnOp, expr: &hir::Expr) -> io::Result<()> {
+        word(&mut self.s, op.as_str())?;
+        self.print_expr_maybe_paren(expr)
+    }
+
+    fn print_expr_addr_of(&mut self,
+                          mutability: hir::Mutability,
+                          expr: &hir::Expr)
+                          -> io::Result<()> {
+        word(&mut self.s, "&")?;
+        self.print_mutability(mutability)?;
+        self.print_expr_maybe_paren(expr)
+    }
+
+    pub fn print_expr(&mut self, expr: &hir::Expr) -> io::Result<()> {
+        self.maybe_print_comment(expr.span.lo)?;
+        self.ibox(indent_unit)?;
+        self.ann.pre(self, NodeExpr(expr))?;
+        match expr.node {
+            hir::ExprBox(ref expr) => {
+                self.word_space("box")?;
+                self.print_expr(expr)?;
+            }
+            hir::ExprVec(ref exprs) => {
+                self.print_expr_vec(&exprs[..])?;
+            }
+            hir::ExprRepeat(ref element, ref count) => {
+                self.print_expr_repeat(&element, &count)?;
+            }
+            hir::ExprStruct(ref path, ref fields, ref wth) => {
+                self.print_expr_struct(path, &fields[..], wth)?;
+            }
+            hir::ExprTup(ref exprs) => {
+                self.print_expr_tup(&exprs[..])?;
+            }
+            hir::ExprCall(ref func, ref args) => {
+                self.print_expr_call(&func, &args[..])?;
+            }
+            hir::ExprMethodCall(name, ref tys, ref args) => {
+                self.print_expr_method_call(name, &tys[..], &args[..])?;
+            }
+            hir::ExprBinary(op, ref lhs, ref rhs) => {
+                self.print_expr_binary(op, &lhs, &rhs)?;
+            }
+            hir::ExprUnary(op, ref expr) => {
+                self.print_expr_unary(op, &expr)?;
+            }
+            hir::ExprAddrOf(m, ref expr) => {
+                self.print_expr_addr_of(m, &expr)?;
+            }
+            hir::ExprLit(ref lit) => {
+                self.print_literal(&lit)?;
+            }
+            hir::ExprCast(ref expr, ref ty) => {
+                self.print_expr(&expr)?;
+                space(&mut self.s)?;
+                self.word_space("as")?;
+                self.print_type(&ty)?;
+            }
+            hir::ExprType(ref expr, ref ty) => {
+                self.print_expr(&expr)?;
+                self.word_space(":")?;
+                self.print_type(&ty)?;
+            }
+            hir::ExprIf(ref test, ref blk, ref elseopt) => {
+                self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e))?;
+            }
+            hir::ExprWhile(ref test, ref blk, opt_ident) => {
+                if let Some(ident) = opt_ident {
+                    self.print_name(ident.name)?;
+                    self.word_space(":")?;
+                }
+                self.head("while")?;
+                self.print_expr(&test)?;
+                space(&mut self.s)?;
+                self.print_block(&blk)?;
+            }
+            hir::ExprLoop(ref blk, opt_ident) => {
+                if let Some(ident) = opt_ident {
+                    self.print_name(ident.name)?;
+                    self.word_space(":")?;
+                }
+                self.head("loop")?;
+                space(&mut self.s)?;
+                self.print_block(&blk)?;
+            }
+            hir::ExprMatch(ref expr, ref arms, _) => {
+                self.cbox(indent_unit)?;
+                self.ibox(4)?;
+                self.word_nbsp("match")?;
+                self.print_expr(&expr)?;
+                space(&mut self.s)?;
+                self.bopen()?;
+                for arm in arms {
+                    self.print_arm(arm)?;
+                }
+                self.bclose_(expr.span, indent_unit)?;
+            }
+            hir::ExprClosure(capture_clause, ref decl, ref body) => {
+                self.print_capture_clause(capture_clause)?;
+
+                self.print_fn_block_args(&decl)?;
+                space(&mut self.s)?;
+
+                let default_return = match decl.output {
+                    hir::DefaultReturn(..) => true,
+                    _ => false,
+                };
+
+                if !default_return || !body.stmts.is_empty() || body.expr.is_none() {
+                    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 {
+                        hir::ExprBlock(ref blk) => {
+                            self.print_block_unclosed(&blk)?;
+                        }
+                        _ => {
+                            // this is a bare expression
+                            self.print_expr(body.expr.as_ref().map(|e| &**e).unwrap())?;
+                            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.
+                self.ibox(0)?;
+            }
+            hir::ExprBlock(ref blk) => {
+                // containing cbox, will be closed by print-block at }
+                self.cbox(indent_unit)?;
+                // head-box, will be closed by print-block after {
+                self.ibox(0)?;
+                self.print_block(&blk)?;
+            }
+            hir::ExprAssign(ref lhs, ref rhs) => {
+                self.print_expr(&lhs)?;
+                space(&mut self.s)?;
+                self.word_space("=")?;
+                self.print_expr(&rhs)?;
+            }
+            hir::ExprAssignOp(op, ref lhs, ref rhs) => {
+                self.print_expr(&lhs)?;
+                space(&mut self.s)?;
+                word(&mut self.s, op.node.as_str())?;
+                self.word_space("=")?;
+                self.print_expr(&rhs)?;
+            }
+            hir::ExprField(ref expr, name) => {
+                self.print_expr(&expr)?;
+                word(&mut self.s, ".")?;
+                self.print_name(name.node)?;
+            }
+            hir::ExprTupField(ref expr, id) => {
+                self.print_expr(&expr)?;
+                word(&mut self.s, ".")?;
+                self.print_usize(id.node)?;
+            }
+            hir::ExprIndex(ref expr, ref index) => {
+                self.print_expr(&expr)?;
+                word(&mut self.s, "[")?;
+                self.print_expr(&index)?;
+                word(&mut self.s, "]")?;
+            }
+            hir::ExprPath(None, ref path) => {
+                self.print_path(path, true, 0)?
+            }
+            hir::ExprPath(Some(ref qself), ref path) => {
+                self.print_qpath(path, qself, true)?
+            }
+            hir::ExprBreak(opt_ident) => {
+                word(&mut self.s, "break")?;
+                space(&mut self.s)?;
+                if let Some(ident) = opt_ident {
+                    self.print_name(ident.node.name)?;
+                    space(&mut self.s)?;
+                }
+            }
+            hir::ExprAgain(opt_ident) => {
+                word(&mut self.s, "continue")?;
+                space(&mut self.s)?;
+                if let Some(ident) = opt_ident {
+                    self.print_name(ident.node.name)?;
+                    space(&mut self.s)?
+                }
+            }
+            hir::ExprRet(ref result) => {
+                word(&mut self.s, "return")?;
+                match *result {
+                    Some(ref expr) => {
+                        word(&mut self.s, " ")?;
+                        self.print_expr(&expr)?;
+                    }
+                    _ => (),
+                }
+            }
+            hir::ExprInlineAsm(ref a, ref outputs, ref inputs) => {
+                word(&mut self.s, "asm!")?;
+                self.popen()?;
+                self.print_string(&a.asm, a.asm_str_style)?;
+                self.word_space(":")?;
+
+                let mut out_idx = 0;
+                self.commasep(Inconsistent, &a.outputs, |s, out| {
+                    match out.constraint.slice_shift_char() {
+                        Some(('=', operand)) if out.is_rw => {
+                            s.print_string(&format!("+{}", operand), ast::StrStyle::Cooked)?
+                        }
+                        _ => s.print_string(&out.constraint, ast::StrStyle::Cooked)?,
+                    }
+                    s.popen()?;
+                    s.print_expr(&outputs[out_idx])?;
+                    s.pclose()?;
+                    out_idx += 1;
+                    Ok(())
+                })?;
+                space(&mut self.s)?;
+                self.word_space(":")?;
+
+                let mut in_idx = 0;
+                self.commasep(Inconsistent, &a.inputs, |s, co| {
+                    s.print_string(&co, ast::StrStyle::Cooked)?;
+                    s.popen()?;
+                    s.print_expr(&inputs[in_idx])?;
+                    s.pclose()?;
+                    in_idx += 1;
+                    Ok(())
+                })?;
+                space(&mut self.s)?;
+                self.word_space(":")?;
+
+                self.commasep(Inconsistent, &a.clobbers, |s, co| {
+                    s.print_string(&co, ast::StrStyle::Cooked)?;
+                    Ok(())
+                })?;
+
+                let mut options = vec![];
+                if a.volatile {
+                    options.push("volatile");
+                }
+                if a.alignstack {
+                    options.push("alignstack");
+                }
+                if a.dialect == ast::AsmDialect::Intel {
+                    options.push("intel");
+                }
+
+                if !options.is_empty() {
+                    space(&mut self.s)?;
+                    self.word_space(":")?;
+                    self.commasep(Inconsistent, &options, |s, &co| {
+                        s.print_string(co, ast::StrStyle::Cooked)?;
+                        Ok(())
+                    })?;
+                }
+
+                self.pclose()?;
+            }
+        }
+        self.ann.post(self, NodeExpr(expr))?;
+        self.end()
+    }
+
+    pub fn print_local_decl(&mut self, loc: &hir::Local) -> io::Result<()> {
+        self.print_pat(&loc.pat)?;
+        if let Some(ref ty) = loc.ty {
+            self.word_space(":")?;
+            self.print_type(&ty)?;
+        }
+        Ok(())
+    }
+
+    pub fn print_decl(&mut self, decl: &hir::Decl) -> io::Result<()> {
+        self.maybe_print_comment(decl.span.lo)?;
+        match decl.node {
+            hir::DeclLocal(ref loc) => {
+                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.end()
+            }
+            hir::DeclItem(ref item) => {
+                self.print_item_id(item)
+            }
+        }
+    }
+
+    pub fn print_usize(&mut self, i: usize) -> io::Result<()> {
+        word(&mut self.s, &i.to_string())
+    }
+
+    pub fn print_name(&mut self, name: ast::Name) -> io::Result<()> {
+        word(&mut self.s, &name.as_str())?;
+        self.ann.post(self, NodeName(&name))
+    }
+
+    pub fn print_for_decl(&mut self, loc: &hir::Local, coll: &hir::Expr) -> io::Result<()> {
+        self.print_local_decl(loc)?;
+        space(&mut self.s)?;
+        self.word_space("in")?;
+        self.print_expr(coll)
+    }
+
+    fn print_path(&mut self,
+                  path: &hir::Path,
+                  colons_before_params: bool,
+                  depth: usize)
+                  -> io::Result<()> {
+        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 {
+                word(&mut self.s, "::")?
+            }
+
+            self.print_name(segment.identifier.name)?;
+
+            self.print_path_parameters(&segment.parameters, colons_before_params)?;
+        }
+
+        Ok(())
+    }
+
+    fn print_qpath(&mut self,
+                   path: &hir::Path,
+                   qself: &hir::QSelf,
+                   colons_before_params: bool)
+                   -> io::Result<()> {
+        word(&mut self.s, "<")?;
+        self.print_type(&qself.ty)?;
+        if qself.position > 0 {
+            space(&mut self.s)?;
+            self.word_space("as")?;
+            let depth = path.segments.len() - qself.position;
+            self.print_path(&path, false, depth)?;
+        }
+        word(&mut self.s, ">")?;
+        word(&mut self.s, "::")?;
+        let item_segment = path.segments.last().unwrap();
+        self.print_name(item_segment.identifier.name)?;
+        self.print_path_parameters(&item_segment.parameters, colons_before_params)
+    }
+
+    fn print_path_parameters(&mut self,
+                             parameters: &hir::PathParameters,
+                             colons_before_params: bool)
+                             -> io::Result<()> {
+        if parameters.is_empty() {
+            return Ok(());
+        }
+
+        if colons_before_params {
+            word(&mut self.s, "::")?
+        }
+
+        match *parameters {
+            hir::AngleBracketedParameters(ref data) => {
+                word(&mut self.s, "<")?;
+
+                let mut comma = false;
+                for lifetime in &data.lifetimes {
+                    if comma {
+                        self.word_space(",")?
+                    }
+                    self.print_lifetime(lifetime)?;
+                    comma = true;
+                }
+
+                if !data.types.is_empty() {
+                    if comma {
+                        self.word_space(",")?
+                    }
+                    self.commasep(Inconsistent, &data.types, |s, ty| s.print_type(&ty))?;
+                    comma = true;
+                }
+
+                for binding in data.bindings.iter() {
+                    if comma {
+                        self.word_space(",")?
+                    }
+                    self.print_name(binding.name)?;
+                    space(&mut self.s)?;
+                    self.word_space("=")?;
+                    self.print_type(&binding.ty)?;
+                    comma = true;
+                }
+
+                word(&mut self.s, ">")?
+            }
+
+            hir::ParenthesizedParameters(ref data) => {
+                word(&mut self.s, "(")?;
+                self.commasep(Inconsistent, &data.inputs, |s, ty| s.print_type(&ty))?;
+                word(&mut self.s, ")")?;
+
+                match data.output {
+                    None => {}
+                    Some(ref ty) => {
+                        self.space_if_not_bol()?;
+                        self.word_space("->")?;
+                        self.print_type(&ty)?;
+                    }
+                }
+            }
+        }
+
+        Ok(())
+    }
+
+    pub fn print_pat(&mut self, pat: &hir::Pat) -> io::Result<()> {
+        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 {
+            PatKind::Wild => word(&mut self.s, "_")?,
+            PatKind::Ident(binding_mode, ref path1, ref sub) => {
+                match binding_mode {
+                    hir::BindByRef(mutbl) => {
+                        self.word_nbsp("ref")?;
+                        self.print_mutability(mutbl)?;
+                    }
+                    hir::BindByValue(hir::MutImmutable) => {}
+                    hir::BindByValue(hir::MutMutable) => {
+                        self.word_nbsp("mut")?;
+                    }
+                }
+                self.print_name(path1.node.name)?;
+                match *sub {
+                    Some(ref p) => {
+                        word(&mut self.s, "@")?;
+                        self.print_pat(&p)?;
+                    }
+                    None => (),
+                }
+            }
+            PatKind::TupleStruct(ref path, ref args_) => {
+                self.print_path(path, true, 0)?;
+                match *args_ {
+                    None => word(&mut self.s, "(..)")?,
+                    Some(ref args) => {
+                        self.popen()?;
+                        self.commasep(Inconsistent, &args[..], |s, p| s.print_pat(&p))?;
+                        self.pclose()?;
+                    }
+                }
+            }
+            PatKind::Path(ref path) => {
+                self.print_path(path, true, 0)?;
+            }
+            PatKind::QPath(ref qself, ref path) => {
+                self.print_qpath(path, qself, false)?;
+            }
+            PatKind::Struct(ref path, ref fields, etc) => {
+                self.print_path(path, true, 0)?;
+                self.nbsp()?;
+                self.word_space("{")?;
+                self.commasep_cmnt(Consistent,
+                                   &fields[..],
+                                   |s, f| {
+                                       s.cbox(indent_unit)?;
+                                       if !f.node.is_shorthand {
+                                           s.print_name(f.node.name)?;
+                                           s.word_nbsp(":")?;
+                                       }
+                                       s.print_pat(&f.node.pat)?;
+                                       s.end()
+                                   },
+                                   |f| f.node.pat.span)?;
+                if etc {
+                    if !fields.is_empty() {
+                        self.word_space(",")?;
+                    }
+                    word(&mut self.s, "..")?;
+                }
+                space(&mut self.s)?;
+                word(&mut self.s, "}")?;
+            }
+            PatKind::Tup(ref elts) => {
+                self.popen()?;
+                self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?;
+                if elts.len() == 1 {
+                    word(&mut self.s, ",")?;
+                }
+                self.pclose()?;
+            }
+            PatKind::Box(ref inner) => {
+                word(&mut self.s, "box ")?;
+                self.print_pat(&inner)?;
+            }
+            PatKind::Ref(ref inner, mutbl) => {
+                word(&mut self.s, "&")?;
+                if mutbl == hir::MutMutable {
+                    word(&mut self.s, "mut ")?;
+                }
+                self.print_pat(&inner)?;
+            }
+            PatKind::Lit(ref e) => self.print_expr(&e)?,
+            PatKind::Range(ref begin, ref end) => {
+                self.print_expr(&begin)?;
+                space(&mut self.s)?;
+                word(&mut self.s, "...")?;
+                self.print_expr(&end)?;
+            }
+            PatKind::Vec(ref before, ref slice, ref after) => {
+                word(&mut self.s, "[")?;
+                self.commasep(Inconsistent, &before[..], |s, p| s.print_pat(&p))?;
+                if let Some(ref p) = *slice {
+                    if !before.is_empty() {
+                        self.word_space(",")?;
+                    }
+                    if p.node != PatKind::Wild {
+                        self.print_pat(&p)?;
+                    }
+                    word(&mut self.s, "..")?;
+                    if !after.is_empty() {
+                        self.word_space(",")?;
+                    }
+                }
+                self.commasep(Inconsistent, &after[..], |s, p| s.print_pat(&p))?;
+                word(&mut self.s, "]")?;
+            }
+        }
+        self.ann.post(self, NodePat(pat))
+    }
+
+    fn print_arm(&mut self, arm: &hir::Arm) -> io::Result<()> {
+        // I have no idea why this check is necessary, but here it
+        // is :(
+        if arm.attrs.is_empty() {
+            space(&mut self.s)?;
+        }
+        self.cbox(indent_unit)?;
+        self.ibox(0)?;
+        self.print_outer_attributes(&arm.attrs)?;
+        let mut first = true;
+        for p in &arm.pats {
+            if first {
+                first = false;
+            } else {
+                space(&mut self.s)?;
+                self.word_space("|")?;
+            }
+            self.print_pat(&p)?;
+        }
+        space(&mut self.s)?;
+        if let Some(ref e) = arm.guard {
+            self.word_space("if")?;
+            self.print_expr(&e)?;
+            space(&mut self.s)?;
+        }
+        self.word_space("=>")?;
+
+        match arm.body.node {
+            hir::ExprBlock(ref blk) => {
+                // the block will close the pattern's ibox
+                self.print_block_unclosed_indent(&blk, indent_unit)?;
+
+                // If it is a user-provided unsafe block, print a comma after it
+                if let hir::UnsafeBlock(hir::UserProvided) = blk.rules {
+                    word(&mut self.s, ",")?;
+                }
+            }
+            _ => {
+                self.end()?; // close the ibox for the pattern
+                self.print_expr(&arm.body)?;
+                word(&mut self.s, ",")?;
+            }
+        }
+        self.end() // close enclosing cbox
+    }
+
+    // Returns whether it printed anything
+    fn print_explicit_self(&mut self,
+                           explicit_self: &hir::ExplicitSelf_,
+                           mutbl: hir::Mutability)
+                           -> io::Result<bool> {
+        self.print_mutability(mutbl)?;
+        match *explicit_self {
+            hir::SelfStatic => {
+                return Ok(false);
+            }
+            hir::SelfValue(_) => {
+                word(&mut self.s, "self")?;
+            }
+            hir::SelfRegion(ref lt, m, _) => {
+                word(&mut self.s, "&")?;
+                self.print_opt_lifetime(lt)?;
+                self.print_mutability(m)?;
+                word(&mut self.s, "self")?;
+            }
+            hir::SelfExplicit(ref typ, _) => {
+                word(&mut self.s, "self")?;
+                self.word_space(":")?;
+                self.print_type(&typ)?;
+            }
+        }
+        return Ok(true);
+    }
+
+    pub fn print_fn(&mut self,
+                    decl: &hir::FnDecl,
+                    unsafety: hir::Unsafety,
+                    constness: hir::Constness,
+                    abi: Abi,
+                    name: Option<ast::Name>,
+                    generics: &hir::Generics,
+                    opt_explicit_self: Option<&hir::ExplicitSelf_>,
+                    vis: hir::Visibility)
+                    -> io::Result<()> {
+        self.print_fn_header_info(unsafety, constness, abi, vis)?;
+
+        if let Some(name) = name {
+            self.nbsp()?;
+            self.print_name(name)?;
+        }
+        self.print_generics(generics)?;
+        self.print_fn_args_and_ret(decl, opt_explicit_self)?;
+        self.print_where_clause(&generics.where_clause)
+    }
+
+    pub fn print_fn_args(&mut self,
+                         decl: &hir::FnDecl,
+                         opt_explicit_self: Option<&hir::ExplicitSelf_>,
+                         is_closure: bool)
+                         -> io::Result<()> {
+        // It is unfortunate to duplicate the commasep logic, but we want the
+        // self type and the args all in the same box.
+        self.rbox(0, Inconsistent)?;
+        let mut first = true;
+        if let Some(explicit_self) = opt_explicit_self {
+            let m = match explicit_self {
+                &hir::SelfStatic => hir::MutImmutable,
+                _ => match decl.inputs[0].pat.node {
+                    PatKind::Ident(hir::BindByValue(m), _, _) => m,
+                    _ => hir::MutImmutable,
+                },
+            };
+            first = !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 {
+                self.word_space(",")?;
+            }
+            self.print_arg(arg, is_closure)?;
+        }
+
+        self.end()
+    }
+
+    pub fn print_fn_args_and_ret(&mut self,
+                                 decl: &hir::FnDecl,
+                                 opt_explicit_self: Option<&hir::ExplicitSelf_>)
+                                 -> io::Result<()> {
+        self.popen()?;
+        self.print_fn_args(decl, opt_explicit_self, false)?;
+        if decl.variadic {
+            word(&mut self.s, ", ...")?;
+        }
+        self.pclose()?;
+
+        self.print_fn_output(decl)
+    }
+
+    pub fn print_fn_block_args(&mut self, decl: &hir::FnDecl) -> io::Result<()> {
+        word(&mut self.s, "|")?;
+        self.print_fn_args(decl, None, true)?;
+        word(&mut self.s, "|")?;
+
+        if let hir::DefaultReturn(..) = decl.output {
+            return Ok(());
+        }
+
+        self.space_if_not_bol()?;
+        self.word_space("->")?;
+        match decl.output {
+            hir::Return(ref ty) => {
+                self.print_type(&ty)?;
+                self.maybe_print_comment(ty.span.lo)
+            }
+            hir::DefaultReturn(..) => unreachable!(),
+            hir::NoReturn(span) => {
+                self.word_nbsp("!")?;
+                self.maybe_print_comment(span.lo)
+            }
+        }
+    }
+
+    pub fn print_capture_clause(&mut self, capture_clause: hir::CaptureClause) -> io::Result<()> {
+        match capture_clause {
+            hir::CaptureByValue => self.word_space("move"),
+            hir::CaptureByRef => Ok(()),
+        }
+    }
+
+    pub fn print_bounds(&mut self, prefix: &str, bounds: &[hir::TyParamBound]) -> io::Result<()> {
+        if !bounds.is_empty() {
+            word(&mut self.s, prefix)?;
+            let mut first = true;
+            for bound in bounds {
+                self.nbsp()?;
+                if first {
+                    first = false;
+                } else {
+                    self.word_space("+")?;
+                }
+
+                match *bound {
+                    TraitTyParamBound(ref tref, TraitBoundModifier::None) => {
+                        self.print_poly_trait_ref(tref)
+                    }
+                    TraitTyParamBound(ref tref, TraitBoundModifier::Maybe) => {
+                        word(&mut self.s, "?")?;
+                        self.print_poly_trait_ref(tref)
+                    }
+                    RegionTyParamBound(ref lt) => {
+                        self.print_lifetime(lt)
+                    }
+                }?
+            }
+            Ok(())
+        } else {
+            Ok(())
+        }
+    }
+
+    pub fn print_lifetime(&mut self, lifetime: &hir::Lifetime) -> io::Result<()> {
+        self.print_name(lifetime.name)
+    }
+
+    pub fn print_lifetime_def(&mut self, lifetime: &hir::LifetimeDef) -> io::Result<()> {
+        self.print_lifetime(&lifetime.lifetime)?;
+        let mut sep = ":";
+        for v in &lifetime.bounds {
+            word(&mut self.s, sep)?;
+            self.print_lifetime(v)?;
+            sep = "+";
+        }
+        Ok(())
+    }
+
+    pub fn print_generics(&mut self, generics: &hir::Generics) -> io::Result<()> {
+        let total = generics.lifetimes.len() + generics.ty_params.len();
+        if total == 0 {
+            return Ok(());
+        }
+
+        word(&mut self.s, "<")?;
+
+        let mut ints = Vec::new();
+        for i in 0..total {
+            ints.push(i);
+        }
+
+        self.commasep(Inconsistent, &ints[..], |s, &idx| {
+            if idx < generics.lifetimes.len() {
+                let lifetime = &generics.lifetimes[idx];
+                s.print_lifetime_def(lifetime)
+            } else {
+                let idx = idx - generics.lifetimes.len();
+                let param = &generics.ty_params[idx];
+                s.print_ty_param(param)
+            }
+        })?;
+
+        word(&mut self.s, ">")?;
+        Ok(())
+    }
+
+    pub fn print_ty_param(&mut self, param: &hir::TyParam) -> io::Result<()> {
+        self.print_name(param.name)?;
+        self.print_bounds(":", &param.bounds)?;
+        match param.default {
+            Some(ref default) => {
+                space(&mut self.s)?;
+                self.word_space("=")?;
+                self.print_type(&default)
+            }
+            _ => Ok(()),
+        }
+    }
+
+    pub fn print_where_clause(&mut self, where_clause: &hir::WhereClause) -> io::Result<()> {
+        if where_clause.predicates.is_empty() {
+            return Ok(());
+        }
+
+        space(&mut self.s)?;
+        self.word_space("where")?;
+
+        for (i, predicate) in where_clause.predicates.iter().enumerate() {
+            if i != 0 {
+                self.word_space(",")?;
+            }
+
+            match predicate {
+                &hir::WherePredicate::BoundPredicate(hir::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)?;
+                }
+                &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate{ref lifetime,
+                                                                                ref bounds,
+                                                                                ..}) => {
+                    self.print_lifetime(lifetime)?;
+                    word(&mut self.s, ":")?;
+
+                    for (i, bound) in bounds.iter().enumerate() {
+                        self.print_lifetime(bound)?;
+
+                        if i != 0 {
+                            word(&mut self.s, ":")?;
+                        }
+                    }
+                }
+                &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate{ref path, ref ty, ..}) => {
+                    self.print_path(path, false, 0)?;
+                    space(&mut self.s)?;
+                    self.word_space("=")?;
+                    self.print_type(&ty)?;
+                }
+            }
+        }
+
+        Ok(())
+    }
+
+    pub fn print_view_path(&mut self, vp: &hir::ViewPath) -> io::Result<()> {
+        match vp.node {
+            hir::ViewPathSimple(name, ref path) => {
+                self.print_path(path, false, 0)?;
+
+                if path.segments.last().unwrap().identifier.name != name {
+                    space(&mut self.s)?;
+                    self.word_space("as")?;
+                    self.print_name(name)?;
+                }
+
+                Ok(())
+            }
+
+            hir::ViewPathGlob(ref path) => {
+                self.print_path(path, false, 0)?;
+                word(&mut self.s, "::*")
+            }
+
+            hir::ViewPathList(ref path, ref segments) => {
+                if path.segments.is_empty() {
+                    word(&mut self.s, "{")?;
+                } else {
+                    self.print_path(path, false, 0)?;
+                    word(&mut self.s, "::{")?;
+                }
+                self.commasep(Inconsistent, &segments[..], |s, w| {
+                    match w.node {
+                        hir::PathListIdent { name, .. } => {
+                            s.print_name(name)
+                        }
+                        hir::PathListMod { .. } => {
+                            word(&mut s.s, "self")
+                        }
+                    }
+                })?;
+                word(&mut self.s, "}")
+            }
+        }
+    }
+
+    pub fn print_mutability(&mut self, mutbl: hir::Mutability) -> io::Result<()> {
+        match mutbl {
+            hir::MutMutable => self.word_nbsp("mut"),
+            hir::MutImmutable => Ok(()),
+        }
+    }
+
+    pub fn print_mt(&mut self, mt: &hir::MutTy) -> io::Result<()> {
+        self.print_mutability(mt.mutbl)?;
+        self.print_type(&mt.ty)
+    }
+
+    pub fn print_arg(&mut self, input: &hir::Arg, is_closure: bool) -> io::Result<()> {
+        self.ibox(indent_unit)?;
+        match input.ty.node {
+            hir::TyInfer if is_closure => self.print_pat(&input.pat)?,
+            _ => {
+                match input.pat.node {
+                    PatKind::Ident(_, ref path1, _) if
+                        path1.node.name ==
+                            parse::token::special_idents::invalid.name => {
+                        // Do nothing.
+                    }
+                    _ => {
+                        self.print_pat(&input.pat)?;
+                        word(&mut self.s, ":")?;
+                        space(&mut self.s)?;
+                    }
+                }
+                self.print_type(&input.ty)?;
+            }
+        }
+        self.end()
+    }
+
+    pub fn print_fn_output(&mut self, decl: &hir::FnDecl) -> io::Result<()> {
+        if let hir::DefaultReturn(..) = decl.output {
+            return Ok(());
+        }
+
+        self.space_if_not_bol()?;
+        self.ibox(indent_unit)?;
+        self.word_space("->")?;
+        match decl.output {
+            hir::NoReturn(_) => self.word_nbsp("!")?,
+            hir::DefaultReturn(..) => unreachable!(),
+            hir::Return(ref ty) => self.print_type(&ty)?,
+        }
+        self.end()?;
+
+        match decl.output {
+            hir::Return(ref output) => self.maybe_print_comment(output.span.lo),
+            _ => Ok(()),
+        }
+    }
+
+    pub fn print_ty_fn(&mut self,
+                       abi: Abi,
+                       unsafety: hir::Unsafety,
+                       decl: &hir::FnDecl,
+                       name: Option<ast::Name>,
+                       generics: &hir::Generics,
+                       opt_explicit_self: Option<&hir::ExplicitSelf_>)
+                       -> io::Result<()> {
+        self.ibox(indent_unit)?;
+        if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() {
+            word(&mut self.s, "for")?;
+            self.print_generics(generics)?;
+        }
+        let generics = hir::Generics {
+            lifetimes: hir::HirVec::new(),
+            ty_params: hir::HirVec::new(),
+            where_clause: hir::WhereClause {
+                id: ast::DUMMY_NODE_ID,
+                predicates: hir::HirVec::new(),
+            },
+        };
+        self.print_fn(decl,
+                      unsafety,
+                      hir::Constness::NotConst,
+                      abi,
+                      name,
+                      &generics,
+                      opt_explicit_self,
+                      hir::Inherited)?;
+        self.end()
+    }
+
+    pub fn maybe_print_trailing_comment(&mut self,
+                                        span: codemap::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 {
+                    self.print_comment(cmnt)?;
+                    self.cur_cmnt_and_lit.cur_cmnt += 1;
+                }
+            }
+            _ => (),
+        }
+        Ok(())
+    }
+
+    pub fn print_remaining_comments(&mut self) -> io::Result<()> {
+        // 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() {
+            hardbreak(&mut self.s)?;
+        }
+        loop {
+            match self.next_comment() {
+                Some(ref cmnt) => {
+                    self.print_comment(cmnt)?;
+                    self.cur_cmnt_and_lit.cur_cmnt += 1;
+                }
+                _ => break,
+            }
+        }
+        Ok(())
+    }
+
+    pub fn print_opt_abi_and_extern_if_nondefault(&mut self,
+                                                  opt_abi: Option<Abi>)
+                                                  -> io::Result<()> {
+        match opt_abi {
+            Some(Abi::Rust) => Ok(()),
+            Some(abi) => {
+                self.word_nbsp("extern")?;
+                self.word_nbsp(&abi.to_string())
+            }
+            None => Ok(()),
+        }
+    }
+
+    pub fn print_extern_opt_abi(&mut self, opt_abi: Option<Abi>) -> io::Result<()> {
+        match opt_abi {
+            Some(abi) => {
+                self.word_nbsp("extern")?;
+                self.word_nbsp(&abi.to_string())
+            }
+            None => Ok(()),
+        }
+    }
+
+    pub fn print_fn_header_info(&mut self,
+                                unsafety: hir::Unsafety,
+                                constness: hir::Constness,
+                                abi: Abi,
+                                vis: hir::Visibility)
+                                -> io::Result<()> {
+        word(&mut self.s, &visibility_qualified(vis, ""))?;
+        self.print_unsafety(unsafety)?;
+
+        match constness {
+            hir::Constness::NotConst => {}
+            hir::Constness::Const => self.word_nbsp("const")?,
+        }
+
+        if abi != Abi::Rust {
+            self.word_nbsp("extern")?;
+            self.word_nbsp(&abi.to_string())?;
+        }
+
+        word(&mut self.s, "fn")
+    }
+
+    pub fn print_unsafety(&mut self, s: hir::Unsafety) -> io::Result<()> {
+        match s {
+            hir::Unsafety::Normal => Ok(()),
+            hir::Unsafety::Unsafe => self.word_nbsp("unsafe"),
+        }
+    }
+}
+
+// Dup'ed from parse::classify, but adapted for the HIR.
+/// Does this expression require a semicolon to be treated
+/// as a statement? The negation of this: 'can this expression
+/// be used as a statement without a semicolon' -- is used
+/// as an early-bail-out in the parser so that, for instance,
+///     if true {...} else {...}
+///      |x| 5
+/// isn't parsed as (if true {...} else {...} | x) | 5
+fn expr_requires_semi_to_be_stmt(e: &hir::Expr) -> bool {
+    match e.node {
+        hir::ExprIf(..) |
+        hir::ExprMatch(..) |
+        hir::ExprBlock(_) |
+        hir::ExprWhile(..) |
+        hir::ExprLoop(..) => false,
+        _ => true,
+    }
+}
+
+/// this statement requires a semicolon after it.
+/// note that in one case (stmt_semi), we've already
+/// seen the semicolon, and thus don't need another.
+fn stmt_ends_with_semi(stmt: &hir::Stmt_) -> bool {
+    match *stmt {
+        hir::StmtDecl(ref d, _) => {
+            match d.node {
+                hir::DeclLocal(_) => true,
+                hir::DeclItem(_) => false,
+            }
+        }
+        hir::StmtExpr(ref e, _) => {
+            expr_requires_semi_to_be_stmt(&e)
+        }
+        hir::StmtSemi(..) => {
+            false
+        }
+    }
+}
diff --git a/src/librustc/hir/svh.rs b/src/librustc/hir/svh.rs
new file mode 100644
index 00000000000..7ae20f68ad0
--- /dev/null
+++ b/src/librustc/hir/svh.rs
@@ -0,0 +1,439 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Calculation and management of a Strict Version Hash for crates
+//!
+//! # Today's ABI problem
+//!
+//! In today's implementation of rustc, it is incredibly difficult to achieve
+//! forward binary compatibility without resorting to C-like interfaces. Within
+//! rust code itself, abi details such as symbol names suffer from a variety of
+//! unrelated factors to code changing such as the "def id drift" problem. This
+//! ends up yielding confusing error messages about metadata mismatches and
+//! such.
+//!
+//! The core of this problem is when an upstream dependency changes and
+//! downstream dependents are not recompiled. This causes compile errors because
+//! the upstream crate's metadata has changed but the downstream crates are
+//! still referencing the older crate's metadata.
+//!
+//! This problem exists for many reasons, the primary of which is that rust does
+//! not currently support forwards ABI compatibility (in place upgrades of a
+//! crate).
+//!
+//! # SVH and how it alleviates the problem
+//!
+//! With all of this knowledge on hand, this module contains the implementation
+//! of a notion of a "Strict Version Hash" for a crate. This is essentially a
+//! hash of all contents of a crate which can somehow be exposed to downstream
+//! crates.
+//!
+//! This hash is currently calculated by just hashing the AST, but this is
+//! obviously wrong (doc changes should not result in an incompatible ABI).
+//! Implementation-wise, this is required at this moment in time.
+//!
+//! By encoding this strict version hash into all crate's metadata, stale crates
+//! can be detected immediately and error'd about by rustc itself.
+//!
+//! # Relevant links
+//!
+//! Original issue: https://github.com/rust-lang/rust/issues/10207
+
+use std::fmt;
+use std::hash::{Hash, SipHasher, Hasher};
+use hir;
+use hir::intravisit as visit;
+
+#[derive(Clone, PartialEq, Debug)]
+pub struct Svh {
+    hash: String,
+}
+
+impl Svh {
+    pub fn new(hash: &str) -> Svh {
+        assert!(hash.len() == 16);
+        Svh { hash: hash.to_string() }
+    }
+
+    pub fn as_str<'a>(&'a self) -> &'a str {
+        &self.hash
+    }
+
+    pub fn calculate(crate_disambiguator: &str, krate: &hir::Crate) -> Svh {
+        // FIXME (#14132): This is better than it used to be, but it still not
+        // ideal. We now attempt to hash only the relevant portions of the
+        // Crate AST as well as the top-level crate attributes. (However,
+        // the hashing of the crate attributes should be double-checked
+        // to ensure it is not incorporating implementation artifacts into
+        // the hash that are not otherwise visible.)
+
+        // FIXME: this should use SHA1, not SipHash. SipHash is not built to
+        //        avoid collisions.
+        let mut state = SipHasher::new();
+
+        "crate_disambiguator".hash(&mut state);
+        crate_disambiguator.len().hash(&mut state);
+        crate_disambiguator.hash(&mut state);
+
+        {
+            let mut visit = svh_visitor::make(&mut state, krate);
+            visit::walk_crate(&mut visit, krate);
+        }
+
+        // FIXME (#14132): This hash is still sensitive to e.g. the
+        // spans of the crate Attributes and their underlying
+        // MetaItems; we should make ContentHashable impl for those
+        // types and then use hash_content.  But, since all crate
+        // attributes should appear near beginning of the file, it is
+        // not such a big deal to be sensitive to their spans for now.
+        //
+        // We hash only the MetaItems instead of the entire Attribute
+        // to avoid hashing the AttrId
+        for attr in &krate.attrs {
+            attr.node.value.hash(&mut state);
+        }
+
+        let hash = state.finish();
+        return Svh {
+            hash: (0..64).step_by(4).map(|i| hex(hash >> i)).collect()
+        };
+
+        fn hex(b: u64) -> char {
+            let b = (b & 0xf) as u8;
+            let b = match b {
+                0 ... 9 => '0' as u8 + b,
+                _ => 'a' as u8 + b - 10,
+            };
+            b as char
+        }
+    }
+}
+
+impl fmt::Display for Svh {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad(self.as_str())
+    }
+}
+
+// FIXME (#14132): Even this SVH computation still has implementation
+// artifacts: namely, the order of item declaration will affect the
+// hash computation, but for many kinds of items the order of
+// declaration should be irrelevant to the ABI.
+
+mod svh_visitor {
+    pub use self::SawExprComponent::*;
+    pub use self::SawStmtComponent::*;
+    use self::SawAbiComponent::*;
+    use syntax::ast::{self, Name, NodeId};
+    use syntax::codemap::Span;
+    use syntax::parse::token;
+    use hir::intravisit as visit;
+    use hir::intravisit::{Visitor, FnKind};
+    use hir::*;
+    use hir;
+
+    use std::hash::{Hash, SipHasher};
+
+    pub struct StrictVersionHashVisitor<'a> {
+        pub krate: &'a Crate,
+        pub st: &'a mut SipHasher,
+    }
+
+    pub fn make<'a>(st: &'a mut SipHasher, krate: &'a Crate) -> StrictVersionHashVisitor<'a> {
+        StrictVersionHashVisitor { st: st, krate: krate }
+    }
+
+    // To off-load the bulk of the hash-computation on #[derive(Hash)],
+    // we define a set of enums corresponding to the content that our
+    // crate visitor will encounter as it traverses the ast.
+    //
+    // The important invariant is that all of the Saw*Component enums
+    // do not carry any Spans, Names, or Idents.
+    //
+    // Not carrying any Names/Idents is the important fix for problem
+    // noted on PR #13948: using the ident.name as the basis for a
+    // hash leads to unstable SVH, because ident.name is just an index
+    // into intern table (i.e. essentially a random address), not
+    // computed from the name content.
+    //
+    // With the below enums, the SVH computation is not sensitive to
+    // artifacts of how rustc was invoked nor of how the source code
+    // was laid out.  (Or at least it is *less* sensitive.)
+
+    // This enum represents the different potential bits of code the
+    // visitor could encounter that could affect the ABI for the crate,
+    // and assigns each a distinct tag to feed into the hash computation.
+    #[derive(Hash)]
+    enum SawAbiComponent<'a> {
+
+        // FIXME (#14132): should we include (some function of)
+        // ident.ctxt as well?
+        SawIdent(token::InternedString),
+        SawStructDef(token::InternedString),
+
+        SawLifetime(token::InternedString),
+        SawLifetimeDef(token::InternedString),
+
+        SawMod,
+        SawForeignItem,
+        SawItem,
+        SawDecl,
+        SawTy,
+        SawGenerics,
+        SawFn,
+        SawTraitItem,
+        SawImplItem,
+        SawStructField,
+        SawVariant,
+        SawExplicitSelf,
+        SawPath,
+        SawBlock,
+        SawPat,
+        SawLocal,
+        SawArm,
+        SawExpr(SawExprComponent<'a>),
+        SawStmt(SawStmtComponent),
+    }
+
+    /// SawExprComponent carries all of the information that we want
+    /// to include in the hash that *won't* be covered by the
+    /// subsequent recursive traversal of the expression's
+    /// substructure by the visitor.
+    ///
+    /// We know every Expr_ variant is covered by a variant because
+    /// `fn saw_expr` maps each to some case below.  Ensuring that
+    /// each variant carries an appropriate payload has to be verified
+    /// by hand.
+    ///
+    /// (However, getting that *exactly* right is not so important
+    /// because the SVH is just a developer convenience; there is no
+    /// guarantee of collision-freedom, hash collisions are just
+    /// (hopefully) unlikely.)
+    #[derive(Hash)]
+    pub enum SawExprComponent<'a> {
+
+        SawExprLoop(Option<token::InternedString>),
+        SawExprField(token::InternedString),
+        SawExprTupField(usize),
+        SawExprBreak(Option<token::InternedString>),
+        SawExprAgain(Option<token::InternedString>),
+
+        SawExprBox,
+        SawExprVec,
+        SawExprCall,
+        SawExprMethodCall,
+        SawExprTup,
+        SawExprBinary(hir::BinOp_),
+        SawExprUnary(hir::UnOp),
+        SawExprLit(ast::LitKind),
+        SawExprCast,
+        SawExprType,
+        SawExprIf,
+        SawExprWhile,
+        SawExprMatch,
+        SawExprClosure,
+        SawExprBlock,
+        SawExprAssign,
+        SawExprAssignOp(hir::BinOp_),
+        SawExprIndex,
+        SawExprPath(Option<usize>),
+        SawExprAddrOf(hir::Mutability),
+        SawExprRet,
+        SawExprInlineAsm(&'a hir::InlineAsm),
+        SawExprStruct,
+        SawExprRepeat,
+    }
+
+    fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> {
+        match *node {
+            ExprBox(..)              => SawExprBox,
+            ExprVec(..)              => SawExprVec,
+            ExprCall(..)             => SawExprCall,
+            ExprMethodCall(..)       => SawExprMethodCall,
+            ExprTup(..)              => SawExprTup,
+            ExprBinary(op, _, _)     => SawExprBinary(op.node),
+            ExprUnary(op, _)         => SawExprUnary(op),
+            ExprLit(ref lit)         => SawExprLit(lit.node.clone()),
+            ExprCast(..)             => SawExprCast,
+            ExprType(..)             => SawExprType,
+            ExprIf(..)               => SawExprIf,
+            ExprWhile(..)            => SawExprWhile,
+            ExprLoop(_, id)          => SawExprLoop(id.map(|id| id.name.as_str())),
+            ExprMatch(..)            => SawExprMatch,
+            ExprClosure(..)          => SawExprClosure,
+            ExprBlock(..)            => SawExprBlock,
+            ExprAssign(..)           => SawExprAssign,
+            ExprAssignOp(op, _, _)   => SawExprAssignOp(op.node),
+            ExprField(_, name)       => SawExprField(name.node.as_str()),
+            ExprTupField(_, id)      => SawExprTupField(id.node),
+            ExprIndex(..)            => SawExprIndex,
+            ExprPath(ref qself, _)   => SawExprPath(qself.as_ref().map(|q| q.position)),
+            ExprAddrOf(m, _)         => SawExprAddrOf(m),
+            ExprBreak(id)            => SawExprBreak(id.map(|id| id.node.name.as_str())),
+            ExprAgain(id)            => SawExprAgain(id.map(|id| id.node.name.as_str())),
+            ExprRet(..)              => SawExprRet,
+            ExprInlineAsm(ref a,_,_) => SawExprInlineAsm(a),
+            ExprStruct(..)           => SawExprStruct,
+            ExprRepeat(..)           => SawExprRepeat,
+        }
+    }
+
+    /// SawStmtComponent is analogous to SawExprComponent, but for statements.
+    #[derive(Hash)]
+    pub enum SawStmtComponent {
+        SawStmtDecl,
+        SawStmtExpr,
+        SawStmtSemi,
+    }
+
+    fn saw_stmt(node: &Stmt_) -> SawStmtComponent {
+        match *node {
+            StmtDecl(..) => SawStmtDecl,
+            StmtExpr(..) => SawStmtExpr,
+            StmtSemi(..) => SawStmtSemi,
+        }
+    }
+
+    impl<'a> Visitor<'a> for StrictVersionHashVisitor<'a> {
+        fn visit_nested_item(&mut self, item: ItemId) {
+            self.visit_item(self.krate.item(item.id))
+        }
+
+        fn visit_variant_data(&mut self, s: &'a VariantData, name: Name,
+                              g: &'a Generics, _: NodeId, _: Span) {
+            SawStructDef(name.as_str()).hash(self.st);
+            visit::walk_generics(self, g);
+            visit::walk_struct_def(self, s)
+        }
+
+        fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) {
+            SawVariant.hash(self.st);
+            // walk_variant does not call walk_generics, so do it here.
+            visit::walk_generics(self, g);
+            visit::walk_variant(self, v, g, item_id)
+        }
+
+        // All of the remaining methods just record (in the hash
+        // SipHasher) that the visitor saw that particular variant
+        // (with its payload), and continue walking as the default
+        // visitor would.
+        //
+        // Some of the implementations have some notes as to how one
+        // might try to make their SVH computation less discerning
+        // (e.g. by incorporating reachability analysis).  But
+        // currently all of their implementations are uniform and
+        // uninteresting.
+        //
+        // (If you edit a method such that it deviates from the
+        // pattern, please move that method up above this comment.)
+
+        fn visit_name(&mut self, _: Span, name: Name) {
+            SawIdent(name.as_str()).hash(self.st);
+        }
+
+        fn visit_lifetime(&mut self, l: &'a Lifetime) {
+            SawLifetime(l.name.as_str()).hash(self.st);
+        }
+
+        fn visit_lifetime_def(&mut self, l: &'a LifetimeDef) {
+            SawLifetimeDef(l.lifetime.name.as_str()).hash(self.st);
+        }
+
+        // We do recursively walk the bodies of functions/methods
+        // (rather than omitting their bodies from the hash) since
+        // monomorphization and cross-crate inlining generally implies
+        // that a change to a crate body will require downstream
+        // crates to be recompiled.
+        fn visit_expr(&mut self, ex: &'a Expr) {
+            SawExpr(saw_expr(&ex.node)).hash(self.st); visit::walk_expr(self, ex)
+        }
+
+        fn visit_stmt(&mut self, s: &'a Stmt) {
+            SawStmt(saw_stmt(&s.node)).hash(self.st); visit::walk_stmt(self, s)
+        }
+
+        fn visit_foreign_item(&mut self, i: &'a ForeignItem) {
+            // FIXME (#14132) ideally we would incorporate privacy (or
+            // perhaps reachability) somewhere here, so foreign items
+            // that do not leak into downstream crates would not be
+            // part of the ABI.
+            SawForeignItem.hash(self.st); visit::walk_foreign_item(self, i)
+        }
+
+        fn visit_item(&mut self, i: &'a Item) {
+            // FIXME (#14132) ideally would incorporate reachability
+            // analysis somewhere here, so items that never leak into
+            // downstream crates (e.g. via monomorphisation or
+            // inlining) would not be part of the ABI.
+            SawItem.hash(self.st); visit::walk_item(self, i)
+        }
+
+        fn visit_mod(&mut self, m: &'a Mod, _s: Span, _n: NodeId) {
+            SawMod.hash(self.st); visit::walk_mod(self, m)
+        }
+
+        fn visit_decl(&mut self, d: &'a Decl) {
+            SawDecl.hash(self.st); visit::walk_decl(self, d)
+        }
+
+        fn visit_ty(&mut self, t: &'a Ty) {
+            SawTy.hash(self.st); visit::walk_ty(self, t)
+        }
+
+        fn visit_generics(&mut self, g: &'a Generics) {
+            SawGenerics.hash(self.st); visit::walk_generics(self, g)
+        }
+
+        fn visit_fn(&mut self, fk: FnKind<'a>, fd: &'a FnDecl,
+                    b: &'a Block, s: Span, _: NodeId) {
+            SawFn.hash(self.st); visit::walk_fn(self, fk, fd, b, s)
+        }
+
+        fn visit_trait_item(&mut self, ti: &'a TraitItem) {
+            SawTraitItem.hash(self.st); visit::walk_trait_item(self, ti)
+        }
+
+        fn visit_impl_item(&mut self, ii: &'a ImplItem) {
+            SawImplItem.hash(self.st); visit::walk_impl_item(self, ii)
+        }
+
+        fn visit_struct_field(&mut self, s: &'a StructField) {
+            SawStructField.hash(self.st); visit::walk_struct_field(self, s)
+        }
+
+        fn visit_explicit_self(&mut self, es: &'a ExplicitSelf) {
+            SawExplicitSelf.hash(self.st); visit::walk_explicit_self(self, es)
+        }
+
+        fn visit_path(&mut self, path: &'a Path, _: ast::NodeId) {
+            SawPath.hash(self.st); visit::walk_path(self, path)
+        }
+
+        fn visit_path_list_item(&mut self, prefix: &'a Path, item: &'a PathListItem) {
+            SawPath.hash(self.st); visit::walk_path_list_item(self, prefix, item)
+        }
+
+        fn visit_block(&mut self, b: &'a Block) {
+            SawBlock.hash(self.st); visit::walk_block(self, b)
+        }
+
+        fn visit_pat(&mut self, p: &'a Pat) {
+            SawPat.hash(self.st); visit::walk_pat(self, p)
+        }
+
+        fn visit_local(&mut self, l: &'a Local) {
+            SawLocal.hash(self.st); visit::walk_local(self, l)
+        }
+
+        fn visit_arm(&mut self, a: &'a Arm) {
+            SawArm.hash(self.st); visit::walk_arm(self, a)
+        }
+    }
+}
diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index 8079a6d1bbc..a7553f4eb1f 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -73,13 +73,13 @@ use super::region_inference::SameRegions;
 
 use std::collections::HashSet;
 
-use front::map as ast_map;
-use rustc_front::hir;
-use rustc_front::print::pprust;
+use hir::map as ast_map;
+use hir;
+use hir::print as pprust;
 
 use middle::cstore::CrateStore;
-use middle::def::Def;
-use middle::def_id::DefId;
+use hir::def::Def;
+use hir::def_id::DefId;
 use infer::{self, TypeOrigin};
 use middle::region;
 use ty::subst;
@@ -587,13 +587,9 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
             // Only external crates, if either is from a local
             // module we could have false positives
             if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate {
-                let exp_path = self.tcx.with_path(did1,
-                                                  |p| p.map(|x| x.to_string())
-                                                       .collect::<Vec<_>>());
-                let found_path = self.tcx.with_path(did2,
-                                                    |p| p.map(|x| x.to_string())
-                                                         .collect::<Vec<_>>());
-                // We compare strings because PathMod and PathName can be different
+                let exp_path = self.tcx.item_path_str(did1);
+                let found_path = self.tcx.item_path_str(did2);
+                // We compare strings because DefPath can be different
                 // for imported and non-imported crates
                 if exp_path == found_path {
                     let crate_name = self.tcx.sess.cstore.crate_name(did1.krate);
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index e22fb988904..4c1216aa862 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -18,8 +18,8 @@ pub use ty::IntVarValue;
 pub use self::freshen::TypeFreshener;
 pub use self::region_inference::{GenericKind, VerifyBound};
 
-use middle::def_id::DefId;
-use rustc_front::hir;
+use hir::def_id::DefId;
+use hir;
 use middle::free_region::FreeRegionMap;
 use middle::mem_categorization as mc;
 use middle::mem_categorization::McResult;
diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs
index 3cc076f1f00..c2a8d04ac00 100644
--- a/src/librustc/infer/type_variable.rs
+++ b/src/librustc/infer/type_variable.rs
@@ -11,7 +11,7 @@
 pub use self::RelationDir::*;
 use self::TypeVariableValue::*;
 use self::UndoEntry::*;
-use middle::def_id::{DefId};
+use hir::def_id::{DefId};
 use ty::{self, Ty};
 use syntax::codemap::Span;
 
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 03a08231c74..deb20627772 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -38,6 +38,7 @@
 #![feature(rustc_private)]
 #![feature(slice_patterns)]
 #![feature(staged_api)]
+#![feature(step_by)]
 #![feature(str_char)]
 #![feature(question_mark)]
 #![cfg_attr(test, feature(test))]
@@ -51,7 +52,6 @@ extern crate graphviz;
 extern crate libc;
 extern crate rbml;
 extern crate rustc_back;
-extern crate rustc_front;
 extern crate rustc_data_structures;
 extern crate serialize;
 extern crate collections;
@@ -72,19 +72,9 @@ mod macros;
 // registered before they are used.
 pub mod diagnostics;
 
-pub mod back {
-    pub use rustc_back::rpath;
-    pub use rustc_back::svh;
-}
-
 pub mod cfg;
 pub mod dep_graph;
-
-pub mod front {
-    pub mod check_attr;
-    pub mod map;
-}
-
+pub mod hir;
 pub mod infer;
 pub mod lint;
 
@@ -96,8 +86,6 @@ pub mod middle {
     pub mod cstore;
     pub mod dataflow;
     pub mod dead;
-    pub mod def;
-    pub mod def_id;
     pub mod dependency_format;
     pub mod effect;
     pub mod entry;
@@ -106,7 +94,6 @@ pub mod middle {
     pub mod lang_items;
     pub mod liveness;
     pub mod mem_categorization;
-    pub mod pat_util;
     pub mod privacy;
     pub mod reachable;
     pub mod region;
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index e78ff513ac4..1c6dd265889 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -39,16 +39,15 @@ use std::cell::RefCell;
 use std::cmp;
 use std::default::Default as StdDefault;
 use std::mem;
-use syntax::ast_util::{self, IdVisitingOperation};
 use syntax::attr::{self, AttrMetaMethods};
 use syntax::codemap::Span;
 use syntax::errors::DiagnosticBuilder;
 use syntax::parse::token::InternedString;
 use syntax::ast;
 use syntax::attr::ThinAttributesExt;
-use rustc_front::hir;
-use rustc_front::util;
-use rustc_front::intravisit as hir_visit;
+use hir;
+use hir::intravisit as hir_visit;
+use hir::intravisit::{IdVisitor, IdVisitingOperation};
 use syntax::visit as ast_visit;
 
 /// Information about the registered lints.
@@ -654,16 +653,6 @@ impl<'a> EarlyContext<'a> {
             level_stack: vec![],
         }
     }
-
-    fn visit_ids<F>(&mut self, f: F)
-        where F: FnOnce(&mut ast_util::IdVisitor<EarlyContext>)
-    {
-        let mut v = ast_util::IdVisitor {
-            operation: self,
-            visited_outermost: false,
-        };
-        f(&mut v);
-    }
 }
 
 impl<'a, 'tcx> LateContext<'a, 'tcx> {
@@ -685,9 +674,9 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> {
     }
 
     fn visit_ids<F>(&mut self, f: F)
-        where F: FnOnce(&mut util::IdVisitor<LateContext>)
+        where F: FnOnce(&mut IdVisitor<LateContext>)
     {
-        let mut v = util::IdVisitor::new(self);
+        let mut v = IdVisitor::new(self);
         f(&mut v);
     }
 }
@@ -928,7 +917,6 @@ impl<'a, 'v> ast_visit::Visitor<'v> for EarlyContext<'a> {
     fn visit_item(&mut self, it: &ast::Item) {
         self.with_lint_attrs(&it.attrs, |cx| {
             run_lints!(cx, check_item, early_passes, it);
-            cx.visit_ids(|v| v.visit_item(it));
             ast_visit::walk_item(cx, it);
             run_lints!(cx, check_item_post, early_passes, it);
         })
@@ -978,7 +966,7 @@ impl<'a, 'v> ast_visit::Visitor<'v> for EarlyContext<'a> {
     }
 
     fn visit_struct_field(&mut self, s: &ast::StructField) {
-        self.with_lint_attrs(&s.node.attrs, |cx| {
+        self.with_lint_attrs(&s.attrs, |cx| {
             run_lints!(cx, check_struct_field, early_passes, s);
             ast_visit::walk_struct_field(cx, s);
         })
@@ -1042,7 +1030,6 @@ impl<'a, 'v> ast_visit::Visitor<'v> for EarlyContext<'a> {
     fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) {
         self.with_lint_attrs(&trait_item.attrs, |cx| {
             run_lints!(cx, check_trait_item, early_passes, trait_item);
-            cx.visit_ids(|v| v.visit_trait_item(trait_item));
             ast_visit::walk_trait_item(cx, trait_item);
             run_lints!(cx, check_trait_item_post, early_passes, trait_item);
         });
@@ -1051,7 +1038,6 @@ impl<'a, 'v> ast_visit::Visitor<'v> for EarlyContext<'a> {
     fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) {
         self.with_lint_attrs(&impl_item.attrs, |cx| {
             run_lints!(cx, check_impl_item, early_passes, impl_item);
-            cx.visit_ids(|v| v.visit_impl_item(impl_item));
             ast_visit::walk_impl_item(cx, impl_item);
             run_lints!(cx, check_impl_item_post, early_passes, impl_item);
         });
@@ -1099,18 +1085,6 @@ impl<'a, 'tcx> IdVisitingOperation for LateContext<'a, 'tcx> {
         }
     }
 }
-impl<'a> IdVisitingOperation for EarlyContext<'a> {
-    fn visit_id(&mut self, id: ast::NodeId) {
-        match self.sess.lints.borrow_mut().remove(&id) {
-            None => {}
-            Some(lints) => {
-                for (lint_id, span, msg) in lints {
-                    self.span_lint(lint_id.lint, span, &msg[..])
-                }
-            }
-        }
-    }
-}
 
 // This lint pass is defined here because it touches parts of the `LateContext`
 // that we don't want to expose. It records the lint level at certain AST
@@ -1292,11 +1266,12 @@ pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) {
 
     // Visit the whole crate.
     cx.with_lint_attrs(&krate.attrs, |cx| {
-        cx.visit_id(ast::CRATE_NODE_ID);
-        cx.visit_ids(|v| {
-            v.visited_outermost = true;
-            ast_visit::walk_crate(v, krate);
-        });
+        // Lints may be assigned to the whole crate.
+        if let Some(lints) = cx.sess.lints.borrow_mut().remove(&ast::CRATE_NODE_ID) {
+            for (lint_id, span, msg) in lints {
+                cx.span_lint(lint_id.lint, span, &msg[..])
+            }
+        }
 
         // since the root module isn't visited as an item (because it isn't an
         // item), warn for it here.
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index 133d0163a8c..28994e1a7c4 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -34,10 +34,10 @@ pub use self::LintSource::*;
 use std::hash;
 use std::ascii::AsciiExt;
 use syntax::codemap::Span;
-use rustc_front::intravisit::FnKind;
+use hir::intravisit::FnKind;
 use syntax::visit as ast_visit;
 use syntax::ast;
-use rustc_front::hir;
+use hir;
 
 pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore,
                         raw_emit_lint, check_crate, check_ast_crate, gather_attrs,
diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs
index b86d74545cb..2a27732b953 100644
--- a/src/librustc/middle/astconv_util.rs
+++ b/src/librustc/middle/astconv_util.rs
@@ -14,11 +14,11 @@
  * Almost certainly this could (and should) be refactored out of existence.
  */
 
-use middle::def::Def;
+use hir::def::Def;
 use ty::{Ty, TyCtxt};
 
 use syntax::codemap::Span;
-use rustc_front::hir as ast;
+use hir as ast;
 
 pub fn prohibit_type_params(tcx: &TyCtxt, segments: &[ast::PathSegment]) {
     for segment in segments {
diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs
index a939389c460..3621cb267d9 100644
--- a/src/librustc/middle/const_val.rs
+++ b/src/librustc/middle/const_val.rs
@@ -11,7 +11,7 @@
 use syntax::parse::token::InternedString;
 use syntax::ast;
 use std::rc::Rc;
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use std::hash;
 use std::mem::transmute;
 use rustc_const_math::*;
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index 4efb40abdb0..1f6328187a5 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -22,12 +22,12 @@
 // are *mostly* used as a part of that interface, but these should
 // probably get a better home if someone can find one.
 
-use back::svh::Svh;
-use front::map as hir_map;
-use middle::def::{self, Def};
+use hir::svh::Svh;
+use hir::map as hir_map;
+use hir::def::{self, Def};
 use middle::lang_items;
 use ty::{self, Ty, TyCtxt, VariantKind};
-use middle::def_id::{DefId, DefIndex};
+use hir::def_id::{DefId, DefIndex};
 use mir::repr::Mir;
 use mir::mir_map::MirMap;
 use session::Session;
@@ -38,15 +38,13 @@ use std::cell::RefCell;
 use std::rc::Rc;
 use std::path::PathBuf;
 use syntax::ast;
-use syntax::ast_util::{IdVisitingOperation};
 use syntax::attr;
 use syntax::codemap::Span;
 use syntax::ptr::P;
 use syntax::parse::token::InternedString;
 use rustc_back::target::Target;
-use rustc_front::hir;
-use rustc_front::intravisit::Visitor;
-use rustc_front::util::IdVisitor;
+use hir;
+use hir::intravisit::{IdVisitor, IdVisitingOperation, Visitor};
 
 pub use self::DefLike::{DlDef, DlField, DlImpl};
 pub use self::NativeLibraryKind::{NativeStatic, NativeFramework, NativeUnknown};
@@ -168,9 +166,7 @@ pub trait CrateStore<'tcx> : Any {
     fn repr_attrs(&self, def: DefId) -> Vec<attr::ReprAttr>;
     fn item_type(&self, tcx: &TyCtxt<'tcx>, def: DefId)
                  -> ty::TypeScheme<'tcx>;
-    fn relative_item_path(&self, def: DefId) -> Vec<hir_map::PathElem>;
     fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap<DefId>>;
-    fn extern_item_path(&self, def: DefId) -> Vec<hir_map::PathElem>;
     fn item_name(&self, def: DefId) -> ast::Name;
     fn item_predicates(&self, tcx: &TyCtxt<'tcx>, def: DefId)
                        -> ty::GenericPredicates<'tcx>;
@@ -347,12 +343,9 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
     fn repr_attrs(&self, def: DefId) -> Vec<attr::ReprAttr> { bug!("repr_attrs") }
     fn item_type(&self, tcx: &TyCtxt<'tcx>, def: DefId)
                  -> ty::TypeScheme<'tcx> { bug!("item_type") }
-    fn relative_item_path(&self, def: DefId)
-                          -> Vec<hir_map::PathElem> { bug!("relative_item_path") }
     fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap<DefId>> {
         bug!("visible_parent_map")
     }
-    fn extern_item_path(&self, def: DefId) -> Vec<hir_map::PathElem> { bug!("extern_item_path") }
     fn item_name(&self, def: DefId) -> ast::Name { bug!("item_name") }
     fn item_predicates(&self, tcx: &TyCtxt<'tcx>, def: DefId)
                        -> ty::GenericPredicates<'tcx> { bug!("item_predicates") }
@@ -506,7 +499,7 @@ pub mod tls {
     use std::mem;
     use ty::{self, Ty, TyCtxt};
     use ty::subst::Substs;
-    use middle::def_id::DefId;
+    use hir::def_id::DefId;
 
     pub trait EncodingContext<'tcx> {
         fn tcx<'a>(&'a self) -> &'a TyCtxt<'tcx>;
diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs
index 6468187e219..1aaaa4bcd77 100644
--- a/src/librustc/middle/dataflow.rs
+++ b/src/librustc/middle/dataflow.rs
@@ -21,13 +21,12 @@ use std::io;
 use std::mem;
 use std::usize;
 use syntax::ast;
-use syntax::ast_util::IdRange;
 use syntax::print::pp;
 use syntax::print::pprust::PrintState;
 use util::nodemap::NodeMap;
-use rustc_front::hir;
-use rustc_front::intravisit;
-use rustc_front::print::pprust;
+use hir;
+use hir::intravisit::{self, IdRange};
+use hir::print as pprust;
 
 
 #[derive(Copy, Clone, Debug)]
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 18bea745858..dcdc02c9df6 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -13,14 +13,14 @@
 // from live codes are live, and everything else is dead.
 
 use dep_graph::DepNode;
-use front::map as ast_map;
-use rustc_front::hir::{self, PatKind};
-use rustc_front::intravisit::{self, Visitor};
+use hir::map as ast_map;
+use hir::{self, pat_util, PatKind};
+use hir::intravisit::{self, Visitor};
 
-use middle::{pat_util, privacy};
+use middle::privacy;
 use ty::{self, TyCtxt};
-use middle::def::Def;
-use middle::def_id::{DefId};
+use hir::def::Def;
+use hir::def_id::{DefId};
 use lint;
 
 use std::collections::HashSet;
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index fa949073f4e..ac7a1b8aa0d 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -13,15 +13,15 @@
 use self::RootUnsafeContext::*;
 
 use dep_graph::DepNode;
-use middle::def::Def;
+use hir::def::Def;
 use ty::{self, Ty, TyCtxt};
 use ty::MethodCall;
 
 use syntax::ast;
 use syntax::codemap::Span;
-use rustc_front::hir;
-use rustc_front::intravisit;
-use rustc_front::intravisit::{FnKind, Visitor};
+use hir;
+use hir::intravisit;
+use hir::intravisit::{FnKind, Visitor};
 
 #[derive(Copy, Clone)]
 struct UnsafeContext {
diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs
index 67e96816abf..602889375e9 100644
--- a/src/librustc/middle/entry.rs
+++ b/src/librustc/middle/entry.rs
@@ -10,15 +10,15 @@
 
 
 use dep_graph::DepNode;
-use front::map as ast_map;
-use middle::def_id::{CRATE_DEF_INDEX};
+use hir::map as ast_map;
+use hir::def_id::{CRATE_DEF_INDEX};
 use session::{config, Session};
 use syntax::ast::NodeId;
 use syntax::attr;
 use syntax::codemap::Span;
 use syntax::entry::EntryPointType;
-use rustc_front::hir::{Item, ItemFn};
-use rustc_front::intravisit::Visitor;
+use hir::{Item, ItemFn};
+use hir::intravisit::Visitor;
 
 struct EntryContext<'a, 'tcx: 'a> {
     session: &'a Session,
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index bfc96005bc8..c4d6f100671 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -19,14 +19,14 @@ pub use self::MatchMode::*;
 use self::TrackMatchMode::*;
 use self::OverloadedCallType::*;
 
-use middle::pat_util;
-use middle::def::Def;
-use middle::def_id::{DefId};
+use hir::pat_util;
+use hir::def::Def;
+use hir::def_id::{DefId};
 use infer;
 use middle::mem_categorization as mc;
 use ty::{self, TyCtxt, adjustment};
 
-use rustc_front::hir::{self, PatKind};
+use hir::{self, PatKind};
 
 use syntax::ast;
 use syntax::ptr::P;
@@ -479,7 +479,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
             }
 
             hir::ExprUnary(op, ref lhs) => {
-                let pass_args = if ::rustc_front::util::is_by_value_unop(op) {
+                let pass_args = if op.is_by_value() {
                     PassArgs::ByValue
                 } else {
                     PassArgs::ByRef
@@ -491,7 +491,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
             }
 
             hir::ExprBinary(op, ref lhs, ref rhs) => {
-                let pass_args = if ::rustc_front::util::is_by_value_binop(op.node) {
+                let pass_args = if op.node.is_by_value() {
                     PassArgs::ByValue
                 } else {
                     PassArgs::ByRef
@@ -524,7 +524,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
 
             hir::ExprAssignOp(op, ref lhs, ref rhs) => {
                 // NB All our assignment operations take the RHS by value
-                assert!(::rustc_front::util::is_by_value_binop(op.node));
+                assert!(op.node.is_by_value());
 
                 if !self.walk_overloaded_operator(expr, lhs, vec![rhs], PassArgs::ByValue) {
                     self.mutate_expr(expr, &lhs, MutateMode::WriteAndRead);
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index fd74ccac975..767c5adc81e 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -9,8 +9,8 @@
 // except according to those terms.
 
 use dep_graph::DepNode;
-use middle::def::Def;
-use middle::def_id::DefId;
+use hir::def::Def;
+use hir::def_id::DefId;
 use ty::subst::{Subst, Substs, EnumeratedItems};
 use ty::{TransmuteRestriction, TyCtxt};
 use ty::{self, Ty, TypeFoldable};
@@ -20,8 +20,8 @@ use std::fmt;
 use syntax::abi::Abi::RustIntrinsic;
 use syntax::ast;
 use syntax::codemap::Span;
-use rustc_front::intravisit::{self, Visitor, FnKind};
-use rustc_front::hir;
+use hir::intravisit::{self, Visitor, FnKind};
+use hir;
 
 pub fn check_crate(tcx: &TyCtxt) {
     let mut visitor = IntrinsicCheckingVisitor {
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index bb0b8ed91df..86531ced8df 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -22,10 +22,10 @@
 pub use self::LangItem::*;
 
 use dep_graph::DepNode;
-use front::map as hir_map;
+use hir::map as hir_map;
 use session::Session;
 use middle::cstore::CrateStore;
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use ty;
 use middle::weak_lang_items;
 use util::nodemap::FnvHashMap;
@@ -33,8 +33,8 @@ use util::nodemap::FnvHashMap;
 use syntax::ast;
 use syntax::attr::AttrMetaMethods;
 use syntax::parse::token::InternedString;
-use rustc_front::intravisit::Visitor;
-use rustc_front::hir;
+use hir::intravisit::Visitor;
+use hir;
 
 // The actual lang items defined come at the end of this file in one handy table.
 // So you probably just want to nip down to the end.
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 4451e7ac472..35991ae56c8 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -110,8 +110,8 @@ use self::LiveNodeKind::*;
 use self::VarKind::*;
 
 use dep_graph::DepNode;
-use middle::def::*;
-use middle::pat_util;
+use hir::def::*;
+use hir::pat_util;
 use ty::{self, TyCtxt, ParameterEnvironment};
 use traits::{self, ProjectionMode};
 use infer;
@@ -128,10 +128,10 @@ use syntax::codemap::{BytePos, original_sp, Span};
 use syntax::parse::token::special_idents;
 use syntax::ptr::P;
 
-use rustc_front::hir::Expr;
-use rustc_front::hir;
-use rustc_front::print::pprust::{expr_to_string, block_to_string};
-use rustc_front::intravisit::{self, Visitor, FnKind};
+use hir::Expr;
+use hir;
+use hir::print::{expr_to_string, block_to_string};
+use hir::intravisit::{self, Visitor, FnKind};
 
 /// For use with `propagate_through_loop`.
 enum LoopKind<'a> {
@@ -484,7 +484,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
         ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
         intravisit::walk_expr(ir, expr);
       }
-      hir::ExprBinary(op, _, _) if ::rustc_front::util::lazy_binop(op.node) => {
+      hir::ExprBinary(op, _, _) if op.node.is_lazy() => {
         ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
         intravisit::walk_expr(ir, expr);
       }
@@ -1142,7 +1142,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             self.propagate_through_exprs(&exprs[..], succ)
           }
 
-          hir::ExprBinary(op, ref l, ref r) if ::rustc_front::util::lazy_binop(op.node) => {
+          hir::ExprBinary(op, ref l, ref r) if op.node.is_lazy() => {
             let r_succ = self.propagate_through_expr(&r, succ);
 
             let ln = self.live_node(expr.id, expr.span);
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index ef031ad13f1..2f77552c389 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -71,16 +71,16 @@ pub use self::deref_kind::*;
 
 use self::Aliasability::*;
 
-use middle::def_id::DefId;
-use front::map as ast_map;
+use hir::def_id::DefId;
+use hir::map as ast_map;
 use infer;
 use middle::const_qualif::ConstQualif;
-use middle::def::Def;
+use hir::def::Def;
 use ty::adjustment;
 use ty::{self, Ty, TyCtxt};
 
-use rustc_front::hir::{MutImmutable, MutMutable, PatKind};
-use rustc_front::hir;
+use hir::{MutImmutable, MutMutable, PatKind};
+use hir;
 use syntax::ast;
 use syntax::codemap::Span;
 
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 149e895717c..63bccc2d02e 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -16,9 +16,9 @@
 // reachable as well.
 
 use dep_graph::DepNode;
-use front::map as ast_map;
-use middle::def::Def;
-use middle::def_id::DefId;
+use hir::map as ast_map;
+use hir::def::Def;
+use hir::def_id::DefId;
 use ty::{self, TyCtxt};
 use middle::privacy;
 use session::config;
@@ -28,9 +28,9 @@ use std::collections::HashSet;
 use syntax::abi::Abi;
 use syntax::ast;
 use syntax::attr;
-use rustc_front::hir;
-use rustc_front::intravisit::Visitor;
-use rustc_front::intravisit;
+use hir;
+use hir::intravisit::Visitor;
+use hir::intravisit;
 
 // Returns true if the given set of generics implies that the item it's
 // associated with must be inlined.
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 2cde6ce9320..f8c0b63bf11 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -17,7 +17,7 @@
 //! `middle/infer/region_inference/README.md`
 
 use dep_graph::DepNode;
-use front::map as ast_map;
+use hir::map as ast_map;
 use session::Session;
 use util::nodemap::{FnvHashMap, NodeMap, NodeSet};
 use middle::cstore::InlinedItem;
@@ -30,10 +30,9 @@ use std::mem;
 use syntax::codemap::{self, Span};
 use syntax::ast::{self, NodeId};
 
-use rustc_front::hir;
-use rustc_front::intravisit::{self, Visitor, FnKind};
-use rustc_front::hir::{Block, Item, FnDecl, Arm, Pat, PatKind, Stmt, Expr, Local};
-use rustc_front::util::stmt_id;
+use hir;
+use hir::intravisit::{self, Visitor, FnKind};
+use hir::{Block, Item, FnDecl, Arm, Pat, PatKind, Stmt, Expr, Local};
 
 #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable,
            RustcDecodable, Copy)]
@@ -765,7 +764,7 @@ fn resolve_pat(visitor: &mut RegionResolutionVisitor, pat: &hir::Pat) {
 }
 
 fn resolve_stmt(visitor: &mut RegionResolutionVisitor, stmt: &hir::Stmt) {
-    let stmt_id = stmt_id(stmt);
+    let stmt_id = stmt.node.id();
     debug!("resolve_stmt(stmt.id={:?})", stmt_id);
 
     // Every statement will clean up the temporaries created during
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index d3757629d30..585b65b9f5e 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -19,9 +19,9 @@ pub use self::DefRegion::*;
 use self::ScopeChain::*;
 
 use dep_graph::DepNode;
-use front::map::Map;
+use hir::map::Map;
 use session::Session;
-use middle::def::{Def, DefMap};
+use hir::def::{Def, DefMap};
 use middle::region;
 use ty::subst;
 use ty;
@@ -32,9 +32,9 @@ use syntax::codemap::Span;
 use syntax::parse::token::special_idents;
 use util::nodemap::NodeMap;
 
-use rustc_front::hir;
-use rustc_front::print::pprust::lifetime_to_string;
-use rustc_front::intravisit::{self, Visitor, FnKind};
+use hir;
+use hir::print::lifetime_to_string;
+use hir::intravisit::{self, Visitor, FnKind};
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
 pub enum DefRegion {
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index e589743222b..6c7c7f160f4 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -14,12 +14,12 @@
 pub use self::StabilityLevel::*;
 
 use dep_graph::DepNode;
-use front::map as hir_map;
+use hir::map as hir_map;
 use session::Session;
 use lint;
 use middle::cstore::{CrateStore, LOCAL_CRATE};
-use middle::def::Def;
-use middle::def_id::{CRATE_DEF_INDEX, DefId};
+use hir::def::Def;
+use hir::def_id::{CRATE_DEF_INDEX, DefId};
 use ty::{self, TyCtxt};
 use middle::privacy::AccessLevels;
 use syntax::parse::token::InternedString;
@@ -30,9 +30,9 @@ use syntax::feature_gate::{GateIssue, emit_feature_err};
 use syntax::attr::{self, Stability, Deprecation, AttrMetaMethods};
 use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap};
 
-use rustc_front::hir;
-use rustc_front::hir::{Item, Generics, StructField, Variant, PatKind};
-use rustc_front::intravisit::{self, Visitor};
+use hir;
+use hir::{Item, Generics, StructField, Variant, PatKind};
+use hir::intravisit::{self, Visitor};
 
 use std::mem::replace;
 use std::cmp::Ordering;
diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs
index 6059d7ee74e..74bb41785cb 100644
--- a/src/librustc/middle/weak_lang_items.rs
+++ b/src/librustc/middle/weak_lang_items.rs
@@ -18,9 +18,9 @@ use middle::lang_items;
 use syntax::ast;
 use syntax::codemap::Span;
 use syntax::parse::token::InternedString;
-use rustc_front::intravisit::Visitor;
-use rustc_front::intravisit;
-use rustc_front::hir;
+use hir::intravisit::Visitor;
+use hir::intravisit;
+use hir;
 
 use std::collections::HashSet;
 
diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs
index a33ee6bd204..28437fa1336 100644
--- a/src/librustc/mir/repr.rs
+++ b/src/librustc/mir/repr.rs
@@ -11,12 +11,12 @@
 use graphviz::IntoCow;
 use middle::const_val::ConstVal;
 use rustc_const_math::{ConstUsize, ConstInt};
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use ty::subst::Substs;
 use ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty};
 use util::ppaux;
 use rustc_back::slice;
-use rustc_front::hir::InlineAsm;
+use hir::InlineAsm;
 use std::ascii;
 use std::borrow::{Cow};
 use std::fmt::{self, Debug, Formatter, Write};
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index ecac5d2f73f..d710417bf20 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -17,7 +17,7 @@ use mir::repr::*;
 use ty::subst::{Subst, Substs};
 use ty::{self, AdtDef, Ty, TyCtxt};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
-use rustc_front::hir;
+use hir;
 
 #[derive(Copy, Clone, Debug)]
 pub enum LvalueTy<'tcx> {
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 403c749fe4b..ae803f50231 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use middle::const_val::ConstVal;
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use ty::subst::Substs;
 use ty::{ClosureSubsts, FnOutput, Region, Ty};
 use mir::repr::*;
diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs
index a0ac5148526..6710d2a653c 100644
--- a/src/librustc/traits/coherence.rs
+++ b/src/librustc/traits/coherence.rs
@@ -13,7 +13,7 @@
 use super::{SelectionContext, Obligation, ObligationCause};
 
 use middle::cstore::LOCAL_CRATE;
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use ty::subst::TypeSpace;
 use ty::{self, Ty, TyCtxt};
 use infer::{self, InferCtxt, TypeOrigin};
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index f15b9ee44ce..9357dda2583 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -24,7 +24,7 @@ use super::{
 };
 
 use fmt_macros::{Parser, Piece, Position};
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use infer::InferCtxt;
 use ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable};
 use ty::fast_reject;
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 867bd054fa9..a160465e2e8 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -15,7 +15,7 @@ pub use self::FulfillmentErrorCode::*;
 pub use self::Vtable::*;
 pub use self::ObligationCauseCode::*;
 
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use middle::free_region::FreeRegionMap;
 use ty::subst;
 use ty::{self, Ty, TypeFoldable};
diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs
index 7cd2ac5938d..9af2cfbd04d 100644
--- a/src/librustc/traits/object_safety.rs
+++ b/src/librustc/traits/object_safety.rs
@@ -20,7 +20,7 @@
 use super::supertraits;
 use super::elaborate_predicates;
 
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use ty::subst::{self, SelfSpace, TypeSpace};
 use traits;
 use ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index d4d61ec0244..a0d6f5f912b 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -23,7 +23,7 @@ use super::VtableClosureData;
 use super::VtableImplData;
 use super::util;
 
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use infer::{self, InferOk, TypeOrigin};
 use ty::subst::Subst;
 use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt};
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index f68386feddb..8d7df6e44ae 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -36,7 +36,7 @@ use super::{VtableImplData, VtableObjectData, VtableBuiltinData,
 use super::object_safety;
 use super::util;
 
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use infer;
 use infer::{InferCtxt, InferOk, TypeFreshener, TypeOrigin};
 use ty::subst::{Subst, Substs, TypeSpace};
@@ -49,7 +49,7 @@ use std::cell::RefCell;
 use std::fmt;
 use std::rc::Rc;
 use syntax::abi::Abi;
-use rustc_front::hir;
+use hir;
 use util::common::ErrorReported;
 use util::nodemap::FnvHashMap;
 
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index 88f4129d886..63647515a97 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -21,7 +21,7 @@ use super::{SelectionContext, FulfillmentContext};
 use super::util::{fresh_type_vars_for_impl, impl_trait_ref_and_oblig};
 
 use middle::cstore::CrateStore;
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use infer::{self, InferCtxt, TypeOrigin};
 use middle::region;
 use ty::subst::{Subst, Substs};
diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs
index d3146697ee6..51b0b6b8b38 100644
--- a/src/librustc/traits/specialize/specialization_graph.rs
+++ b/src/librustc/traits/specialize/specialization_graph.rs
@@ -14,7 +14,7 @@ use std::rc::Rc;
 use super::{Overlap, specializes};
 
 use middle::cstore::CrateStore;
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use infer;
 use traits::{self, ProjectionMode};
 use ty::{self, TyCtxt, ImplOrTraitItem, TraitDef, TypeFoldable};
diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs
index befca878bc0..7668b8bf202 100644
--- a/src/librustc/traits/util.rs
+++ b/src/librustc/traits/util.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use infer::InferCtxt;
 use ty::subst::{Subst, Substs};
 use ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef};
diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs
index 90ccdeea928..41008823c85 100644
--- a/src/librustc/ty/adjustment.rs
+++ b/src/librustc/ty/adjustment.rs
@@ -17,7 +17,7 @@ use ty::LvaluePreference::{NoPreference};
 use syntax::ast;
 use syntax::codemap::Span;
 
-use rustc_front::hir;
+use hir;
 
 #[derive(Copy, Clone)]
 pub enum AutoAdjustment<'tcx> {
diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs
index ba237184a9f..f5dedb13248 100644
--- a/src/librustc/ty/contents.rs
+++ b/src/librustc/ty/contents.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use middle::def_id::{DefId};
+use hir::def_id::{DefId};
 use ty::{self, Ty, TyCtxt};
 use util::common::MemoizationMap;
 use util::nodemap::FnvHashMap;
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 2074339f2e6..bdba700f49a 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -11,13 +11,13 @@
 //! type context book-keeping
 
 use dep_graph::{DepGraph, DepTrackingMap};
-use front::map as ast_map;
+use hir::map as ast_map;
 use session::Session;
 use lint;
 use middle;
 use middle::cstore::{CrateStore, LOCAL_CRATE};
-use middle::def::DefMap;
-use middle::def_id::DefId;
+use hir::def::DefMap;
+use hir::def_id::DefId;
 use middle::free_region::FreeRegionMap;
 use middle::region::RegionMaps;
 use middle::resolve_lifetime;
@@ -27,7 +27,7 @@ use traits;
 use ty::{self, TraitRef, Ty, TypeAndMut};
 use ty::{TyS, TypeVariants};
 use ty::{AdtDef, ClosureSubsts, ExistentialBounds, Region};
-use ty::{FreevarMap};
+use hir::FreevarMap;
 use ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, TraitTy};
 use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
 use ty::TypeVariants::*;
@@ -45,7 +45,7 @@ use syntax::ast::{self, Name, NodeId};
 use syntax::attr;
 use syntax::parse::token::{self, special_idents};
 
-use rustc_front::hir;
+use hir;
 
 /// Internal storage
 pub struct CtxtArenas<'tcx> {
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index 9ab48505828..73bafc5e850 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use ty::subst;
 use infer::type_variable;
 use ty::{self, BoundRegion, Region, Ty, TyCtxt};
@@ -19,7 +19,7 @@ use syntax::ast::{self, Name};
 use syntax::codemap::Span;
 use syntax::errors::DiagnosticBuilder;
 
-use rustc_front::hir;
+use hir;
 
 #[derive(Clone, Copy, Debug)]
 pub struct ExpectedFound<T> {
diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs
index 0865e059f59..29647253ad2 100644
--- a/src/librustc/ty/fast_reject.rs
+++ b/src/librustc/ty/fast_reject.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use ty::{self, Ty, TyCtxt};
 use syntax::ast;
 
diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs
index caf7e6fe629..5c1e19aee7b 100644
--- a/src/librustc/ty/item_path.rs
+++ b/src/librustc/ty/item_path.rs
@@ -8,9 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use front::map::DefPathData;
+use hir::map::DefPathData;
 use middle::cstore::LOCAL_CRATE;
-use middle::def_id::{DefId, CRATE_DEF_INDEX};
+use hir::def_id::{DefId, CRATE_DEF_INDEX};
 use ty::{self, Ty, TyCtxt};
 use syntax::ast;
 
@@ -24,6 +24,11 @@ impl<'tcx> TyCtxt<'tcx> {
         buffer.into_string()
     }
 
+    /// Returns a string identifying this local node-id.
+    pub fn node_path_str(&self, id: ast::NodeId) -> String {
+        self.item_path_str(self.map.local_def_id(id))
+    }
+
     /// Returns a string identifying this def-id. This string is
     /// suitable for user output. It always begins with a crate identifier.
     pub fn absolute_item_path_str(&self, def_id: DefId) -> String {
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index 77b6b03e48f..65a96e79ff4 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use dep_graph::{DepNode, DepTrackingMapConfig};
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use ty;
 use std::marker::PhantomData;
 use std::rc::Rc;
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index edfad09ae1f..444fea0918f 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -19,12 +19,11 @@ pub use self::LvaluePreference::*;
 pub use self::fold::TypeFoldable;
 
 use dep_graph::{self, DepNode};
-use front::map as ast_map;
-use front::map::LinkedPath;
+use hir::map as ast_map;
 use middle;
 use middle::cstore::{self, CrateStore, LOCAL_CRATE};
-use middle::def::{self, Def, ExportMap};
-use middle::def_id::DefId;
+use hir::def::{self, Def, ExportMap};
+use hir::def_id::DefId;
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
 use middle::region::{CodeExtent};
 use traits;
@@ -33,7 +32,7 @@ use ty::fold::TypeFolder;
 use ty::subst::{Subst, Substs, VecPerParamSpace};
 use ty::walk::TypeWalker;
 use util::common::MemoizationMap;
-use util::nodemap::{NodeMap, NodeSet};
+use util::nodemap::NodeSet;
 use util::nodemap::FnvHashMap;
 
 use serialize::{Encodable, Encoder, Decodable, Decoder};
@@ -44,7 +43,6 @@ use std::iter;
 use std::rc::Rc;
 use std::slice;
 use std::vec::IntoIter;
-use std::collections::{HashMap, HashSet};
 use syntax::ast::{self, CrateNum, Name, NodeId};
 use syntax::attr::{self, AttrMetaMethods};
 use syntax::codemap::{DUMMY_SP, Span};
@@ -52,9 +50,9 @@ use syntax::parse::token::InternedString;
 
 use rustc_const_math::ConstInt;
 
-use rustc_front::hir;
-use rustc_front::hir::{ItemImpl, ItemTrait, PatKind};
-use rustc_front::intravisit::Visitor;
+use hir;
+use hir::{ItemImpl, ItemTrait, PatKind};
+use hir::intravisit::Visitor;
 
 pub use self::sty::{Binder, DebruijnIndex};
 pub use self::sty::{BuiltinBound, BuiltinBounds, ExistentialBounds};
@@ -115,7 +113,7 @@ pub struct CrateAnalysis<'a> {
     pub access_levels: middle::privacy::AccessLevels,
     pub reachable: NodeSet,
     pub name: &'a str,
-    pub glob_map: Option<GlobMap>,
+    pub glob_map: Option<hir::GlobMap>,
 }
 
 #[derive(Copy, Clone)]
@@ -2232,39 +2230,9 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
-    pub fn with_path<T, F>(&self, id: DefId, f: F) -> T where
-        F: FnOnce(ast_map::PathElems) -> T,
-    {
-        if let Some(id) = self.map.as_local_node_id(id) {
-            self.map.with_path(id, f)
-        } else {
-            let mut path: Vec<_>;
-            if let Some(extern_crate) = self.sess.cstore.extern_crate(id.krate) {
-                if !extern_crate.direct {
-                    // this comes from some crate that we don't have a direct
-                    // path to; we'll settle for just prepending the name of
-                    // the crate.
-                    path = self.sess.cstore.extern_item_path(id)
-                } else {
-                    // start with the path to the extern crate, then
-                    // add the relative path to the actual item
-                    fn collector(elems: ast_map::PathElems) -> Vec<ast_map::PathElem> {
-                        elems.collect()
-                    }
-                    path = self.with_path(extern_crate.def_id, collector);
-                    path.extend(self.sess.cstore.relative_item_path(id));
-                }
-            } else {
-                // if this was injected, just make a path with name of crate
-                path = self.sess.cstore.extern_item_path(id);
-            }
-            f(path.iter().cloned().chain(LinkedPath::empty()))
-        }
-    }
-
     pub fn item_name(&self, id: DefId) -> ast::Name {
         if let Some(id) = self.map.as_local_node_id(id) {
-            self.map.get_path_elem(id).name()
+            self.map.name(id)
         } else {
             self.sess.cstore.item_name(id)
         }
@@ -2724,30 +2692,9 @@ pub enum ExplicitSelfCategory {
     ByBox,
 }
 
-/// A free variable referred to in a function.
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
-pub struct Freevar {
-    /// The variable being accessed free.
-    pub def: Def,
-
-    // First span where it is accessed (there can be multiple).
-    pub span: Span
-}
-
-pub type FreevarMap = NodeMap<Vec<Freevar>>;
-
-pub type CaptureModeMap = NodeMap<hir::CaptureClause>;
-
-// Trait method resolution
-pub type TraitMap = NodeMap<Vec<DefId>>;
-
-// Map from the NodeId of a glob import to a list of items which are actually
-// imported.
-pub type GlobMap = HashMap<NodeId, HashSet<Name>>;
-
 impl<'tcx> TyCtxt<'tcx> {
     pub fn with_freevars<T, F>(&self, fid: NodeId, f: F) -> T where
-        F: FnOnce(&[Freevar]) -> T,
+        F: FnOnce(&[hir::Freevar]) -> T,
     {
         match self.freevars.borrow().get(&fid) {
             None => f(&[]),
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index b39cb5ef939..f14e680e9e0 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -13,13 +13,13 @@
 //! can be other things. Examples of type relations are subtyping,
 //! type equality, etc.
 
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use ty::subst::{ParamSpace, Substs};
 use ty::{self, Ty, TyCtxt, TypeFoldable};
 use ty::error::{ExpectedFound, TypeError};
 use std::rc::Rc;
 use syntax::abi;
-use rustc_front::hir as ast;
+use hir as ast;
 
 pub type RelateResult<'tcx, T> = Result<T, TypeError<'tcx>>;
 
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 82cc9e7f2e3..bbf6d0329b4 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -17,7 +17,7 @@ use std::rc::Rc;
 use syntax::abi;
 use syntax::ptr::P;
 
-use rustc_front::hir;
+use hir;
 
 ///////////////////////////////////////////////////////////////////////////
 // Lift implementations
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index fee0aaff445..c0fb60d4dd3 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -11,7 +11,7 @@
 //! This module contains TypeVariants and its major components
 
 use middle::cstore;
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use middle::region;
 use ty::subst::{self, Substs};
 use traits;
@@ -28,7 +28,7 @@ use syntax::parse::token::special_idents;
 
 use serialize::{Decodable, Decoder};
 
-use rustc_front::hir;
+use hir;
 
 use self::FnOutput::*;
 use self::InferTy::*;
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index 93157f28482..dd547da59e9 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -13,7 +13,7 @@
 pub use self::ParamSpace::*;
 
 use middle::cstore;
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use ty::{self, Ty, TyCtxt};
 use ty::fold::{TypeFoldable, TypeFolder};
 
diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs
index 3ebf2ba4c84..94f4e31efc6 100644
--- a/src/librustc/ty/trait_def.rs
+++ b/src/librustc/ty/trait_def.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use dep_graph::DepNode;
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use traits::{self, specialization_graph};
 use ty;
 use ty::fast_reject;
@@ -17,7 +17,7 @@ use ty::{Ty, TyCtxt, TraitRef};
 use std::borrow::{Borrow};
 use std::cell::{Cell, Ref, RefCell};
 use syntax::ast::Name;
-use rustc_front::hir;
+use hir;
 use util::nodemap::FnvHashMap;
 
 /// As `TypeScheme` but for a trait ref.
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 6e8363f629b..354744b2787 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -10,11 +10,11 @@
 
 //! misc. type-system utilities too small to deserve their own file
 
-use back::svh::Svh;
-use middle::def_id::DefId;
+use hir::svh::Svh;
+use hir::def_id::DefId;
 use ty::subst;
 use infer;
-use middle::pat_util;
+use hir::pat_util;
 use traits::{self, ProjectionMode};
 use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
 use ty::{Disr, ParameterEnvironment};
@@ -28,7 +28,7 @@ use syntax::ast::{self, Name};
 use syntax::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt};
 use syntax::codemap::Span;
 
-use rustc_front::hir;
+use hir;
 
 pub trait IntTypeExt {
     fn to_ty<'tcx>(&self, cx: &TyCtxt<'tcx>) -> Ty<'tcx>;
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index e6c4e90babb..9ea634bb41c 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use infer::InferCtxt;
 use ty::outlives::{self, Component};
 use ty::subst::Substs;
diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs
index 888a623b24a..bdfb97549d5 100644
--- a/src/librustc/util/common.rs
+++ b/src/librustc/util/common.rs
@@ -19,9 +19,9 @@ use std::iter::repeat;
 use std::path::Path;
 use std::time::Instant;
 
-use rustc_front::hir;
-use rustc_front::intravisit;
-use rustc_front::intravisit::Visitor;
+use hir;
+use hir::intravisit;
+use hir::intravisit::Visitor;
 
 // The name of the associated type for `Fn` return types
 pub const FN_OUTPUT_NAME: &'static str = "Output";
diff --git a/src/librustc/util/nodemap.rs b/src/librustc/util/nodemap.rs
index 4a45797602d..69bcc9cbfff 100644
--- a/src/librustc/util/nodemap.rs
+++ b/src/librustc/util/nodemap.rs
@@ -12,7 +12,7 @@
 
 #![allow(non_snake_case)]
 
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use syntax::ast;
 
 pub use rustc_data_structures::fnv::FnvHashMap;
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 20f16a1d255..a84a42fc2b5 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 
-use middle::def_id::DefId;
+use hir::def_id::DefId;
 use ty::subst::{self, Subst};
 use ty::{BrAnon, BrEnv, BrFresh, BrNamed};
 use ty::{TyBool, TyChar, TyStruct, TyEnum};
@@ -23,7 +23,7 @@ use std::fmt;
 use syntax::abi::Abi;
 use syntax::parse::token;
 use syntax::ast::CRATE_NODE_ID;
-use rustc_front::hir;
+use hir;
 
 pub fn verbose() -> bool {
     ty::tls::with(|tcx| tcx.sess.verbose())