about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-01-08 11:36:52 +0000
committerbors <bors@rust-lang.org>2017-01-08 11:36:52 +0000
commitcbf88730e755d099c854f84dd0f1990490bf0088 (patch)
treed963b89f70bd039ba13fb0ef7f5393a30e315226 /src
parent7ac9d337dcc544b4b1959997cdd36f1ba0c8d3e1 (diff)
parentcde0a7e7e01f64caed45e97ff958821d9247959e (diff)
downloadrust-cbf88730e755d099c854f84dd0f1990490bf0088.tar.gz
rust-cbf88730e755d099c854f84dd0f1990490bf0088.zip
Auto merge of #38813 - eddyb:lazy-11, r=nikomatsakis
[11/n] Separate ty::Tables into one per each body.

_This is part of a series ([prev](https://github.com/rust-lang/rust/pull/38449) | [next]()) of patches designed to rework rustc into an out-of-order on-demand pipeline model for both better feature support (e.g. [MIR-based](https://github.com/solson/miri) early constant evaluation) and incremental execution of compiler passes (e.g. type-checking), with beneficial consequences to IDE support as well.
If any motivation is unclear, please ask for additional PR description clarifications or code comments._

<hr>

In order to track the results of type-checking and inference for incremental recompilation, they must be stored separately for each function or constant value, instead of lumped together.

These side-`Tables` also have to be tracked by various passes, as they visit through bodies (all of which have `Tables`, even if closures share the ones from their parent functions). This is usually done by switching a `tables` field in an override of `visit_nested_body` before recursing through `visit_body`, to the relevant one and then restoring it - however, in many cases the nesting is unnecessary and creating the visitor for each body in the crate and then visiting that body, would be a much cleaner solution.

To simplify handling of inlined HIR & its side-tables, their `NodeId` remapping and entries HIR map were fully stripped out, which means that `NodeId`s from inlined HIR must not be used where a local `NodeId` is expected. It might be possible to make the nodes (`Expr`, `Block`, `Pat`, etc.) that only show up within a `Body` have IDs that are scoped to that `Body`, which would also allow `Tables` to use `Vec`s.

That last part also fixes #38790 which was accidentally introduced in a previous refactor.
Diffstat (limited to 'src')
-rw-r--r--src/Cargo.lock1
-rw-r--r--src/librustc/cfg/construct.rs24
-rw-r--r--src/librustc/dep_graph/dep_node.rs3
-rw-r--r--src/librustc/hir/map/blocks.rs19
-rw-r--r--src/librustc/hir/map/collector.rs38
-rw-r--r--src/librustc/hir/map/mod.rs242
-rw-r--r--src/librustc/infer/mod.rs192
-rw-r--r--src/librustc/lint/context.rs46
-rw-r--r--src/librustc/middle/const_val.rs15
-rw-r--r--src/librustc/middle/dead.rs47
-rw-r--r--src/librustc/middle/effect.rs22
-rw-r--r--src/librustc/middle/expr_use_visitor.rs4
-rw-r--r--src/librustc/middle/intrinsicck.rs60
-rw-r--r--src/librustc/middle/liveness.rs85
-rw-r--r--src/librustc/middle/mem_categorization.rs2
-rw-r--r--src/librustc/middle/reachable.rs41
-rw-r--r--src/librustc/mir/mod.rs11
-rw-r--r--src/librustc/traits/mod.rs4
-rw-r--r--src/librustc/traits/specialize/mod.rs4
-rw-r--r--src/librustc/traits/specialize/specialization_graph.rs2
-rw-r--r--src/librustc/ty/context.rs37
-rw-r--r--src/librustc/ty/maps.rs3
-rw-r--r--src/librustc/ty/mod.rs38
-rw-r--r--src/librustc/ty/util.rs4
-rw-r--r--src/librustc_borrowck/borrowck/check_loans.rs4
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs12
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/mod.rs36
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs33
-rw-r--r--src/librustc_const_eval/check_match.rs18
-rw-r--r--src/librustc_const_eval/eval.rs374
-rw-r--r--src/librustc_const_eval/pattern.rs53
-rw-r--r--src/librustc_driver/pretty.rs20
-rw-r--r--src/librustc_driver/test.rs2
-rw-r--r--src/librustc_lint/builtin.rs51
-rw-r--r--src/librustc_lint/types.rs25
-rw-r--r--src/librustc_lint/unused.rs4
-rw-r--r--src/librustc_metadata/astencode.rs118
-rw-r--r--src/librustc_metadata/cstore.rs2
-rw-r--r--src/librustc_metadata/cstore_impl.rs21
-rw-r--r--src/librustc_metadata/decoder.rs63
-rw-r--r--src/librustc_metadata/encoder.rs2
-rw-r--r--src/librustc_mir/build/mod.rs9
-rw-r--r--src/librustc_mir/hair/cx/block.rs4
-rw-r--r--src/librustc_mir/hair/cx/expr.rs81
-rw-r--r--src/librustc_mir/hair/cx/mod.rs25
-rw-r--r--src/librustc_mir/mir_map.rs201
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs2
-rw-r--r--src/librustc_mir/transform/type_check.rs2
-rw-r--r--src/librustc_passes/consts.rs65
-rw-r--r--src/librustc_passes/rvalues.rs27
-rw-r--r--src/librustc_privacy/lib.rs22
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs50
-rw-r--r--src/librustc_save_analysis/lib.rs36
-rw-r--r--src/librustc_trans/common.rs2
-rw-r--r--src/librustc_trans/consts.rs2
-rw-r--r--src/librustc_trans/context.rs2
-rw-r--r--src/librustc_trans/debuginfo/metadata.rs8
-rw-r--r--src/librustc_trans/glue.rs2
-rw-r--r--src/librustc_trans/mir/constant.rs1
-rw-r--r--src/librustc_typeck/astconv.rs3
-rw-r--r--src/librustc_typeck/check/closure.rs4
-rw-r--r--src/librustc_typeck/check/compare_method.rs4
-rw-r--r--src/librustc_typeck/check/dropck.rs2
-rw-r--r--src/librustc_typeck/check/method/probe.rs12
-rw-r--r--src/librustc_typeck/check/mod.rs28
-rw-r--r--src/librustc_typeck/check/upvar.rs6
-rw-r--r--src/librustc_typeck/check/writeback.rs78
-rw-r--r--src/librustc_typeck/coherence/builtin.rs2
-rw-r--r--src/librustc_typeck/coherence/overlap.rs2
-rw-r--r--src/librustc_typeck/collect.rs10
-rw-r--r--src/librustc_typeck/lib.rs2
-rw-r--r--src/librustdoc/Cargo.toml1
-rw-r--r--src/librustdoc/clean/mod.rs20
-rw-r--r--src/librustdoc/lib.rs1
-rw-r--r--src/test/compile-fail/const-eval-overflow.rs14
-rw-r--r--src/test/run-pass/issue-28189.rs15
76 files changed, 1120 insertions, 1407 deletions
diff --git a/src/Cargo.lock b/src/Cargo.lock
index 3da29933c81..d153945dc09 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -569,7 +569,6 @@ dependencies = [
  "rustc 0.0.0",
  "rustc_back 0.0.0",
  "rustc_const_eval 0.0.0",
- "rustc_const_math 0.0.0",
  "rustc_data_structures 0.0.0",
  "rustc_driver 0.0.0",
  "rustc_errors 0.0.0",
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index 4d66bba9f07..35afdd75cb8 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -18,6 +18,7 @@ use hir::{self, PatKind};
 
 struct CFGBuilder<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    tables: &'a ty::Tables<'tcx>,
     graph: CFGGraph,
     fn_exit: CFGIndex,
     loop_scopes: Vec<LoopScope>,
@@ -42,10 +43,23 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let fn_exit = graph.add_node(CFGNodeData::Exit);
     let body_exit;
 
+    // Find the function this expression is from.
+    let mut node_id = body.id;
+    loop {
+        let node = tcx.map.get(node_id);
+        if hir::map::blocks::FnLikeNode::from_node(node).is_some() {
+            break;
+        }
+        let parent = tcx.map.get_parent_node(node_id);
+        assert!(node_id != parent);
+        node_id = parent;
+    }
+
     let mut cfg_builder = CFGBuilder {
+        tcx: tcx,
+        tables: tcx.item_tables(tcx.map.local_def_id(node_id)),
         graph: graph,
         fn_exit: fn_exit,
-        tcx: tcx,
         loop_scopes: Vec::new()
     };
     body_exit = cfg_builder.expr(body, entry);
@@ -310,11 +324,11 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
             }
 
             hir::ExprIndex(ref l, ref r) |
-            hir::ExprBinary(_, ref l, ref r) if self.tcx.tables().is_method_call(expr.id) => {
+            hir::ExprBinary(_, ref l, ref r) if self.tables.is_method_call(expr.id) => {
                 self.call(expr, pred, &l, Some(&**r).into_iter())
             }
 
-            hir::ExprUnary(_, ref e) if self.tcx.tables().is_method_call(expr.id) => {
+            hir::ExprUnary(_, ref e) if self.tables.is_method_call(expr.id) => {
                 self.call(expr, pred, &e, None::<hir::Expr>.iter())
             }
 
@@ -368,9 +382,9 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
             func_or_rcvr: &hir::Expr,
             args: I) -> CFGIndex {
         let method_call = ty::MethodCall::expr(call_expr.id);
-        let fn_ty = match self.tcx.tables().method_map.get(&method_call) {
+        let fn_ty = match self.tables.method_map.get(&method_call) {
             Some(method) => method.ty,
-            None => self.tcx.tables().expr_ty_adjusted(func_or_rcvr)
+            None => self.tables.expr_ty_adjusted(func_or_rcvr)
         };
 
         let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index e261c699b6a..a68876b5ae9 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -113,6 +113,7 @@ pub enum DepNode<D: Clone + Debug> {
     SizedConstraint(D),
     AssociatedItemDefIds(D),
     InherentImpls(D),
+    Tables(D),
 
     // The set of impls for a given trait. Ultimately, it would be
     // nice to get more fine-grained here (e.g., to include a
@@ -162,6 +163,7 @@ impl<D: Clone + Debug> DepNode<D> {
             ItemSignature,
             AssociatedItemDefIds,
             InherentImpls,
+            Tables,
             TraitImpls,
             ReprHints,
         }
@@ -230,6 +232,7 @@ impl<D: Clone + Debug> DepNode<D> {
             SizedConstraint(ref d) => op(d).map(SizedConstraint),
             AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds),
             InherentImpls(ref d) => op(d).map(InherentImpls),
+            Tables(ref d) => op(d).map(Tables),
             TraitImpls(ref d) => op(d).map(TraitImpls),
             TraitItems(ref d) => op(d).map(TraitItems),
             ReprHints(ref d) => op(d).map(ReprHints),
diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs
index 6e08b52f9a2..91e88e2c73f 100644
--- a/src/librustc/hir/map/blocks.rs
+++ b/src/librustc/hir/map/blocks.rs
@@ -45,15 +45,6 @@ pub struct FnLikeNode<'a> { node: map::Node<'a> }
 /// corresponds to some FnLikeNode.
 pub trait MaybeFnLike { fn is_fn_like(&self) -> bool; }
 
-/// Components shared by fn-like things (fn items, methods, closures).
-pub struct FnParts<'a> {
-    pub decl: &'a FnDecl,
-    pub body: ast::BodyId,
-    pub kind: FnKind<'a>,
-    pub span: Span,
-    pub id:   NodeId,
-}
-
 impl MaybeFnLike for ast::Item {
     fn is_fn_like(&self) -> bool {
         match self.node { ast::ItemFn(..) => true, _ => false, }
@@ -165,16 +156,6 @@ impl<'a> FnLikeNode<'a> {
         }
     }
 
-    pub fn to_fn_parts(self) -> FnParts<'a> {
-        FnParts {
-            decl: self.decl(),
-            body: self.body(),
-            kind: self.kind(),
-            span: self.span(),
-            id:   self.id(),
-        }
-    }
-
     pub fn body(self) -> ast::BodyId {
         self.handle(|i: ItemFnParts<'a>|  i.body,
                     |_, _, _: &'a ast::MethodSig, _, body: ast::BodyId, _, _|  body,
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index a6ffe7cea55..bd0ff695d09 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -23,10 +23,6 @@ pub struct NodeCollector<'ast> {
     pub(super) map: Vec<MapEntry<'ast>>,
     /// The parent of this node
     pub parent_node: NodeId,
-    /// If true, completely ignore nested items. We set this when loading
-    /// HIR from metadata, since in that case we only want the HIR for
-    /// one specific item (and not the ones nested inside of it).
-    pub ignore_nested_items: bool
 }
 
 impl<'ast> NodeCollector<'ast> {
@@ -35,30 +31,12 @@ impl<'ast> NodeCollector<'ast> {
             krate: krate,
             map: vec![],
             parent_node: CRATE_NODE_ID,
-            ignore_nested_items: false
         };
         collector.insert_entry(CRATE_NODE_ID, RootCrate);
 
         collector
     }
 
-    pub(super) fn extend(krate: &'ast Crate,
-                         parent: &'ast InlinedItem,
-                         parent_node: NodeId,
-                         map: Vec<MapEntry<'ast>>)
-                         -> NodeCollector<'ast> {
-        let mut collector = NodeCollector {
-            krate: krate,
-            map: map,
-            parent_node: parent_node,
-            ignore_nested_items: true
-        };
-
-        collector.insert_entry(parent_node, RootInlinedParent(parent));
-
-        collector
-    }
-
     fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'ast>) {
         debug!("ast_map: {:?} => {:?}", id, entry);
         let len = self.map.len();
@@ -92,27 +70,19 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
 
     fn visit_nested_item(&mut self, item: ItemId) {
         debug!("visit_nested_item: {:?}", item);
-        if !self.ignore_nested_items {
-            self.visit_item(self.krate.item(item.id))
-        }
+        self.visit_item(self.krate.item(item.id));
     }
 
     fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
-        if !self.ignore_nested_items {
-            self.visit_trait_item(self.krate.trait_item(item_id))
-        }
+        self.visit_trait_item(self.krate.trait_item(item_id));
     }
 
     fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
-        if !self.ignore_nested_items {
-            self.visit_impl_item(self.krate.impl_item(item_id))
-        }
+        self.visit_impl_item(self.krate.impl_item(item_id));
     }
 
     fn visit_nested_body(&mut self, id: BodyId) {
-        if !self.ignore_nested_items {
-            self.visit_body(self.krate.body(id))
-        }
+        self.visit_body(self.krate.body(id));
     }
 
     fn visit_item(&mut self, i: &'ast Item) {
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 27ebeea9ad9..7c0621279fd 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -25,28 +25,18 @@ use syntax::codemap::Spanned;
 use syntax_pos::Span;
 
 use hir::*;
-use hir::intravisit::Visitor;
 use hir::print::Nested;
+use util::nodemap::DefIdMap;
 
 use arena::TypedArena;
 use std::cell::RefCell;
 use std::io;
-use std::mem;
 
 pub mod blocks;
 mod collector;
 mod def_collector;
 pub mod definitions;
 
-/// The data we save and restore about an inlined item or method.  This is not
-/// part of the AST that we parse from a file, but it becomes part of the tree
-/// that we trans.
-#[derive(Debug)]
-struct InlinedItem {
-    def_id: DefId,
-    body: Body,
-}
-
 #[derive(Copy, Clone, Debug)]
 pub enum Node<'ast> {
     NodeItem(&'ast Item),
@@ -99,7 +89,6 @@ enum MapEntry<'ast> {
 
     /// Roots for node trees.
     RootCrate,
-    RootInlinedParent(&'ast InlinedItem)
 }
 
 impl<'ast> Clone for MapEntry<'ast> {
@@ -152,8 +141,7 @@ impl<'ast> MapEntry<'ast> {
             EntryVisibility(id, _) => id,
 
             NotPresent |
-            RootCrate |
-            RootInlinedParent(_) => return None,
+            RootCrate => return None,
         })
     }
 
@@ -225,7 +213,7 @@ impl<'ast> MapEntry<'ast> {
 pub struct Forest {
     krate: Crate,
     pub dep_graph: DepGraph,
-    inlined_items: TypedArena<InlinedItem>
+    inlined_bodies: TypedArena<Body>
 }
 
 impl Forest {
@@ -233,7 +221,7 @@ impl Forest {
         Forest {
             krate: krate,
             dep_graph: dep_graph.clone(),
-            inlined_items: TypedArena::new()
+            inlined_bodies: TypedArena::new()
         }
     }
 
@@ -263,20 +251,15 @@ pub struct Map<'ast> {
     ///
     /// Also, indexing is pretty quick when you've got a vector and
     /// plain old integers.
-    map: RefCell<Vec<MapEntry<'ast>>>,
+    map: Vec<MapEntry<'ast>>,
 
     definitions: Definitions,
 
-    /// All NodeIds that are numerically greater or equal to this value come
-    /// from inlined items.
-    local_node_id_watermark: NodeId,
+    /// Bodies inlined from other crates are cached here.
+    inlined_bodies: RefCell<DefIdMap<&'ast Body>>,
 }
 
 impl<'ast> Map<'ast> {
-    pub fn is_inlined_node_id(&self, id: NodeId) -> bool {
-        id >= self.local_node_id_watermark
-    }
-
     /// Registers a read in the dependency graph of the AST node with
     /// the given `id`. This needs to be called each time a public
     /// function returns the HIR for a node -- in other words, when it
@@ -289,111 +272,71 @@ impl<'ast> Map<'ast> {
     }
 
     fn dep_node(&self, id0: NodeId) -> DepNode<DefId> {
-        let map = self.map.borrow();
         let mut id = id0;
-        if !self.is_inlined_node_id(id) {
-            let mut last_expr = None;
-            loop {
-                let entry = map[id.as_usize()];
-                match entry {
-                    EntryItem(..) |
-                    EntryTraitItem(..) |
-                    EntryImplItem(..) => {
-                        if let Some(last_id) = last_expr {
-                            // The body may have a separate dep node
-                            if entry.is_body_owner(last_id) {
-                                let def_id = self.local_def_id(id);
-                                return DepNode::HirBody(def_id);
-                            }
+        let mut last_expr = None;
+        loop {
+            let entry = self.map[id.as_usize()];
+            match entry {
+                EntryItem(..) |
+                EntryTraitItem(..) |
+                EntryImplItem(..) => {
+                    if let Some(last_id) = last_expr {
+                        // The body may have a separate dep node
+                        if entry.is_body_owner(last_id) {
+                            let def_id = self.local_def_id(id);
+                            return DepNode::HirBody(def_id);
                         }
-                        return DepNode::Hir(self.local_def_id(id));
                     }
+                    return DepNode::Hir(self.local_def_id(id));
+                }
 
-                    EntryVariant(p, v) => {
-                        id = p;
+                EntryVariant(p, v) => {
+                    id = p;
 
-                        if last_expr.is_some() {
-                            if v.node.disr_expr.map(|e| e.node_id) == last_expr {
-                                // The enum parent holds both Hir and HirBody nodes.
-                                let def_id = self.local_def_id(id);
-                                return DepNode::HirBody(def_id);
-                            }
+                    if last_expr.is_some() {
+                        if v.node.disr_expr.map(|e| e.node_id) == last_expr {
+                            // The enum parent holds both Hir and HirBody nodes.
+                            let def_id = self.local_def_id(id);
+                            return DepNode::HirBody(def_id);
                         }
                     }
+                }
 
-                    EntryForeignItem(p, _) |
-                    EntryField(p, _) |
-                    EntryStmt(p, _) |
-                    EntryTy(p, _) |
-                    EntryTraitRef(p, _) |
-                    EntryLocal(p, _) |
-                    EntryPat(p, _) |
-                    EntryBlock(p, _) |
-                    EntryStructCtor(p, _) |
-                    EntryLifetime(p, _) |
-                    EntryTyParam(p, _) |
-                    EntryVisibility(p, _) =>
-                        id = p,
-
-                    EntryExpr(p, _) => {
-                        last_expr = Some(id);
-                        id = p;
-                    }
-
-                    RootCrate => {
-                        return DepNode::Hir(DefId::local(CRATE_DEF_INDEX));
-                    }
-
-                    RootInlinedParent(_) =>
-                        bug!("node {} has inlined ancestor but is not inlined", id0),
-
-                    NotPresent =>
-                        // Some nodes, notably macro definitions, are not
-                        // present in the map for whatever reason, but
-                        // they *do* have def-ids. So if we encounter an
-                        // empty hole, check for that case.
-                        return self.opt_local_def_id(id)
-                                   .map(|def_id| DepNode::Hir(def_id))
-                                   .unwrap_or_else(|| {
-                                       bug!("Walking parents from `{}` \
-                                             led to `NotPresent` at `{}`",
-                                            id0, id)
-                                   }),
+                EntryForeignItem(p, _) |
+                EntryField(p, _) |
+                EntryStmt(p, _) |
+                EntryTy(p, _) |
+                EntryTraitRef(p, _) |
+                EntryLocal(p, _) |
+                EntryPat(p, _) |
+                EntryBlock(p, _) |
+                EntryStructCtor(p, _) |
+                EntryLifetime(p, _) |
+                EntryTyParam(p, _) |
+                EntryVisibility(p, _) =>
+                    id = p,
+
+                EntryExpr(p, _) => {
+                    last_expr = Some(id);
+                    id = p;
                 }
-            }
-        } else {
-            // reading from an inlined def-id is really a read out of
-            // the metadata from which we loaded the item.
-            loop {
-                match map[id.as_usize()] {
-                    EntryItem(p, _) |
-                    EntryForeignItem(p, _) |
-                    EntryTraitItem(p, _) |
-                    EntryImplItem(p, _) |
-                    EntryVariant(p, _) |
-                    EntryField(p, _) |
-                    EntryExpr(p, _) |
-                    EntryStmt(p, _) |
-                    EntryTy(p, _) |
-                    EntryTraitRef(p, _) |
-                    EntryLocal(p, _) |
-                    EntryPat(p, _) |
-                    EntryBlock(p, _) |
-                    EntryStructCtor(p, _) |
-                    EntryLifetime(p, _) |
-                    EntryTyParam(p, _) |
-                    EntryVisibility(p, _) =>
-                        id = p,
-
-                    RootInlinedParent(parent) =>
-                        return DepNode::MetaData(parent.def_id),
-
-                    RootCrate =>
-                        bug!("node {} has crate ancestor but is inlined", id0),
-
-                    NotPresent =>
-                        bug!("node {} is inlined but not present in map", id0),
+
+                RootCrate => {
+                    return DepNode::Hir(DefId::local(CRATE_DEF_INDEX));
                 }
+
+                NotPresent =>
+                    // Some nodes, notably macro definitions, are not
+                    // present in the map for whatever reason, but
+                    // they *do* have def-ids. So if we encounter an
+                    // empty hole, check for that case.
+                    return self.opt_local_def_id(id)
+                               .map(|def_id| DepNode::Hir(def_id))
+                               .unwrap_or_else(|| {
+                                   bug!("Walking parents from `{}` \
+                                         led to `NotPresent` at `{}`",
+                                        id0, id)
+                               }),
             }
         }
     }
@@ -442,11 +385,11 @@ impl<'ast> Map<'ast> {
     }
 
     fn entry_count(&self) -> usize {
-        self.map.borrow().len()
+        self.map.len()
     }
 
     fn find_entry(&self, id: NodeId) -> Option<MapEntry<'ast>> {
-        self.map.borrow().get(id.as_usize()).cloned()
+        self.map.get(id.as_usize()).cloned()
     }
 
     pub fn krate(&self) -> &'ast Crate {
@@ -483,7 +426,7 @@ impl<'ast> Map<'ast> {
     /// for embedded constant expressions (e.g. `N` in `[T; N]`).
     pub fn body_owner(&self, BodyId { node_id }: BodyId) -> NodeId {
         let parent = self.get_parent_node(node_id);
-        if self.map.borrow()[parent.as_usize()].is_body_owner(node_id) {
+        if self.map[parent.as_usize()].is_body_owner(node_id) {
             parent
         } else {
             node_id
@@ -644,11 +587,7 @@ 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(ii)) => ii.def_id,
-            _ => self.local_def_id(parent)
-        }
+        self.local_def_id(self.get_parent(id))
     }
 
     pub fn get_foreign_abi(&self, id: NodeId) -> Abi {
@@ -660,8 +599,6 @@ impl<'ast> Map<'ast> {
                     _ => None
                 }
             }
-            /// Wrong but OK, because the only inlined foreign items are intrinsics.
-            Some(RootInlinedParent(_)) => Some(Abi::RustIntrinsic),
             _ => None
         };
         match abi {
@@ -737,11 +674,17 @@ impl<'ast> Map<'ast> {
         }
     }
 
-    pub fn expect_inlined_body(&self, id: NodeId) -> &'ast Body {
-        match self.find_entry(id) {
-            Some(RootInlinedParent(inlined_item)) => &inlined_item.body,
-            _ => bug!("expected inlined item, found {}", self.node_to_string(id)),
-        }
+    pub fn get_inlined_body(&self, def_id: DefId) -> Option<&'ast Body> {
+        self.inlined_bodies.borrow().get(&def_id).map(|&body| {
+            self.dep_graph.read(DepNode::MetaData(def_id));
+            body
+        })
+    }
+
+    pub fn intern_inlined_body(&self, def_id: DefId, body: Body) -> &'ast Body {
+        let body = self.forest.inlined_bodies.alloc(body);
+        self.inlined_bodies.borrow_mut().insert(def_id, body);
+        body
     }
 
     /// Returns the name associated with the given NodeId's AST.
@@ -824,7 +767,6 @@ impl<'ast> Map<'ast> {
             Some(EntryVisibility(_, v)) => bug!("unexpected Visibility {:?}", v),
 
             Some(RootCrate) => self.forest.krate.span,
-            Some(RootInlinedParent(parent)) => parent.body.value.span,
             Some(NotPresent) | None => {
                 bug!("hir::map::Map::span: id not in map: {:?}", id)
             }
@@ -973,41 +915,15 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest,
               entries, vector_length, (entries as f64 / vector_length as f64) * 100.);
     }
 
-    let local_node_id_watermark = NodeId::new(map.len());
-
     Map {
         forest: forest,
         dep_graph: forest.dep_graph.clone(),
-        map: RefCell::new(map),
+        map: map,
         definitions: definitions,
-        local_node_id_watermark: local_node_id_watermark,
+        inlined_bodies: RefCell::new(DefIdMap()),
     }
 }
 
-/// Used for bodies loaded from external crate that are being inlined into this
-/// crate.
-pub fn map_decoded_body<'ast>(map: &Map<'ast>,
-                              def_id: DefId,
-                              body: Body,
-                              parent_id: NodeId)
-                              -> &'ast Body {
-    let _ignore = map.forest.dep_graph.in_ignore();
-
-    let ii = map.forest.inlined_items.alloc(InlinedItem {
-        def_id: def_id,
-        body: body
-    });
-
-    let mut collector = NodeCollector::extend(map.krate(),
-                                              ii,
-                                              parent_id,
-                                              mem::replace(&mut *map.map.borrow_mut(), vec![]));
-    collector.visit_body(&ii.body);
-    *map.map.borrow_mut() = collector.map;
-
-    &ii.body
-}
-
 /// Identical to the `PpAnn` implementation for `hir::Crate`,
 /// except it avoids creating a dependency on the whole crate.
 impl<'ast> print::PpAnn for Map<'ast> {
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 7b6ed56b779..b44e1563ee7 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -27,7 +27,6 @@ use middle::region::CodeExtent;
 use middle::lang_items;
 use mir::tcx::LvalueTy;
 use ty::subst::{Kind, Subst, Substs};
-use ty::adjustment;
 use ty::{TyVid, IntVid, FloatVid};
 use ty::{self, Ty, TyCtxt};
 use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
@@ -37,10 +36,11 @@ use traits::{self, ObligationCause, PredicateObligations, Reveal};
 use rustc_data_structures::unify::{self, UnificationTable};
 use std::cell::{Cell, RefCell, Ref, RefMut};
 use std::fmt;
+use std::ops::Deref;
 use syntax::ast;
 use errors::DiagnosticBuilder;
 use syntax_pos::{self, Span, DUMMY_SP};
-use util::nodemap::{FxHashMap, FxHashSet, NodeMap};
+use util::nodemap::{FxHashMap, FxHashSet};
 use arena::DroplessArena;
 
 use self::combine::CombineFields;
@@ -76,28 +76,63 @@ pub type Bound<T> = Option<T>;
 pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
 pub type FixupResult<T> = Result<T, FixupError>; // "fixup result"
 
-/// A version of &ty::Tables which can be global or local.
-/// Only the local version supports borrow_mut.
+/// A version of &ty::Tables which can be `Missing` (not needed),
+/// `InProgress` (during typeck) or `Interned` (result of typeck).
+/// Only the `InProgress` version supports `borrow_mut`.
 #[derive(Copy, Clone)]
 pub enum InferTables<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    Global(&'a RefCell<ty::Tables<'gcx>>),
-    Local(&'a RefCell<ty::Tables<'tcx>>)
+    Interned(&'a ty::Tables<'gcx>),
+    InProgress(&'a RefCell<ty::Tables<'tcx>>),
+    Missing
+}
+
+pub enum InferTablesRef<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+    Interned(&'a ty::Tables<'gcx>),
+    InProgress(Ref<'a, ty::Tables<'tcx>>)
+}
+
+impl<'a, 'gcx, 'tcx> Deref for InferTablesRef<'a, 'gcx, 'tcx> {
+    type Target = ty::Tables<'tcx>;
+    fn deref(&self) -> &Self::Target {
+        match *self {
+            InferTablesRef::Interned(tables) => tables,
+            InferTablesRef::InProgress(ref tables) => tables
+        }
+    }
 }
 
 impl<'a, 'gcx, 'tcx> InferTables<'a, 'gcx, 'tcx> {
-    pub fn borrow(self) -> Ref<'a, ty::Tables<'tcx>> {
+    pub fn borrow(self) -> InferTablesRef<'a, 'gcx, 'tcx> {
         match self {
-            InferTables::Global(tables) => tables.borrow(),
-            InferTables::Local(tables) => tables.borrow()
+            InferTables::Interned(tables) => InferTablesRef::Interned(tables),
+            InferTables::InProgress(tables) => InferTablesRef::InProgress(tables.borrow()),
+            InferTables::Missing => {
+                bug!("InferTables: infcx.tables.borrow() with no tables")
+            }
+        }
+    }
+
+    pub fn expect_interned(self) -> &'a ty::Tables<'gcx> {
+        match self {
+            InferTables::Interned(tables) => tables,
+            InferTables::InProgress(_) => {
+                bug!("InferTables: infcx.tables.expect_interned() during type-checking");
+            }
+            InferTables::Missing => {
+                bug!("InferTables: infcx.tables.expect_interned() with no tables")
+            }
         }
     }
 
     pub fn borrow_mut(self) -> RefMut<'a, ty::Tables<'tcx>> {
         match self {
-            InferTables::Global(_) => {
+            InferTables::Interned(_) => {
                 bug!("InferTables: infcx.tables.borrow_mut() outside of type-checking");
             }
-            InferTables::Local(tables) => tables.borrow_mut()
+            InferTables::InProgress(tables) => tables.borrow_mut(),
+            InferTables::Missing => {
+                bug!("InferTables: infcx.tables.borrow_mut() with no tables")
+            }
         }
     }
 }
@@ -370,27 +405,84 @@ impl fmt::Display for FixupError {
     }
 }
 
+pub trait InferEnv<'a, 'tcx> {
+    fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                -> (Option<&'a ty::Tables<'tcx>>,
+                    Option<ty::Tables<'tcx>>,
+                    Option<ty::ParameterEnvironment<'tcx>>);
+}
+
+impl<'a, 'tcx> InferEnv<'a, 'tcx> for () {
+    fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
+                -> (Option<&'a ty::Tables<'tcx>>,
+                    Option<ty::Tables<'tcx>>,
+                    Option<ty::ParameterEnvironment<'tcx>>) {
+        (None, None, None)
+    }
+}
+
+impl<'a, 'tcx> InferEnv<'a, 'tcx> for ty::ParameterEnvironment<'tcx> {
+    fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
+                -> (Option<&'a ty::Tables<'tcx>>,
+                    Option<ty::Tables<'tcx>>,
+                    Option<ty::ParameterEnvironment<'tcx>>) {
+        (None, None, Some(self))
+    }
+}
+
+impl<'a, 'tcx> InferEnv<'a, 'tcx> for (&'a ty::Tables<'tcx>, ty::ParameterEnvironment<'tcx>) {
+    fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
+                -> (Option<&'a ty::Tables<'tcx>>,
+                    Option<ty::Tables<'tcx>>,
+                    Option<ty::ParameterEnvironment<'tcx>>) {
+        (Some(self.0), None, Some(self.1))
+    }
+}
+
+impl<'a, 'tcx> InferEnv<'a, 'tcx> for (ty::Tables<'tcx>, ty::ParameterEnvironment<'tcx>) {
+    fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
+                -> (Option<&'a ty::Tables<'tcx>>,
+                    Option<ty::Tables<'tcx>>,
+                    Option<ty::ParameterEnvironment<'tcx>>) {
+        (None, Some(self.0), Some(self.1))
+    }
+}
+
+impl<'a, 'tcx> InferEnv<'a, 'tcx> for hir::BodyId {
+    fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                -> (Option<&'a ty::Tables<'tcx>>,
+                    Option<ty::Tables<'tcx>>,
+                    Option<ty::ParameterEnvironment<'tcx>>) {
+        let item_id = tcx.map.body_owner(self);
+        (Some(tcx.item_tables(tcx.map.local_def_id(item_id))),
+         None,
+         Some(ty::ParameterEnvironment::for_item(tcx, item_id)))
+    }
+}
+
 /// Helper type of a temporary returned by tcx.infer_ctxt(...).
 /// Necessary because we can't write the following bound:
 /// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(InferCtxt<'b, 'gcx, 'tcx>).
 pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     global_tcx: TyCtxt<'a, 'gcx, 'gcx>,
     arena: DroplessArena,
-    tables: Option<RefCell<ty::Tables<'tcx>>>,
+    fresh_tables: Option<RefCell<ty::Tables<'tcx>>>,
+    tables: Option<&'a ty::Tables<'gcx>>,
     param_env: Option<ty::ParameterEnvironment<'gcx>>,
     projection_mode: Reveal,
 }
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
-    pub fn infer_ctxt(self,
-                      tables: Option<ty::Tables<'tcx>>,
-                      param_env: Option<ty::ParameterEnvironment<'gcx>>,
-                      projection_mode: Reveal)
-                      -> InferCtxtBuilder<'a, 'gcx, 'tcx> {
+    pub fn infer_ctxt<E: InferEnv<'a, 'gcx>>(self,
+                                             env: E,
+                                             projection_mode: Reveal)
+                                             -> InferCtxtBuilder<'a, 'gcx, 'tcx> {
+        let (tables, fresh_tables, param_env) = env.to_parts(self);
         InferCtxtBuilder {
             global_tcx: self,
             arena: DroplessArena::new(),
-            tables: tables.map(RefCell::new),
+            fresh_tables: fresh_tables.map(RefCell::new),
+            tables: tables,
             param_env: param_env,
             projection_mode: projection_mode,
         }
@@ -399,16 +491,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
     /// Fake InferCtxt with the global tcx. Used by pre-MIR borrowck
     /// for MemCategorizationContext/ExprUseVisitor.
     /// If any inference functionality is used, ICEs will occur.
-    pub fn borrowck_fake_infer_ctxt(self, param_env: ty::ParameterEnvironment<'gcx>)
+    pub fn borrowck_fake_infer_ctxt(self, body: hir::BodyId)
                                     -> InferCtxt<'a, 'gcx, 'gcx> {
+        let (tables, _, param_env) = body.to_parts(self);
         InferCtxt {
             tcx: self,
-            tables: InferTables::Global(&self.tables),
+            tables: InferTables::Interned(tables.unwrap()),
             type_variables: RefCell::new(type_variable::TypeVariableTable::new()),
             int_unification_table: RefCell::new(UnificationTable::new()),
             float_unification_table: RefCell::new(UnificationTable::new()),
             region_vars: RegionVarBindings::new(self),
-            parameter_environment: param_env,
+            parameter_environment: param_env.unwrap(),
             selection_cache: traits::SelectionCache::new(),
             evaluation_cache: traits::EvaluationCache::new(),
             projection_cache: RefCell::new(traits::ProjectionCache::new()),
@@ -428,15 +521,14 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
         let InferCtxtBuilder {
             global_tcx,
             ref arena,
-            ref tables,
+            ref fresh_tables,
+            tables,
             ref mut param_env,
             projection_mode,
         } = *self;
-        let tables = if let Some(ref tables) = *tables {
-            InferTables::Local(tables)
-        } else {
-            InferTables::Global(&global_tcx.tables)
-        };
+        let tables = tables.map(InferTables::Interned).unwrap_or_else(|| {
+            fresh_tables.as_ref().map_or(InferTables::Missing, InferTables::InProgress)
+        });
         let param_env = param_env.take().unwrap_or_else(|| {
             global_tcx.empty_parameter_environment()
         });
@@ -555,7 +647,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
             return value;
         }
 
-        self.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
+        self.infer_ctxt((), Reveal::All).enter(|infcx| {
             value.trans_normalize(&infcx)
         })
     }
@@ -573,7 +665,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
             return value;
         }
 
-        self.infer_ctxt(None, Some(env.clone()), Reveal::All).enter(|infcx| {
+        self.infer_ctxt(env.clone(), Reveal::All).enter(|infcx| {
             value.trans_normalize(&infcx)
        })
     }
@@ -1490,8 +1582,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             // Even if the type may have no inference variables, during
             // type-checking closure types are in local tables only.
             let local_closures = match self.tables {
-                InferTables::Local(_) => ty.has_closure_types(),
-                InferTables::Global(_) => false
+                InferTables::InProgress(_) => ty.has_closure_types(),
+                _ => false
             };
             if !local_closures {
                 return ty.moves_by_default(self.tcx.global_tcx(), self.param_env(), span);
@@ -1526,15 +1618,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             .map(|method| method.def_id)
     }
 
-    pub fn adjustments(&self) -> Ref<NodeMap<adjustment::Adjustment<'tcx>>> {
-        fn project_adjustments<'a, 'tcx>(tables: &'a ty::Tables<'tcx>)
-                                        -> &'a NodeMap<adjustment::Adjustment<'tcx>> {
-            &tables.adjustments
-        }
-
-        Ref::map(self.tables.borrow(), project_adjustments)
-    }
-
     pub fn is_method_call(&self, id: ast::NodeId) -> bool {
         self.tables.borrow().method_map.contains_key(&ty::MethodCall::expr(id))
     }
@@ -1555,15 +1638,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                         def_id: DefId)
                         -> Option<ty::ClosureKind>
     {
-        if def_id.is_local() {
-            self.tables.borrow().closure_kinds.get(&def_id).cloned()
-        } else {
-            // During typeck, ALL closures are local. But afterwards,
-            // during trans, we see closure ids from other traits.
-            // That may require loading the closure data out of the
-            // cstore.
-            Some(self.tcx.closure_kind(def_id))
+        if let InferTables::InProgress(tables) = self.tables {
+            if let Some(id) = self.tcx.map.as_local_node_id(def_id) {
+                return tables.borrow().closure_kinds.get(&id).cloned();
+            }
         }
+
+        // During typeck, ALL closures are local. But afterwards,
+        // during trans, we see closure ids from other traits.
+        // That may require loading the closure data out of the
+        // cstore.
+        Some(self.tcx.closure_kind(def_id))
     }
 
     pub fn closure_type(&self,
@@ -1571,14 +1656,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                         substs: ty::ClosureSubsts<'tcx>)
                         -> ty::ClosureTy<'tcx>
     {
-        if let InferTables::Local(tables) = self.tables {
-            if let Some(ty) = tables.borrow().closure_tys.get(&def_id) {
-                return ty.subst(self.tcx, substs.substs);
+        if let InferTables::InProgress(tables) = self.tables {
+            if let Some(id) = self.tcx.map.as_local_node_id(def_id) {
+                if let Some(ty) = tables.borrow().closure_tys.get(&id) {
+                    return ty.subst(self.tcx, substs.substs);
+                }
             }
         }
 
-        let closure_ty = self.tcx.closure_type(def_id, substs);
-        closure_ty
+        self.tcx.closure_type(def_id, substs)
     }
 }
 
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index cce79820ca8..f7f9a17ee51 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -27,7 +27,7 @@ use self::TargetLint::*;
 
 use dep_graph::DepNode;
 use middle::privacy::AccessLevels;
-use ty::TyCtxt;
+use ty::{self, TyCtxt};
 use session::{config, early_error, Session};
 use lint::{Level, LevelSource, Lint, LintId, LintPass, LintSource};
 use lint::{EarlyLintPassObject, LateLintPassObject};
@@ -336,6 +336,9 @@ pub struct LateContext<'a, 'tcx: 'a> {
     /// Type context we're checking in.
     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
+    /// Side-tables for the body we are in.
+    pub tables: &'a ty::Tables<'tcx>,
+
     /// The crate being checked.
     pub krate: &'a hir::Crate,
 
@@ -703,22 +706,6 @@ impl<'a> EarlyContext<'a> {
 }
 
 impl<'a, 'tcx> LateContext<'a, 'tcx> {
-    fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-           krate: &'a hir::Crate,
-           access_levels: &'a AccessLevels) -> LateContext<'a, 'tcx> {
-        // We want to own the lint store, so move it out of the session.
-        let lint_store = mem::replace(&mut *tcx.sess.lint_store.borrow_mut(),
-                                      LintStore::new());
-
-        LateContext {
-            tcx: tcx,
-            krate: krate,
-            access_levels: access_levels,
-            lints: lint_store,
-            level_stack: vec![],
-        }
-    }
-
     fn visit_ids<'b, F: 'b>(&'b mut self, f: F)
         where F: FnOnce(&mut IdVisitor<'b, 'a, 'tcx>)
     {
@@ -795,6 +782,14 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
         hir_visit::NestedVisitorMap::All(&self.tcx.map)
     }
 
+    fn visit_nested_body(&mut self, body: hir::BodyId) {
+        let old_tables = self.tables;
+        self.tables = self.tcx.body_tables(body);
+        let body = self.tcx.map.body(body);
+        self.visit_body(body);
+        self.tables = old_tables;
+    }
+
     fn visit_item(&mut self, it: &'tcx hir::Item) {
         self.with_lint_attrs(&it.attrs, |cx| {
             run_lints!(cx, check_item, late_passes, it);
@@ -837,10 +832,15 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
 
     fn visit_fn(&mut self, fk: hir_visit::FnKind<'tcx>, decl: &'tcx hir::FnDecl,
                 body_id: hir::BodyId, span: Span, id: ast::NodeId) {
+        // Wrap in tables here, not just in visit_nested_body,
+        // in order for `check_fn` to be able to use them.
+        let old_tables = self.tables;
+        self.tables = self.tcx.body_tables(body_id);
         let body = self.tcx.map.body(body_id);
         run_lints!(self, check_fn, late_passes, fk, decl, body, span, id);
         hir_visit::walk_fn(self, fk, decl, body_id, span, id);
         run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id);
+        self.tables = old_tables;
     }
 
     fn visit_variant_data(&mut self,
@@ -1238,7 +1238,17 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let _task = tcx.dep_graph.in_task(DepNode::LateLintCheck);
 
     let krate = tcx.map.krate();
-    let mut cx = LateContext::new(tcx, krate, access_levels);
+
+    // We want to own the lint store, so move it out of the session.
+    let lint_store = mem::replace(&mut *tcx.sess.lint_store.borrow_mut(), LintStore::new());
+    let mut cx = LateContext {
+        tcx: tcx,
+        tables: &ty::Tables::empty(),
+        krate: krate,
+        access_levels: access_levels,
+        lints: lint_store,
+        level_stack: vec![],
+    };
 
     // Visit the whole crate.
     cx.with_lint_attrs(&krate.attrs, |cx| {
diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs
index 9677082a43a..f583f601726 100644
--- a/src/librustc/middle/const_val.rs
+++ b/src/librustc/middle/const_val.rs
@@ -15,6 +15,8 @@ use hir::def_id::DefId;
 use rustc_const_math::*;
 use self::ConstVal::*;
 
+use std::collections::BTreeMap;
+
 #[derive(Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
 pub enum ConstVal {
     Float(ConstFloat),
@@ -22,16 +24,12 @@ pub enum ConstVal {
     Str(InternedString),
     ByteStr(Rc<Vec<u8>>),
     Bool(bool),
-    Struct(ast::NodeId),
-    Tuple(ast::NodeId),
     Function(DefId),
-    Array(ast::NodeId, u64),
-    Repeat(ast::NodeId, u64),
+    Struct(BTreeMap<ast::Name, ConstVal>),
+    Tuple(Vec<ConstVal>),
+    Array(Vec<ConstVal>),
+    Repeat(Box<ConstVal>, u64),
     Char(char),
-    /// A value that only occurs in case `eval_const_expr` reported an error. You should never
-    /// handle this case. Its sole purpose is to allow more errors to be reported instead of
-    /// causing a fatal error.
-    Dummy,
 }
 
 impl ConstVal {
@@ -48,7 +46,6 @@ impl ConstVal {
             Array(..) => "array",
             Repeat(..) => "repeat",
             Char(..) => "char",
-            Dummy => "dummy value",
         }
     }
 }
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 00e21410c70..5af62d0172f 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -49,6 +49,7 @@ fn should_explore<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 struct MarkSymbolVisitor<'a, 'tcx: 'a> {
     worklist: Vec<ast::NodeId>,
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    tables: &'a ty::Tables<'tcx>,
     live_symbols: Box<FxHashSet<ast::NodeId>>,
     struct_has_extern_repr: bool,
     ignore_non_const_paths: bool,
@@ -57,19 +58,6 @@ struct MarkSymbolVisitor<'a, 'tcx: 'a> {
 }
 
 impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
-    fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-           worklist: Vec<ast::NodeId>) -> MarkSymbolVisitor<'a, 'tcx> {
-        MarkSymbolVisitor {
-            worklist: worklist,
-            tcx: tcx,
-            live_symbols: box FxHashSet(),
-            struct_has_extern_repr: false,
-            ignore_non_const_paths: false,
-            inherited_pub_visibility: false,
-            ignore_variant_stack: vec![],
-        }
-    }
-
     fn check_def_id(&mut self, def_id: DefId) {
         if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
             if should_explore(self.tcx, node_id) {
@@ -109,12 +97,12 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
 
     fn lookup_and_handle_method(&mut self, id: ast::NodeId) {
         let method_call = ty::MethodCall::expr(id);
-        let method = self.tcx.tables().method_map[&method_call];
+        let method = self.tables.method_map[&method_call];
         self.check_def_id(method.def_id);
     }
 
     fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) {
-        match self.tcx.tables().expr_ty_adjusted(lhs).sty {
+        match self.tables.expr_ty_adjusted(lhs).sty {
             ty::TyAdt(def, _) => {
                 self.insert_def_id(def.struct_variant().field_named(name).did);
             }
@@ -123,7 +111,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
     }
 
     fn handle_tup_field_access(&mut self, lhs: &hir::Expr, idx: usize) {
-        match self.tcx.tables().expr_ty_adjusted(lhs).sty {
+        match self.tables.expr_ty_adjusted(lhs).sty {
             ty::TyAdt(def, _) => {
                 self.insert_def_id(def.struct_variant().fields[idx].did);
             }
@@ -134,7 +122,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
 
     fn handle_field_pattern_match(&mut self, lhs: &hir::Pat, def: Def,
                                   pats: &[codemap::Spanned<hir::FieldPat>]) {
-        let variant = match self.tcx.tables().node_id_to_type(lhs.id).sty {
+        let variant = match self.tables.node_id_to_type(lhs.id).sty {
             ty::TyAdt(adt, _) => adt.variant_of_def(def),
             _ => span_bug!(lhs.span, "non-ADT in struct pattern")
         };
@@ -209,7 +197,15 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
 
 impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.tcx.map)
+        NestedVisitorMap::None
+    }
+
+    fn visit_nested_body(&mut self, body: hir::BodyId) {
+        let old_tables = self.tables;
+        self.tables = self.tcx.body_tables(body);
+        let body = self.tcx.map.body(body);
+        self.visit_body(body);
+        self.tables = old_tables;
     }
 
     fn visit_variant_data(&mut self, def: &'tcx hir::VariantData, _: ast::Name,
@@ -227,7 +223,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
         match expr.node {
             hir::ExprPath(ref qpath @ hir::QPath::TypeRelative(..)) => {
-                let def = self.tcx.tables().qpath_def(qpath, expr.id);
+                let def = self.tables.qpath_def(qpath, expr.id);
                 self.handle_definition(def);
             }
             hir::ExprMethodCall(..) => {
@@ -267,7 +263,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
                 self.handle_field_pattern_match(pat, path.def, fields);
             }
             PatKind::Path(ref qpath @ hir::QPath::TypeRelative(..)) => {
-                let def = self.tcx.tables().qpath_def(qpath, pat.id);
+                let def = self.tables.qpath_def(qpath, pat.id);
                 self.handle_definition(def);
             }
             _ => ()
@@ -393,7 +389,16 @@ fn find_live<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                        krate: &hir::Crate)
                        -> Box<FxHashSet<ast::NodeId>> {
     let worklist = create_and_seed_worklist(tcx, access_levels, krate);
-    let mut symbol_visitor = MarkSymbolVisitor::new(tcx, worklist);
+    let mut symbol_visitor = MarkSymbolVisitor {
+        worklist: worklist,
+        tcx: tcx,
+        tables: &ty::Tables::empty(),
+        live_symbols: box FxHashSet(),
+        struct_has_extern_repr: false,
+        ignore_non_const_paths: false,
+        inherited_pub_visibility: false,
+        ignore_variant_stack: vec![],
+    };
     symbol_visitor.mark_live_symbols();
     symbol_visitor.live_symbols
 }
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index 38b0b18b012..c42e8fcb08c 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -52,6 +52,7 @@ fn type_is_unsafe_function(ty: Ty) -> bool {
 
 struct EffectCheckVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    tables: &'a ty::Tables<'tcx>,
 
     /// Whether we're in an unsafe context.
     unsafe_context: UnsafeContext,
@@ -94,7 +95,15 @@ impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> {
 
 impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.tcx.map)
+        NestedVisitorMap::None
+    }
+
+    fn visit_nested_body(&mut self, body: hir::BodyId) {
+        let old_tables = self.tables;
+        self.tables = self.tcx.body_tables(body);
+        let body = self.tcx.map.body(body);
+        self.visit_body(body);
+        self.tables = old_tables;
     }
 
     fn visit_fn(&mut self, fn_kind: FnKind<'tcx>, fn_decl: &'tcx hir::FnDecl,
@@ -163,7 +172,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> {
         match expr.node {
             hir::ExprMethodCall(..) => {
                 let method_call = MethodCall::expr(expr.id);
-                let base_type = self.tcx.tables().method_map[&method_call].ty;
+                let base_type = self.tables.method_map[&method_call].ty;
                 debug!("effect: method call case, base type is {:?}",
                         base_type);
                 if type_is_unsafe_function(base_type) {
@@ -172,7 +181,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> {
                 }
             }
             hir::ExprCall(ref base, _) => {
-                let base_type = self.tcx.tables().expr_ty_adjusted(base);
+                let base_type = self.tables.expr_ty_adjusted(base);
                 debug!("effect: call case, base type is {:?}",
                         base_type);
                 if type_is_unsafe_function(base_type) {
@@ -180,7 +189,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> {
                 }
             }
             hir::ExprUnary(hir::UnDeref, ref base) => {
-                let base_type = self.tcx.tables().expr_ty_adjusted(base);
+                let base_type = self.tables.expr_ty_adjusted(base);
                 debug!("effect: unary case, base type is {:?}",
                         base_type);
                 if let ty::TyRawPtr(_) = base_type.sty {
@@ -204,7 +213,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> {
                 }
             }
             hir::ExprField(ref base_expr, field) => {
-                if let ty::TyAdt(adt, ..) = self.tcx.tables().expr_ty_adjusted(base_expr).sty {
+                if let ty::TyAdt(adt, ..) = self.tables.expr_ty_adjusted(base_expr).sty {
                     if adt.is_union() {
                         self.require_unsafe(field.span, "access to union field");
                     }
@@ -218,7 +227,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> {
 
     fn visit_pat(&mut self, pat: &'tcx hir::Pat) {
         if let PatKind::Struct(_, ref fields, _) = pat.node {
-            if let ty::TyAdt(adt, ..) = self.tcx.tables().pat_ty(pat).sty {
+            if let ty::TyAdt(adt, ..) = self.tables.pat_ty(pat).sty {
                 if adt.is_union() {
                     for field in fields {
                         self.require_unsafe(field.span, "matching on union field");
@@ -236,6 +245,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
 
     let mut visitor = EffectCheckVisitor {
         tcx: tcx,
+        tables: &ty::Tables::empty(),
         unsafe_context: UnsafeContext::new(SafeContext),
     };
 
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index a3a49c91633..0eacbba3fdd 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -708,7 +708,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
     fn walk_adjustment(&mut self, expr: &hir::Expr) {
         let infcx = self.mc.infcx;
         //NOTE(@jroesch): mixed RefCell borrow causes crash
-        let adj = infcx.adjustments().get(&expr.id).map(|x| x.clone());
+        let adj = infcx.tables.borrow().adjustments.get(&expr.id).map(|x| x.clone());
         if let Some(adjustment) = adj {
             match adjustment.kind {
                 adjustment::Adjust::NeverToAny |
@@ -989,7 +989,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                 PatKind::Struct(ref qpath, ..) => qpath,
                 _ => return
             };
-            let def = tcx.tables().qpath_def(qpath, pat.id);
+            let def = infcx.tables.borrow().qpath_def(qpath, pat.id);
             match def {
                 Def::Variant(variant_did) |
                 Def::VariantCtor(variant_did, ..) => {
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index d932061d42d..d42b866d472 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -19,7 +19,7 @@ use ty::layout::{LayoutError, Pointer, SizeSkeleton};
 use syntax::abi::Abi::RustIntrinsic;
 use syntax::ast;
 use syntax_pos::Span;
-use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
+use hir::intravisit::{self, Visitor, NestedVisitorMap};
 use hir;
 
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
@@ -33,18 +33,6 @@ struct ItemVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>
 }
 
-impl<'a, 'tcx> ItemVisitor<'a, 'tcx> {
-    fn visit_const(&mut self, item_id: ast::NodeId, body: hir::BodyId) {
-        let param_env = ty::ParameterEnvironment::for_item(self.tcx, item_id);
-        self.tcx.infer_ctxt(None, Some(param_env), Reveal::All).enter(|infcx| {
-            let mut visitor = ExprVisitor {
-                infcx: &infcx
-            };
-            visitor.visit_nested_body(body);
-        });
-    }
-}
-
 struct ExprVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>
 }
@@ -118,64 +106,36 @@ impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> {
 
 impl<'a, 'tcx> Visitor<'tcx> for ItemVisitor<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.tcx.map)
+        NestedVisitorMap::None
     }
 
-    // const, static and N in [T; N].
-    fn visit_body(&mut self, body: &'tcx hir::Body) {
-        self.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
+    fn visit_nested_body(&mut self, body_id: hir::BodyId) {
+        let body = self.tcx.map.body(body_id);
+        self.tcx.infer_ctxt(body_id, Reveal::All).enter(|infcx| {
             let mut visitor = ExprVisitor {
                 infcx: &infcx
             };
             visitor.visit_body(body);
         });
-    }
-
-    fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
-        if let hir::TraitItemKind::Const(_, Some(body)) = item.node {
-            self.visit_const(item.id, body);
-        } else {
-            intravisit::walk_trait_item(self, item);
-        }
-    }
-
-    fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
-        if let hir::ImplItemKind::Const(_, body) = item.node {
-            self.visit_const(item.id, body);
-        } else {
-            intravisit::walk_impl_item(self, item);
-        }
-    }
-
-    fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
-                b: hir::BodyId, s: Span, id: ast::NodeId) {
-        if let FnKind::Closure(..) = fk {
-            span_bug!(s, "intrinsicck: closure outside of function")
-        }
-        let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
-        self.tcx.infer_ctxt(None, Some(param_env), Reveal::All).enter(|infcx| {
-            let mut visitor = ExprVisitor {
-                infcx: &infcx
-            };
-            visitor.visit_fn(fk, fd, b, s, id);
-        });
+        self.visit_body(body);
     }
 }
 
 impl<'a, 'gcx, 'tcx> Visitor<'gcx> for ExprVisitor<'a, 'gcx, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
-        NestedVisitorMap::OnlyBodies(&self.infcx.tcx.map)
+        NestedVisitorMap::None
     }
 
     fn visit_expr(&mut self, expr: &'gcx hir::Expr) {
         let def = if let hir::ExprPath(ref qpath) = expr.node {
-            self.infcx.tcx.tables().qpath_def(qpath, expr.id)
+            self.infcx.tables.borrow().qpath_def(qpath, expr.id)
         } else {
             Def::Err
         };
         match def {
             Def::Fn(did) if self.def_id_is_transmute(did) => {
-                let typ = self.infcx.tcx.tables().node_id_to_type(expr.id);
+                let typ = self.infcx.tables.borrow().node_id_to_type(expr.id);
+                let typ = self.infcx.tcx.lift_to_global(&typ).unwrap();
                 match typ.sty {
                     ty::TyFnDef(.., ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
                         let from = bare_fn_ty.sig.skip_binder().inputs()[0];
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 745a94a5ddb..5307b4ec774 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -351,22 +351,6 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::None
-    }
-
-    fn visit_local(&mut self, l: &'tcx hir::Local) {
-        check_local(self, l);
-    }
-    fn visit_expr(&mut self, ex: &'tcx Expr) {
-        check_expr(self, ex);
-    }
-    fn visit_arm(&mut self, a: &'tcx hir::Arm) {
-        check_arm(self, a);
-    }
-}
-
 fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
                           fk: FnKind<'tcx>,
                           decl: &'tcx hir::FnDecl,
@@ -394,24 +378,13 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
     // and so forth:
     intravisit::walk_fn(&mut fn_maps, fk, decl, body_id, sp, id);
 
-    // Special nodes and variables:
-    // - exit_ln represents the end of the fn, either by return or panic
-    // - implicit_ret_var is a pseudo-variable that represents
-    //   an implicit return
-    let specials = Specials {
-        exit_ln: fn_maps.add_live_node(ExitNode),
-        fallthrough_ln: fn_maps.add_live_node(ExitNode),
-        no_ret_var: fn_maps.add_variable(ImplicitRet),
-        clean_exit_var: fn_maps.add_variable(CleanExit)
-    };
-
     // compute liveness
-    let mut lsets = Liveness::new(&mut fn_maps, specials);
+    let mut lsets = Liveness::new(&mut fn_maps, body_id);
     let entry_ln = lsets.compute(&body.value);
 
     // check for various error conditions
     lsets.visit_body(body);
-    lsets.check_ret(id, sp, fk, entry_ln, body);
+    lsets.check_ret(id, sp, entry_ln, body);
     lsets.warn_about_unused_args(body, entry_ln);
 }
 
@@ -539,6 +512,7 @@ const ACC_USE: u32 = 4;
 
 struct Liveness<'a, 'tcx: 'a> {
     ir: &'a mut IrMaps<'a, 'tcx>,
+    tables: &'a ty::Tables<'tcx>,
     s: Specials,
     successors: Vec<LiveNode>,
     users: Vec<Users>,
@@ -553,11 +527,26 @@ struct Liveness<'a, 'tcx: 'a> {
 }
 
 impl<'a, 'tcx> Liveness<'a, 'tcx> {
-    fn new(ir: &'a mut IrMaps<'a, 'tcx>, specials: Specials) -> Liveness<'a, 'tcx> {
+    fn new(ir: &'a mut IrMaps<'a, 'tcx>, body: hir::BodyId) -> Liveness<'a, 'tcx> {
+        // Special nodes and variables:
+        // - exit_ln represents the end of the fn, either by return or panic
+        // - implicit_ret_var is a pseudo-variable that represents
+        //   an implicit return
+        let specials = Specials {
+            exit_ln: ir.add_live_node(ExitNode),
+            fallthrough_ln: ir.add_live_node(ExitNode),
+            no_ret_var: ir.add_variable(ImplicitRet),
+            clean_exit_var: ir.add_variable(CleanExit)
+        };
+
+        let tables = ir.tcx.body_tables(body);
+
         let num_live_nodes = ir.num_live_nodes;
         let num_vars = ir.num_vars;
+
         Liveness {
             ir: ir,
+            tables: tables,
             s: specials,
             successors: vec![invalid_node(); num_live_nodes],
             users: vec![invalid_users(); num_live_nodes * num_vars],
@@ -1065,7 +1054,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
           hir::ExprAssignOp(_, ref l, ref r) => {
             // an overloaded assign op is like a method call
-            if self.ir.tcx.tables().is_method_call(expr.id) {
+            if self.tables.is_method_call(expr.id) {
                 let succ = self.propagate_through_expr(&l, succ);
                 self.propagate_through_expr(&r, succ)
             } else {
@@ -1092,8 +1081,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
           hir::ExprCall(ref f, ref args) => {
             // FIXME(canndrew): This is_never should really be an is_uninhabited
-            let diverges = !self.ir.tcx.tables().is_method_call(expr.id) &&
-                self.ir.tcx.tables().expr_ty_adjusted(&f).fn_ret().0.is_never();
+            let diverges = !self.tables.is_method_call(expr.id) &&
+                self.tables.expr_ty_adjusted(&f).fn_ret().0.is_never();
             let succ = if diverges {
                 self.s.exit_ln
             } else {
@@ -1105,7 +1094,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
           hir::ExprMethodCall(.., ref args) => {
             let method_call = ty::MethodCall::expr(expr.id);
-            let method_ty = self.ir.tcx.tables().method_map[&method_call].ty;
+            let method_ty = self.tables.method_map[&method_call].ty;
             // FIXME(canndrew): This is_never should really be an is_uninhabited
             let succ = if method_ty.fn_ret().0.is_never() {
                 self.s.exit_ln
@@ -1355,6 +1344,22 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 // _______________________________________________________________________
 // Checking for error conditions
 
+impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::None
+    }
+
+    fn visit_local(&mut self, l: &'tcx hir::Local) {
+        check_local(self, l);
+    }
+    fn visit_expr(&mut self, ex: &'tcx Expr) {
+        check_expr(self, ex);
+    }
+    fn visit_arm(&mut self, a: &'tcx hir::Arm) {
+        check_arm(self, a);
+    }
+}
+
 fn check_local<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, local: &'tcx hir::Local) {
     match local.init {
         Some(_) => {
@@ -1389,7 +1394,7 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) {
       }
 
       hir::ExprAssignOp(_, ref l, _) => {
-        if !this.ir.tcx.tables().is_method_call(expr.id) {
+        if !this.tables.is_method_call(expr.id) {
             this.check_lvalue(&l);
         }
 
@@ -1432,15 +1437,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
     fn check_ret(&self,
                  id: NodeId,
                  sp: Span,
-                 fk: FnKind,
                  entry_ln: LiveNode,
                  body: &hir::Body)
     {
-        let fn_ty = if let FnKind::Closure(_) = fk {
-            self.ir.tcx.tables().node_id_to_type(id)
-        } else {
-            self.ir.tcx.item_type(self.ir.tcx.map.local_def_id(id))
-        };
+        let fn_ty = self.ir.tcx.item_type(self.ir.tcx.map.local_def_id(id));
         let fn_ret = match fn_ty.sty {
             ty::TyClosure(closure_def_id, substs) =>
                 self.ir.tcx.closure_type(closure_def_id, substs).sig.output(),
@@ -1457,8 +1457,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         if !fn_ret.is_never() && self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() {
             let param_env = ParameterEnvironment::for_item(self.ir.tcx, id);
             let t_ret_subst = fn_ret.subst(self.ir.tcx, &param_env.free_substs);
-            let is_nil = self.ir.tcx.infer_ctxt(None, Some(param_env),
-                                                Reveal::All).enter(|infcx| {
+            let is_nil = self.ir.tcx.infer_ctxt(param_env, Reveal::All).enter(|infcx| {
                 let cause = traits::ObligationCause::dummy();
                 traits::fully_normalize(&infcx, cause, &t_ret_subst).unwrap().is_nil()
             });
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 2d88567b8b8..92e69d7d729 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -384,7 +384,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
     }
 
     pub fn cat_expr(&self, expr: &hir::Expr) -> McResult<cmt<'tcx>> {
-        match self.infcx.adjustments().get(&expr.id) {
+        match self.infcx.tables.borrow().adjustments.get(&expr.id) {
             None => {
                 // No adjustments.
                 self.cat_expr_unadjusted(expr)
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 765d93742d8..6eaf3448d02 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -79,6 +79,7 @@ fn method_might_be_inlined<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 struct ReachableContext<'a, 'tcx: 'a> {
     // The type context.
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    tables: &'a ty::Tables<'tcx>,
     // The set of items which must be exported in the linkage sense.
     reachable_symbols: NodeSet,
     // A worklist of item IDs. Each item ID in this worklist will be inlined
@@ -90,17 +91,25 @@ struct ReachableContext<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx> Visitor<'tcx> for ReachableContext<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.tcx.map)
+        NestedVisitorMap::None
+    }
+
+    fn visit_nested_body(&mut self, body: hir::BodyId) {
+        let old_tables = self.tables;
+        self.tables = self.tcx.body_tables(body);
+        let body = self.tcx.map.body(body);
+        self.visit_body(body);
+        self.tables = old_tables;
     }
 
     fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
         let def = match expr.node {
             hir::ExprPath(ref qpath) => {
-                Some(self.tcx.tables().qpath_def(qpath, expr.id))
+                Some(self.tables.qpath_def(qpath, expr.id))
             }
             hir::ExprMethodCall(..) => {
                 let method_call = ty::MethodCall::expr(expr.id);
-                let def_id = self.tcx.tables.borrow().method_map[&method_call].def_id;
+                let def_id = self.tables.method_map[&method_call].def_id;
                 Some(Def::Method(def_id))
             }
             _ => None
@@ -135,20 +144,6 @@ impl<'a, 'tcx> Visitor<'tcx> for ReachableContext<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
-    // Creates a new reachability computation context.
-    fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ReachableContext<'a, 'tcx> {
-        let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| {
-            *ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib ||
-            *ty == config::CrateTypeProcMacro
-        });
-        ReachableContext {
-            tcx: tcx,
-            reachable_symbols: NodeSet(),
-            worklist: Vec::new(),
-            any_library: any_library,
-        }
-    }
-
     // Returns true if the given def ID represents a local item that is
     // eligible for inlining and false otherwise.
     fn def_id_represents_local_inlined_item(&self, def_id: DefId) -> bool {
@@ -369,7 +364,17 @@ pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                 -> NodeSet {
     let _task = tcx.dep_graph.in_task(DepNode::Reachability);
 
-    let mut reachable_context = ReachableContext::new(tcx);
+    let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| {
+        *ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib ||
+        *ty == config::CrateTypeProcMacro
+    });
+    let mut reachable_context = ReachableContext {
+        tcx: tcx,
+        tables: &ty::Tables::empty(),
+        reachable_symbols: NodeSet(),
+        worklist: Vec::new(),
+        any_library: any_library,
+    };
 
     // Step 1: Seed the worklist with all nodes which were found to be public as
     //         a result of the privacy pass along with all local lang items and impl items.
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 1d0e95245ea..5bae0e347f7 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -29,7 +29,7 @@ use std::fmt::{self, Debug, Formatter, Write};
 use std::{iter, u32};
 use std::ops::{Index, IndexMut};
 use std::vec::IntoIter;
-use syntax::ast::{self, Name};
+use syntax::ast::Name;
 use syntax_pos::Span;
 
 mod cache;
@@ -1271,17 +1271,12 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
         }
         Bool(b) => write!(fmt, "{:?}", b),
         Function(def_id) => write!(fmt, "{}", item_path_str(def_id)),
-        Struct(node_id) | Tuple(node_id) | Array(node_id, _) | Repeat(node_id, _) =>
-            write!(fmt, "{}", node_to_string(node_id)),
+        Struct(_) | Tuple(_) | Array(_) | Repeat(..) =>
+            bug!("ConstVal `{:?}` should not be in MIR", const_val),
         Char(c) => write!(fmt, "{:?}", c),
-        Dummy => bug!(),
     }
 }
 
-fn node_to_string(node_id: ast::NodeId) -> String {
-    ty::tls::with(|tcx| tcx.map.node_to_user_string(node_id))
-}
-
 fn item_path_str(def_id: DefId) -> String {
     ty::tls::with(|tcx| tcx.item_path_str(def_id))
 }
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 5c5bf130c3b..4893e240911 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -474,7 +474,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     let elaborated_env = unnormalized_env.with_caller_bounds(predicates);
 
-    tcx.infer_ctxt(None, Some(elaborated_env), Reveal::NotSpecializable).enter(|infcx| {
+    tcx.infer_ctxt(elaborated_env, Reveal::NotSpecializable).enter(|infcx| {
         let predicates = match fully_normalize(&infcx, cause,
                                                &infcx.parameter_environment.caller_bounds) {
             Ok(predicates) => predicates,
@@ -576,7 +576,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     debug!("normalize_and_test_predicates(predicates={:?})",
            predicates);
 
-    tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
+    tcx.infer_ctxt((), Reveal::All).enter(|infcx| {
         let mut selcx = SelectionContext::new(&infcx);
         let mut fulfill_cx = FulfillmentContext::new();
         let cause = ObligationCause::dummy();
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index 59e3d398b2f..0fe054b30ba 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -123,7 +123,7 @@ pub fn find_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let ancestors = trait_def.ancestors(impl_data.impl_def_id);
     match ancestors.defs(tcx, name, ty::AssociatedKind::Method).next() {
         Some(node_item) => {
-            let substs = tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
+            let substs = tcx.infer_ctxt((), Reveal::All).enter(|infcx| {
                 let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
                 let substs = translate_substs(&infcx, impl_data.impl_def_id,
                                               substs, node_item.node);
@@ -189,7 +189,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              .subst(tcx, &penv.free_substs);
 
     // Create a infcx, taking the predicates of impl1 as assumptions:
-    let result = tcx.infer_ctxt(None, Some(penv), Reveal::ExactMatch).enter(|infcx| {
+    let result = tcx.infer_ctxt(penv, Reveal::ExactMatch).enter(|infcx| {
         // Normalize the trait reference. The WF rules ought to ensure
         // that this always succeeds.
         let impl1_trait_ref =
diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs
index a41523f2def..368b1fb4bcb 100644
--- a/src/librustc/traits/specialize/specialization_graph.rs
+++ b/src/librustc/traits/specialize/specialization_graph.rs
@@ -108,7 +108,7 @@ impl<'a, 'gcx, 'tcx> Children {
             let possible_sibling = *slot;
 
             let tcx = tcx.global_tcx();
-            let (le, ge) = tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|infcx| {
+            let (le, ge) = tcx.infer_ctxt((), Reveal::ExactMatch).enter(|infcx| {
                 let overlap = traits::overlapping_impls(&infcx,
                                                         possible_sibling,
                                                         impl_def_id);
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 644df8741e8..3df64ebd158 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -65,6 +65,7 @@ pub struct GlobalArenas<'tcx> {
     trait_def: TypedArena<ty::TraitDef>,
     adt_def: TypedArena<ty::AdtDef>,
     mir: TypedArena<RefCell<Mir<'tcx>>>,
+    tables: TypedArena<ty::Tables<'tcx>>,
 }
 
 impl<'tcx> GlobalArenas<'tcx> {
@@ -75,6 +76,7 @@ impl<'tcx> GlobalArenas<'tcx> {
             trait_def: TypedArena::new(),
             adt_def: TypedArena::new(),
             mir: TypedArena::new(),
+            tables: TypedArena::new(),
         }
     }
 }
@@ -189,6 +191,7 @@ pub struct CommonTypes<'tcx> {
     pub err: Ty<'tcx>,
 }
 
+#[derive(RustcEncodable, RustcDecodable)]
 pub struct Tables<'tcx> {
     /// Resolved definitions for `<T>::X` associated paths.
     pub type_relative_path_defs: NodeMap<Def>,
@@ -211,13 +214,11 @@ pub struct Tables<'tcx> {
     /// Borrows
     pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>,
 
-    /// Records the type of each closure. The def ID is the ID of the
-    /// expression defining the closure.
-    pub closure_tys: DefIdMap<ty::ClosureTy<'tcx>>,
+    /// Records the type of each closure.
+    pub closure_tys: NodeMap<ty::ClosureTy<'tcx>>,
 
-    /// Records the type of each closure. The def ID is the ID of the
-    /// expression defining the closure.
-    pub closure_kinds: DefIdMap<ty::ClosureKind>,
+    /// Records the type of each closure.
+    pub closure_kinds: NodeMap<ty::ClosureKind>,
 
     /// For each fn, records the "liberated" types of its arguments
     /// and return type. Liberated means that all bound regions
@@ -233,7 +234,7 @@ pub struct Tables<'tcx> {
     pub fru_field_types: NodeMap<Vec<Ty<'tcx>>>
 }
 
-impl<'a, 'gcx, 'tcx> Tables<'tcx> {
+impl<'tcx> Tables<'tcx> {
     pub fn empty() -> Tables<'tcx> {
         Tables {
             type_relative_path_defs: NodeMap(),
@@ -242,8 +243,8 @@ impl<'a, 'gcx, 'tcx> Tables<'tcx> {
             adjustments: NodeMap(),
             method_map: FxHashMap(),
             upvar_capture_map: FxHashMap(),
-            closure_tys: DefIdMap(),
-            closure_kinds: DefIdMap(),
+            closure_tys: NodeMap(),
+            closure_kinds: NodeMap(),
             liberated_fn_sigs: NodeMap(),
             fru_field_types: NodeMap()
         }
@@ -401,7 +402,7 @@ pub struct GlobalCtxt<'tcx> {
     free_region_maps: RefCell<NodeMap<FreeRegionMap>>,
     // FIXME: jroesch make this a refcell
 
-    pub tables: RefCell<Tables<'tcx>>,
+    pub tables: RefCell<DepTrackingMap<maps::Tables<'tcx>>>,
 
     /// Maps from a trait item to the trait item "descriptor"
     pub associated_items: RefCell<DepTrackingMap<maps::AssociatedItems<'tcx>>>,
@@ -524,6 +525,14 @@ pub struct GlobalCtxt<'tcx> {
     /// Caches CoerceUnsized kinds for impls on custom types.
     pub custom_coerce_unsized_kinds: RefCell<DefIdMap<ty::adjustment::CustomCoerceUnsized>>,
 
+    /// Records the type of each closure. The def ID is the ID of the
+    /// expression defining the closure.
+    pub closure_tys: RefCell<DepTrackingMap<maps::ClosureTypes<'tcx>>>,
+
+    /// Records the type of each closure. The def ID is the ID of the
+    /// expression defining the closure.
+    pub closure_kinds: RefCell<DepTrackingMap<maps::ClosureKinds<'tcx>>>,
+
     /// Maps a cast expression to its kind. This is keyed on the
     /// *from* expression of the cast, not the cast itself.
     pub cast_kinds: RefCell<NodeMap<ty::cast::CastKind>>,
@@ -645,6 +654,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.global_arenas.mir.alloc(RefCell::new(mir))
     }
 
+    pub fn alloc_tables(self, tables: ty::Tables<'gcx>) -> &'gcx ty::Tables<'gcx> {
+        self.global_arenas.tables.alloc(tables)
+    }
+
     pub fn alloc_trait_def(self, def: ty::TraitDef) -> &'gcx ty::TraitDef {
         self.global_arenas.trait_def.alloc(def)
     }
@@ -743,7 +756,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             variance_computed: Cell::new(false),
             sess: s,
             trait_map: resolutions.trait_map,
-            tables: RefCell::new(Tables::empty()),
+            tables: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             impl_trait_refs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             trait_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             adt_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
@@ -777,6 +790,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             repr_hint_cache: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             rvalue_promotable_to_static: RefCell::new(NodeMap()),
             custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
+            closure_tys: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
+            closure_kinds: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             cast_kinds: RefCell::new(NodeMap()),
             fragment_infos: RefCell::new(DefIdMap()),
             crate_name: Symbol::intern(crate_name),
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index 42b3544421f..59d22d270b1 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -46,3 +46,6 @@ dep_map_ty! { ItemVariances: ItemSignature(DefId) -> Rc<Vec<ty::Variance>> }
 dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Vec<DefId> }
 dep_map_ty! { ReprHints: ReprHints(DefId) -> Rc<Vec<attr::ReprAttr>> }
 dep_map_ty! { Mir: Mir(DefId) -> &'tcx RefCell<mir::Mir<'tcx>> }
+dep_map_ty! { ClosureKinds: ItemSignature(DefId) -> ty::ClosureKind }
+dep_map_ty! { ClosureTypes: ItemSignature(DefId) -> ty::ClosureTy<'tcx> }
+dep_map_ty! { Tables: Tables(DefId) -> &'tcx ty::Tables<'tcx> }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index fa62e893a28..a88b1e3ece9 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -321,7 +321,7 @@ pub struct MethodCallee<'tcx> {
 /// needed to add to the side tables. Thus to disambiguate
 /// we also keep track of whether there's an adjustment in
 /// our key.
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct MethodCall {
     pub expr_id: NodeId,
     pub autoderef: u32
@@ -501,7 +501,7 @@ impl<T> Slice<T> {
 /// Upvars do not get their own node-id. Instead, we use the pair of
 /// the original var id (that is, the root variable that is referenced
 /// by the upvar) and the id of the closure expression.
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub struct UpvarId {
     pub var_id: NodeId,
     pub closure_expr_id: NodeId,
@@ -1917,8 +1917,30 @@ impl BorrowKind {
 }
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
-    pub fn tables(self) -> Ref<'a, Tables<'gcx>> {
-        self.tables.borrow()
+    pub fn body_tables(self, body: hir::BodyId) -> &'gcx Tables<'gcx> {
+        self.item_tables(self.map.body_owner_def_id(body))
+    }
+
+    pub fn item_tables(self, def_id: DefId) -> &'gcx Tables<'gcx> {
+        self.tables.memoize(def_id, || {
+            if def_id.is_local() {
+                // Closures' tables come from their outermost function,
+                // as they are part of the same "inference environment".
+                let outer_def_id = self.closure_base_def_id(def_id);
+                if outer_def_id != def_id {
+                    return self.item_tables(outer_def_id);
+                }
+
+                bug!("No def'n found for {:?} in tcx.tables", def_id);
+            }
+
+            // Cross-crate side-tables only exist alongside serialized HIR.
+            self.sess.cstore.maybe_get_item_body(self.global_tcx(), def_id).map(|_| {
+                self.tables.borrow()[&def_id]
+            }).unwrap_or_else(|| {
+                bug!("tcx.item_tables({:?}): missing from metadata", def_id)
+            })
+        })
     }
 
     pub fn expr_span(self, id: NodeId) -> Span {
@@ -2454,12 +2476,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         // If this is a local def-id, it should be inserted into the
         // tables by typeck; else, it will be retreived from
         // the external crate metadata.
-        if let Some(&kind) = self.tables.borrow().closure_kinds.get(&def_id) {
+        if let Some(&kind) = self.closure_kinds.borrow().get(&def_id) {
             return kind;
         }
 
         let kind = self.sess.cstore.closure_kind(def_id);
-        self.tables.borrow_mut().closure_kinds.insert(def_id, kind);
+        self.closure_kinds.borrow_mut().insert(def_id, kind);
         kind
     }
 
@@ -2471,12 +2493,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         // If this is a local def-id, it should be inserted into the
         // tables by typeck; else, it will be retreived from
         // the external crate metadata.
-        if let Some(ty) = self.tables.borrow().closure_tys.get(&def_id) {
+        if let Some(ty) = self.closure_tys.borrow().get(&def_id) {
             return ty.subst(self, substs.substs);
         }
 
         let ty = self.sess.cstore.closure_ty(self.global_tcx(), def_id);
-        self.tables.borrow_mut().closure_tys.insert(def_id, ty.clone());
+        self.closure_tys.borrow_mut().insert(def_id, ty.clone());
         ty.subst(self, substs.substs)
     }
 
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 0b1030f74b0..65bec9ecdaf 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -146,7 +146,7 @@ impl<'tcx> ParameterEnvironment<'tcx> {
                                        self_type: Ty<'tcx>, span: Span)
                                        -> Result<(), CopyImplementationError> {
         // FIXME: (@jroesch) float this code up
-        tcx.infer_ctxt(None, Some(self.clone()), Reveal::NotSpecializable).enter(|infcx| {
+        tcx.infer_ctxt(self.clone(), Reveal::NotSpecializable).enter(|infcx| {
             let (adt, substs) = match self_type.sty {
                 ty::TyAdt(adt, substs) => (adt, substs),
                 _ => return Err(CopyImplementationError::NotAnAdt)
@@ -536,7 +536,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
             }
         }
         let result =
-            tcx.infer_ctxt(None, Some(param_env.clone()), Reveal::ExactMatch)
+            tcx.infer_ctxt(param_env.clone(), Reveal::ExactMatch)
             .enter(|infcx| {
                 traits::type_known_to_meet_bound(&infcx, self, def_id, span)
             });
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index dc2214dd34e..0605644d497 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -188,12 +188,10 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                      dfcx_loans: &LoanDataFlow<'b, 'tcx>,
                                      move_data: &move_data::FlowedMoveData<'c, 'tcx>,
                                      all_loans: &[Loan<'tcx>],
-                                     fn_id: ast::NodeId,
                                      body: &hir::Body) {
     debug!("check_loans(body id={})", body.value.id);
 
-    let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);
-    let infcx = bccx.tcx.borrowck_fake_infer_ctxt(param_env);
+    let infcx = bccx.tcx.borrowck_fake_infer_ctxt(body.id());
     let mut clcx = CheckLoanCtxt {
         bccx: bccx,
         dfcx_loans: dfcx_loans,
diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
index 2c277c04a52..c33ced52e2b 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
@@ -18,7 +18,7 @@ use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::mem_categorization as mc;
 use rustc::middle::mem_categorization::Categorization;
 use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
-use rustc::ty;
+use rustc::ty::{self, Ty};
 
 use std::rc::Rc;
 use syntax::ast;
@@ -34,12 +34,10 @@ struct GatherMoveInfo<'tcx> {
 
 pub fn gather_decl<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                              move_data: &MoveData<'tcx>,
-                             decl_id: ast::NodeId,
-                             _decl_span: Span,
-                             var_id: ast::NodeId) {
-    let ty = bccx.tcx.tables().node_id_to_type(var_id);
-    let loan_path = Rc::new(LoanPath::new(LpVar(var_id), ty));
-    move_data.add_move(bccx.tcx, loan_path, decl_id, Declared);
+                             var_id: ast::NodeId,
+                             var_ty: Ty<'tcx>) {
+    let loan_path = Rc::new(LoanPath::new(LpVar(var_id), var_ty));
+    move_data.add_move(bccx.tcx, loan_path, var_id, Declared);
 }
 
 pub fn gather_move_from_expr<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index 34f1ad57c62..7101d843b4c 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -18,6 +18,7 @@
 
 use borrowck::*;
 use borrowck::move_data::MoveData;
+use rustc::infer::InferCtxt;
 use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::mem_categorization as mc;
 use rustc::middle::mem_categorization::Categorization;
@@ -25,7 +26,6 @@ use rustc::middle::region;
 use rustc::ty::{self, TyCtxt};
 
 use syntax::ast;
-use syntax::ast::NodeId;
 use syntax_pos::Span;
 use rustc::hir;
 use rustc::hir::Expr;
@@ -40,20 +40,20 @@ mod gather_moves;
 mod move_error;
 
 pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
-                                    fn_id: NodeId,
-                                    body: &hir::Body)
+                                    body: hir::BodyId)
                                     -> (Vec<Loan<'tcx>>,
                                         move_data::MoveData<'tcx>) {
+    let infcx = bccx.tcx.borrowck_fake_infer_ctxt(body);
     let mut glcx = GatherLoanCtxt {
         bccx: bccx,
+        infcx: &infcx,
         all_loans: Vec::new(),
-        item_ub: bccx.tcx.region_maps.node_extent(body.value.id),
+        item_ub: bccx.tcx.region_maps.node_extent(body.node_id),
         move_data: MoveData::new(),
         move_error_collector: move_error::MoveErrorCollector::new(),
     };
 
-    let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);
-    let infcx = bccx.tcx.borrowck_fake_infer_ctxt(param_env);
+    let body = glcx.bccx.tcx.map.body(body);
     euv::ExprUseVisitor::new(&mut glcx, &infcx).consume_body(body);
 
     glcx.report_potential_errors();
@@ -63,6 +63,7 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
 
 struct GatherLoanCtxt<'a, 'tcx: 'a> {
     bccx: &'a BorrowckCtxt<'a, 'tcx>,
+    infcx: &'a InferCtxt<'a, 'tcx, 'tcx>,
     move_data: move_data::MoveData<'tcx>,
     move_error_collector: move_error::MoveErrorCollector<'tcx>,
     all_loans: Vec<Loan<'tcx>>,
@@ -158,8 +159,9 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> {
                                         mode);
     }
 
-    fn decl_without_init(&mut self, id: ast::NodeId, span: Span) {
-        gather_moves::gather_decl(self.bccx, &self.move_data, id, span, id);
+    fn decl_without_init(&mut self, id: ast::NodeId, _span: Span) {
+        let ty = self.infcx.tables.borrow().node_id_to_type(id);
+        gather_moves::gather_decl(self.bccx, &self.move_data, id, ty);
     }
 }
 
@@ -516,19 +518,17 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
 /// sure the loans being taken are sound.
 struct StaticInitializerCtxt<'a, 'tcx: 'a> {
     bccx: &'a BorrowckCtxt<'a, 'tcx>,
-    item_id: ast::NodeId
+    body_id: hir::BodyId,
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for StaticInitializerCtxt<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.bccx.tcx.map)
+        NestedVisitorMap::None
     }
 
     fn visit_expr(&mut self, ex: &'tcx Expr) {
         if let hir::ExprAddrOf(mutbl, ref base) = ex.node {
-            let param_env = ty::ParameterEnvironment::for_item(self.bccx.tcx,
-                                                               self.item_id);
-            let infcx = self.bccx.tcx.borrowck_fake_infer_ctxt(param_env);
+            let infcx = self.bccx.tcx.borrowck_fake_infer_ctxt(self.body_id);
             let mc = mc::MemCategorizationContext::new(&infcx);
             let base_cmt = mc.cat_expr(&base).unwrap();
             let borrow_kind = ty::BorrowKind::from_mutbl(mutbl);
@@ -545,16 +545,14 @@ impl<'a, 'tcx> Visitor<'tcx> for StaticInitializerCtxt<'a, 'tcx> {
     }
 }
 
-pub fn gather_loans_in_static_initializer<'a, 'tcx>(bccx: &mut BorrowckCtxt<'a, 'tcx>,
-                                                    item_id: ast::NodeId,
-                                                    body: hir::BodyId) {
-
+pub fn gather_loans_in_static_initializer(bccx: &mut BorrowckCtxt, body: hir::BodyId) {
     debug!("gather_loans_in_static_initializer(expr={:?})", body);
 
     let mut sicx = StaticInitializerCtxt {
         bccx: bccx,
-        item_id: item_id
+        body_id: body
     };
 
-    sicx.visit_nested_body(body);
+    let body = sicx.bccx.tcx.map.body(body);
+    sicx.visit_body(body);
 }
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 1ba313015d5..c0e038d183d 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -24,7 +24,7 @@ use self::InteriorKind::*;
 
 use rustc::dep_graph::DepNode;
 use rustc::hir::map as hir_map;
-use rustc::hir::map::blocks::{FnParts, FnLikeNode};
+use rustc::hir::map::blocks::FnLikeNode;
 use rustc::cfg;
 use rustc::middle::dataflow::DataFlowContext;
 use rustc::middle::dataflow::BitwiseOperator;
@@ -89,14 +89,14 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> {
 
     fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
         if let hir::TraitItemKind::Const(_, Some(expr)) = ti.node {
-            gather_loans::gather_loans_in_static_initializer(self, ti.id, expr);
+            gather_loans::gather_loans_in_static_initializer(self, expr);
         }
         intravisit::walk_trait_item(self, ti);
     }
 
     fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
         if let hir::ImplItemKind::Const(_, expr) = ii.node {
-            gather_loans::gather_loans_in_static_initializer(self, ii.id, expr);
+            gather_loans::gather_loans_in_static_initializer(self, expr);
         }
         intravisit::walk_impl_item(self, ii);
     }
@@ -143,7 +143,7 @@ fn borrowck_item<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, item: &'tcx hir::I
     match item.node {
         hir::ItemStatic(.., ex) |
         hir::ItemConst(_, ex) => {
-            gather_loans::gather_loans_in_static_initializer(this, item.id, ex);
+            gather_loans::gather_loans_in_static_initializer(this, ex);
         }
         _ => { }
     }
@@ -179,7 +179,7 @@ fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
     let AnalysisData { all_loans,
                        loans: loan_dfcx,
                        move_data: flowed_moves } =
-        build_borrowck_dataflow_data(this, &cfg, body, id);
+        build_borrowck_dataflow_data(this, &cfg, body_id);
 
     move_data::fragments::instrument_move_fragments(&flowed_moves.move_data,
                                                     this.tcx,
@@ -189,31 +189,26 @@ fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
                                                  &flowed_moves.move_data,
                                                  id);
 
-    check_loans::check_loans(this,
-                             &loan_dfcx,
-                             &flowed_moves,
-                             &all_loans[..],
-                             id,
-                             body);
+    check_loans::check_loans(this, &loan_dfcx, &flowed_moves, &all_loans[..], body);
 
     intravisit::walk_fn(this, fk, decl, body_id, sp, id);
 }
 
 fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
                                           cfg: &cfg::CFG,
-                                          body: &'tcx hir::Body,
-                                          id: ast::NodeId)
+                                          body_id: hir::BodyId)
                                           -> AnalysisData<'a, 'tcx>
 {
     // Check the body of fn items.
     let tcx = this.tcx;
+    let body = tcx.map.body(body_id);
     let id_range = {
         let mut visitor = intravisit::IdRangeComputingVisitor::new(&tcx.map);
         visitor.visit_body(body);
         visitor.result()
     };
     let (all_loans, move_data) =
-        gather_loans::gather_loans_in_fn(this, id, body);
+        gather_loans::gather_loans_in_fn(this, body_id);
 
     let mut loan_dfcx =
         DataFlowContext::new(this.tcx,
@@ -246,7 +241,7 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
 /// the `BorrowckCtxt` itself , e.g. the flowgraph visualizer.
 pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    fn_parts: FnParts<'tcx>,
+    body: hir::BodyId,
     cfg: &cfg::CFG)
     -> (BorrowckCtxt<'a, 'tcx>, AnalysisData<'a, 'tcx>)
 {
@@ -262,13 +257,7 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>(
         }
     };
 
-    let body = tcx.map.body(fn_parts.body);
-
-    let dataflow_data = build_borrowck_dataflow_data(&mut bccx,
-                                                     cfg,
-                                                     body,
-                                                     fn_parts.id);
-
+    let dataflow_data = build_borrowck_dataflow_data(&mut bccx, cfg, body);
     (bccx, dataflow_data)
 }
 
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index 2949cf0d535..400af3c7023 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -51,6 +51,7 @@ impl<'a, 'tcx> Visitor<'tcx> for OuterVisitor<'a, 'tcx> {
 
         MatchVisitor {
             tcx: self.tcx,
+            tables: self.tcx.body_tables(b),
             param_env: &ty::ParameterEnvironment::for_item(self.tcx, id)
         }.visit_body(self.tcx.map.body(b));
     }
@@ -68,6 +69,7 @@ fn create_e0004<'a>(sess: &'a Session, sp: Span, error_message: String) -> Diagn
 
 struct MatchVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    tables: &'a ty::Tables<'tcx>,
     param_env: &'a ty::ParameterEnvironment<'tcx>
 }
 
@@ -156,7 +158,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
 
             let inlined_arms : Vec<(Vec<_>, _)> = arms.iter().map(|arm| (
                 arm.pats.iter().map(|pat| {
-                    let mut patcx = PatternContext::new(self.tcx);
+                    let mut patcx = PatternContext::new(self.tcx, self.tables);
                     let pattern = expand_pattern(cx, patcx.lower_pattern(&pat));
                     if !patcx.errors.is_empty() {
                         self.report_inlining_errors(patcx, pat.span);
@@ -181,7 +183,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
                 .flat_map(|arm| &arm.0)
                 .map(|pat| vec![pat.0])
                 .collect();
-            let scrut_ty = cx.tcx.tables().node_id_to_type(scrut.id);
+            let scrut_ty = self.tables.node_id_to_type(scrut.id);
             check_exhaustive(cx, scrut_ty, scrut.span, &matrix, source);
         })
     }
@@ -195,7 +197,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
 
         let module = self.tcx.map.local_def_id(self.tcx.map.get_module_parent(pat.id));
         MatchCheckCtxt::create_and_enter(self.tcx, module, |ref mut cx| {
-            let mut patcx = PatternContext::new(self.tcx);
+            let mut patcx = PatternContext::new(self.tcx, self.tables);
             let pattern = patcx.lower_pattern(pat);
             let pattern_ty = pattern.ty;
             let pats : Matrix = vec![vec![
@@ -228,7 +230,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
 fn check_for_bindings_named_the_same_as_variants(cx: &MatchVisitor, pat: &Pat) {
     pat.walk(|p| {
         if let PatKind::Binding(hir::BindByValue(hir::MutImmutable), _, name, None) = p.node {
-            let pat_ty = cx.tcx.tables().pat_ty(p);
+            let pat_ty = cx.tables.pat_ty(p);
             if let ty::TyAdt(edef, _) = pat_ty.sty {
                 if edef.is_enum() && edef.variants.iter().any(|variant| {
                     variant.name == name.node && variant.ctor_kind == CtorKind::Const
@@ -455,7 +457,7 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
     for pat in pats {
         pat.walk(|p| {
             if let PatKind::Binding(hir::BindByValue(..), _, _, ref sub) = p.node {
-                let pat_ty = cx.tcx.tables().node_id_to_type(p.id);
+                let pat_ty = cx.tables.node_id_to_type(p.id);
                 if pat_ty.moves_by_default(cx.tcx, cx.param_env, pat.span) {
                     check_move(p, sub.as_ref().map(|p| &**p));
                 }
@@ -470,13 +472,11 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
 ///
 /// FIXME: this should be done by borrowck.
 fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) {
-    cx.tcx.infer_ctxt(None, Some(cx.param_env.clone()),
-                      Reveal::NotSpecializable).enter(|infcx| {
+    cx.tcx.infer_ctxt((cx.tables, cx.param_env.clone()), Reveal::NotSpecializable).enter(|infcx| {
         let mut checker = MutationChecker {
             cx: cx,
         };
-        let mut visitor = ExprUseVisitor::new(&mut checker, &infcx);
-        visitor.walk_expr(guard);
+        ExprUseVisitor::new(&mut checker, &infcx).walk_expr(guard);
     });
 }
 
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 6b8e0e34c1d..bc72c8fb9b6 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -52,34 +52,24 @@ macro_rules! math {
 
 fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                   variant_def: DefId)
-                                  -> Option<&'tcx Expr> {
-    let variant_expr = |variants: &'tcx [hir::Variant], id: ast::NodeId |
-                        -> Option<&'tcx Expr> {
-        for variant in variants {
-            if variant.node.data.id() == id {
-                return variant.node.disr_expr.map(|e| {
-                    &tcx.map.body(e).value
-                });
-            }
-        }
-        None
-    };
-
+                                  -> Option<(&'tcx Expr, Option<&'a ty::Tables<'tcx>>)> {
     if let Some(variant_node_id) = tcx.map.as_local_node_id(variant_def) {
         let enum_node_id = tcx.map.get_parent(variant_node_id);
-        match tcx.map.find(enum_node_id) {
-            None => None,
-            Some(ast_map::NodeItem(it)) => match it.node {
-                hir::ItemEnum(hir::EnumDef { ref variants }, _) => {
-                    variant_expr(variants, variant_node_id)
+        if let Some(ast_map::NodeItem(it)) = tcx.map.find(enum_node_id) {
+            if let hir::ItemEnum(ref edef, _) = it.node {
+                for variant in &edef.variants {
+                    if variant.node.data.id() == variant_node_id {
+                        return variant.node.disr_expr.map(|e| {
+                            let def_id = tcx.map.body_owner_def_id(e);
+                            (&tcx.map.body(e).value,
+                             tcx.tables.borrow().get(&def_id).cloned())
+                        });
+                    }
                 }
-                _ => None
-            },
-            Some(_) => None
+            }
         }
-    } else {
-        None
     }
+    None
 }
 
 /// * `def_id` is the id of the constant.
@@ -90,17 +80,22 @@ fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                         def_id: DefId,
                                         substs: Option<&'tcx Substs<'tcx>>)
-                                        -> Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)> {
+                                        -> Option<(&'tcx Expr,
+                                                   Option<&'a ty::Tables<'tcx>>,
+                                                   Option<ty::Ty<'tcx>>)> {
     if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
         match tcx.map.find(node_id) {
             None => None,
-            Some(ast_map::NodeItem(it)) => match it.node {
-                hir::ItemConst(ref ty, body) => {
-                    Some((&tcx.map.body(body).value,
-                          tcx.ast_ty_to_prim_ty(ty)))
-                }
-                _ => None
-            },
+            Some(ast_map::NodeItem(&hir::Item {
+                node: hir::ItemConst(ref ty, body), ..
+            })) |
+            Some(ast_map::NodeImplItem(&hir::ImplItem {
+                node: hir::ImplItemKind::Const(ref ty, body), ..
+            })) => {
+                Some((&tcx.map.body(body).value,
+                      tcx.tables.borrow().get(&def_id).cloned(),
+                      tcx.ast_ty_to_prim_ty(ty)))
+            }
             Some(ast_map::NodeTraitItem(ti)) => match ti.node {
                 hir::TraitItemKind::Const(ref ty, default) => {
                     if let Some(substs) = substs {
@@ -111,6 +106,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         let trait_id = tcx.map.local_def_id(trait_id);
                         let default_value = default.map(|body| {
                             (&tcx.map.body(body).value,
+                             tcx.tables.borrow().get(&def_id).cloned(),
                              tcx.ast_ty_to_prim_ty(ty))
                         });
                         resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs)
@@ -126,18 +122,12 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 }
                 _ => None
             },
-            Some(ast_map::NodeImplItem(ii)) => match ii.node {
-                hir::ImplItemKind::Const(ref ty, body) => {
-                    Some((&tcx.map.body(body).value,
-                          tcx.ast_ty_to_prim_ty(ty)))
-                }
-                _ => None
-            },
             Some(_) => None
         }
     } else {
-        let expr_ty = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
-            (&body.value, Some(tcx.sess.cstore.item_type(tcx, def_id)))
+        let expr_tables_ty = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
+            (&body.value, Some(tcx.item_tables(def_id)),
+             Some(tcx.sess.cstore.item_type(tcx, def_id)))
         });
         match tcx.sess.cstore.describe_def(def_id) {
             Some(Def::AssociatedConst(_)) => {
@@ -148,34 +138,38 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 // substitutions for the reference to it.
                 if let Some(trait_id) = trait_id {
                     if let Some(substs) = substs {
-                        resolve_trait_associated_const(tcx, def_id, expr_ty, trait_id, substs)
+                        resolve_trait_associated_const(tcx, def_id, expr_tables_ty,
+                                                       trait_id, substs)
                     } else {
                         None
                     }
                 } else {
-                    expr_ty
+                    expr_tables_ty
                 }
             },
-            Some(Def::Const(..)) => expr_ty,
+            Some(Def::Const(..)) => expr_tables_ty,
             _ => None
         }
     }
 }
 
 fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-                                   -> Option<&'tcx hir::Body>
+                                   -> Option<(&'tcx hir::Body, Option<&'a ty::Tables<'tcx>>)>
 {
     if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
         FnLikeNode::from_node(tcx.map.get(node_id)).and_then(|fn_like| {
             if fn_like.constness() == hir::Constness::Const {
-                Some(tcx.map.body(fn_like.body()))
+                Some((tcx.map.body(fn_like.body()),
+                      tcx.tables.borrow().get(&def_id).cloned()))
             } else {
                 None
             }
         })
     } else {
         if tcx.sess.cstore.is_const_fn(def_id) {
-            tcx.sess.cstore.maybe_get_item_body(tcx, def_id)
+            tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
+                (body, Some(tcx.item_tables(def_id)))
+            })
         } else {
             None
         }
@@ -230,30 +224,38 @@ pub fn note_const_eval_err<'a, 'tcx>(
     }
 }
 
-pub fn eval_const_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                 e: &Expr) -> ConstVal {
-    match eval_const_expr_checked(tcx, e) {
-        Ok(r) => r,
-        // non-const path still needs to be a fatal error, because enums are funky
-        Err(s) => {
-            report_const_eval_err(tcx, &s, e.span, "expression").emit();
-            match s.kind {
-                NonConstPath |
-                UnimplementedConstVal(_) => tcx.sess.abort_if_errors(),
-                _ => {}
-            }
-            Dummy
-        },
-    }
+pub struct ConstContext<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    tables: Option<&'a ty::Tables<'tcx>>,
+    fn_args: Option<DefIdMap<ConstVal>>
 }
 
-pub fn eval_const_expr_checked<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                         e: &Expr) -> EvalResult
-{
-    eval_const_expr_partial(tcx, e, ExprTypeChecked, None)
-}
+impl<'a, 'tcx> ConstContext<'a, 'tcx> {
+    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, body: hir::BodyId) -> Self {
+        let def_id = tcx.map.body_owner_def_id(body);
+        ConstContext {
+            tcx: tcx,
+            tables: tcx.tables.borrow().get(&def_id).cloned(),
+            fn_args: None
+        }
+    }
 
-pub type FnArgMap<'a> = Option<&'a DefIdMap<ConstVal>>;
+    pub fn with_tables(tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::Tables<'tcx>) -> Self {
+        ConstContext {
+            tcx: tcx,
+            tables: Some(tables),
+            fn_args: None
+        }
+    }
+
+    /// Evaluate a constant expression in a context where the expression isn't
+    /// guaranteed to be evaluatable. `ty_hint` is usually ExprTypeChecked,
+    /// but a few places need to evaluate constants during type-checking, like
+    /// computing the length of an array. (See also the FIXME above EvalHint.)
+    pub fn eval(&self, e: &Expr, ty_hint: EvalHint<'tcx>) -> EvalResult {
+        eval_const_expr_partial(self, e, ty_hint)
+    }
+}
 
 #[derive(Clone, Debug)]
 pub struct ConstEvalErr {
@@ -433,20 +435,16 @@ macro_rules! signal {
     }
 }
 
-/// Evaluate a constant expression in a context where the expression isn't
-/// guaranteed to be evaluatable. `ty_hint` is usually ExprTypeChecked,
-/// but a few places need to evaluate constants during type-checking, like
-/// computing the length of an array. (See also the FIXME above EvalHint.)
-pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                         e: &Expr,
-                                         ty_hint: EvalHint<'tcx>,
-                                         fn_args: FnArgMap) -> EvalResult {
+fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
+                                     e: &Expr,
+                                     ty_hint: EvalHint<'tcx>) -> EvalResult {
+    let tcx = cx.tcx;
     // Try to compute the type of the expression based on the EvalHint.
     // (See also the definition of EvalHint, and the FIXME above EvalHint.)
     let ety = match ty_hint {
         ExprTypeChecked => {
             // After type-checking, expr_ty is guaranteed to succeed.
-            Some(tcx.tables().expr_ty(e))
+            cx.tables.map(|tables| tables.expr_ty(e))
         }
         UncheckedExprHint(ty) => {
             // Use the type hint; it's not guaranteed to be right, but it's
@@ -457,7 +455,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             // This expression might not be type-checked, and we have no hint.
             // Try to query the context for a type anyway; we might get lucky
             // (for example, if the expression was imported from another crate).
-            tcx.tables().expr_ty_opt(e)
+            cx.tables.and_then(|tables| tables.expr_ty_opt(e))
         }
     };
     let result = match e.node {
@@ -510,14 +508,14 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 _ => {},
             }
         }
-        match eval_const_expr_partial(tcx, &inner, ty_hint, fn_args)? {
+        match cx.eval(inner, ty_hint)? {
           Float(f) => Float(-f),
           Integral(i) => Integral(math!(e, -i)),
           const_val => signal!(e, NegateOn(const_val)),
         }
       }
       hir::ExprUnary(hir::UnNot, ref inner) => {
-        match eval_const_expr_partial(tcx, &inner, ty_hint, fn_args)? {
+        match cx.eval(inner, ty_hint)? {
           Integral(i) => Integral(math!(e, !i)),
           Bool(b) => Bool(!b),
           const_val => signal!(e, NotOn(const_val)),
@@ -533,8 +531,8 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // gives us a type through a type-suffix, cast or const def type
         // we need to re-eval the other value of the BinOp if it was
         // not inferred
-        match (eval_const_expr_partial(tcx, &a, ty_hint, fn_args)?,
-               eval_const_expr_partial(tcx, &b, b_ty, fn_args)?) {
+        match (cx.eval(a, ty_hint)?,
+               cx.eval(b, b_ty)?) {
           (Float(a), Float(b)) => {
             use std::cmp::Ordering::*;
             match op.node {
@@ -604,13 +602,13 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         let base_hint = if let ExprTypeChecked = ty_hint {
             ExprTypeChecked
         } else {
-            match tcx.tables().expr_ty_opt(&base) {
+            match cx.tables.and_then(|tables| tables.expr_ty_opt(&base)) {
                 Some(t) => UncheckedExprHint(t),
                 None => ty_hint
             }
         };
 
-        let val = match eval_const_expr_partial(tcx, &base, base_hint, fn_args) {
+        let val = match cx.eval(base, base_hint) {
             Ok(val) => val,
             Err(ConstEvalErr { kind: ErroneousReferencedConstant(
                 box ConstEvalErr { kind: TypeMismatch(_, val), .. }), .. }) |
@@ -623,7 +621,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     // we had a type hint, so we can't have an unknown type
                     None => bug!(),
                 };
-                eval_const_expr_partial(tcx, &base, hint, fn_args)?
+                cx.eval(base, hint)?
             },
             Err(e) => return Err(e),
         };
@@ -633,22 +631,29 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
       }
       hir::ExprPath(ref qpath) => {
-          let def = tcx.tables().qpath_def(qpath, e.id);
+          let def = cx.tables.map(|tables| tables.qpath_def(qpath, e.id)).unwrap_or_else(|| {
+            // There are no tables so we can only handle already-resolved HIR.
+            match *qpath {
+                hir::QPath::Resolved(_, ref path) => path.def,
+                hir::QPath::TypeRelative(..) => Def::Err
+            }
+          });
           match def {
               Def::Const(def_id) |
               Def::AssociatedConst(def_id) => {
                   let substs = if let ExprTypeChecked = ty_hint {
-                      Some(tcx.tables().node_id_item_substs(e.id)
+                      Some(cx.tables.and_then(|tables| tables.node_id_item_substs(e.id))
                         .unwrap_or_else(|| tcx.intern_substs(&[])))
                   } else {
                       None
                   };
-                  if let Some((expr, ty)) = lookup_const_by_id(tcx, def_id, substs) {
+                  if let Some((expr, tables, ty)) = lookup_const_by_id(tcx, def_id, substs) {
                       let item_hint = match ty {
                           Some(ty) => ty_hint.checked_or(ty),
                           None => ty_hint,
                       };
-                      match eval_const_expr_partial(tcx, expr, item_hint, None) {
+                      let cx = ConstContext { tcx: tcx, tables: tables, fn_args: None };
+                      match cx.eval(expr, item_hint) {
                           Ok(val) => val,
                           Err(err) => {
                               debug!("bad reference: {:?}, {:?}", err.description(), err.span);
@@ -660,8 +665,9 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                   }
               },
               Def::VariantCtor(variant_def, ..) => {
-                  if let Some(const_expr) = lookup_variant_by_id(tcx, variant_def) {
-                      match eval_const_expr_partial(tcx, const_expr, ty_hint, None) {
+                  if let Some((expr, tables)) = lookup_variant_by_id(tcx, variant_def) {
+                      let cx = ConstContext { tcx: tcx, tables: tables, fn_args: None };
+                      match cx.eval(expr, ty_hint) {
                           Ok(val) => val,
                           Err(err) => {
                               debug!("bad reference: {:?}, {:?}", err.description(), err.span);
@@ -673,11 +679,11 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                   }
               }
               Def::StructCtor(..) => {
-                  ConstVal::Struct(e.id)
+                  ConstVal::Struct(Default::default())
               }
               Def::Local(def_id) => {
-                  debug!("Def::Local({:?}): {:?}", def_id, fn_args);
-                  if let Some(val) = fn_args.and_then(|args| args.get(&def_id)) {
+                  debug!("Def::Local({:?}): {:?}", def_id, cx.fn_args);
+                  if let Some(val) = cx.fn_args.as_ref().and_then(|args| args.get(&def_id)) {
                       val.clone()
                   } else {
                       signal!(e, NonConstPath);
@@ -690,14 +696,14 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
       }
       hir::ExprCall(ref callee, ref args) => {
           let sub_ty_hint = ty_hint.erase_hint();
-          let callee_val = eval_const_expr_partial(tcx, callee, sub_ty_hint, fn_args)?;
+          let callee_val = cx.eval(callee, sub_ty_hint)?;
           let did = match callee_val {
               Function(did) => did,
               Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")),
               callee => signal!(e, CallOn(callee)),
           };
-          let body = match lookup_const_fn_by_id(tcx, did) {
-              Some(body) => body,
+          let (body, tables) = match lookup_const_fn_by_id(tcx, did) {
+              Some(x) => x,
               None => signal!(e, NonConstPath),
           };
 
@@ -710,19 +716,19 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
           let mut call_args = DefIdMap();
           for (arg, arg_expr) in arg_defs.into_iter().zip(args.iter()) {
               let arg_hint = ty_hint.erase_hint();
-              let arg_val = eval_const_expr_partial(
-                  tcx,
-                  arg_expr,
-                  arg_hint,
-                  fn_args
-              )?;
+              let arg_val = cx.eval(arg_expr, arg_hint)?;
               debug!("const call arg: {:?}", arg);
               if let Some(def_id) = arg {
                 assert!(call_args.insert(def_id, arg_val).is_none());
               }
           }
           debug!("const call({:?})", call_args);
-          eval_const_expr_partial(tcx, &body.value, ty_hint, Some(&call_args))?
+          let callee_cx = ConstContext {
+            tcx: tcx,
+            tables: tables,
+            fn_args: Some(call_args)
+          };
+          callee_cx.eval(&body.value, ty_hint)?
       },
       hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) {
           Ok(val) => val,
@@ -730,46 +736,49 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
       },
       hir::ExprBlock(ref block) => {
         match block.expr {
-            Some(ref expr) => eval_const_expr_partial(tcx, &expr, ty_hint, fn_args)?,
+            Some(ref expr) => cx.eval(expr, ty_hint)?,
             None => signal!(e, UnimplementedConstVal("empty block")),
         }
       }
-      hir::ExprType(ref e, _) => eval_const_expr_partial(tcx, &e, ty_hint, fn_args)?,
-      hir::ExprTup(_) => Tuple(e.id),
-      hir::ExprStruct(..) => Struct(e.id),
+      hir::ExprType(ref e, _) => cx.eval(e, ty_hint)?,
+      hir::ExprTup(ref fields) => {
+        let field_hint = ty_hint.erase_hint();
+        Tuple(fields.iter().map(|e| cx.eval(e, field_hint)).collect::<Result<_, _>>()?)
+      }
+      hir::ExprStruct(_, ref fields, _) => {
+        let field_hint = ty_hint.erase_hint();
+        Struct(fields.iter().map(|f| {
+            cx.eval(&f.expr, field_hint).map(|v| (f.name.node, v))
+        }).collect::<Result<_, _>>()?)
+      }
       hir::ExprIndex(ref arr, ref idx) => {
         if !tcx.sess.features.borrow().const_indexing {
             signal!(e, IndexOpFeatureGated);
         }
         let arr_hint = ty_hint.erase_hint();
-        let arr = eval_const_expr_partial(tcx, arr, arr_hint, fn_args)?;
+        let arr = cx.eval(arr, arr_hint)?;
         let idx_hint = ty_hint.checked_or(tcx.types.usize);
-        let idx = match eval_const_expr_partial(tcx, idx, idx_hint, fn_args)? {
+        let idx = match cx.eval(idx, idx_hint)? {
             Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
             Integral(_) => bug!(),
             _ => signal!(idx, IndexNotInt),
         };
         assert_eq!(idx as usize as u64, idx);
         match arr {
-            Array(_, n) if idx >= n => {
-                signal!(e, IndexOutOfBounds { len: n, index: idx })
+            Array(ref v) => {
+                if let Some(elem) = v.get(idx as usize) {
+                    elem.clone()
+                } else {
+                    let n = v.len() as u64;
+                    assert_eq!(n as usize as u64, n);
+                    signal!(e, IndexOutOfBounds { len: n, index: idx })
+                }
             }
-            Array(v, n) => if let hir::ExprArray(ref v) = tcx.map.expect_expr(v).node {
-                assert_eq!(n as usize as u64, n);
-                eval_const_expr_partial(tcx, &v[idx as usize], ty_hint, fn_args)?
-            } else {
-                bug!()
-            },
 
-            Repeat(_, n) if idx >= n => {
+            Repeat(.., n) if idx >= n => {
                 signal!(e, IndexOutOfBounds { len: n, index: idx })
             }
-            Repeat(elem, _) => eval_const_expr_partial(
-                tcx,
-                &tcx.map.expect_expr(elem),
-                ty_hint,
-                fn_args,
-            )?,
+            Repeat(ref elem, _) => (**elem).clone(),
 
             ByteStr(ref data) if idx >= data.len() as u64 => {
                 signal!(e, IndexOutOfBounds { len: data.len() as u64, index: idx })
@@ -781,31 +790,38 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             _ => signal!(e, IndexedNonVec),
         }
       }
-      hir::ExprArray(ref v) => Array(e.id, v.len() as u64),
-      hir::ExprRepeat(_, n) => {
+      hir::ExprArray(ref v) => {
+        let elem_hint = ty_hint.erase_hint();
+        Array(v.iter().map(|e| cx.eval(e, elem_hint)).collect::<Result<_, _>>()?)
+      }
+      hir::ExprRepeat(ref elem, count) => {
+          let elem_hint = ty_hint.erase_hint();
           let len_hint = ty_hint.checked_or(tcx.types.usize);
-          let n = &tcx.map.body(n).value;
-          Repeat(
-              e.id,
-              match eval_const_expr_partial(tcx, n, len_hint, fn_args)? {
-                  Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
-                  Integral(_) => signal!(e, RepeatCountNotNatural),
-                  _ => signal!(e, RepeatCountNotInt),
-              },
-          )
+          let n = if let Some(ty) = ety {
+            // For cross-crate constants, we have the type already,
+            // but not the body for `count`, so use the type.
+            match ty.sty {
+                ty::TyArray(_, n) => n as u64,
+                _ => bug!()
+            }
+          } else {
+            let n = &tcx.map.body(count).value;
+            match ConstContext::new(tcx, count).eval(n, len_hint)? {
+                Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
+                Integral(_) => signal!(e, RepeatCountNotNatural),
+                _ => signal!(e, RepeatCountNotInt),
+            }
+          };
+          Repeat(Box::new(cx.eval(elem, elem_hint)?), n)
       },
       hir::ExprTupField(ref base, index) => {
         let base_hint = ty_hint.erase_hint();
-        let c = eval_const_expr_partial(tcx, base, base_hint, fn_args)?;
-        if let Tuple(tup_id) = c {
-            if let hir::ExprTup(ref fields) = tcx.map.expect_expr(tup_id).node {
-                if index.node < fields.len() {
-                    eval_const_expr_partial(tcx, &fields[index.node], ty_hint, fn_args)?
-                } else {
-                    signal!(e, TupleIndexOutOfBounds);
-                }
+        let c = cx.eval(base, base_hint)?;
+        if let Tuple(ref fields) = c {
+            if let Some(elem) = fields.get(index.node) {
+                elem.clone()
             } else {
-                bug!()
+                signal!(e, TupleIndexOutOfBounds);
             }
         } else {
             signal!(base, ExpectedConstTuple);
@@ -813,20 +829,12 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
       }
       hir::ExprField(ref base, field_name) => {
         let base_hint = ty_hint.erase_hint();
-        // Get the base expression if it is a struct and it is constant
-        let c = eval_const_expr_partial(tcx, base, base_hint, fn_args)?;
-        if let Struct(struct_id) = c {
-            if let hir::ExprStruct(_, ref fields, _) = tcx.map.expect_expr(struct_id).node {
-                // Check that the given field exists and evaluate it
-                // if the idents are compared run-pass/issue-19244 fails
-                if let Some(f) = fields.iter().find(|f| f.name.node
-                                                     == field_name.node) {
-                    eval_const_expr_partial(tcx, &f.expr, ty_hint, fn_args)?
-                } else {
-                    signal!(e, MissingStructField);
-                }
+        let c = cx.eval(base, base_hint)?;
+        if let Struct(ref fields) = c {
+            if let Some(f) = fields.get(&field_name.node) {
+                f.clone()
             } else {
-                bug!()
+                signal!(e, MissingStructField);
             }
         } else {
             signal!(base, ExpectedConstStruct);
@@ -909,17 +917,17 @@ fn infer<'a, 'tcx>(i: ConstInt,
 fn resolve_trait_associated_const<'a, 'tcx: 'a>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     trait_item_id: DefId,
-    default_value: Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)>,
+    default_value: Option<(&'tcx Expr, Option<&'a ty::Tables<'tcx>>, Option<ty::Ty<'tcx>>)>,
     trait_id: DefId,
     rcvr_substs: &'tcx Substs<'tcx>
-) -> Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)>
+) -> Option<(&'tcx Expr, Option<&'a ty::Tables<'tcx>>, Option<ty::Ty<'tcx>>)>
 {
     let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs));
     debug!("resolve_trait_associated_const: trait_ref={:?}",
            trait_ref);
 
     tcx.populate_implementations_for_trait_if_necessary(trait_id);
-    tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
+    tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
         let mut selcx = traits::SelectionContext::new(&infcx);
         let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
                                                  trait_ref.to_poly_trait_predicate());
@@ -1160,36 +1168,40 @@ pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal)
     }
 }
 
-pub fn compare_lit_exprs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                   span: Span,
-                                   a: &Expr,
-                                   b: &Expr) -> Result<Ordering, ErrorReported> {
-    let a = match eval_const_expr_partial(tcx, a, ExprTypeChecked, None) {
-        Ok(a) => a,
-        Err(e) => {
-            report_const_eval_err(tcx, &e, a.span, "expression").emit();
-            return Err(ErrorReported);
-        }
-    };
-    let b = match eval_const_expr_partial(tcx, b, ExprTypeChecked, None) {
-        Ok(b) => b,
-        Err(e) => {
-            report_const_eval_err(tcx, &e, b.span, "expression").emit();
-            return Err(ErrorReported);
-        }
-    };
-    compare_const_vals(tcx, span, &a, &b)
+impl<'a, 'tcx> ConstContext<'a, 'tcx> {
+    pub fn compare_lit_exprs(&self,
+                             span: Span,
+                             a: &Expr,
+                             b: &Expr) -> Result<Ordering, ErrorReported> {
+        let tcx = self.tcx;
+        let a = match self.eval(a, ExprTypeChecked) {
+            Ok(a) => a,
+            Err(e) => {
+                report_const_eval_err(tcx, &e, a.span, "expression").emit();
+                return Err(ErrorReported);
+            }
+        };
+        let b = match self.eval(b, ExprTypeChecked) {
+            Ok(b) => b,
+            Err(e) => {
+                report_const_eval_err(tcx, &e, b.span, "expression").emit();
+                return Err(ErrorReported);
+            }
+        };
+        compare_const_vals(tcx, span, &a, &b)
+    }
 }
 
 
 /// Returns the value of the length-valued expression
 pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                             count_expr: &hir::Expr,
+                             count: hir::BodyId,
                              reason: &str)
                              -> Result<usize, ErrorReported>
 {
     let hint = UncheckedExprHint(tcx.types.usize);
-    match eval_const_expr_partial(tcx, count_expr, hint, None) {
+    let count_expr = &tcx.map.body(count).value;
+    match ConstContext::new(tcx, count).eval(count_expr, hint) {
         Ok(Integral(Usize(count))) => {
             let val = count.as_u64(tcx.sess.target.uint_type);
             assert_eq!(val as usize as u64, val);
diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs
index 42394f4745f..fbd15b6eb10 100644
--- a/src/librustc_const_eval/pattern.rs
+++ b/src/librustc_const_eval/pattern.rs
@@ -119,8 +119,7 @@ fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result {
         ConstVal::Tuple(_) |
         ConstVal::Function(_) |
         ConstVal::Array(..) |
-        ConstVal::Repeat(..) |
-        ConstVal::Dummy => bug!("{:?} not printable in a pattern", value)
+        ConstVal::Repeat(..) => bug!("{:?} not printable in a pattern", value)
     }
 }
 
@@ -261,12 +260,15 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
 
 pub struct PatternContext<'a, 'gcx: 'tcx, 'tcx: 'a> {
     pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
+    pub tables: &'a ty::Tables<'gcx>,
     pub errors: Vec<PatternError>,
 }
 
 impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
-    pub fn from_hir(tcx: TyCtxt<'a, 'gcx, 'tcx>, pat: &hir::Pat) -> Self {
-        let mut pcx = PatternContext::new(tcx);
+    pub fn from_hir(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                    tables: &'a ty::Tables<'gcx>,
+                    pat: &hir::Pat) -> Self {
+        let mut pcx = PatternContext::new(tcx, tables);
         let result = pcx.lower_pattern(pat);
         if !pcx.errors.is_empty() {
             span_bug!(pat.span, "encountered errors lowering pattern: {:?}", pcx.errors)
@@ -277,12 +279,12 @@ impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
 }
 
 impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
-    pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self {
-        PatternContext { tcx: tcx, errors: vec![] }
+    pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, tables: &'a ty::Tables<'gcx>) -> Self {
+        PatternContext { tcx: tcx, tables: tables, errors: vec![] }
     }
 
     pub fn lower_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> {
-        let mut ty = self.tcx.tables().node_id_to_type(pat.id);
+        let mut ty = self.tables.node_id_to_type(pat.id);
 
         let kind = match pat.node {
             PatKind::Wild => PatternKind::Wild,
@@ -309,7 +311,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
             }
 
             PatKind::Slice(ref prefix, ref slice, ref suffix) => {
-                let ty = self.tcx.tables().node_id_to_type(pat.id);
+                let ty = self.tables.node_id_to_type(pat.id);
                 match ty.sty {
                     ty::TyRef(_, mt) =>
                         PatternKind::Deref {
@@ -334,7 +336,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
             }
 
             PatKind::Tuple(ref subpatterns, ddpos) => {
-                let ty = self.tcx.tables().node_id_to_type(pat.id);
+                let ty = self.tables.node_id_to_type(pat.id);
                 match ty.sty {
                     ty::TyTuple(ref tys) => {
                         let subpatterns =
@@ -355,7 +357,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
 
             PatKind::Binding(bm, def_id, ref ident, ref sub) => {
                 let id = self.tcx.map.as_local_node_id(def_id).unwrap();
-                let var_ty = self.tcx.tables().node_id_to_type(pat.id);
+                let var_ty = self.tables.node_id_to_type(pat.id);
                 let region = match var_ty.sty {
                     ty::TyRef(r, _) => Some(r),
                     _ => None,
@@ -392,7 +394,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
             }
 
             PatKind::TupleStruct(ref qpath, ref subpatterns, ddpos) => {
-                let def = self.tcx.tables().qpath_def(qpath, pat.id);
+                let def = self.tables.qpath_def(qpath, pat.id);
                 let adt_def = match ty.sty {
                     ty::TyAdt(adt_def, _) => adt_def,
                     _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT"),
@@ -411,7 +413,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
             }
 
             PatKind::Struct(ref qpath, ref fields, _) => {
-                let def = self.tcx.tables().qpath_def(qpath, pat.id);
+                let def = self.tables.qpath_def(qpath, pat.id);
                 let adt_def = match ty.sty {
                     ty::TyAdt(adt_def, _) => adt_def,
                     _ => {
@@ -569,16 +571,21 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
                   pat_id: ast::NodeId,
                   span: Span)
                   -> Pattern<'tcx> {
-        let ty = self.tcx.tables().node_id_to_type(id);
-        let def = self.tcx.tables().qpath_def(qpath, id);
+        let ty = self.tables.node_id_to_type(id);
+        let def = self.tables.qpath_def(qpath, id);
         let kind = match def {
             Def::Const(def_id) | Def::AssociatedConst(def_id) => {
                 let tcx = self.tcx.global_tcx();
-                let substs = tcx.tables().node_id_item_substs(id)
+                let substs = self.tables.node_id_item_substs(id)
                     .unwrap_or_else(|| tcx.intern_substs(&[]));
                 match eval::lookup_const_by_id(tcx, def_id, Some(substs)) {
-                    Some((const_expr, _const_ty)) => {
-                        return self.lower_const_expr(const_expr, pat_id, span);
+                    Some((const_expr, const_tables, _const_ty)) => {
+                        // Enter the inlined constant's tables temporarily.
+                        let old_tables = self.tables;
+                        self.tables = const_tables.expect("missing tables after typeck");
+                        let pat = self.lower_const_expr(const_expr, pat_id, span);
+                        self.tables = old_tables;
+                        return pat;
                     }
                     None => {
                         self.errors.push(PatternError::StaticInPattern(span));
@@ -597,7 +604,8 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
     }
 
     fn lower_lit(&mut self, expr: &hir::Expr) -> PatternKind<'tcx> {
-        match eval::eval_const_expr_checked(self.tcx.global_tcx(), expr) {
+        let const_cx = eval::ConstContext::with_tables(self.tcx.global_tcx(), self.tables);
+        match const_cx.eval(expr, eval::EvalHint::ExprTypeChecked) {
             Ok(value) => {
                 PatternKind::Constant { value: value }
             }
@@ -613,7 +621,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
                         pat_id: ast::NodeId,
                         span: Span)
                         -> Pattern<'tcx> {
-        let pat_ty = self.tcx.tables().expr_ty(expr);
+        let pat_ty = self.tables.expr_ty(expr);
         debug!("expr={:?} pat_ty={:?} pat_id={}", expr, pat_ty, pat_id);
         match pat_ty.sty {
             ty::TyFloat(_) => {
@@ -659,8 +667,8 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
                     hir::ExprPath(ref qpath) => qpath,
                     _ => bug!()
                 };
-                let ty = self.tcx.tables().node_id_to_type(callee.id);
-                let def = self.tcx.tables().qpath_def(qpath, callee.id);
+                let ty = self.tables.node_id_to_type(callee.id);
+                let def = self.tables.qpath_def(qpath, callee.id);
                 match def {
                     Def::Fn(..) | Def::Method(..) => self.lower_lit(expr),
                     _ => {
@@ -676,8 +684,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
             }
 
             hir::ExprStruct(ref qpath, ref fields, None) => {
-                let def = self.tcx.tables().qpath_def(qpath, expr.id);
-                let pat_ty = self.tcx.tables().node_id_to_type(expr.id);
+                let def = self.tables.qpath_def(qpath, expr.id);
                 let adt_def = match pat_ty.sty {
                     ty::TyAdt(adt_def, _) => adt_def,
                     _ => {
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index cc288619cde..afacfb6e3f9 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -39,6 +39,7 @@ use syntax_pos;
 
 use graphviz as dot;
 
+use std::cell::Cell;
 use std::fs::File;
 use std::io::{self, Write};
 use std::iter;
@@ -236,7 +237,11 @@ impl PpSourceMode {
                                                                  arenas,
                                                                  id,
                                                                  |tcx, _, _, _| {
-                    let annotation = TypedAnnotation { tcx: tcx };
+                    let empty_tables = ty::Tables::empty();
+                    let annotation = TypedAnnotation {
+                        tcx: tcx,
+                        tables: Cell::new(&empty_tables)
+                    };
                     let _ignore = tcx.dep_graph.in_ignore();
                     f(&annotation, payload, ast_map.forest.krate())
                 }),
@@ -488,6 +493,7 @@ impl<'ast> pprust::PpAnn for HygieneAnnotation<'ast> {
 
 struct TypedAnnotation<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    tables: Cell<&'a ty::Tables<'tcx>>,
 }
 
 impl<'b, 'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'b, 'tcx> {
@@ -511,7 +517,13 @@ impl<'b, 'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'b, 'tcx> {
 impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> {
     fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested)
               -> io::Result<()> {
-        pprust_hir::PpAnn::nested(&self.tcx.map, state, nested)
+        let old_tables = self.tables.get();
+        if let pprust_hir::Nested::Body(id) = nested {
+            self.tables.set(self.tcx.body_tables(id));
+        }
+        pprust_hir::PpAnn::nested(&self.tcx.map, state, nested)?;
+        self.tables.set(old_tables);
+        Ok(())
     }
     fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
         match node {
@@ -525,7 +537,7 @@ impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> {
                 pp::space(&mut s.s)?;
                 pp::word(&mut s.s, "as")?;
                 pp::space(&mut s.s)?;
-                pp::word(&mut s.s, &self.tcx.tables().expr_ty(expr).to_string())?;
+                pp::word(&mut s.s, &self.tables.get().expr_ty(expr).to_string())?;
                 s.pclose()
             }
             _ => Ok(()),
@@ -751,7 +763,7 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec<borrowck_dot::Variant>,
         }
         blocks::Code::FnLike(fn_like) => {
             let (bccx, analysis_data) =
-                borrowck::build_borrowck_dataflow_data_for_fn(tcx, fn_like.to_fn_parts(), &cfg);
+                borrowck::build_borrowck_dataflow_data_for_fn(tcx, fn_like.body(), &cfg);
 
             let lcfg = borrowck_dot::DataflowLabeller {
                 inner: lcfg,
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 887e586a311..ede35d052ad 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -149,7 +149,7 @@ fn test_env<F>(source_string: &str,
                              index,
                              "test_crate",
                              |tcx| {
-        tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
+        tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
 
             body(Env { infcx: &infcx });
             let free_regions = FreeRegionMap::new();
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index c021ffee818..8d86e7e2e8b 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -138,7 +138,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxPointers {
     }
 
     fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
-        let ty = cx.tcx.tables().node_id_to_type(e.id);
+        let ty = cx.tables.node_id_to_type(e.id);
         self.check_heap_type(cx, e.span, ty);
     }
 }
@@ -738,8 +738,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
             // is this a recursive call?
             let self_recursive = if node_id != ast::DUMMY_NODE_ID {
                 match method {
-                    Some(ref method) => expr_refers_to_this_method(cx.tcx, method, node_id),
-                    None => expr_refers_to_this_fn(cx.tcx, id, node_id),
+                    Some(ref method) => expr_refers_to_this_method(cx, method, node_id),
+                    None => expr_refers_to_this_fn(cx, id, node_id),
                 }
             } else {
                 false
@@ -787,43 +787,42 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
         // Functions for identifying if the given Expr NodeId `id`
         // represents a call to the function `fn_id`/method `method`.
 
-        fn expr_refers_to_this_fn(tcx: TyCtxt, fn_id: ast::NodeId, id: ast::NodeId) -> bool {
-            match tcx.map.get(id) {
+        fn expr_refers_to_this_fn(cx: &LateContext, fn_id: ast::NodeId, id: ast::NodeId) -> bool {
+            match cx.tcx.map.get(id) {
                 hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => {
                     let def = if let hir::ExprPath(ref qpath) = callee.node {
-                        tcx.tables().qpath_def(qpath, callee.id)
+                        cx.tables.qpath_def(qpath, callee.id)
                     } else {
                         return false;
                     };
-                    def.def_id() == tcx.map.local_def_id(fn_id)
+                    def.def_id() == cx.tcx.map.local_def_id(fn_id)
                 }
                 _ => false,
             }
         }
 
         // Check if the expression `id` performs a call to `method`.
-        fn expr_refers_to_this_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                                method: &ty::AssociatedItem,
-                                                id: ast::NodeId)
-                                                -> bool {
+        fn expr_refers_to_this_method(cx: &LateContext,
+                                      method: &ty::AssociatedItem,
+                                      id: ast::NodeId)
+                                      -> bool {
             use rustc::ty::adjustment::*;
 
             // Check for method calls and overloaded operators.
-            let opt_m = tcx.tables().method_map.get(&ty::MethodCall::expr(id)).cloned();
+            let opt_m = cx.tables.method_map.get(&ty::MethodCall::expr(id)).cloned();
             if let Some(m) = opt_m {
-                if method_call_refers_to_method(tcx, method, m.def_id, m.substs, id) {
+                if method_call_refers_to_method(cx.tcx, method, m.def_id, m.substs, id) {
                     return true;
                 }
             }
 
             // Check for overloaded autoderef method calls.
-            let opt_adj = tcx.tables().adjustments.get(&id).cloned();
+            let opt_adj = cx.tables.adjustments.get(&id).cloned();
             if let Some(Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) = opt_adj {
                 for i in 0..autoderefs {
                     let method_call = ty::MethodCall::autoderef(id, i as u32);
-                    if let Some(m) = tcx.tables().method_map.get(&method_call)
-                                                            .cloned() {
-                        if method_call_refers_to_method(tcx, method, m.def_id, m.substs, id) {
+                    if let Some(m) = cx.tables.method_map.get(&method_call).cloned() {
+                        if method_call_refers_to_method(cx.tcx, method, m.def_id, m.substs, id) {
                             return true;
                         }
                     }
@@ -831,19 +830,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
             }
 
             // Check for calls to methods via explicit paths (e.g. `T::method()`).
-            match tcx.map.get(id) {
+            match cx.tcx.map.get(id) {
                 hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => {
                     let def = if let hir::ExprPath(ref qpath) = callee.node {
-                        tcx.tables().qpath_def(qpath, callee.id)
+                        cx.tables.qpath_def(qpath, callee.id)
                     } else {
                         return false;
                     };
                     match def {
                         Def::Method(def_id) => {
-                            let substs = tcx.tables().node_id_item_substs(callee.id)
-                                .unwrap_or_else(|| tcx.intern_substs(&[]));
+                            let substs = cx.tables.node_id_item_substs(callee.id)
+                                .unwrap_or_else(|| cx.tcx.intern_substs(&[]));
                             method_call_refers_to_method(
-                                tcx, method, def_id, substs, id)
+                                cx.tcx, method, def_id, substs, id)
                         }
                         _ => false,
                     }
@@ -882,8 +881,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
                     // checking, so it's always local
                     let node_id = tcx.map.as_local_node_id(method.def_id).unwrap();
 
-                    let param_env = Some(ty::ParameterEnvironment::for_item(tcx, node_id));
-                    tcx.infer_ctxt(None, param_env, Reveal::NotSpecializable).enter(|infcx| {
+                    let param_env = ty::ParameterEnvironment::for_item(tcx, node_id);
+                    tcx.infer_ctxt(param_env, Reveal::NotSpecializable).enter(|infcx| {
                         let mut selcx = traits::SelectionContext::new(&infcx);
                         match selcx.select(&obligation) {
                             // The method comes from a `T: Trait` bound.
@@ -1073,7 +1072,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes {
              expr: &hir::Expr)
              -> Option<(&'tcx ty::TypeVariants<'tcx>, &'tcx ty::TypeVariants<'tcx>)> {
             let def = if let hir::ExprPath(ref qpath) = expr.node {
-                cx.tcx.tables().qpath_def(qpath, expr.id)
+                cx.tables.qpath_def(qpath, expr.id)
             } else {
                 return None;
             };
@@ -1081,7 +1080,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes {
                 if !def_id_is_transmute(cx, did) {
                     return None;
                 }
-                let typ = cx.tcx.tables().node_id_to_type(expr.id);
+                let typ = cx.tables.node_id_to_type(expr.id);
                 match typ.sty {
                     ty::TyFnDef(.., ref bare_fn) if bare_fn.abi == RustIntrinsic => {
                         let from = bare_fn.sig.skip_binder().inputs()[0];
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 570365c407f..2a77e9a4a7c 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -16,7 +16,7 @@ use rustc::ty::{self, AdtKind, Ty, TyCtxt};
 use rustc::ty::layout::{Layout, Primitive};
 use rustc::traits::Reveal;
 use middle::const_val::ConstVal;
-use rustc_const_eval::eval_const_expr_partial;
+use rustc_const_eval::ConstContext;
 use rustc_const_eval::EvalHint::ExprTypeChecked;
 use util::nodemap::FxHashSet;
 use lint::{LateContext, LintContext, LintArray};
@@ -89,14 +89,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
                 }
             }
             hir::ExprBinary(binop, ref l, ref r) => {
-                if is_comparison(binop) && !check_limits(cx.tcx, binop, &l, &r) {
+                if is_comparison(binop) && !check_limits(cx, binop, &l, &r) {
                     cx.span_lint(UNUSED_COMPARISONS,
                                  e.span,
                                  "comparison is useless due to type limits");
                 }
 
                 if binop.node.is_shift() {
-                    let opt_ty_bits = match cx.tcx.tables().node_id_to_type(l.id).sty {
+                    let opt_ty_bits = match cx.tables.node_id_to_type(l.id).sty {
                         ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.int_type)),
                         ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.uint_type)),
                         _ => None,
@@ -110,7 +110,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
                                 false
                             }
                         } else {
-                            match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked, None) {
+                            let const_cx = ConstContext::with_tables(cx.tcx, cx.tables);
+                            match const_cx.eval(&r, ExprTypeChecked) {
                                 Ok(ConstVal::Integral(i)) => {
                                     i.is_negative() ||
                                     i.to_u64()
@@ -129,7 +130,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
                 }
             }
             hir::ExprLit(ref lit) => {
-                match cx.tcx.tables().node_id_to_type(e.id).sty {
+                match cx.tables.node_id_to_type(e.id).sty {
                     ty::TyInt(t) => {
                         match lit.node {
                             ast::LitKind::Int(v, ast::LitIntType::Signed(_)) |
@@ -274,11 +275,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
             }
         }
 
-        fn check_limits<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                  binop: hir::BinOp,
-                                  l: &hir::Expr,
-                                  r: &hir::Expr)
-                                  -> bool {
+        fn check_limits(cx: &LateContext,
+                        binop: hir::BinOp,
+                        l: &hir::Expr,
+                        r: &hir::Expr)
+                        -> bool {
             let (lit, expr, swap) = match (&l.node, &r.node) {
                 (&hir::ExprLit(_), _) => (l, r, true),
                 (_, &hir::ExprLit(_)) => (r, l, false),
@@ -287,7 +288,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
             // Normalize the binop so that the literal is always on the RHS in
             // the comparison
             let norm_binop = if swap { rev_binop(binop) } else { binop };
-            match tcx.tables().node_id_to_type(expr.id).sty {
+            match cx.tables.node_id_to_type(expr.id).sty {
                 ty::TyInt(int_ty) => {
                     let (min, max) = int_ty_range(int_ty);
                     let lit_val: i128 = match lit.node {
@@ -696,7 +697,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
             if gens.ty_params.is_empty() {
                 // sizes only make sense for non-generic types
                 let t = cx.tcx.item_type(cx.tcx.map.local_def_id(it.id));
-                let layout = cx.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
+                let layout = cx.tcx.infer_ctxt((), Reveal::All).enter(|infcx| {
                     let ty = cx.tcx.erase_regions(&t);
                     ty.layout(&infcx).unwrap_or_else(|e| {
                         bug!("failed to get layout for `{}`: {}", t, e)
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index b7ee688117d..48d9f5e72c2 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -139,7 +139,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
             return;
         }
 
-        let t = cx.tcx.tables().expr_ty(&expr);
+        let t = cx.tables.expr_ty(&expr);
         let warned = match t.sty {
             ty::TyTuple(ref tys) if tys.is_empty() => return,
             ty::TyNever => return,
@@ -440,7 +440,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAllocation {
             _ => return,
         }
 
-        if let Some(adjustment) = cx.tcx.tables().adjustments.get(&e.id) {
+        if let Some(adjustment) = cx.tables.adjustments.get(&e.id) {
             if let adjustment::Adjust::DerefRef { autoref, .. } = adjustment.kind {
                 match autoref {
                     Some(adjustment::AutoBorrow::Ref(_, hir::MutImmutable)) => {
diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs
index b27b164bd47..3c14d38cc38 100644
--- a/src/librustc_metadata/astencode.rs
+++ b/src/librustc_metadata/astencode.rs
@@ -8,59 +8,31 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::hir::map as ast_map;
+use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
 
-use rustc::hir::intravisit::{Visitor, IdRangeComputingVisitor, IdRange, NestedVisitorMap};
-
-use cstore::CrateMetadata;
 use encoder::EncodeContext;
 use schema::*;
 
 use rustc::hir;
-use rustc::hir::def::Def;
-use rustc::hir::def_id::DefId;
-use rustc::ty::{self, TyCtxt, Ty};
-
-use syntax::ast;
+use rustc::ty;
 
 use rustc_serialize::Encodable;
 
 #[derive(RustcEncodable, RustcDecodable)]
 pub struct Ast<'tcx> {
-    id_range: IdRange,
-    body: Lazy<hir::Body>,
-    side_tables: LazySeq<(ast::NodeId, TableEntry<'tcx>)>,
+    pub body: Lazy<hir::Body>,
+    pub tables: Lazy<ty::Tables<'tcx>>,
     pub nested_bodies: LazySeq<hir::Body>,
     pub rvalue_promotable_to_static: bool,
 }
 
-#[derive(RustcEncodable, RustcDecodable)]
-enum TableEntry<'tcx> {
-    TypeRelativeDef(Def),
-    NodeType(Ty<'tcx>),
-    ItemSubsts(ty::ItemSubsts<'tcx>),
-    Adjustment(ty::adjustment::Adjustment<'tcx>),
-}
-
 impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
-    pub fn encode_body(&mut self, body: hir::BodyId) -> Lazy<Ast<'tcx>> {
-        let body = self.tcx.map.body(body);
-
-        let mut id_visitor = IdRangeComputingVisitor::new(&self.tcx.map);
-        id_visitor.visit_body(body);
+    pub fn encode_body(&mut self, body_id: hir::BodyId) -> Lazy<Ast<'tcx>> {
+        let body = self.tcx.map.body(body_id);
+        let lazy_body = self.lazy(body);
 
-        let body_pos = self.position();
-        body.encode(self).unwrap();
-
-        let tables_pos = self.position();
-        let tables_count = {
-            let mut visitor = SideTableEncodingIdVisitor {
-                ecx: self,
-                count: 0,
-            };
-            visitor.visit_body(body);
-            visitor.count
-        };
+        let tables = self.tcx.body_tables(body_id);
+        let lazy_tables = self.lazy(tables);
 
         let nested_pos = self.position();
         let nested_count = {
@@ -76,44 +48,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             self.tcx.rvalue_promotable_to_static.borrow()[&body.value.id];
 
         self.lazy(&Ast {
-            id_range: id_visitor.result(),
-            body: Lazy::with_position(body_pos),
-            side_tables: LazySeq::with_position_and_length(tables_pos, tables_count),
+            body: lazy_body,
+            tables: lazy_tables,
             nested_bodies: LazySeq::with_position_and_length(nested_pos, nested_count),
             rvalue_promotable_to_static: rvalue_promotable_to_static
         })
     }
 }
 
-struct SideTableEncodingIdVisitor<'a, 'b: 'a, 'tcx: 'b> {
-    ecx: &'a mut EncodeContext<'b, 'tcx>,
-    count: usize,
-}
-
-impl<'a, 'b, 'tcx> Visitor<'tcx> for SideTableEncodingIdVisitor<'a, 'b, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.ecx.tcx.map)
-    }
-
-    fn visit_id(&mut self, id: ast::NodeId) {
-        debug!("Encoding side tables for id {}", id);
-
-        let tcx = self.ecx.tcx;
-        let mut encode = |entry: Option<TableEntry>| {
-            if let Some(entry) = entry {
-                (id, entry).encode(self.ecx).unwrap();
-                self.count += 1;
-            }
-        };
-
-        encode(tcx.tables().type_relative_path_defs.get(&id).cloned()
-                  .map(TableEntry::TypeRelativeDef));
-        encode(tcx.tables().node_types.get(&id).cloned().map(TableEntry::NodeType));
-        encode(tcx.tables().item_substs.get(&id).cloned().map(TableEntry::ItemSubsts));
-        encode(tcx.tables().adjustments.get(&id).cloned().map(TableEntry::Adjustment));
-    }
-}
-
 struct NestedBodyEncodingVisitor<'a, 'b: 'a, 'tcx: 'b> {
     ecx: &'a mut EncodeContext<'b, 'tcx>,
     count: usize,
@@ -132,41 +74,3 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for NestedBodyEncodingVisitor<'a, 'b, 'tcx> {
         self.visit_body(body);
     }
 }
-
-/// Decodes an item's body from its AST in the cdata's metadata and adds it to the
-/// ast-map.
-pub fn decode_body<'a, 'tcx>(cdata: &CrateMetadata,
-                             tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                             def_id: DefId,
-                             ast: Ast<'tcx>)
-                             -> &'tcx hir::Body {
-    debug!("> Decoding inlined fn: {}", tcx.item_path_str(def_id));
-
-    let cnt = ast.id_range.max.as_usize() - ast.id_range.min.as_usize();
-    let start = tcx.sess.reserve_node_ids(cnt);
-    let id_ranges = [ast.id_range,
-                     IdRange {
-                         min: start,
-                         max: ast::NodeId::new(start.as_usize() + cnt),
-                     }];
-
-    for (id, entry) in ast.side_tables.decode((cdata, tcx, id_ranges)) {
-        match entry {
-            TableEntry::TypeRelativeDef(def) => {
-                tcx.tables.borrow_mut().type_relative_path_defs.insert(id, def);
-            }
-            TableEntry::NodeType(ty) => {
-                tcx.tables.borrow_mut().node_types.insert(id, ty);
-            }
-            TableEntry::ItemSubsts(item_substs) => {
-                tcx.tables.borrow_mut().item_substs.insert(id, item_substs);
-            }
-            TableEntry::Adjustment(adj) => {
-                tcx.tables.borrow_mut().adjustments.insert(id, adj);
-            }
-        }
-    }
-
-    let body = ast.body.decode((cdata, tcx, id_ranges));
-    ast_map::map_decoded_body(&tcx.map, def_id, body, tcx.sess.next_node_id())
-}
diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs
index aab4034b770..efc19abb33e 100644
--- a/src/librustc_metadata/cstore.rs
+++ b/src/librustc_metadata/cstore.rs
@@ -97,7 +97,6 @@ pub struct CStore {
     used_link_args: RefCell<Vec<String>>,
     statically_included_foreign_items: RefCell<FxHashSet<DefIndex>>,
     pub dllimport_foreign_items: RefCell<FxHashSet<DefIndex>>,
-    pub inlined_item_cache: RefCell<DefIdMap<Option<ast::NodeId>>>,
     pub visible_parent_map: RefCell<DefIdMap<DefId>>,
 }
 
@@ -112,7 +111,6 @@ impl CStore {
             statically_included_foreign_items: RefCell::new(FxHashSet()),
             dllimport_foreign_items: RefCell::new(FxHashSet()),
             visible_parent_map: RefCell::new(FxHashMap()),
-            inlined_item_cache: RefCell::new(FxHashMap()),
         }
     }
 
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 64513fa41b2..3d025e984b0 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -434,27 +434,14 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
                                def_id: DefId)
                                -> Option<&'tcx hir::Body>
     {
-        self.dep_graph.read(DepNode::MetaData(def_id));
-
-        if let Some(&cached) = self.inlined_item_cache.borrow().get(&def_id) {
-            return cached.map(|root_id| {
-                // Already inline
-                debug!("maybe_get_item_body({}): already inline", tcx.item_path_str(def_id));
-                tcx.map.expect_inlined_body(root_id)
-            });
+        if let Some(cached) = tcx.map.get_inlined_body(def_id) {
+            return Some(cached);
         }
 
+        self.dep_graph.read(DepNode::MetaData(def_id));
         debug!("maybe_get_item_body({}): inlining item", tcx.item_path_str(def_id));
 
-        let inlined = self.get_crate_data(def_id.krate).maybe_get_item_body(tcx, def_id.index);
-
-        self.inlined_item_cache.borrow_mut().insert(def_id, inlined.map(|body| {
-            let root_id = tcx.map.get_parent_node(body.value.id);
-            assert_eq!(tcx.map.get_parent_node(root_id), root_id);
-            root_id
-        }));
-
-        inlined
+        self.get_crate_data(def_id.krate).maybe_get_item_body(tcx, def_id.index)
     }
 
     fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body> {
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index dad956afb5e..f3a673898b2 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -10,13 +10,11 @@
 
 // Decoding metadata from a single crate's metadata
 
-use astencode::decode_body;
 use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary};
 use schema::*;
 
 use rustc::hir::map::{DefKey, DefPath, DefPathData};
 use rustc::hir;
-use rustc::hir::intravisit::IdRange;
 
 use rustc::middle::cstore::LinkagePreference;
 use rustc::hir::def::{self, Def, CtorKind};
@@ -40,7 +38,7 @@ use std::u32;
 
 use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque};
 use syntax::attr;
-use syntax::ast::{self, NodeId};
+use syntax::ast;
 use syntax::codemap;
 use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP};
 use rustc_i128::{u128, i128};
@@ -50,8 +48,6 @@ pub struct DecodeContext<'a, 'tcx: 'a> {
     cdata: Option<&'a CrateMetadata>,
     sess: Option<&'a Session>,
     tcx: Option<TyCtxt<'a, 'tcx, 'tcx>>,
-    from_id_range: IdRange,
-    to_id_range: IdRange,
 
     // Cache the last used filemap for translating spans as an optimization.
     last_filemap_index: usize,
@@ -67,18 +63,12 @@ pub trait Metadata<'a, 'tcx>: Copy {
     fn tcx(self) -> Option<TyCtxt<'a, 'tcx, 'tcx>> { None }
 
     fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> {
-        let id_range = IdRange {
-            min: NodeId::from_u32(u32::MIN),
-            max: NodeId::from_u32(u32::MAX),
-        };
         let tcx = self.tcx();
         DecodeContext {
             opaque: opaque::Decoder::new(self.raw_bytes(), pos),
             cdata: self.cdata(),
             sess: self.sess().or(tcx.map(|tcx| tcx.sess)),
             tcx: tcx,
-            from_id_range: id_range,
-            to_id_range: id_range,
             last_filemap_index: 0,
             lazy_state: LazyState::NoNode,
         }
@@ -128,26 +118,6 @@ impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, TyCtxt<'a, 'tcx, 'tcx>
     }
 }
 
-// HACK(eddyb) Only used by astencode to customize the from/to IdRange's.
-impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, TyCtxt<'a, 'tcx, 'tcx>, [IdRange; 2]) {
-    fn raw_bytes(self) -> &'a [u8] {
-        self.0.raw_bytes()
-    }
-    fn cdata(self) -> Option<&'a CrateMetadata> {
-        Some(self.0)
-    }
-    fn tcx(self) -> Option<TyCtxt<'a, 'tcx, 'tcx>> {
-        Some(self.1)
-    }
-
-    fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> {
-        let mut dcx = (self.0, self.1).decoder(pos);
-        dcx.from_id_range = self.2[0];
-        dcx.to_id_range = self.2[1];
-        dcx
-    }
-}
-
 impl<'a, 'tcx: 'a, T: Decodable> Lazy<T> {
     pub fn decode<M: Metadata<'a, 'tcx>>(self, meta: M) -> T {
         let mut dcx = meta.decoder(self.position);
@@ -256,28 +226,6 @@ impl<'a, 'tcx, T> SpecializedDecoder<LazySeq<T>> for DecodeContext<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> SpecializedDecoder<NodeId> for DecodeContext<'a, 'tcx> {
-    fn specialized_decode(&mut self) -> Result<NodeId, Self::Error> {
-        let id = u32::decode(self)?;
-
-        // from_id_range should be non-empty
-        assert!(!self.from_id_range.empty());
-        // Make sure that translating the NodeId will actually yield a
-        // meaningful result
-        if !self.from_id_range.contains(NodeId::from_u32(id)) {
-            bug!("NodeId::decode: {} out of DecodeContext range ({:?} -> {:?})",
-                 id,
-                 self.from_id_range,
-                 self.to_id_range);
-        }
-
-        // Use wrapping arithmetic because otherwise it introduces control flow.
-        // Maybe we should just have the control flow? -- aatch
-        Ok(NodeId::from_u32(id.wrapping_sub(self.from_id_range.min.as_u32())
-            .wrapping_add(self.to_id_range.min.as_u32())))
-    }
-}
-
 impl<'a, 'tcx> SpecializedDecoder<CrateNum> for DecodeContext<'a, 'tcx> {
     fn specialized_decode(&mut self) -> Result<CrateNum, Self::Error> {
         let cnum = CrateNum::from_u32(u32::decode(self)?);
@@ -829,7 +777,14 @@ impl<'a, 'tcx> CrateMetadata {
                                -> Option<&'tcx hir::Body> {
         if self.is_proc_macro(id) { return None; }
         self.entry(id).ast.map(|ast| {
-            decode_body(self, tcx, self.local_def_id(id), ast.decode(self))
+            let def_id = self.local_def_id(id);
+            let ast = ast.decode(self);
+
+            let tables = ast.tables.decode((self, tcx));
+            tcx.tables.borrow_mut().insert(def_id, tcx.alloc_tables(tables));
+
+            let body = ast.body.decode((self, tcx));
+            tcx.map.intern_inlined_body(def_id, body)
         })
     }
 
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index c3bcdf42d4e..7de768b7b90 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -1037,7 +1037,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         let data = ClosureData {
             kind: tcx.closure_kind(def_id),
-            ty: self.lazy(&tcx.tables().closure_tys[&def_id]),
+            ty: self.lazy(&tcx.closure_tys.borrow()[&def_id]),
         };
 
         Entry {
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index cfdc1bf27df..7347841a5f1 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -169,7 +169,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
     let upvar_decls: Vec<_> = tcx.with_freevars(fn_id, |freevars| {
         freevars.iter().map(|fv| {
             let var_id = tcx.map.as_local_node_id(fv.def.def_id()).unwrap();
-            let by_ref = tcx.tables().upvar_capture(ty::UpvarId {
+            let by_ref = hir.tables().upvar_capture(ty::UpvarId {
                 var_id: var_id,
                 closure_expr_id: fn_id
             }).map_or(false, |capture| match capture {
@@ -195,13 +195,12 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
 }
 
 pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
-                                       item_id: ast::NodeId,
                                        body_id: hir::BodyId)
                                        -> Mir<'tcx> {
     let tcx = hir.tcx();
     let ast_expr = &tcx.map.body(body_id).value;
-    let ty = tcx.tables().expr_ty_adjusted(ast_expr);
-    let span = tcx.map.span(item_id);
+    let ty = hir.tables().expr_ty_adjusted(ast_expr);
+    let span = tcx.map.span(tcx.map.body_owner(body_id));
     let mut builder = Builder::new(hir, span, 0, ty);
 
     let extent = tcx.region_maps.temporary_scope(ast_expr.id)
@@ -306,7 +305,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             let lvalue = Lvalue::Local(Local::new(index + 1));
 
             if let Some(pattern) = pattern {
-                let pattern = Pattern::from_hir(self.hir.tcx(), pattern);
+                let pattern = Pattern::from_hir(self.hir.tcx(), self.hir.tables(), pattern);
                 scope = self.declare_bindings(scope, ast_body.span, &pattern);
                 unpack!(block = self.lvalue_into_pattern(block, pattern, &lvalue));
             }
diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs
index b355c8f2c4c..4b3d62fd6d6 100644
--- a/src/librustc_mir/hair/cx/block.rs
+++ b/src/librustc_mir/hair/cx/block.rs
@@ -61,7 +61,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                         let remainder_extent =
                             cx.tcx.region_maps.lookup_code_extent(remainder_extent);
 
-                        let pattern = Pattern::from_hir(cx.tcx, &local.pat);
+                        let pattern = Pattern::from_hir(cx.tcx, cx.tables(), &local.pat);
                         result.push(StmtRef::Mirror(Box::new(Stmt {
                             span: stmt.span,
                             kind: StmtKind::Let {
@@ -82,7 +82,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 pub fn to_expr_ref<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                    block: &'tcx hir::Block)
                                    -> ExprRef<'tcx> {
-    let block_ty = cx.tcx.tables().node_id_to_type(block.id);
+    let block_ty = cx.tables().node_id_to_type(block.id);
     let temp_lifetime = cx.tcx.region_maps.temporary_scope(block.id);
     let expr = Expr {
         ty: block_ty,
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index cc65fdede09..fe10fb57c35 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -17,7 +17,7 @@ use hair::cx::to_ref::ToRef;
 use rustc::hir::map;
 use rustc::hir::def::{Def, CtorKind};
 use rustc::middle::const_val::ConstVal;
-use rustc_const_eval as const_eval;
+use rustc_const_eval::{ConstContext, EvalHint, fatal_const_eval_err};
 use rustc::ty::{self, AdtKind, VariantDef, Ty};
 use rustc::ty::cast::CastKind as TyCastKind;
 use rustc::hir;
@@ -33,7 +33,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
         debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span);
 
         let mut expr = make_mirror_unadjusted(cx, self);
-        let adj = cx.tcx.tables().adjustments.get(&self.id).cloned();
+        let adj = cx.tables().adjustments.get(&self.id).cloned();
 
         debug!("make_mirror: unadjusted-expr={:?} applying adjustments={:?}",
                expr,
@@ -80,13 +80,13 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
                     let i = i as u32;
                     let adjusted_ty =
                         expr.ty.adjust_for_autoderef(cx.tcx, self.id, self.span, i, |mc| {
-                            cx.tcx.tables().method_map.get(&mc).map(|m| m.ty)
+                            cx.tables().method_map.get(&mc).map(|m| m.ty)
                         });
                     debug!("make_mirror: autoderef #{}, adjusted_ty={:?}",
                            i,
                            adjusted_ty);
                     let method_key = ty::MethodCall::autoderef(self.id, i);
-                    let meth_ty = cx.tcx.tables().method_map.get(&method_key).map(|m| m.ty);
+                    let meth_ty = cx.tables().method_map.get(&method_key).map(|m| m.ty);
                     let kind = if let Some(meth_ty) = meth_ty {
                         debug!("make_mirror: overloaded autoderef (meth_ty={:?})", meth_ty);
 
@@ -217,7 +217,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
 fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                           expr: &'tcx hir::Expr)
                                           -> Expr<'tcx> {
-    let expr_ty = cx.tcx.tables().expr_ty(expr);
+    let expr_ty = cx.tables().expr_ty(expr);
     let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
 
     let kind = match expr.node {
@@ -236,7 +236,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprCall(ref fun, ref args) => {
-            if cx.tcx.tables().is_method_call(expr.id) {
+            if cx.tables().is_method_call(expr.id) {
                 // The callee is something implementing Fn, FnMut, or FnOnce.
                 // Find the actual method implementation being called and
                 // build the appropriate UFCS call expression with the
@@ -285,9 +285,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     None
                 };
                 if let Some((adt_def, index)) = adt_data {
-                    let substs = cx.tcx
-                        .tables()
-                        .node_id_item_substs(fun.id)
+                    let substs = cx.tables().node_id_item_substs(fun.id)
                         .unwrap_or_else(|| cx.tcx.intern_substs(&[]));
                     let field_refs = args.iter()
                         .enumerate()
@@ -307,7 +305,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     }
                 } else {
                     ExprKind::Call {
-                        ty: cx.tcx.tables().node_id_to_type(fun.id),
+                        ty: cx.tables().node_id_to_type(fun.id),
                         fun: fun.to_ref(),
                         args: args.to_ref(),
                     }
@@ -337,7 +335,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprAssignOp(op, ref lhs, ref rhs) => {
-            if cx.tcx.tables().is_method_call(expr.id) {
+            if cx.tables().is_method_call(expr.id) {
                 let pass_args = if op.node.is_by_value() {
                     PassArgs::ByValue
                 } else {
@@ -361,7 +359,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         hir::ExprLit(..) => ExprKind::Literal { literal: cx.const_eval_literal(expr) },
 
         hir::ExprBinary(op, ref lhs, ref rhs) => {
-            if cx.tcx.tables().is_method_call(expr.id) {
+            if cx.tables().is_method_call(expr.id) {
                 let pass_args = if op.node.is_by_value() {
                     PassArgs::ByValue
                 } else {
@@ -421,7 +419,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprIndex(ref lhs, ref index) => {
-            if cx.tcx.tables().is_method_call(expr.id) {
+            if cx.tables().is_method_call(expr.id) {
                 overloaded_lvalue(cx,
                                   expr,
                                   ty::MethodCall::expr(expr.id),
@@ -437,7 +435,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprUnary(hir::UnOp::UnDeref, ref arg) => {
-            if cx.tcx.tables().is_method_call(expr.id) {
+            if cx.tables().is_method_call(expr.id) {
                 overloaded_lvalue(cx,
                                   expr,
                                   ty::MethodCall::expr(expr.id),
@@ -450,7 +448,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprUnary(hir::UnOp::UnNot, ref arg) => {
-            if cx.tcx.tables().is_method_call(expr.id) {
+            if cx.tables().is_method_call(expr.id) {
                 overloaded_operator(cx,
                                     expr,
                                     ty::MethodCall::expr(expr.id),
@@ -466,7 +464,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => {
-            if cx.tcx.tables().is_method_call(expr.id) {
+            if cx.tables().is_method_call(expr.id) {
                 overloaded_operator(cx,
                                     expr,
                                     ty::MethodCall::expr(expr.id),
@@ -500,8 +498,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                 base: base.as_ref().map(|base| {
                                     FruInfo {
                                         base: base.to_ref(),
-                                        field_types: cx.tcx.tables().fru_field_types[&expr.id]
-                                            .clone(),
+                                        field_types: cx.tables().fru_field_types[&expr.id].clone(),
                                     }
                                 }),
                             }
@@ -541,7 +538,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprClosure(..) => {
-            let closure_ty = cx.tcx.tables().expr_ty(expr);
+            let closure_ty = cx.tables().expr_ty(expr);
             let (def_id, substs) = match closure_ty.sty {
                 ty::TyClosure(def_id, substs) => (def_id, substs),
                 _ => {
@@ -562,7 +559,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprPath(ref qpath) => {
-            let def = cx.tcx.tables().qpath_def(qpath, expr.id);
+            let def = cx.tables().qpath_def(qpath, expr.id);
             convert_path_expr(cx, expr, def)
         }
 
@@ -575,17 +572,21 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         // Now comes the rote stuff:
-        hir::ExprRepeat(ref v, c) => {
-            let c = &cx.tcx.map.body(c).value;
+        hir::ExprRepeat(ref v, count) => {
+            let tcx = cx.tcx.global_tcx();
+            let c = &cx.tcx.map.body(count).value;
+            let count = match ConstContext::new(tcx, count).eval(c, EvalHint::ExprTypeChecked) {
+                Ok(ConstVal::Integral(ConstInt::Usize(u))) => u,
+                Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other),
+                Err(s) => fatal_const_eval_err(tcx, &s, c.span, "expression")
+            };
+
             ExprKind::Repeat {
                 value: v.to_ref(),
                 count: TypedConstVal {
-                    ty: cx.tcx.tables().expr_ty(c),
+                    ty: cx.tcx.types.usize,
                     span: c.span,
-                    value: match const_eval::eval_const_expr(cx.tcx.global_tcx(), c) {
-                        ConstVal::Integral(ConstInt::Usize(u)) => u,
-                        other => bug!("constant evaluation of repeat count yielded {:?}", other),
-                    },
+                    value: count
                 }
             }
         }
@@ -627,7 +628,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             }
         }
         hir::ExprField(ref source, name) => {
-            let index = match cx.tcx.tables().expr_ty_adjusted(source).sty {
+            let index = match cx.tables().expr_ty_adjusted(source).sty {
                 ty::TyAdt(adt_def, _) => adt_def.variants[0].index_of_field_named(name.node),
                 ref ty => span_bug!(expr.span, "field of non-ADT: {:?}", ty),
             };
@@ -679,7 +680,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                  expr: &hir::Expr,
                                  method_call: ty::MethodCall)
                                  -> Expr<'tcx> {
-    let callee = cx.tcx.tables().method_map[&method_call];
+    let callee = cx.tables().method_map[&method_call];
     let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
     Expr {
         temp_lifetime: temp_lifetime,
@@ -703,7 +704,7 @@ fn to_borrow_kind(m: hir::Mutability) -> BorrowKind {
 
 fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> {
     Arm {
-        patterns: arm.pats.iter().map(|p| Pattern::from_hir(cx.tcx, p)).collect(),
+        patterns: arm.pats.iter().map(|p| Pattern::from_hir(cx.tcx, cx.tables(), p)).collect(),
         guard: arm.guard.to_ref(),
         body: arm.body.to_ref(),
     }
@@ -713,9 +714,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                      expr: &'tcx hir::Expr,
                                      def: Def)
                                      -> ExprKind<'tcx> {
-    let substs = cx.tcx
-        .tables()
-        .node_id_item_substs(expr.id)
+    let substs = cx.tables().node_id_item_substs(expr.id)
         .unwrap_or_else(|| cx.tcx.intern_substs(&[]));
     let def_id = match def {
         // A regular function, constructor function or a constant.
@@ -728,7 +727,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
         Def::StructCtor(def_id, CtorKind::Const) |
         Def::VariantCtor(def_id, CtorKind::Const) => {
-            match cx.tcx.tables().node_id_to_type(expr.id).sty {
+            match cx.tables().node_id_to_type(expr.id).sty {
                 // A unit struct/variant which is used as a value.
                 // We return a completely different ExprKind here to account for this special case.
                 ty::TyAdt(adt_def, substs) => {
@@ -776,7 +775,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                    id_var,
                    index,
                    closure_expr_id);
-            let var_ty = cx.tcx.tables().node_id_to_type(id_var);
+            let var_ty = cx.tables().node_id_to_type(id_var);
 
             let body_id = match cx.tcx.map.find(closure_expr_id) {
                 Some(map::NodeExpr(expr)) => {
@@ -793,7 +792,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             };
 
             // FIXME free regions in closures are not right
-            let closure_ty = cx.tcx.tables().node_id_to_type(closure_expr_id);
+            let closure_ty = cx.tables().node_id_to_type(closure_expr_id);
 
             // FIXME we're just hard-coding the idea that the
             // signature will be &self or &mut self and hence will
@@ -869,7 +868,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 var_id: id_var,
                 closure_expr_id: closure_expr_id,
             };
-            let upvar_capture = match cx.tcx.tables().upvar_capture(upvar_id) {
+            let upvar_capture = match cx.tables().upvar_capture(upvar_id) {
                 Some(c) => c,
                 None => {
                     span_bug!(expr.span, "no upvar_capture for {:?}", upvar_id);
@@ -948,7 +947,7 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
             argrefs.extend(args.iter()
                 .map(|arg| {
-                    let arg_ty = cx.tcx.tables().expr_ty_adjusted(arg);
+                    let arg_ty = cx.tables().expr_ty_adjusted(arg);
                     let adjusted_ty = cx.tcx.mk_ref(region,
                                                     ty::TypeAndMut {
                                                         ty: arg_ty,
@@ -990,7 +989,7 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
     // line up (this is because `*x` and `x[y]` represent lvalues):
 
     // to find the type &T of the content returned by the method;
-    let ref_ty = cx.tcx.tables().method_map[&method_call].ty.fn_ret();
+    let ref_ty = cx.tables().method_map[&method_call].ty.fn_ret();
     let ref_ty = cx.tcx.no_late_bound_regions(&ref_ty).unwrap();
     // callees always have all late-bound regions fully instantiated,
 
@@ -1019,9 +1018,9 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         var_id: id_var,
         closure_expr_id: closure_expr.id,
     };
-    let upvar_capture = cx.tcx.tables().upvar_capture(upvar_id).unwrap();
+    let upvar_capture = cx.tables().upvar_capture(upvar_id).unwrap();
     let temp_lifetime = cx.tcx.region_maps.temporary_scope(closure_expr.id);
-    let var_ty = cx.tcx.tables().node_id_to_type(id_var);
+    let var_ty = cx.tables().node_id_to_type(id_var);
     let captured_var = Expr {
         temp_lifetime: temp_lifetime,
         ty: var_ty,
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 7d111fccd00..4b553a71b83 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -18,9 +18,8 @@ use hair::*;
 use rustc::mir::transform::MirSource;
 
 use rustc::middle::const_val::ConstVal;
-use rustc_const_eval as const_eval;
+use rustc_const_eval::{ConstContext, EvalHint, fatal_const_eval_err};
 use rustc_data_structures::indexed_vec::Idx;
-use rustc::dep_graph::DepNode;
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::infer::InferCtxt;
@@ -52,17 +51,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
             MirSource::Promoted(..) => bug!(),
         };
 
-        let src_node_id = src.item_id();
-
-        // We are going to be accessing various tables
-        // generated by TypeckItemBody; we also assume
-        // that the body passes type check. These tables
-        // are not individually tracked, so just register
-        // a read here.
-        let src_def_id = infcx.tcx.map.local_def_id(src_node_id);
-        infcx.tcx.dep_graph.read(DepNode::TypeckItemBody(src_def_id));
-
-        let attrs = infcx.tcx.map.attrs(src_node_id);
+        let attrs = infcx.tcx.map.attrs(src.item_id());
 
         // Some functions always have overflow checks enabled,
         // however, they may not get codegen'd, depending on
@@ -128,7 +117,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
     }
 
     pub fn const_eval_literal(&mut self, e: &hir::Expr) -> Literal<'tcx> {
-        Literal::Value { value: const_eval::eval_const_expr(self.tcx.global_tcx(), e) }
+        let tcx = self.tcx.global_tcx();
+        match ConstContext::with_tables(tcx, self.tables()).eval(e, EvalHint::ExprTypeChecked) {
+            Ok(value) => Literal::Value { value: value },
+            Err(s) => fatal_const_eval_err(tcx, &s, e.span, "expression")
+        }
     }
 
     pub fn trait_method(&mut self,
@@ -177,6 +170,10 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
         self.tcx
     }
 
+    pub fn tables(&self) -> &'a ty::Tables<'gcx> {
+        self.infcx.tables.expect_interned()
+    }
+
     pub fn check_overflow(&self) -> bool {
         self.check_overflow
     }
diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs
index cbc53ea3c51..453c3e43b6b 100644
--- a/src/librustc_mir/mir_map.rs
+++ b/src/librustc_mir/mir_map.rs
@@ -18,19 +18,18 @@
 
 use build;
 use rustc::dep_graph::DepNode;
-use rustc::hir::def_id::DefId;
 use rustc::mir::Mir;
 use rustc::mir::transform::MirSource;
 use rustc::mir::visit::MutVisitor;
 use pretty;
 use hair::cx::Cx;
 
-use rustc::infer::InferCtxtBuilder;
+use rustc::infer::InferCtxt;
 use rustc::traits::Reveal;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::subst::Substs;
 use rustc::hir;
-use rustc::hir::intravisit::{self, FnKind, Visitor, NestedVisitorMap};
+use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
 use syntax::abi::Abi;
 use syntax::ast;
 use syntax_pos::Span;
@@ -80,34 +79,50 @@ struct BuildMir<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>
 }
 
-/// Helper type of a temporary returned by BuildMir::cx(...).
-/// Necessary because we can't write the following bound:
-/// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(Cx<'b, 'gcx, 'tcx>).
-struct CxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    src: MirSource,
-    def_id: DefId,
-    infcx: InferCtxtBuilder<'a, 'gcx, 'tcx>
-}
+fn build<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+                         body_id: hir::BodyId)
+                         -> (Mir<'tcx>, MirSource) {
+    let tcx = infcx.tcx.global_tcx();
 
-impl<'a, 'gcx, 'tcx> BuildMir<'a, 'gcx> {
-    fn cx<'b>(&'b mut self, src: MirSource) -> CxBuilder<'b, 'gcx, 'tcx> {
-        let param_env = ty::ParameterEnvironment::for_item(self.tcx, src.item_id());
-        let def_id = self.tcx.map.local_def_id(src.item_id());
-        CxBuilder {
-            src: src,
-            infcx: self.tcx.infer_ctxt(None, Some(param_env), Reveal::NotSpecializable),
-            def_id: def_id
-        }
+    let item_id = tcx.map.body_owner(body_id);
+    let src = MirSource::from_node(tcx, item_id);
+    let cx = Cx::new(infcx, src);
+    if let MirSource::Fn(id) = src {
+        // fetch the fully liberated fn signature (that is, all bound
+        // types/lifetimes replaced)
+        let fn_sig = cx.tables().liberated_fn_sigs[&id].clone();
+
+        let ty = tcx.item_type(tcx.map.local_def_id(id));
+        let (abi, implicit_argument) = if let ty::TyClosure(..) = ty.sty {
+            (Abi::Rust, Some((closure_self_ty(tcx, id, body_id), None)))
+        } else {
+            (ty.fn_abi(), None)
+        };
+
+        let body = tcx.map.body(body_id);
+        let explicit_arguments =
+            body.arguments
+                .iter()
+                .enumerate()
+                .map(|(index, arg)| {
+                    (fn_sig.inputs()[index], Some(&*arg.pat))
+                });
+
+        let arguments = implicit_argument.into_iter().chain(explicit_arguments);
+        (build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body), src)
+    } else {
+        (build::construct_const(cx, body_id), src)
     }
 }
 
-impl<'a, 'gcx, 'tcx> CxBuilder<'a, 'gcx, 'tcx> {
-    fn build<F>(&'tcx mut self, f: F)
-        where F: for<'b> FnOnce(Cx<'b, 'gcx, 'tcx>) -> Mir<'tcx>
-    {
-        let (src, def_id) = (self.src, self.def_id);
-        self.infcx.enter(|infcx| {
-            let mut mir = f(Cx::new(&infcx, src));
+impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::None
+    }
+
+    fn visit_nested_body(&mut self, body_id: hir::BodyId) {
+        self.tcx.infer_ctxt(body_id, Reveal::NotSpecializable).enter(|infcx| {
+            let (mut mir, src) = build(&infcx, body_id);
 
             // Convert the Mir to global types.
             let tcx = infcx.tcx.global_tcx();
@@ -117,152 +132,32 @@ impl<'a, 'gcx, 'tcx> CxBuilder<'a, 'gcx, 'tcx> {
             };
             globalizer.visit_mir(&mut mir);
             let mir = unsafe {
-                mem::transmute::<Mir, Mir<'gcx>>(mir)
+                mem::transmute::<Mir, Mir<'tcx>>(mir)
             };
 
             pretty::dump_mir(tcx, "mir_map", &0, src, &mir);
 
             let mir = tcx.alloc_mir(mir);
+            let def_id = tcx.map.local_def_id(src.item_id());
             assert!(tcx.mir_map.borrow_mut().insert(def_id, mir).is_none());
         });
-    }
-}
-
-impl<'a, 'gcx> BuildMir<'a, 'gcx> {
-    fn build_const_integer(&mut self, body: hir::BodyId) {
-        let body = self.tcx.map.body(body);
-        // FIXME(eddyb) Closures should have separate
-        // function definition IDs and expression IDs.
-        // Type-checking should not let closures get
-        // this far in an integer constant position.
-        if let hir::ExprClosure(..) = body.value.node {
-            return;
-        }
-        self.cx(MirSource::Const(body.value.id)).build(|cx| {
-            build::construct_const(cx, body.value.id, body.id())
-        });
-    }
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.tcx.map)
-    }
-
-    // Const and static items.
-    fn visit_item(&mut self, item: &'tcx hir::Item) {
-        match item.node {
-            hir::ItemConst(_, expr) => {
-                self.cx(MirSource::Const(item.id)).build(|cx| {
-                    build::construct_const(cx, item.id, expr)
-                });
-            }
-            hir::ItemStatic(_, m, expr) => {
-                self.cx(MirSource::Static(item.id, m)).build(|cx| {
-                    build::construct_const(cx, item.id, expr)
-                });
-            }
-            _ => {}
-        }
-        intravisit::walk_item(self, item);
-    }
-
-    // Trait associated const defaults.
-    fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
-        if let hir::TraitItemKind::Const(_, Some(expr)) = item.node {
-            self.cx(MirSource::Const(item.id)).build(|cx| {
-                build::construct_const(cx, item.id, expr)
-            });
-        }
-        intravisit::walk_trait_item(self, item);
-    }
-
-    // Impl associated const.
-    fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
-        if let hir::ImplItemKind::Const(_, expr) = item.node {
-            self.cx(MirSource::Const(item.id)).build(|cx| {
-                build::construct_const(cx, item.id, expr)
-            });
-        }
-        intravisit::walk_impl_item(self, item);
-    }
-
-    // Repeat counts, i.e. [expr; constant].
-    fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
-        if let hir::ExprRepeat(_, count) = expr.node {
-            self.build_const_integer(count);
-        }
-        intravisit::walk_expr(self, expr);
-    }
-
-    // Array lengths, i.e. [T; constant].
-    fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
-        if let hir::TyArray(_, length) = ty.node {
-            self.build_const_integer(length);
-        }
-        intravisit::walk_ty(self, ty);
-    }
-
-    // Enum variant discriminant values.
-    fn visit_variant(&mut self, v: &'tcx hir::Variant,
-                     g: &'tcx hir::Generics, item_id: ast::NodeId) {
-        if let Some(expr) = v.node.disr_expr {
-            self.build_const_integer(expr);
-        }
-        intravisit::walk_variant(self, v, g, item_id);
-    }
-
-    fn visit_fn(&mut self,
-                fk: FnKind<'tcx>,
-                decl: &'tcx hir::FnDecl,
-                body_id: hir::BodyId,
-                span: Span,
-                id: ast::NodeId) {
-        // fetch the fully liberated fn signature (that is, all bound
-        // types/lifetimes replaced)
-        let fn_sig = match self.tcx.tables().liberated_fn_sigs.get(&id) {
-            Some(f) => f.clone(),
-            None => {
-                span_bug!(span, "no liberated fn sig for {:?}", id);
-            }
-        };
-
-        let (abi, implicit_argument) = if let FnKind::Closure(..) = fk {
-            (Abi::Rust, Some((closure_self_ty(self.tcx, id, body_id.node_id), None)))
-        } else {
-            let def_id = self.tcx.map.local_def_id(id);
-            (self.tcx.item_type(def_id).fn_abi(), None)
-        };
 
         let body = self.tcx.map.body(body_id);
-        let explicit_arguments =
-            body.arguments
-                .iter()
-                .enumerate()
-                .map(|(index, arg)| {
-                    (fn_sig.inputs()[index], Some(&*arg.pat))
-                });
-
-        let arguments = implicit_argument.into_iter().chain(explicit_arguments);
-        self.cx(MirSource::Fn(id)).build(|cx| {
-            build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body)
-        });
-
-        intravisit::walk_fn(self, fk, decl, body_id, span, id);
+        self.visit_body(body);
     }
 }
 
 fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              closure_expr_id: ast::NodeId,
-                             body_id: ast::NodeId)
+                             body_id: hir::BodyId)
                              -> Ty<'tcx> {
-    let closure_ty = tcx.tables().node_id_to_type(closure_expr_id);
+    let closure_ty = tcx.body_tables(body_id).node_id_to_type(closure_expr_id);
 
     // We're just hard-coding the idea that the signature will be
     // &self or &mut self and hence will have a bound region with
     // number 0, hokey.
     let region = ty::Region::ReFree(ty::FreeRegion {
-        scope: tcx.region_maps.item_extent(body_id),
+        scope: tcx.region_maps.item_extent(body_id.node_id),
         bound_region: ty::BoundRegion::BrAnon(0),
     });
     let region = tcx.mk_region(region);
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index d144651fb7d..fea27ee5c54 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -1038,7 +1038,7 @@ impl<'tcx> MirPass<'tcx> for QualifyAndPromoteConstants {
         // Statics must be Sync.
         if mode == Mode::Static {
             let ty = mir.return_ty;
-            tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
+            tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
                 let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic);
                 let mut fulfillment_cx = traits::FulfillmentContext::new();
                 fulfillment_cx.register_bound(&infcx, ty,
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index 4c86331a525..0fabbe6678a 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -725,7 +725,7 @@ impl<'tcx> MirPass<'tcx> for TypeckMir {
             return;
         }
         let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id());
-        tcx.infer_ctxt(None, Some(param_env), Reveal::NotSpecializable).enter(|infcx| {
+        tcx.infer_ctxt(param_env, Reveal::NotSpecializable).enter(|infcx| {
             let mut checker = TypeChecker::new(&infcx, src.item_id());
             {
                 let mut verifier = TypeVerifier::new(&mut checker, mir);
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index d1d9a201567..8f12817511a 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -26,10 +26,9 @@
 
 use rustc::dep_graph::DepNode;
 use rustc::ty::cast::CastKind;
-use rustc_const_eval::{ConstEvalErr, compare_lit_exprs};
-use rustc_const_eval::{eval_const_expr_partial};
+use rustc_const_eval::{ConstEvalErr, ConstContext};
 use rustc_const_eval::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll, Math};
-use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath};
+use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath, BadType};
 use rustc_const_eval::ErrKind::UnresolvedPath;
 use rustc_const_eval::EvalHint::ExprTypeChecked;
 use rustc_const_math::{ConstMathErr, Op};
@@ -61,15 +60,18 @@ struct CheckCrateVisitor<'a, 'tcx: 'a> {
     promotable: bool,
     mut_rvalue_borrows: NodeSet,
     param_env: ty::ParameterEnvironment<'tcx>,
+    tables: &'a ty::Tables<'tcx>,
 }
 
 impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
     fn check_const_eval(&self, expr: &'gcx hir::Expr) {
-        if let Err(err) = eval_const_expr_partial(self.tcx, expr, ExprTypeChecked, None) {
+        let const_cx = ConstContext::with_tables(self.tcx, self.tables);
+        if let Err(err) = const_cx.eval(expr, ExprTypeChecked) {
             match err.kind {
                 UnimplementedConstVal(_) => {}
                 IndexOpFeatureGated => {}
                 ErroneousReferencedConstant(_) => {}
+                BadType(_) => {}
                 _ => {
                     self.tcx.sess.add_lint(CONST_ERR,
                                            expr.id,
@@ -111,8 +113,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
         NestedVisitorMap::None
     }
 
-    fn visit_nested_body(&mut self, body: hir::BodyId) {
-        match self.tcx.rvalue_promotable_to_static.borrow_mut().entry(body.node_id) {
+    fn visit_nested_body(&mut self, body_id: hir::BodyId) {
+        match self.tcx.rvalue_promotable_to_static.borrow_mut().entry(body_id.node_id) {
             Entry::Occupied(_) => return,
             Entry::Vacant(entry) => {
                 // Prevent infinite recursion on re-entry.
@@ -120,7 +122,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
             }
         }
 
-        let item_id = self.tcx.map.body_owner(body);
+        let item_id = self.tcx.map.body_owner(body_id);
 
         let outer_in_fn = self.in_fn;
         self.in_fn = match MirSource::from_node(self.tcx, item_id) {
@@ -128,19 +130,25 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
             _ => false
         };
 
-        let body = self.tcx.map.body(body);
+        let outer_tables = self.tables;
+        self.tables = self.tcx.item_tables(self.tcx.map.local_def_id(item_id));
+
+        let body = self.tcx.map.body(body_id);
         if !self.in_fn {
             self.check_const_eval(&body.value);
         }
 
-        let param_env = ty::ParameterEnvironment::for_item(self.tcx, item_id);
-        let outer_param_env = mem::replace(&mut self.param_env, param_env);
-        self.tcx.infer_ctxt(None, Some(self.param_env.clone()), Reveal::NotSpecializable)
-            .enter(|infcx| euv::ExprUseVisitor::new(self, &infcx).consume_body(body));
+        let outer_penv = self.tcx.infer_ctxt(body_id, Reveal::NotSpecializable).enter(|infcx| {
+            let param_env = infcx.parameter_environment.clone();
+            let outer_penv = mem::replace(&mut self.param_env, param_env);
+            euv::ExprUseVisitor::new(self, &infcx).consume_body(body);
+            outer_penv
+        });
 
         self.visit_body(body);
 
-        self.param_env = outer_param_env;
+        self.param_env = outer_penv;
+        self.tables = outer_tables;
         self.in_fn = outer_in_fn;
     }
 
@@ -150,10 +158,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
                 self.check_const_eval(lit);
             }
             PatKind::Range(ref start, ref end) => {
-                self.check_const_eval(start);
-                self.check_const_eval(end);
-
-                match compare_lit_exprs(self.tcx, p.span, start, end) {
+                let const_cx = ConstContext::with_tables(self.tcx, self.tables);
+                match const_cx.compare_lit_exprs(p.span, start, end) {
                     Ok(Ordering::Less) |
                     Ok(Ordering::Equal) => {}
                     Ok(Ordering::Greater) => {
@@ -193,7 +199,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
         let outer = self.promotable;
         self.promotable = true;
 
-        let node_ty = self.tcx.tables().node_id_to_type(ex.id);
+        let node_ty = self.tables.node_id_to_type(ex.id);
         check_expr(self, ex, node_ty);
         check_adjustments(self, ex);
 
@@ -219,7 +225,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
         }
 
         if self.in_fn && self.promotable {
-            match eval_const_expr_partial(self.tcx, ex, ExprTypeChecked, None) {
+            let const_cx = ConstContext::with_tables(self.tcx, self.tables);
+            match const_cx.eval(ex, ExprTypeChecked) {
                 Ok(_) => {}
                 Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }) |
                 Err(ConstEvalErr { kind: MiscCatchAll, .. }) |
@@ -230,6 +237,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
                 Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shr)), .. }) |
                 Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shl)), .. }) |
                 Err(ConstEvalErr { kind: IndexOpFeatureGated, .. }) => {}
+                Err(ConstEvalErr { kind: BadType(_), .. }) => {}
                 Err(msg) => {
                     self.tcx.sess.add_lint(CONST_ERR,
                                            ex.id,
@@ -262,14 +270,14 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
     match e.node {
         hir::ExprUnary(..) |
         hir::ExprBinary(..) |
-        hir::ExprIndex(..) if v.tcx.tables().method_map.contains_key(&method_call) => {
+        hir::ExprIndex(..) if v.tables.method_map.contains_key(&method_call) => {
             v.promotable = false;
         }
         hir::ExprBox(_) => {
             v.promotable = false;
         }
         hir::ExprUnary(op, ref inner) => {
-            match v.tcx.tables().node_id_to_type(inner.id).sty {
+            match v.tables.node_id_to_type(inner.id).sty {
                 ty::TyRawPtr(_) => {
                     assert!(op == hir::UnDeref);
 
@@ -279,7 +287,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
             }
         }
         hir::ExprBinary(op, ref lhs, _) => {
-            match v.tcx.tables().node_id_to_type(lhs.id).sty {
+            match v.tables.node_id_to_type(lhs.id).sty {
                 ty::TyRawPtr(_) => {
                     assert!(op.node == hir::BiEq || op.node == hir::BiNe ||
                             op.node == hir::BiLe || op.node == hir::BiLt ||
@@ -301,7 +309,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
             }
         }
         hir::ExprPath(ref qpath) => {
-            let def = v.tcx.tables().qpath_def(qpath, e.id);
+            let def = v.tables.qpath_def(qpath, e.id);
             match def {
                 Def::VariantCtor(..) | Def::StructCtor(..) |
                 Def::Fn(..) | Def::Method(..) => {}
@@ -337,7 +345,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
             }
             // The callee is an arbitrary expression, it doesn't necessarily have a definition.
             let def = if let hir::ExprPath(ref qpath) = callee.node {
-                v.tcx.tables().qpath_def(qpath, callee.id)
+                v.tables.qpath_def(qpath, callee.id)
             } else {
                 Def::Err
             };
@@ -359,14 +367,14 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
             }
         }
         hir::ExprMethodCall(..) => {
-            let method = v.tcx.tables().method_map[&method_call];
+            let method = v.tables.method_map[&method_call];
             match v.tcx.associated_item(method.def_id).container {
                 ty::ImplContainer(_) => v.handle_const_fn_call(method.def_id, node_ty),
                 ty::TraitContainer(_) => v.promotable = false
             }
         }
         hir::ExprStruct(..) => {
-            if let ty::TyAdt(adt, ..) = v.tcx.tables().expr_ty(e).sty {
+            if let ty::TyAdt(adt, ..) = v.tables.expr_ty(e).sty {
                 // unsafe_cell_type doesn't necessarily exist with no_core
                 if Some(adt.did) == v.tcx.lang_items.unsafe_cell_type() {
                     v.promotable = false;
@@ -420,7 +428,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
 fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) {
     use rustc::ty::adjustment::*;
 
-    match v.tcx.tables().adjustments.get(&e.id).map(|adj| adj.kind) {
+    match v.tables.adjustments.get(&e.id).map(|adj| adj.kind) {
         None |
         Some(Adjust::NeverToAny) |
         Some(Adjust::ReifyFnPointer) |
@@ -429,7 +437,7 @@ fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Exp
 
         Some(Adjust::DerefRef { autoderefs, .. }) => {
             if (0..autoderefs as u32)
-                .any(|autoderef| v.tcx.tables().is_overloaded_autoderef(e.id, autoderef)) {
+                .any(|autoderef| v.tables.is_overloaded_autoderef(e.id, autoderef)) {
                 v.promotable = false;
             }
         }
@@ -440,6 +448,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     tcx.visit_all_item_likes_in_krate(DepNode::CheckConst,
                                       &mut CheckCrateVisitor {
                                           tcx: tcx,
+                                          tables: &ty::Tables::empty(),
                                           in_fn: false,
                                           promotable: false,
                                           mut_rvalue_borrows: NodeSet(),
diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs
index 3da4f24b6c2..78b591a48cc 100644
--- a/src/librustc_passes/rvalues.rs
+++ b/src/librustc_passes/rvalues.rs
@@ -14,11 +14,11 @@
 use rustc::dep_graph::DepNode;
 use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::mem_categorization as mc;
-use rustc::ty::{self, TyCtxt, ParameterEnvironment};
+use rustc::ty::{self, TyCtxt};
 use rustc::traits::Reveal;
 
 use rustc::hir;
-use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
+use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
 use syntax::ast;
 use syntax_pos::Span;
 
@@ -33,28 +33,19 @@ struct RvalueContext<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx> Visitor<'tcx> for RvalueContext<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.tcx.map)
+        NestedVisitorMap::None
     }
 
-    fn visit_fn(&mut self,
-                fk: intravisit::FnKind<'tcx>,
-                fd: &'tcx hir::FnDecl,
-                b: hir::BodyId,
-                s: Span,
-                fn_id: ast::NodeId) {
-        // FIXME (@jroesch) change this to be an inference context
-        let param_env = ParameterEnvironment::for_item(self.tcx, fn_id);
-        self.tcx.infer_ctxt(None, Some(param_env.clone()),
-                            Reveal::NotSpecializable).enter(|infcx| {
+    fn visit_nested_body(&mut self, body_id: hir::BodyId) {
+        let body = self.tcx.map.body(body_id);
+        self.tcx.infer_ctxt(body_id, Reveal::NotSpecializable).enter(|infcx| {
             let mut delegate = RvalueContextDelegate {
                 tcx: infcx.tcx,
-                param_env: &param_env
+                param_env: &infcx.parameter_environment
             };
-            let body = infcx.tcx.map.body(b);
-            let mut euv = euv::ExprUseVisitor::new(&mut delegate, &infcx);
-            euv.consume_body(body);
+            euv::ExprUseVisitor::new(&mut delegate, &infcx).consume_body(body);
         });
-        intravisit::walk_fn(self, fk, fd, b, s, fn_id)
+        self.visit_body(body);
     }
 }
 
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 84fa2e9d6bb..ef7a1f695ff 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -392,6 +392,7 @@ struct PrivacyVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     curitem: DefId,
     in_foreign: bool,
+    tables: &'a ty::Tables<'tcx>,
 }
 
 impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
@@ -435,6 +436,14 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivacyVisitor<'a, 'tcx> {
         NestedVisitorMap::All(&self.tcx.map)
     }
 
+    fn visit_nested_body(&mut self, body: hir::BodyId) {
+        let old_tables = self.tables;
+        self.tables = self.tcx.body_tables(body);
+        let body = self.tcx.map.body(body);
+        self.visit_body(body);
+        self.tables = old_tables;
+    }
+
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         let orig_curitem = replace(&mut self.curitem, self.tcx.map.local_def_id(item.id));
         intravisit::walk_item(self, item);
@@ -445,12 +454,12 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivacyVisitor<'a, 'tcx> {
         match expr.node {
             hir::ExprMethodCall(..) => {
                 let method_call = ty::MethodCall::expr(expr.id);
-                let method = self.tcx.tables().method_map[&method_call];
+                let method = self.tables.method_map[&method_call];
                 self.check_method(expr.span, method.def_id);
             }
             hir::ExprStruct(ref qpath, ref expr_fields, _) => {
-                let def = self.tcx.tables().qpath_def(qpath, expr.id);
-                let adt = self.tcx.tables().expr_ty(expr).ty_adt_def().unwrap();
+                let def = self.tables.qpath_def(qpath, expr.id);
+                let adt = self.tables.expr_ty(expr).ty_adt_def().unwrap();
                 let variant = adt.variant_of_def(def);
                 // RFC 736: ensure all unmentioned fields are visible.
                 // Rather than computing the set of unmentioned fields
@@ -511,15 +520,15 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivacyVisitor<'a, 'tcx> {
 
         match pattern.node {
             PatKind::Struct(ref qpath, ref fields, _) => {
-                let def = self.tcx.tables().qpath_def(qpath, pattern.id);
-                let adt = self.tcx.tables().pat_ty(pattern).ty_adt_def().unwrap();
+                let def = self.tables.qpath_def(qpath, pattern.id);
+                let adt = self.tables.pat_ty(pattern).ty_adt_def().unwrap();
                 let variant = adt.variant_of_def(def);
                 for field in fields {
                     self.check_field(field.span, adt, variant.field_named(field.node.name));
                 }
             }
             PatKind::TupleStruct(_, ref fields, ddpos) => {
-                match self.tcx.tables().pat_ty(pattern).sty {
+                match self.tables.pat_ty(pattern).sty {
                     // enum fields have no privacy at this time
                     ty::TyAdt(def, _) if !def.is_enum() => {
                         let expected_len = def.struct_variant().fields.len();
@@ -1203,6 +1212,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         curitem: DefId::local(CRATE_DEF_INDEX),
         in_foreign: false,
         tcx: tcx,
+        tables: &ty::Tables::empty(),
     };
     intravisit::walk_crate(&mut visitor, krate);
 
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 093a739c69f..424017ebd12 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -99,7 +99,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         }
     }
 
-    fn nest<F>(&mut self, scope_id: NodeId, f: F)
+    fn nest_scope<F>(&mut self, scope_id: NodeId, f: F)
         where F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, D>)
     {
         let parent_scope = self.cur_scope;
@@ -108,6 +108,16 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         self.cur_scope = parent_scope;
     }
 
+    fn nest_tables<F>(&mut self, item_id: NodeId, f: F)
+        where F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, D>)
+    {
+        let old_tables = self.save_ctxt.tables;
+        let item_def_id = self.tcx.map.local_def_id(item_id);
+        self.save_ctxt.tables = self.tcx.item_tables(item_def_id);
+        f(self);
+        self.save_ctxt.tables = old_tables;
+    }
+
     pub fn dump_crate_info(&mut self, name: &str, krate: &ast::Crate) {
         let source_file = self.tcx.sess.local_crate_source_file.as_ref();
         let crate_root = source_file.map(|source_file| {
@@ -337,7 +347,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             collector.visit_pat(&arg.pat);
             let span_utils = self.span.clone();
             for &(id, ref p, ..) in &collector.collected_paths {
-                let typ = match self.tcx.tables().node_types.get(&id) {
+                let typ = match self.save_ctxt.tables.node_types.get(&id) {
                     Some(s) => s.to_string(),
                     None => continue,
                 };
@@ -378,7 +388,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
 
             let sig_str = ::make_signature(&sig.decl, &sig.generics);
             if body.is_some() {
-                self.process_formals(&sig.decl.inputs, &method_data.qualname);
+                self.nest_tables(id, |v| {
+                    v.process_formals(&sig.decl.inputs, &method_data.qualname)
+                });
             }
 
             // If the method is defined in an impl, then try and find the corresponding
@@ -448,7 +460,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
 
         // walk the fn body
         if let Some(body) = body {
-            self.nest(id, |v| v.visit_block(body));
+            self.nest_tables(id, |v| v.nest_scope(id, |v| v.visit_block(body)));
         }
     }
 
@@ -520,7 +532,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                 self.dumper.function(fn_data.clone().lower(self.tcx));
             }
 
-            self.process_formals(&decl.inputs, &fn_data.qualname);
+            self.nest_tables(item.id, |v| v.process_formals(&decl.inputs, &fn_data.qualname));
             self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id);
         }
 
@@ -532,7 +544,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             self.visit_ty(&ret_ty);
         }
 
-        self.nest(item.id, |v| v.visit_block(&body));
+        self.nest_tables(item.id, |v| v.nest_scope(item.id, |v| v.visit_block(&body)));
     }
 
     fn process_static_or_const_item(&mut self,
@@ -991,7 +1003,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         match p.node {
             PatKind::Struct(ref path, ref fields, _) => {
                 visit::walk_path(self, path);
-                let adt = match self.tcx.tables().node_id_to_type_opt(p.id) {
+                let adt = match self.save_ctxt.tables.node_id_to_type_opt(p.id) {
                     Some(ty) => ty.ty_adt_def().unwrap(),
                     None => {
                         visit::walk_pat(self, p);
@@ -1032,7 +1044,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                 ast::Mutability::Immutable => value.to_string(),
                 _ => String::new(),
             };
-            let typ = match self.tcx.tables().node_types.get(&id) {
+            let typ = match self.save_ctxt.tables.node_types.get(&id) {
                 Some(typ) => {
                     let typ = typ.to_string();
                     if !value.is_empty() {
@@ -1286,7 +1298,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
                 self.process_trait(item, generics, trait_refs, methods),
             Mod(ref m) => {
                 self.process_mod(item);
-                self.nest(item.id, |v| visit::walk_mod(v, m));
+                self.nest_scope(item.id, |v| visit::walk_mod(v, m));
             }
             Ty(ref ty, ref ty_params) => {
                 let qualname = format!("::{}", self.tcx.node_path_str(item.id));
@@ -1349,6 +1361,10 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
 
                 visit::walk_path(self, path);
             }
+            ast::TyKind::Array(ref element, ref length) => {
+                self.visit_ty(element);
+                self.nest_tables(length.id, |v| v.visit_expr(length));
+            }
             _ => visit::walk_ty(self, t),
         }
     }
@@ -1367,7 +1383,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
             }
             ast::ExprKind::Struct(ref path, ref fields, ref base) => {
                 let hir_expr = self.save_ctxt.tcx.map.expect_expr(ex.id);
-                let adt = match self.tcx.tables().expr_ty_opt(&hir_expr) {
+                let adt = match self.save_ctxt.tables.expr_ty_opt(&hir_expr) {
                     Some(ty) => ty.ty_adt_def().unwrap(),
                     None => {
                         visit::walk_expr(self, ex);
@@ -1399,7 +1415,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
                         return;
                     }
                 };
-                let ty = match self.tcx.tables().expr_ty_adjusted_opt(&hir_node) {
+                let ty = match self.save_ctxt.tables.expr_ty_adjusted_opt(&hir_node) {
                     Some(ty) => &ty.sty,
                     None => {
                         visit::walk_expr(self, ex);
@@ -1427,7 +1443,6 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
             ast::ExprKind::Closure(_, ref decl, ref body, _fn_decl_span) => {
                 let mut id = String::from("$");
                 id.push_str(&ex.id.to_string());
-                self.process_formals(&decl.inputs, &id);
 
                 // walk arg and return types
                 for arg in &decl.inputs {
@@ -1439,7 +1454,10 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
                 }
 
                 // walk the body
-                self.nest(ex.id, |v| v.visit_expr(body));
+                self.nest_tables(ex.id, |v| {
+                    v.process_formals(&decl.inputs, &id);
+                    v.nest_scope(ex.id, |v| v.visit_expr(body))
+                });
             }
             ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) |
             ast::ExprKind::WhileLet(ref pattern, ref subexpression, ref block, _) => {
@@ -1455,6 +1473,10 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
                 visit::walk_block(self, block);
                 opt_else.as_ref().map(|el| visit::walk_expr(self, el));
             }
+            ast::ExprKind::Repeat(ref element, ref count) => {
+                self.visit_expr(element);
+                self.nest_tables(count.id, |v| v.visit_expr(count));
+            }
             _ => {
                 visit::walk_expr(self, ex)
             }
@@ -1492,7 +1514,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
                     } else {
                         "<mutable>".to_string()
                     };
-                    let typ = self.tcx.tables().node_types
+                    let typ = self.save_ctxt.tables.node_types
                                   .get(&id).map(|t| t.to_string()).unwrap_or(String::new());
                     value.push_str(": ");
                     value.push_str(&typ);
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 3f7f3bdba01..0fbe29880b9 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -84,6 +84,7 @@ pub mod recorder {
 
 pub struct SaveContext<'l, 'tcx: 'l> {
     tcx: TyCtxt<'l, 'tcx, 'tcx>,
+    tables: &'l ty::Tables<'tcx>,
     analysis: &'l ty::CrateAnalysis<'tcx>,
     span_utils: SpanUtils<'tcx>,
 }
@@ -93,24 +94,6 @@ macro_rules! option_try(
 );
 
 impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
-    pub fn new(tcx: TyCtxt<'l, 'tcx, 'tcx>,
-               analysis: &'l ty::CrateAnalysis<'tcx>)
-               -> SaveContext<'l, 'tcx> {
-        let span_utils = SpanUtils::new(&tcx.sess);
-        SaveContext::from_span_utils(tcx, analysis, span_utils)
-    }
-
-    pub fn from_span_utils(tcx: TyCtxt<'l, 'tcx, 'tcx>,
-                           analysis: &'l ty::CrateAnalysis<'tcx>,
-                           span_utils: SpanUtils<'tcx>)
-                           -> SaveContext<'l, 'tcx> {
-        SaveContext {
-            tcx: tcx,
-            analysis: analysis,
-            span_utils: span_utils,
-        }
-    }
-
     // List external crates used by the current crate.
     pub fn get_external_crates(&self) -> Vec<CrateData> {
         let mut result = Vec::new();
@@ -460,7 +443,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
 
     pub fn get_expr_data(&self, expr: &ast::Expr) -> Option<Data> {
         let hir_node = self.tcx.map.expect_expr(expr.id);
-        let ty = self.tcx.tables().expr_ty_adjusted_opt(&hir_node);
+        let ty = self.tables.expr_ty_adjusted_opt(&hir_node);
         if ty.is_none() || ty.unwrap().sty == ty::TyError {
             return None;
         }
@@ -474,7 +457,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                         return None;
                     }
                 };
-                match self.tcx.tables().expr_ty_adjusted(&hir_node).sty {
+                match self.tables.expr_ty_adjusted(&hir_node).sty {
                     ty::TyAdt(def, _) if !def.is_enum() => {
                         let f = def.struct_variant().field_named(ident.node.name);
                         let sub_span = self.span_utils.span_for_last_ident(expr.span);
@@ -493,7 +476,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                 }
             }
             ast::ExprKind::Struct(ref path, ..) => {
-                match self.tcx.tables().expr_ty_adjusted(&hir_node).sty {
+                match self.tables.expr_ty_adjusted(&hir_node).sty {
                     ty::TyAdt(def, _) if !def.is_enum() => {
                         let sub_span = self.span_utils.span_for_last_ident(path.span);
                         filter!(self.span_utils, sub_span, path.span, None);
@@ -514,7 +497,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             }
             ast::ExprKind::MethodCall(..) => {
                 let method_call = ty::MethodCall::expr(expr.id);
-                let method_id = self.tcx.tables().method_map[&method_call].def_id;
+                let method_id = self.tables.method_map[&method_call].def_id;
                 let (def_id, decl_id) = match self.tcx.associated_item(method_id).container {
                     ty::ImplContainer(_) => (Some(method_id), None),
                     ty::TraitContainer(_) => (None, Some(method_id)),
@@ -551,7 +534,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             Node::NodePat(&hir::Pat { node: hir::PatKind::Path(ref qpath), .. }) |
             Node::NodePat(&hir::Pat { node: hir::PatKind::Struct(ref qpath, ..), .. }) |
             Node::NodePat(&hir::Pat { node: hir::PatKind::TupleStruct(ref qpath, ..), .. }) => {
-                self.tcx.tables().qpath_def(qpath, id)
+                self.tables.qpath_def(qpath, id)
             }
 
             Node::NodeLocal(&hir::Pat { node: hir::PatKind::Binding(_, def_id, ..), .. }) => {
@@ -914,7 +897,12 @@ pub fn process_crate<'l, 'tcx>(tcx: TyCtxt<'l, 'tcx, 'tcx>,
     root_path.pop();
     let output = &mut output_file;
 
-    let save_ctxt = SaveContext::new(tcx, analysis);
+    let save_ctxt = SaveContext {
+        tcx: tcx,
+        tables: &ty::Tables::empty(),
+        analysis: analysis,
+        span_utils: SpanUtils::new(&tcx.sess),
+    };
 
     macro_rules! dump {
         ($new_dumper: expr) => {{
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index 13163518f94..eb6ea8fa94b 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -465,7 +465,7 @@ pub fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
 
         // Do the initial selection for the obligation. This yields the
         // shallow result we are looking for -- that is, what specific impl.
-        tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
+        tcx.infer_ctxt((), Reveal::All).enter(|infcx| {
             let mut selcx = SelectionContext::new(&infcx);
 
             let obligation_cause = traits::ObligationCause::misc(span,
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index 2e2644d91bb..a9c1edfdc66 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -95,8 +95,6 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
                 let sym = ccx.symbol_map()
                              .get(TransItem::Static(id))
                              .expect("Local statics should always be in the SymbolMap");
-                // Make sure that this is never executed for something inlined.
-                assert!(!ccx.tcx().map.is_inlined_node_id(id));
 
                 let defined_in_current_codegen_unit = ccx.codegen_unit()
                                                          .items()
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index 413b6437408..5efdd129a32 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -851,7 +851,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
     }
 
     pub fn layout_of(&self, ty: Ty<'tcx>) -> &'tcx ty::layout::Layout {
-        self.tcx().infer_ctxt(None, None, traits::Reveal::All).enter(|infcx| {
+        self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| {
             ty.layout(&infcx).unwrap_or_else(|e| {
                 match e {
                     ty::layout::LayoutError::SizeOverflow(_) =>
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index f6428465eda..1473e55b264 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -1738,14 +1738,6 @@ pub fn create_global_var_metadata(cx: &CrateContext,
 
     let tcx = cx.tcx();
 
-    // Don't create debuginfo for globals inlined from other crates. The other
-    // crate should already contain debuginfo for it. More importantly, the
-    // global might not even exist in un-inlined form anywhere which would lead
-    // to a linker errors.
-    if tcx.map.is_inlined_node_id(node_id) {
-        return;
-    }
-
     let node_def_id = tcx.map.local_def_id(node_id);
     let (var_scope, span) = get_namespace_and_span_for_item(cx, node_def_id);
 
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index 4fe07c9b86a..b24f00ee697 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -80,7 +80,7 @@ pub fn get_drop_glue_type<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, t: Ty<'t
     }
     match t.sty {
         ty::TyBox(typ) if !scx.type_needs_drop(typ) && scx.type_is_sized(typ) => {
-            scx.tcx().infer_ctxt(None, None, traits::Reveal::All).enter(|infcx| {
+            scx.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| {
                 let layout = t.layout(&infcx).unwrap();
                 if layout.size(&scx.tcx().data_layout).bytes() == 0 {
                     // `Box<ZeroSizeType>` does not allocate.
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 13e659a5ae0..9ac2bea3b82 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -101,7 +101,6 @@ impl<'tcx> Const<'tcx> {
                 bug!("MIR must not use `{:?}` (which refers to a local ID)", cv)
             }
             ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
-            ConstVal::Dummy => bug!(),
         };
 
         assert!(!ty.has_erasable_regions());
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 75c25a605af..bc984949fc6 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1660,8 +1660,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 self.associated_path_def_to_ty(ast_ty.id, ast_ty.span, ty, def, segment).0
             }
             hir::TyArray(ref ty, length) => {
-                let e = &tcx.map.body(length).value;
-                if let Ok(length) = eval_length(tcx.global_tcx(), e, "array length") {
+                if let Ok(length) = eval_length(tcx.global_tcx(), length, "array length") {
                     tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), length)
                 } else {
                     self.tcx().types.err
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 9412c9105c7..0551887e2e8 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -99,10 +99,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                fn_ty.sig,
                opt_kind);
 
-        self.tables.borrow_mut().closure_tys.insert(expr_def_id, fn_ty);
+        self.tables.borrow_mut().closure_tys.insert(expr.id, fn_ty);
         match opt_kind {
             Some(kind) => {
-                self.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind);
+                self.tables.borrow_mut().closure_kinds.insert(expr.id, kind);
             }
             None => {}
         }
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index be10b77bd8b..3960dc9edbd 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -227,7 +227,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                                                trait_param_env,
                                                                normalize_cause.clone());
 
-    tcx.infer_ctxt(None, Some(trait_param_env), Reveal::NotSpecializable).enter(|infcx| {
+    tcx.infer_ctxt(trait_param_env, Reveal::NotSpecializable).enter(|infcx| {
         let inh = Inherited::new(ccx, infcx);
         let infcx = &inh.infcx;
         let fulfillment_cx = &inh.fulfillment_cx;
@@ -747,7 +747,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
 
     let tcx = ccx.tcx;
-    tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
+    tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
         let mut fulfillment_cx = traits::FulfillmentContext::new();
 
         // The below is for the most part highly similar to the procedure
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index e13c4ea314f..9cd54bd94c8 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -81,7 +81,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
     // check that the impl type can be made to match the trait type.
 
     let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_node_id);
-    tcx.infer_ctxt(None, Some(impl_param_env), Reveal::NotSpecializable).enter(|infcx| {
+    tcx.infer_ctxt(impl_param_env, Reveal::NotSpecializable).enter(|infcx| {
         let tcx = infcx.tcx;
         let mut fulfillment_cx = traits::FulfillmentContext::new();
 
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 5c3da4237be..f331c561f0c 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -801,13 +801,19 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
         // If so, add "synthetic impls".
         let steps = self.steps.clone();
         for step in steps.iter() {
-            let closure_def_id = match step.self_ty.sty {
-                ty::TyClosure(a, _) => a,
+            let closure_id = match step.self_ty.sty {
+                ty::TyClosure(def_id, _) => {
+                    if let Some(id) = self.tcx.map.as_local_node_id(def_id) {
+                        id
+                    } else {
+                        continue;
+                    }
+                }
                 _ => continue,
             };
 
             let closure_kinds = &self.tables.borrow().closure_kinds;
-            let closure_kind = match closure_kinds.get(&closure_def_id) {
+            let closure_kind = match closure_kinds.get(&closure_id) {
                 Some(&k) => k,
                 None => {
                     return Err(MethodError::ClosureAmbiguity(trait_def_id));
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index e1cfc64f3c7..ceb97c63d13 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -105,7 +105,7 @@ use lint;
 use util::common::{ErrorReported, indenter};
 use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap};
 
-use std::cell::{Cell, Ref, RefCell};
+use std::cell::{Cell, RefCell};
 use std::cmp;
 use std::mem::replace;
 use std::ops::{self, Deref};
@@ -483,12 +483,11 @@ pub struct InheritedBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 impl<'a, 'gcx, 'tcx> CrateCtxt<'a, 'gcx> {
     pub fn inherited(&'a self, id: ast::NodeId)
                      -> InheritedBuilder<'a, 'gcx, 'tcx> {
+        let tables = ty::Tables::empty();
         let param_env = ParameterEnvironment::for_item(self.tcx, id);
         InheritedBuilder {
             ccx: self,
-            infcx: self.tcx.infer_ctxt(Some(ty::Tables::empty()),
-                                       Some(param_env),
-                                       Reveal::NotSpecializable)
+            infcx: self.tcx.infer_ctxt((tables, param_env), Reveal::NotSpecializable)
         }
     }
 }
@@ -612,8 +611,7 @@ pub fn check_item_bodies(ccx: &CrateCtxt) -> CompileResult {
             let _task = ccx.tcx.dep_graph.in_task(DepNode::TypeckItemBody(def_id));
 
             let param_env = ParameterEnvironment::for_item(ccx.tcx, item_id);
-            ccx.tcx.infer_ctxt(None, Some(param_env),
-                               Reveal::NotSpecializable).enter(|infcx| {
+            ccx.tcx.infer_ctxt(param_env, Reveal::NotSpecializable).enter(|infcx| {
                 let mut fulfillment_cx = traits::FulfillmentContext::new();
                 for obligation in obligations.iter().map(|o| o.to_obligation()) {
                     fulfillment_cx.register_predicate_obligation(&infcx, obligation);
@@ -681,7 +679,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         fcx.select_all_obligations_or_error(); // Casts can introduce new obligations.
 
         fcx.regionck_fn(fn_id, body);
-        fcx.resolve_type_vars_in_body(body, fn_id);
+        fcx.resolve_type_vars_in_body(body);
     });
 }
 
@@ -1248,7 +1246,7 @@ fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
         fcx.select_all_obligations_or_error();
 
         fcx.regionck_expr(body);
-        fcx.resolve_type_vars_in_body(body, id);
+        fcx.resolve_type_vars_in_body(body);
     });
 }
 
@@ -1871,17 +1869,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn item_substs(&self) -> Ref<NodeMap<ty::ItemSubsts<'tcx>>> {
-        // NOTE: @jroesch this is hack that appears to be fixed on nightly, will monitor if
-        // it changes when we upgrade the snapshot compiler
-        fn project_item_susbts<'a, 'tcx>(tables: &'a ty::Tables<'tcx>)
-                                        -> &'a NodeMap<ty::ItemSubsts<'tcx>> {
-            &tables.item_substs
-        }
-
-        Ref::map(self.tables.borrow(), project_item_susbts)
-    }
-
     pub fn opt_node_ty_substs<F>(&self,
                                  id: ast::NodeId,
                                  f: F) where
@@ -3872,8 +3859,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             tcx.mk_array(unified, args.len())
           }
           hir::ExprRepeat(ref element, count) => {
-            let count_expr = &tcx.map.body(count).value;
-            let count = eval_length(self.tcx.global_tcx(), count_expr, "repeat count")
+            let count = eval_length(self.tcx.global_tcx(), count, "repeat count")
                   .unwrap_or(0);
 
             let uty = match expected {
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index 5d927a503a1..95da5a97f67 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -106,8 +106,7 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> {
                      expr: &hir::Expr,
                      capture_clause: hir::CaptureClause)
     {
-        let closure_def_id = self.fcx.tcx.map.local_def_id(expr.id);
-        if !self.fcx.tables.borrow().closure_kinds.contains_key(&closure_def_id) {
+        if !self.fcx.tables.borrow().closure_kinds.contains_key(&expr.id) {
             self.temp_closure_kinds.insert(expr.id, ty::ClosureKind::Fn);
             debug!("check_closure: adding closure {:?} as Fn", expr.id);
         }
@@ -211,8 +210,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
         // main table and process any deferred resolutions.
         let closure_def_id = self.fcx.tcx.map.local_def_id(id);
         if let Some(&kind) = self.temp_closure_kinds.get(&id) {
-            self.fcx.tables.borrow_mut().closure_kinds
-                                        .insert(closure_def_id, kind);
+            self.fcx.tables.borrow_mut().closure_kinds.insert(id, kind);
             debug!("closure_kind({:?}) = {:?}", closure_def_id, kind);
 
             let mut deferred_call_resolutions =
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 6d32b7364f8..02ac7c196b5 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -33,10 +33,12 @@ use rustc::hir;
 // Entry point
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-    pub fn resolve_type_vars_in_body(&self,
-                                     body: &'gcx hir::Body,
-                                     item_id: ast::NodeId) {
+    pub fn resolve_type_vars_in_body(&self, body: &'gcx hir::Body) {
         assert_eq!(self.writeback_errors.get(), false);
+
+        let item_id = self.tcx.map.body_owner(body.id());
+        let item_def_id = self.tcx.map.local_def_id(item_id);
+
         let mut wbcx = WritebackCx::new(self);
         for arg in &body.arguments {
             wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id);
@@ -49,6 +51,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         wbcx.visit_anon_types();
         wbcx.visit_deferred_obligations(item_id);
         wbcx.visit_type_nodes();
+
+        let tables = self.tcx.alloc_tables(wbcx.tables);
+        self.tcx.tables.borrow_mut().insert(item_def_id, tables);
     }
 }
 
@@ -63,6 +68,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 struct WritebackCx<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
     fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>,
 
+    tables: ty::Tables<'gcx>,
+
     // Mapping from free regions of the function to the
     // early-bound versions of them, visible from the
     // outside of the function. This is needed by, and
@@ -74,6 +81,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
     fn new(fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>) -> WritebackCx<'cx, 'gcx, 'tcx> {
         let mut wbcx = WritebackCx {
             fcx: fcx,
+            tables: ty::Tables::empty(),
             free_to_bound_regions: DefIdMap()
         };
 
@@ -113,10 +121,10 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
         self.fcx.tcx
     }
 
-    fn write_ty_to_tcx(&self, node_id: ast::NodeId, ty: Ty<'gcx>) {
-        debug!("write_ty_to_tcx({}, {:?})", node_id,  ty);
+    fn write_ty_to_tables(&mut self, node_id: ast::NodeId, ty: Ty<'gcx>) {
+        debug!("write_ty_to_tables({}, {:?})", node_id,  ty);
         assert!(!ty.needs_infer());
-        self.tcx().tables.borrow_mut().node_types.insert(node_id, ty);
+        self.tables.node_types.insert(node_id, ty);
     }
 
     // Hacky hack: During type-checking, we treat *all* operators
@@ -228,11 +236,6 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
 
         self.visit_node_id(ResolvingPattern(p.span), p.id);
 
-        debug!("Type for pattern binding {} (id {}) resolved to {:?}",
-               self.tcx().map.node_to_pretty_string(p.id),
-               p.id,
-               self.tcx().tables().node_id_to_type(p.id));
-
         intravisit::walk_pat(self, p);
     }
 
@@ -243,13 +246,13 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
 
         let var_ty = self.fcx.local_ty(l.span, l.id);
         let var_ty = self.resolve(&var_ty, ResolvingLocal(l.span));
-        self.write_ty_to_tcx(l.id, var_ty);
+        self.write_ty_to_tables(l.id, var_ty);
         intravisit::walk_local(self, l);
     }
 }
 
 impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
-    fn visit_upvar_borrow_map(&self) {
+    fn visit_upvar_borrow_map(&mut self) {
         if self.fcx.writeback_errors.get() {
             return;
         }
@@ -267,11 +270,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
             debug!("Upvar capture for {:?} resolved to {:?}",
                    upvar_id,
                    new_upvar_capture);
-            self.tcx()
-                .tables
-                .borrow_mut()
-                .upvar_capture_map
-                .insert(*upvar_id, new_upvar_capture);
+            self.tables.upvar_capture_map.insert(*upvar_id, new_upvar_capture);
         }
     }
 
@@ -280,13 +279,15 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
             return
         }
 
-        for (def_id, closure_ty) in self.fcx.tables.borrow().closure_tys.iter() {
-            let closure_ty = self.resolve(closure_ty, ResolvingClosure(*def_id));
-            self.tcx().tables.borrow_mut().closure_tys.insert(*def_id, closure_ty);
+        for (&id, closure_ty) in self.fcx.tables.borrow().closure_tys.iter() {
+            let closure_ty = self.resolve(closure_ty, ResolvingClosure(id));
+            let def_id = self.tcx().map.local_def_id(id);
+            self.tcx().closure_tys.borrow_mut().insert(def_id, closure_ty);
         }
 
-        for (def_id, &closure_kind) in self.fcx.tables.borrow().closure_kinds.iter() {
-            self.tcx().tables.borrow_mut().closure_kinds.insert(*def_id, closure_kind);
+        for (&id, &closure_kind) in self.fcx.tables.borrow().closure_kinds.iter() {
+            let def_id = self.tcx().map.local_def_id(id);
+            self.tcx().closure_kinds.borrow_mut().insert(def_id, closure_kind);
         }
     }
 
@@ -339,10 +340,10 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
         }
     }
 
-    fn visit_node_id(&self, reason: ResolveReason, id: ast::NodeId) {
+    fn visit_node_id(&mut self, reason: ResolveReason, id: ast::NodeId) {
         // Export associated path extensions.
         if let Some(def) = self.fcx.tables.borrow_mut().type_relative_path_defs.remove(&id) {
-            self.tcx().tables.borrow_mut().type_relative_path_defs.insert(id, def);
+            self.tables.type_relative_path_defs.insert(id, def);
         }
 
         // Resolve any borrowings for the node with id `id`
@@ -351,7 +352,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
         // Resolve the type of the node with id `id`
         let n_ty = self.fcx.node_ty(id);
         let n_ty = self.resolve(&n_ty, reason);
-        self.write_ty_to_tcx(id, n_ty);
+        self.write_ty_to_tables(id, n_ty);
         debug!("Node {} has type {:?}", id, n_ty);
 
         // Resolve any substitutions
@@ -360,12 +361,12 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
             if !item_substs.is_noop() {
                 debug!("write_substs_to_tcx({}, {:?})", id, item_substs);
                 assert!(!item_substs.substs.needs_infer());
-                self.tcx().tables.borrow_mut().item_substs.insert(id, item_substs);
+                self.tables.item_substs.insert(id, item_substs);
             }
         });
     }
 
-    fn visit_adjustments(&self, reason: ResolveReason, id: ast::NodeId) {
+    fn visit_adjustments(&mut self, reason: ResolveReason, id: ast::NodeId) {
         let adjustments = self.fcx.tables.borrow_mut().adjustments.remove(&id);
         match adjustments {
             None => {
@@ -408,13 +409,12 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
                     target: self.resolve(&adjustment.target, reason)
                 };
                 debug!("Adjustments for node {}: {:?}", id, resolved_adjustment);
-                self.tcx().tables.borrow_mut().adjustments.insert(
-                    id, resolved_adjustment);
+                self.tables.adjustments.insert(id, resolved_adjustment);
             }
         }
     }
 
-    fn visit_method_map_entry(&self,
+    fn visit_method_map_entry(&mut self,
                               reason: ResolveReason,
                               method_call: MethodCall) {
         // Resolve any method map entry
@@ -436,25 +436,25 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
 
         //NB(jroesch): We need to match twice to avoid a double borrow which would cause an ICE
         if let Some(method) = new_method {
-            self.tcx().tables.borrow_mut().method_map.insert(method_call, method);
+            self.tables.method_map.insert(method_call, method);
         }
     }
 
-    fn visit_liberated_fn_sigs(&self) {
+    fn visit_liberated_fn_sigs(&mut self) {
         for (&node_id, fn_sig) in self.fcx.tables.borrow().liberated_fn_sigs.iter() {
             let fn_sig = self.resolve(fn_sig, ResolvingFnSig(node_id));
-            self.tcx().tables.borrow_mut().liberated_fn_sigs.insert(node_id, fn_sig.clone());
+            self.tables.liberated_fn_sigs.insert(node_id, fn_sig.clone());
         }
     }
 
-    fn visit_fru_field_types(&self) {
+    fn visit_fru_field_types(&mut self) {
         for (&node_id, ftys) in self.fcx.tables.borrow().fru_field_types.iter() {
             let ftys = self.resolve(ftys, ResolvingFieldTypes(node_id));
-            self.tcx().tables.borrow_mut().fru_field_types.insert(node_id, ftys);
+            self.tables.fru_field_types.insert(node_id, ftys);
         }
     }
 
-    fn visit_deferred_obligations(&self, item_id: ast::NodeId) {
+    fn visit_deferred_obligations(&mut self, item_id: ast::NodeId) {
         let deferred_obligations = self.fcx.deferred_obligations.borrow();
         let obligations: Vec<_> = deferred_obligations.iter().map(|obligation| {
             let reason = ResolvingDeferredObligation(obligation.cause.span);
@@ -496,7 +496,7 @@ enum ResolveReason {
     ResolvingLocal(Span),
     ResolvingPattern(Span),
     ResolvingUpvar(ty::UpvarId),
-    ResolvingClosure(DefId),
+    ResolvingClosure(ast::NodeId),
     ResolvingFnSig(ast::NodeId),
     ResolvingFieldTypes(ast::NodeId),
     ResolvingAnonTy(DefId),
@@ -513,12 +513,12 @@ impl<'a, 'gcx, 'tcx> ResolveReason {
             ResolvingUpvar(upvar_id) => {
                 tcx.expr_span(upvar_id.closure_expr_id)
             }
+            ResolvingClosure(id) |
             ResolvingFnSig(id) |
             ResolvingFieldTypes(id) |
             ResolvingTyNode(id) => {
                 tcx.map.span(id)
             }
-            ResolvingClosure(did) |
             ResolvingAnonTy(did) => {
                 tcx.def_span(did)
             }
diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs
index ba95a179891..57df0fb2cee 100644
--- a/src/librustc_typeck/coherence/builtin.rs
+++ b/src/librustc_typeck/coherence/builtin.rs
@@ -205,7 +205,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
            source,
            target);
 
-    tcx.infer_ctxt(None, Some(param_env), Reveal::ExactMatch).enter(|infcx| {
+    tcx.infer_ctxt(param_env, Reveal::ExactMatch).enter(|infcx| {
         let cause = ObligationCause::misc(span, impl_node_id);
         let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
                            mt_b: ty::TypeAndMut<'tcx>,
diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs
index a09bdf0533a..08293c1d874 100644
--- a/src/librustc_typeck/coherence/overlap.rs
+++ b/src/librustc_typeck/coherence/overlap.rs
@@ -87,7 +87,7 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
 
         for (i, &impl1_def_id) in impls.iter().enumerate() {
             for &impl2_def_id in &impls[(i + 1)..] {
-                self.tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|infcx| {
+                self.tcx.infer_ctxt((), Reveal::ExactMatch).enter(|infcx| {
                     if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
                         self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
                     }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 7ddf10375bf..f832bf8d86e 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -63,7 +63,7 @@ use constrained_type_params as ctp;
 use middle::lang_items::SizedTraitLangItem;
 use middle::const_val::ConstVal;
 use rustc_const_eval::EvalHint::UncheckedExprHint;
-use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err};
+use rustc_const_eval::{ConstContext, report_const_eval_err};
 use rustc::ty::subst::Substs;
 use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContainer};
 use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
@@ -1039,8 +1039,9 @@ fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     adt
 }
 
-    fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, e: &hir::Expr)
+    fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, body: hir::BodyId)
                           -> Option<ty::Disr> {
+        let e = &ccx.tcx.map.body(body).value;
         debug!("disr expr, checking {}", ccx.tcx.map.node_to_pretty_string(e.id));
 
         let ty_hint = repr_ty.to_ty(ccx.tcx);
@@ -1052,9 +1053,9 @@ fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         };
 
         let hint = UncheckedExprHint(ty_hint);
-        match eval_const_expr_partial(ccx.tcx, e, hint, None) {
+        match ConstContext::new(ccx.tcx, body).eval(e, hint) {
             Ok(ConstVal::Integral(i)) => {
-                // FIXME: eval_const_expr_partial should return an error if the hint is wrong
+                // FIXME: eval should return an error if the hint is wrong
                 match (repr_ty, i) {
                     (attr::SignedInt(ast::IntTy::I8), ConstInt::I8(_)) |
                     (attr::SignedInt(ast::IntTy::I16), ConstInt::I16(_)) |
@@ -1103,7 +1104,6 @@ fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     let variants = def.variants.iter().map(|v| {
         let wrapped_disr = prev_disr.map_or(initial, |d| d.wrap_incr());
         let disr = if let Some(e) = v.node.disr_expr {
-            let e = &tcx.map.body(e).value;
             evaluate_disr_expr(ccx, repr_type, e)
         } else if let Some(disr) = repr_type.disr_incr(tcx, prev_disr) {
             Some(disr)
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 75cd9e2f967..6d30a85b582 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -177,7 +177,7 @@ fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                 expected: Ty<'tcx>,
                                 actual: Ty<'tcx>)
                                 -> bool {
-    ccx.tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
+    ccx.tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
         match infcx.eq_types(false, &cause, expected, actual) {
             Ok(InferOk { obligations, .. }) => {
                 // FIXME(#32730) propagate obligations
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index d66d2001f23..93c0bd6d6d8 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -14,7 +14,6 @@ arena = { path = "../libarena" }
 rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
 rustc_const_eval = { path = "../librustc_const_eval" }
-rustc_const_math = { path = "../librustc_const_math" }
 rustc_driver = { path = "../librustc_driver" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_errors = { path = "../librustc_errors" }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index faf39db5723..6a640e7b5ed 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1692,22 +1692,10 @@ impl Clean<Type> for hir::Ty {
                 BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx),
                              type_: box m.ty.clean(cx)},
             TySlice(ref ty) => Vector(box ty.clean(cx)),
-            TyArray(ref ty, e) => {
-                use rustc_const_math::{ConstInt, ConstUsize};
-                use rustc_const_eval::eval_const_expr;
-                use rustc::middle::const_val::ConstVal;
-
-                let e = &cx.tcx.map.body(e).value;
-                let n = match eval_const_expr(cx.tcx, e) {
-                    ConstVal::Integral(ConstInt::Usize(u)) => match u {
-                        ConstUsize::Us16(u) => u.to_string(),
-                        ConstUsize::Us32(u) => u.to_string(),
-                        ConstUsize::Us64(u) => u.to_string(),
-                    },
-                    // after type checking this can't fail
-                    _ => unreachable!(),
-                };
-                FixedVector(box ty.clean(cx), n)
+            TyArray(ref ty, length) => {
+                use rustc_const_eval::eval_length;
+                let n = eval_length(cx.tcx, length, "array length").unwrap();
+                FixedVector(box ty.clean(cx), n.to_string())
             },
             TyTup(ref tys) => Tuple(tys.clean(cx)),
             TyPath(hir::QPath::Resolved(None, ref path)) => {
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index c6951d4edd6..503ef4c3183 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -33,7 +33,6 @@ extern crate getopts;
 extern crate libc;
 extern crate rustc;
 extern crate rustc_const_eval;
-extern crate rustc_const_math;
 extern crate rustc_data_structures;
 extern crate rustc_trans;
 extern crate rustc_driver;
diff --git a/src/test/compile-fail/const-eval-overflow.rs b/src/test/compile-fail/const-eval-overflow.rs
index b8f3f714a84..3c688d58fd1 100644
--- a/src/test/compile-fail/const-eval-overflow.rs
+++ b/src/test/compile-fail/const-eval-overflow.rs
@@ -15,6 +15,8 @@
 // change this warn to a deny, then the compiler will exit before
 // those errors are detected.
 
+#![warn(const_err)]
+
 use std::fmt;
 use std::{i8, i16, i32, i64, isize};
 use std::{u8, u16, u32, u64, usize};
@@ -80,7 +82,8 @@ const VALS_I64: (i64, i64, i64, i64) =
      );
 
 const VALS_U8: (u8, u8, u8, u8) =
-    (-(u8::MIN as i8) as u8,
+    ( //~ WARN constant evaluation error: attempt to subtract with overflow.
+     -(u8::MIN as i8) as u8,
      u8::MIN - 1,
      //~^ ERROR constant evaluation error
      //~| attempt to subtract with overflow
@@ -93,7 +96,8 @@ const VALS_U8: (u8, u8, u8, u8) =
      );
 
 const VALS_U16: (u16, u16, u16, u16) =
-    (-(u16::MIN as i16) as u16,
+    ( //~ WARN constant evaluation error: attempt to subtract with overflow.
+     -(u16::MIN as i16) as u16,
      u16::MIN - 1,
      //~^ ERROR constant evaluation error
      //~| attempt to subtract with overflow
@@ -106,7 +110,8 @@ const VALS_U16: (u16, u16, u16, u16) =
      );
 
 const VALS_U32: (u32, u32, u32, u32) =
-    (-(u32::MIN as i32) as u32,
+    ( //~ WARN constant evaluation error: attempt to subtract with overflow.
+     -(u32::MIN as i32) as u32,
      u32::MIN - 1,
      //~^ ERROR constant evaluation error
      //~| attempt to subtract with overflow
@@ -119,7 +124,8 @@ const VALS_U32: (u32, u32, u32, u32) =
      );
 
 const VALS_U64: (u64, u64, u64, u64) =
-    (-(u64::MIN as i64) as u64,
+    ( //~ WARN constant evaluation error: attempt to subtract with overflow.
+     -(u64::MIN as i64) as u64,
      u64::MIN - 1,
      //~^ ERROR constant evaluation error
      //~| attempt to subtract with overflow
diff --git a/src/test/run-pass/issue-28189.rs b/src/test/run-pass/issue-28189.rs
deleted file mode 100644
index 0e624a77858..00000000000
--- a/src/test/run-pass/issue-28189.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-// 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.
-
-struct S<T>(T) where [T; (||{}, 1).1]: Copy;
-
-fn main() {
-
-}