about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-06-29 00:03:37 +0000
committerbors <bors@rust-lang.org>2015-06-29 00:03:37 +0000
commita973e4cda5191040ca219fb4a4f8041e9b560301 (patch)
treebc5e59e528305223710334dcb55d39786aa8fd52
parent2671e8cee08eb35013dc211286a6765c80b49c29 (diff)
parent5c3753f6b457dbc8e4cf0e8ec2d085d03f310911 (diff)
downloadrust-a973e4cda5191040ca219fb4a4f8041e9b560301.tar.gz
rust-a973e4cda5191040ca219fb4a4f8041e9b560301.zip
Auto merge of #26582 - jroesch:infer-ctxt-refactor, r=nikomatsakis
This branch begins the work of unifying our type checking contexts into a single piece of state. The goal is to eventually have a single context that we can pass around instead of the fractured situation we currently have. There are still several things that must be done before beginning to make tables item local:

- [ ] move FulfillmentContext into InferCtxt
- [ ] modify SelectionContext to only take a single context argument
- [ ] remove remaining typer impls 
- [ ] remove the ClosureTyper + Typer trait
- [ ] do some renaming to make these things more applicable to their new roles

r? @nikomatsakis 

As a side note there are a couple oddities that are temporary refactors that will be quickly cleaned up in a follow-up PR.

cc @eddyb @Aatch @arielb1 @nrc
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/middle/astencode.rs31
-rw-r--r--src/librustc/middle/cfg/construct.rs4
-rw-r--r--src/librustc/middle/check_const.rs9
-rw-r--r--src/librustc/middle/check_match.rs1
-rw-r--r--src/librustc/middle/const_eval.rs5
-rw-r--r--src/librustc/middle/dead.rs2
-rw-r--r--src/librustc/middle/effect.rs2
-rw-r--r--src/librustc/middle/expr_use_visitor.rs9
-rw-r--r--src/librustc/middle/infer/mod.rs204
-rw-r--r--src/librustc/middle/liveness.rs2
-rw-r--r--src/librustc/middle/mem_categorization.rs8
-rw-r--r--src/librustc/middle/reachable.rs2
-rw-r--r--src/librustc/middle/stability.rs2
-rw-r--r--src/librustc/middle/traits/mod.rs13
-rw-r--r--src/librustc/middle/traits/select.rs2
-rw-r--r--src/librustc/middle/ty.rs120
-rw-r--r--src/librustc/util/ppaux.rs2
-rw-r--r--src/librustc_driver/driver.rs2
-rw-r--r--src/librustc_driver/test.rs2
-rw-r--r--src/librustc_lint/builtin.rs4
-rw-r--r--src/librustc_privacy/lib.rs2
-rw-r--r--src/librustc_trans/lib.rs1
-rw-r--r--src/librustc_trans/save/dump_csv.rs2
-rw-r--r--src/librustc_trans/trans/base.rs2
-rw-r--r--src/librustc_trans/trans/callee.rs4
-rw-r--r--src/librustc_trans/trans/closure.rs2
-rw-r--r--src/librustc_trans/trans/common.rs35
-rw-r--r--src/librustc_trans/trans/consts.rs6
-rw-r--r--src/librustc_trans/trans/expr.rs33
-rw-r--r--src/librustc_trans/trans/meth.rs12
-rw-r--r--src/librustc_trans/trans/monomorphize.rs5
-rw-r--r--src/librustc_typeck/check/callee.rs8
-rw-r--r--src/librustc_typeck/check/closure.rs6
-rw-r--r--src/librustc_typeck/check/coercion.rs2
-rw-r--r--src/librustc_typeck/check/compare_method.rs15
-rw-r--r--src/librustc_typeck/check/dropck.rs3
-rw-r--r--src/librustc_typeck/check/method/confirm.rs8
-rw-r--r--src/librustc_typeck/check/method/mod.rs2
-rw-r--r--src/librustc_typeck/check/method/probe.rs12
-rw-r--r--src/librustc_typeck/check/method/suggest.rs2
-rw-r--r--src/librustc_typeck/check/mod.rs176
-rw-r--r--src/librustc_typeck/check/op.rs3
-rw-r--r--src/librustc_typeck/check/regionck.rs56
-rw-r--r--src/librustc_typeck/check/upvar.rs24
-rw-r--r--src/librustc_typeck/check/wf.rs31
-rw-r--r--src/librustc_typeck/check/writeback.rs39
-rw-r--r--src/librustc_typeck/coherence/mod.rs10
-rw-r--r--src/librustc_typeck/coherence/overlap.rs2
-rw-r--r--src/librustc_typeck/collect.rs2
-rw-r--r--src/librustc_typeck/lib.rs5
51 files changed, 586 insertions, 351 deletions
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index c19ba19f5b7..2cec42b76bc 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -61,6 +61,7 @@
 #![feature(str_match_indices)]
 #![feature(vec_push_all)]
 #![feature(wrapping)]
+#![feature(cell_extras)]
 #![cfg_attr(test, feature(test))]
 
 #![allow(trivial_casts)]
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index 21e2ad19881..d2c79e1d820 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -1027,7 +1027,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
         })
     }
 
-    if let Some(item_substs) = tcx.item_substs.borrow().get(&id) {
+    if let Some(item_substs) = tcx.tables.borrow().item_substs.get(&id) {
         rbml_w.tag(c::tag_table_item_subst, |rbml_w| {
             rbml_w.id(id);
             rbml_w.emit_substs(ecx, &item_substs.substs);
@@ -1051,7 +1051,12 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
                     var_id: var_id,
                     closure_expr_id: id
                 };
-                let upvar_capture = tcx.upvar_capture_map.borrow().get(&upvar_id).unwrap().clone();
+                let upvar_capture = tcx.tables
+                                       .borrow()
+                                       .upvar_capture_map
+                                       .get(&upvar_id)
+                                       .unwrap()
+                                       .clone();
                 var_id.encode(rbml_w);
                 upvar_capture.encode(rbml_w);
             })
@@ -1074,19 +1079,19 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
     }
 
     let method_call = MethodCall::expr(id);
-    if let Some(method) = tcx.method_map.borrow().get(&method_call) {
+    if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) {
         rbml_w.tag(c::tag_table_method_map, |rbml_w| {
             rbml_w.id(id);
             encode_method_callee(ecx, rbml_w, method_call.autoderef, method)
         })
     }
 
-    if let Some(adjustment) = tcx.adjustments.borrow().get(&id) {
+    if let Some(adjustment) = tcx.tables.borrow().adjustments.get(&id) {
         match *adjustment {
             ty::AdjustDerefRef(ref adj) => {
                 for autoderef in 0..adj.autoderefs {
                     let method_call = MethodCall::autoderef(id, autoderef as u32);
-                    if let Some(method) = tcx.method_map.borrow().get(&method_call) {
+                    if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) {
                         rbml_w.tag(c::tag_table_method_map, |rbml_w| {
                             rbml_w.id(id);
                             encode_method_callee(ecx, rbml_w,
@@ -1104,14 +1109,14 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
         })
     }
 
-    if let Some(closure_type) = tcx.closure_tys.borrow().get(&ast_util::local_def(id)) {
+    if let Some(closure_type) = tcx.tables.borrow().closure_tys.get(&ast_util::local_def(id)) {
         rbml_w.tag(c::tag_table_closure_tys, |rbml_w| {
             rbml_w.id(id);
             rbml_w.emit_closure_type(ecx, closure_type);
         })
     }
 
-    if let Some(closure_kind) = tcx.closure_kinds.borrow().get(&ast_util::local_def(id)) {
+    if let Some(closure_kind) = tcx.tables.borrow().closure_kinds.get(&ast_util::local_def(id)) {
         rbml_w.tag(c::tag_table_closure_kinds, |rbml_w| {
             rbml_w.id(id);
             encode_closure_kind(rbml_w, *closure_kind)
@@ -1630,7 +1635,7 @@ fn decode_side_tables(dcx: &DecodeContext,
                         let item_substs = ty::ItemSubsts {
                             substs: val_dsr.read_substs(dcx)
                         };
-                        dcx.tcx.item_substs.borrow_mut().insert(
+                        dcx.tcx.tables.borrow_mut().item_substs.insert(
                             id, item_substs);
                     }
                     c::tag_table_freevars => {
@@ -1646,7 +1651,7 @@ fn decode_side_tables(dcx: &DecodeContext,
                             closure_expr_id: id
                         };
                         let ub: ty::UpvarCapture = Decodable::decode(val_dsr).unwrap();
-                        dcx.tcx.upvar_capture_map.borrow_mut().insert(upvar_id, ub.tr(dcx));
+                        dcx.tcx.tables.borrow_mut().upvar_capture_map.insert(upvar_id, ub.tr(dcx));
                     }
                     c::tag_table_tcache => {
                         let type_scheme = val_dsr.read_type_scheme(dcx);
@@ -1663,22 +1668,22 @@ fn decode_side_tables(dcx: &DecodeContext,
                             expr_id: id,
                             autoderef: autoderef
                         };
-                        dcx.tcx.method_map.borrow_mut().insert(method_call, method);
+                        dcx.tcx.tables.borrow_mut().method_map.insert(method_call, method);
                     }
                     c::tag_table_adjustments => {
                         let adj: ty::AutoAdjustment = val_dsr.read_auto_adjustment(dcx);
-                        dcx.tcx.adjustments.borrow_mut().insert(id, adj);
+                        dcx.tcx.tables.borrow_mut().adjustments.insert(id, adj);
                     }
                     c::tag_table_closure_tys => {
                         let closure_ty =
                             val_dsr.read_closure_ty(dcx);
-                        dcx.tcx.closure_tys.borrow_mut().insert(ast_util::local_def(id),
+                        dcx.tcx.tables.borrow_mut().closure_tys.insert(ast_util::local_def(id),
                                                                 closure_ty);
                     }
                     c::tag_table_closure_kinds => {
                         let closure_kind =
                             val_dsr.read_closure_kind(dcx);
-                        dcx.tcx.closure_kinds.borrow_mut().insert(ast_util::local_def(id),
+                        dcx.tcx.tables.borrow_mut().closure_kinds.insert(ast_util::local_def(id),
                                                                   closure_kind);
                     }
                     c::tag_table_cast_kinds => {
diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs
index 801b3a721e4..7d62b6ff900 100644
--- a/src/librustc/middle/cfg/construct.rs
+++ b/src/librustc/middle/cfg/construct.rs
@@ -411,7 +411,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
             func_or_rcvr: &ast::Expr,
             args: I) -> CFGIndex {
         let method_call = ty::MethodCall::expr(call_expr.id);
-        let fn_ty = match self.tcx.method_map.borrow().get(&method_call) {
+        let fn_ty = match self.tcx.tables.borrow().method_map.get(&method_call) {
             Some(method) => method.ty,
             None => self.tcx.expr_ty_adjusted(func_or_rcvr)
         };
@@ -634,6 +634,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
 
     fn is_method_call(&self, expr: &ast::Expr) -> bool {
         let method_call = ty::MethodCall::expr(expr.id);
-        self.tcx.method_map.borrow().contains_key(&method_call)
+        self.tcx.tables.borrow().method_map.contains_key(&method_call)
     }
 }
diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs
index 62bf1648725..8bbb6ae757f 100644
--- a/src/librustc/middle/check_const.rs
+++ b/src/librustc/middle/check_const.rs
@@ -283,12 +283,11 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
 
     fn check_static_type(&self, e: &ast::Expr) {
         let ty = self.tcx.node_id_to_type(e.id);
-        let infcx = infer::new_infer_ctxt(self.tcx);
+        let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None);
         let mut fulfill_cx = traits::FulfillmentContext::new(false);
         let cause = traits::ObligationCause::new(e.span, e.id, traits::SharedStatic);
         fulfill_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause);
-        let env = self.tcx.empty_parameter_environment();
-        match fulfill_cx.select_all_or_error(&infcx, &env) {
+        match fulfill_cx.select_all_or_error(&infcx, &infcx.parameter_environment) {
             Ok(()) => { },
             Err(ref errors) => {
                 traits::report_fulfillment_errors(&infcx, errors);
@@ -544,7 +543,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
     match e.node {
         ast::ExprUnary(..) |
         ast::ExprBinary(..) |
-        ast::ExprIndex(..) if v.tcx.method_map.borrow().contains_key(&method_call) => {
+        ast::ExprIndex(..) if v.tcx.tables.borrow().method_map.contains_key(&method_call) => {
             v.add_qualif(ConstQualif::NOT_CONST);
             if v.mode != Mode::Var {
                 span_err!(v.tcx.sess, e.span, E0011,
@@ -695,7 +694,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
             }
         }
         ast::ExprMethodCall(..) => {
-            let method_did = match v.tcx.method_map.borrow()[&method_call].origin {
+            let method_did = match v.tcx.tables.borrow().method_map[&method_call].origin {
                 ty::MethodStatic(did) => Some(did),
                 _ => None
             };
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index d2b3b83e4f4..f61884e2136 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -98,6 +98,7 @@ impl<'a> FromIterator<Vec<&'a Pat>> for Matrix<'a> {
     }
 }
 
+//NOTE: appears to be the only place other then InferCtxt to contain a ParamEnv
 pub struct MatchCheckCtxt<'a, 'tcx: 'a> {
     pub tcx: &'a ty::ctxt<'tcx>,
     pub param_env: ParameterEnvironment<'a, 'tcx>,
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index 1b1725dd15c..a6b7d7f832a 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -1031,10 +1031,9 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
                                               substs: trait_substs });
 
     tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id());
-    let infcx = infer::new_infer_ctxt(tcx);
+    let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
 
-    let param_env = tcx.empty_parameter_environment();
-    let mut selcx = traits::SelectionContext::new(&infcx, &param_env);
+    let mut selcx = traits::SelectionContext::new(&infcx, &infcx.parameter_environment);
     let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
                                              trait_ref.to_poly_trait_predicate());
     let selection = match selcx.select(&obligation) {
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index bd8b8afbdfe..d8ee38b8478 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -96,7 +96,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
     fn lookup_and_handle_method(&mut self, id: ast::NodeId,
                                 span: codemap::Span) {
         let method_call = ty::MethodCall::expr(id);
-        match self.tcx.method_map.borrow().get(&method_call) {
+        match self.tcx.tables.borrow().method_map.get(&method_call) {
             Some(method) => {
                 match method.origin {
                     ty::MethodStatic(def_id) => {
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index c48d5d5da40..8084c2b0c39 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -140,7 +140,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
         match expr.node {
             ast::ExprMethodCall(_, _, _) => {
                 let method_call = MethodCall::expr(expr.id);
-                let base_type = self.tcx.method_map.borrow().get(&method_call).unwrap().ty;
+                let base_type = self.tcx.tables.borrow().method_map.get(&method_call).unwrap().ty;
                 debug!("effect: method call case, base type is {:?}",
                         base_type);
                 if type_is_unsafe_function(base_type) {
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index a15d02ea296..25728c50c61 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -257,8 +257,9 @@ impl OverloadedCallType {
     fn from_closure(tcx: &ty::ctxt, closure_did: ast::DefId)
                     -> OverloadedCallType {
         let trait_did =
-            tcx.closure_kinds
+            tcx.tables
                .borrow()
+               .closure_kinds
                .get(&closure_did)
                .expect("OverloadedCallType::from_closure: didn't find closure id")
                .trait_did(tcx);
@@ -787,8 +788,10 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
     // process.
     fn walk_adjustment(&mut self, expr: &ast::Expr) {
         let typer = self.typer;
-        if let Some(adjustment) = typer.adjustments().borrow().get(&expr.id) {
-            match *adjustment {
+        //NOTE(@jroesch): mixed RefCell borrow causes crash
+        let adj = typer.adjustments().get(&expr.id).map(|x| x.clone());
+        if let Some(adjustment) = adj {
+            match adjustment {
                 ty::AdjustReifyFnPointer |
                 ty::AdjustUnsafeFnPointer => {
                     // Creating a closure/fn-pointer or unsizing consumes
diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs
index f1af2705d4e..c355e8b82a6 100644
--- a/src/librustc/middle/infer/mod.rs
+++ b/src/librustc/middle/infer/mod.rs
@@ -23,19 +23,24 @@ pub use self::freshen::TypeFreshener;
 pub use self::region_inference::GenericKind;
 
 use middle::free_region::FreeRegionMap;
+use middle::mem_categorization as mc;
+use middle::mem_categorization::McResult;
+use middle::region::CodeExtent;
 use middle::subst;
 use middle::subst::Substs;
+use middle::subst::Subst;
+use middle::traits;
 use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, UnconstrainedNumeric};
 use middle::ty::{self, Ty, HasTypeFlags};
 use middle::ty_fold::{self, TypeFolder, TypeFoldable};
 use middle::ty_relate::{Relate, RelateResult, TypeRelation};
 use rustc_data_structures::unify::{self, UnificationTable};
-use std::cell::{RefCell};
+use std::cell::{RefCell, Ref};
 use std::fmt;
 use syntax::ast;
 use syntax::codemap;
 use syntax::codemap::Span;
-use util::nodemap::FnvHashMap;
+use util::nodemap::{FnvHashMap, NodeMap};
 
 use self::combine::CombineFields;
 use self::region_inference::{RegionVarBindings, RegionSnapshot};
@@ -64,6 +69,8 @@ pub type fres<T> = Result<T, fixup_err>; // "fixup result"
 pub struct InferCtxt<'a, 'tcx: 'a> {
     pub tcx: &'a ty::ctxt<'tcx>,
 
+    pub tables: &'a RefCell<ty::Tables<'tcx>>,
+
     // We instantiate UnificationTable with bounds<Ty> because the
     // types that might instantiate a general type variable have an
     // order, represented by its upper and lower bounds.
@@ -77,6 +84,17 @@ pub struct InferCtxt<'a, 'tcx: 'a> {
 
     // For region variables.
     region_vars: RegionVarBindings<'a, 'tcx>,
+
+    pub parameter_environment: ty::ParameterEnvironment<'a, 'tcx>,
+
+    // This is a temporary field used for toggling on normalization in the inference context,
+    // as we move towards the approach described here:
+    // https://internals.rust-lang.org/t/flattening-the-contexts-for-fun-and-profit/2293
+    // At a point sometime in the future normalization will be done by the typing context
+    // directly.
+    normalize: bool,
+
+    err_count_on_creation: usize,
 }
 
 /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized
@@ -309,14 +327,20 @@ pub fn fixup_err_to_string(f: fixup_err) -> String {
     }
 }
 
-pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>)
+pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>,
+                                tables: &'a RefCell<ty::Tables<'tcx>>,
+                                param_env: Option<ty::ParameterEnvironment<'a, 'tcx>>)
                                 -> InferCtxt<'a, 'tcx> {
     InferCtxt {
         tcx: tcx,
+        tables: tables,
         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(tcx),
+        parameter_environment: param_env.unwrap_or(tcx.empty_parameter_environment()),
+        normalize: false,
+        err_count_on_creation: tcx.sess.err_count()
     }
 }
 
@@ -431,6 +455,127 @@ pub struct CombinedSnapshot {
     region_vars_snapshot: RegionSnapshot,
 }
 
+impl<'a, 'tcx> mc::Typer<'tcx> for InferCtxt<'a, 'tcx> {
+    fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>> {
+        let ty = self.node_ty(id);
+        self.resolve_type_vars_or_error(&ty)
+    }
+
+    fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult<Ty<'tcx>> {
+        let ty = self.adjust_expr_ty(expr, self.tables.borrow().adjustments.get(&expr.id));
+        self.resolve_type_vars_or_error(&ty)
+    }
+
+    fn type_moves_by_default(&self, ty: Ty<'tcx>, span: Span) -> bool {
+        let ty = self.resolve_type_vars_if_possible(&ty);
+        !traits::type_known_to_meet_builtin_bound(self, self, ty, ty::BoundCopy, span)
+    }
+
+    fn node_method_ty(&self, method_call: ty::MethodCall)
+                      -> Option<Ty<'tcx>> {
+        self.tables
+            .borrow()
+            .method_map
+            .get(&method_call)
+            .map(|method| method.ty)
+            .map(|ty| self.resolve_type_vars_if_possible(&ty))
+    }
+
+    fn node_method_origin(&self, method_call: ty::MethodCall)
+                          -> Option<ty::MethodOrigin<'tcx>>
+    {
+        self.tables
+            .borrow()
+            .method_map
+            .get(&method_call)
+            .map(|method| method.origin.clone())
+    }
+
+    fn adjustments(&self) -> Ref<NodeMap<ty::AutoAdjustment<'tcx>>> {
+        fn project_adjustments<'a, 'tcx>(tables: &'a ty::Tables<'tcx>)
+                                        -> &'a NodeMap<ty::AutoAdjustment<'tcx>> {
+            &tables.adjustments
+        }
+
+        Ref::map(self.tables.borrow(), project_adjustments)
+    }
+
+    fn is_method_call(&self, id: ast::NodeId) -> bool {
+        self.tables.borrow().method_map.contains_key(&ty::MethodCall::expr(id))
+    }
+
+    fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<CodeExtent> {
+        self.parameter_environment.temporary_scope(rvalue_id)
+    }
+
+    fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
+        self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned()
+    }
+}
+
+impl<'a, 'tcx> ty::ClosureTyper<'tcx> for InferCtxt<'a, 'tcx> {
+    fn param_env<'b>(&'b self) -> &'b ty::ParameterEnvironment<'b,'tcx> {
+        &self.parameter_environment
+    }
+
+    fn closure_kind(&self,
+                    def_id: ast::DefId)
+                    -> Option<ty::ClosureKind>
+    {
+        self.tables.borrow().closure_kinds.get(&def_id).cloned()
+    }
+
+    fn closure_type(&self,
+                    def_id: ast::DefId,
+                    substs: &subst::Substs<'tcx>)
+                    -> ty::ClosureTy<'tcx>
+    {
+
+        let closure_ty = self.tables
+                             .borrow()
+                             .closure_tys
+                             .get(&def_id)
+                             .unwrap()
+                             .subst(self.tcx, substs);
+
+        if self.normalize {
+            // NOTE: this flag is currently *always* set to false, we are slowly folding
+            // normalization into this trait and will come back to remove this in the near
+            // future.
+
+            // code from NormalizingClosureTyper:
+            // the substitutions in `substs` are already monomorphized,
+            // but we still must normalize associated types
+            // normalize_associated_type(self.param_env.tcx, &closure_ty)
+            panic!("see issue 26597: fufillment context refactor must occur")
+        } else {
+            closure_ty
+        }
+    }
+
+    fn closure_upvars(&self,
+                      def_id: ast::DefId,
+                      substs: &Substs<'tcx>)
+                      -> Option<Vec<ty::ClosureUpvar<'tcx>>>
+    {
+        let result = ty::ctxt::closure_upvars(self, def_id, substs);
+
+        if self.normalize {
+            // NOTE: this flag is currently *always* set to false, we are slowly folding
+            // normalization into this trait and will come back to remove this in the near
+            // future.
+
+            // code from NormalizingClosureTyper:
+            // the substitutions in `substs` are already monomorphized,
+            // but we still must normalize associated types
+            // monomorphize::normalize_associated_type(self.param_env.tcx, &result)
+            panic!("see issue 26597: fufillment context refactor must occur")
+        } else {
+            result
+        }
+    }
+}
+
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     pub fn freshen<T:TypeFoldable<'tcx>>(&self, t: T) -> T {
         t.fold_with(&mut self.freshener())
@@ -852,6 +997,49 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         self.region_vars.new_bound(debruijn)
     }
 
+    /// Apply `adjustment` to the type of `expr`
+    pub fn adjust_expr_ty(&self,
+                          expr: &ast::Expr,
+                          adjustment: Option<&ty::AutoAdjustment<'tcx>>)
+                          -> Ty<'tcx>
+    {
+        let raw_ty = self.expr_ty(expr);
+        let raw_ty = self.shallow_resolve(raw_ty);
+        let resolve_ty = |ty: Ty<'tcx>| self.resolve_type_vars_if_possible(&ty);
+        raw_ty.adjust(self.tcx,
+                      expr.span,
+                      expr.id,
+                      adjustment,
+                      |method_call| self.tables
+                                        .borrow()
+                                        .method_map
+                                        .get(&method_call)
+                                        .map(|method| resolve_ty(method.ty)))
+    }
+
+    pub fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx> {
+        match self.tables.borrow().node_types.get(&id) {
+            Some(&t) => t,
+            // FIXME
+            None if self.tcx.sess.err_count() - self.err_count_on_creation != 0 =>
+                self.tcx.types.err,
+            None => {
+                self.tcx.sess.bug(
+                    &format!("no type for node {}: {} in fcx",
+                            id, self.tcx.map.node_to_string(id)));
+            }
+        }
+    }
+
+    pub fn expr_ty(&self, ex: &ast::Expr) -> Ty<'tcx> {
+        match self.tables.borrow().node_types.get(&ex.id) {
+            Some(&t) => t,
+            None => {
+                self.tcx.sess.bug(&format!("no type for expr in fcx"));
+            }
+        }
+    }
+
     pub fn resolve_regions_and_report_errors(&self,
                                              free_regions: &FreeRegionMap,
                                              subject_node_id: ast::NodeId) {
@@ -926,6 +1114,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         value.fold_with(&mut r)
     }
 
+    /// Resolves all type variables in `t` and then, if any were left
+    /// unresolved, substitutes an error type. This is used after the
+    /// main checking when doing a second pass before writeback. The
+    /// justification is that writeback will produce an error for
+    /// these unconstrained type variables.
+    fn resolve_type_vars_or_error(&self, t: &Ty<'tcx>) -> mc::McResult<Ty<'tcx>> {
+        let ty = self.resolve_type_vars_if_possible(t);
+        if ty.has_infer_types() || ty.references_error() { Err(()) } else { Ok(ty) }
+    }
+
     pub fn fully_resolve<T:TypeFoldable<'tcx>>(&self, value: &T) -> fres<T> {
         /*!
          * Attempts to resolve all type/region variables in
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index d354c1667da..7d237a511c4 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -1150,7 +1150,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
           ast::ExprMethodCall(_, _, ref args) => {
             let method_call = ty::MethodCall::expr(expr.id);
-            let method_ty = self.ir.tcx.method_map.borrow().get(&method_call).unwrap().ty;
+            let method_ty = self.ir.tcx.tables.borrow().method_map.get(&method_call).unwrap().ty;
             let succ = if method_ty.fn_ret().diverges() {
                 self.s.exit_ln
             } else {
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 969ffaf88a7..13e127e9126 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -83,7 +83,7 @@ use syntax::ast::{MutImmutable, MutMutable};
 use syntax::ast;
 use syntax::codemap::Span;
 
-use std::cell::RefCell;
+use std::cell::Ref;
 use std::fmt;
 use std::rc::Rc;
 
@@ -289,7 +289,7 @@ pub trait Typer<'tcx> : ty::ClosureTyper<'tcx> {
     fn node_method_ty(&self, method_call: ty::MethodCall) -> Option<Ty<'tcx>>;
     fn node_method_origin(&self, method_call: ty::MethodCall)
                           -> Option<ty::MethodOrigin<'tcx>>;
-    fn adjustments<'a>(&'a self) -> &'a RefCell<NodeMap<ty::AutoAdjustment<'tcx>>>;
+    fn adjustments(&self) -> Ref<NodeMap<ty::AutoAdjustment<'tcx>>>;
     fn is_method_call(&self, id: ast::NodeId) -> bool;
     fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<region::CodeExtent>;
     fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture>;
@@ -408,7 +408,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
         let unadjusted_ty = try!(self.expr_ty(expr));
         Ok(unadjusted_ty.adjust(
             self.tcx(), expr.span, expr.id,
-            self.typer.adjustments().borrow().get(&expr.id),
+            self.typer.adjustments().get(&expr.id),
             |method_call| self.typer.node_method_ty(method_call)))
     }
 
@@ -440,7 +440,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
     }
 
     pub fn cat_expr(&self, expr: &ast::Expr) -> McResult<cmt<'tcx>> {
-        match self.typer.adjustments().borrow().get(&expr.id) {
+        match self.typer.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 0bbcfa70038..6ea726062ca 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -128,7 +128,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> {
             }
             ast::ExprMethodCall(..) => {
                 let method_call = ty::MethodCall::expr(expr.id);
-                match (*self.tcx.method_map.borrow()).get(&method_call).unwrap().origin {
+                match self.tcx.tables.borrow().method_map.get(&method_call).unwrap().origin {
                     ty::MethodStatic(def_id) => {
                         if is_local(def_id) {
                             if self.def_id_represents_local_inlined_item(def_id) {
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 4766ae8933d..e6bbae6405b 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -406,7 +406,7 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr,
         ast::ExprMethodCall(i, _, _) => {
             span = i.span;
             let method_call = ty::MethodCall::expr(e.id);
-            match tcx.method_map.borrow().get(&method_call) {
+            match tcx.tables.borrow().method_map.get(&method_call) {
                 Some(method) => {
                     match method.origin {
                         ty::MethodStatic(def_id) => {
diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs
index 845ba62307f..9df6ed5d681 100644
--- a/src/librustc/middle/traits/mod.rs
+++ b/src/librustc/middle/traits/mod.rs
@@ -351,6 +351,7 @@ pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
     }
 }
 
+// FIXME: this is gonna need to be removed ...
 /// Normalizes the parameter environment, reporting errors if they occur.
 pub fn normalize_param_env_or_error<'a,'tcx>(unnormalized_env: ty::ParameterEnvironment<'a,'tcx>,
                                              cause: ObligationCause<'tcx>)
@@ -396,13 +397,13 @@ pub fn normalize_param_env_or_error<'a,'tcx>(unnormalized_env: ty::ParameterEnvi
 
     let elaborated_env = unnormalized_env.with_caller_bounds(predicates);
 
-    let infcx = infer::new_infer_ctxt(tcx);
-    let predicates = match fully_normalize(&infcx, &elaborated_env, cause,
-                                           &elaborated_env.caller_bounds) {
+    let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(elaborated_env));
+    let predicates = match fully_normalize(&infcx, &infcx.parameter_environment, cause,
+                                           &infcx.parameter_environment.caller_bounds) {
         Ok(predicates) => predicates,
         Err(errors) => {
             report_fulfillment_errors(&infcx, &errors);
-            return unnormalized_env; // an unnormalized env is better than nothing
+            return infcx.parameter_environment; // an unnormalized env is better than nothing
         }
     };
 
@@ -420,11 +421,11 @@ pub fn normalize_param_env_or_error<'a,'tcx>(unnormalized_env: ty::ParameterEnvi
             // all things considered.
             let err_msg = fixup_err_to_string(fixup_err);
             tcx.sess.span_err(span, &err_msg);
-            return elaborated_env; // an unnormalized env is better than nothing
+            return infcx.parameter_environment; // an unnormalized env is better than nothing
         }
     };
 
-    elaborated_env.with_caller_bounds(predicates)
+    infcx.parameter_environment.with_caller_bounds(predicates)
 }
 
 pub fn fully_normalize<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs
index 01faa6b7cf7..ae15c8aa8e0 100644
--- a/src/librustc/middle/traits/select.rs
+++ b/src/librustc/middle/traits/select.rs
@@ -54,6 +54,7 @@ use util::nodemap::FnvHashMap;
 
 pub struct SelectionContext<'cx, 'tcx:'cx> {
     infcx: &'cx InferCtxt<'cx, 'tcx>,
+
     closure_typer: &'cx (ty::ClosureTyper<'tcx>+'cx),
 
     /// Freshener used specifically for skolemizing entries on the
@@ -77,6 +78,7 @@ pub struct SelectionContext<'cx, 'tcx:'cx> {
     /// other words, we consider `$0 : Bar` to be unimplemented if
     /// there is no type that the user could *actually name* that
     /// would satisfy it. This avoids crippling inference, basically.
+
     intercrate: bool,
 }
 
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 302ec08db6f..489ce7bc4cf 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -728,7 +728,7 @@ impl MethodCall {
 
 // maps from an expression id that corresponds to a method call to the details
 // of the method to be invoked
-pub type MethodMap<'tcx> = RefCell<FnvHashMap<MethodCall, MethodCallee<'tcx>>>;
+pub type MethodMap<'tcx> = FnvHashMap<MethodCall, MethodCallee<'tcx>>;
 
 // Contains information needed to resolve types and (in the future) look up
 // the types of AST nodes.
@@ -815,6 +815,48 @@ pub struct CommonTypes<'tcx> {
     pub err: Ty<'tcx>,
 }
 
+pub struct Tables<'tcx> {
+    /// Stores the types for various nodes in the AST.  Note that this table
+    /// is not guaranteed to be populated until after typeck.  See
+    /// typeck::check::fn_ctxt for details.
+    pub node_types: NodeMap<Ty<'tcx>>,
+
+    /// Stores the type parameters which were substituted to obtain the type
+    /// of this node.  This only applies to nodes that refer to entities
+    /// parameterized by type parameters, such as generic fns, types, or
+    /// other items.
+    pub item_substs: NodeMap<ItemSubsts<'tcx>>,
+
+    pub adjustments: NodeMap<ty::AutoAdjustment<'tcx>>,
+
+    pub method_map: MethodMap<'tcx>,
+
+    /// Borrows
+    pub upvar_capture_map: UpvarCaptureMap,
+
+    /// Records the type of each closure. The def ID is the ID of the
+    /// expression defining the closure.
+    pub closure_tys: DefIdMap<ClosureTy<'tcx>>,
+
+    /// Records the type of each closure. The def ID is the ID of the
+    /// expression defining the closure.
+    pub closure_kinds: DefIdMap<ClosureKind>,
+}
+
+impl<'tcx> Tables<'tcx> {
+    pub fn empty() -> Tables<'tcx> {
+        Tables {
+            node_types: FnvHashMap(),
+            item_substs: NodeMap(),
+            adjustments: NodeMap(),
+            method_map: FnvHashMap(),
+            upvar_capture_map: FnvHashMap(),
+            closure_tys: DefIdMap(),
+            closure_kinds: DefIdMap(),
+        }
+    }
+}
+
 /// The data structure to keep track of all the information that typechecker
 /// generates so that so that it can be reused and doesn't have to be redone
 /// later on.
@@ -850,17 +892,9 @@ pub struct ctxt<'tcx> {
     // borrowck. (They are not used during trans, and hence are not
     // serialized or needed for cross-crate fns.)
     free_region_maps: RefCell<NodeMap<FreeRegionMap>>,
+    // FIXME: jroesch make this a refcell
 
-    /// Stores the types for various nodes in the AST.  Note that this table
-    /// is not guaranteed to be populated until after typeck.  See
-    /// typeck::check::fn_ctxt for details.
-    node_types: RefCell<NodeMap<Ty<'tcx>>>,
-
-    /// Stores the type parameters which were substituted to obtain the type
-    /// of this node.  This only applies to nodes that refer to entities
-    /// parameterized by type parameters, such as generic fns, types, or
-    /// other items.
-    pub item_substs: RefCell<NodeMap<ItemSubsts<'tcx>>>,
+    pub tables: RefCell<Tables<'tcx>>,
 
     /// Maps from a trait item to the trait item "descriptor"
     pub impl_or_trait_items: RefCell<DefIdMap<ImplOrTraitItem<'tcx>>>,
@@ -894,7 +928,6 @@ pub struct ctxt<'tcx> {
     pub ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
     pub enum_var_cache: RefCell<DefIdMap<Rc<Vec<Rc<VariantInfo<'tcx>>>>>>,
     pub ty_param_defs: RefCell<NodeMap<TypeParameterDef<'tcx>>>,
-    pub adjustments: RefCell<NodeMap<AutoAdjustment<'tcx>>>,
     pub normalized_cache: RefCell<FnvHashMap<Ty<'tcx>, Ty<'tcx>>>,
     pub lang_items: middle::lang_items::LanguageItems,
     /// A mapping of fake provided method def_ids to the default implementation
@@ -944,26 +977,13 @@ pub struct ctxt<'tcx> {
     /// FIXME(arielb1): why is this separate from populated_external_types?
     pub populated_external_primitive_impls: RefCell<DefIdSet>,
 
-    /// Borrows
-    pub upvar_capture_map: RefCell<UpvarCaptureMap>,
-
     /// These caches are used by const_eval when decoding external constants.
     pub extern_const_statics: RefCell<DefIdMap<ast::NodeId>>,
     pub extern_const_variants: RefCell<DefIdMap<ast::NodeId>>,
     pub extern_const_fns: RefCell<DefIdMap<ast::NodeId>>,
 
-    pub method_map: MethodMap<'tcx>,
-
     pub dependency_formats: RefCell<dependency_format::Dependencies>,
 
-    /// Records the type of each closure. The def ID is the ID of the
-    /// expression defining the closure.
-    pub closure_kinds: RefCell<DefIdMap<ClosureKind>>,
-
-    /// Records the type of each closure. The def ID is the ID of the
-    /// expression defining the closure.
-    pub closure_tys: RefCell<DefIdMap<ClosureTy<'tcx>>>,
-
     pub node_lint_levels: RefCell<FnvHashMap<(ast::NodeId, lint::LintId),
                                               lint::LevelSource>>,
 
@@ -1000,9 +1020,16 @@ pub struct ctxt<'tcx> {
 }
 
 impl<'tcx> ctxt<'tcx> {
-    pub fn node_types(&self) -> Ref<NodeMap<Ty<'tcx>>> { self.node_types.borrow() }
+    pub fn node_types(&self) -> Ref<NodeMap<Ty<'tcx>>> {
+        fn projection<'a, 'tcx>(tables: &'a Tables<'tcx>) ->  &'a NodeMap<Ty<'tcx>> {
+            &tables.node_types
+        }
+
+        Ref::map(self.tables.borrow(), projection)
+    }
+
     pub fn node_type_insert(&self, id: NodeId, ty: Ty<'tcx>) {
-        self.node_types.borrow_mut().insert(id, ty);
+        self.tables.borrow_mut().node_types.insert(id, ty);
     }
 
     pub fn intern_trait_def(&self, def: TraitDef<'tcx>) -> &'tcx TraitDef<'tcx> {
@@ -3421,8 +3448,7 @@ impl<'tcx> ctxt<'tcx> {
             variance_computed: Cell::new(false),
             sess: s,
             def_map: def_map,
-            node_types: RefCell::new(FnvHashMap()),
-            item_substs: RefCell::new(NodeMap()),
+            tables: RefCell::new(Tables::empty()),
             impl_trait_refs: RefCell::new(DefIdMap()),
             trait_defs: RefCell::new(DefIdMap()),
             predicates: RefCell::new(DefIdMap()),
@@ -3439,7 +3465,6 @@ impl<'tcx> ctxt<'tcx> {
             trait_item_def_ids: RefCell::new(DefIdMap()),
             trait_items_cache: RefCell::new(DefIdMap()),
             ty_param_defs: RefCell::new(NodeMap()),
-            adjustments: RefCell::new(NodeMap()),
             normalized_cache: RefCell::new(FnvHashMap()),
             lang_items: lang_items,
             provided_method_sources: RefCell::new(DefIdMap()),
@@ -3452,14 +3477,10 @@ impl<'tcx> ctxt<'tcx> {
             used_mut_nodes: RefCell::new(NodeSet()),
             populated_external_types: RefCell::new(DefIdSet()),
             populated_external_primitive_impls: RefCell::new(DefIdSet()),
-            upvar_capture_map: RefCell::new(FnvHashMap()),
             extern_const_statics: RefCell::new(DefIdMap()),
             extern_const_variants: RefCell::new(DefIdMap()),
             extern_const_fns: RefCell::new(DefIdMap()),
-            method_map: RefCell::new(FnvHashMap()),
             dependency_formats: RefCell::new(FnvHashMap()),
-            closure_kinds: RefCell::new(DefIdMap()),
-            closure_tys: RefCell::new(DefIdMap()),
             node_lint_levels: RefCell::new(FnvHashMap()),
             transmute_restrictions: RefCell::new(Vec::new()),
             stability: RefCell::new(stability),
@@ -3515,7 +3536,7 @@ impl<'tcx> ctxt<'tcx> {
     }
 
     pub fn closure_kind(&self, def_id: ast::DefId) -> ty::ClosureKind {
-        *self.closure_kinds.borrow().get(&def_id).unwrap()
+        *self.tables.borrow().closure_kinds.get(&def_id).unwrap()
     }
 
     pub fn closure_type(&self,
@@ -3523,7 +3544,7 @@ impl<'tcx> ctxt<'tcx> {
                         substs: &subst::Substs<'tcx>)
                         -> ty::ClosureTy<'tcx>
     {
-        self.closure_tys.borrow().get(&def_id).unwrap().subst(self, substs)
+        self.tables.borrow().closure_tys.get(&def_id).unwrap().subst(self, substs)
     }
 
     pub fn type_parameter_def(&self,
@@ -4369,7 +4390,8 @@ impl<'tcx> TyS<'tcx> {
                        span: Span)
                        -> bool
     {
-        let infcx = infer::new_infer_ctxt(param_env.tcx());
+        let tcx = param_env.tcx();
+        let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env.clone()));
 
         let is_impld = traits::type_known_to_meet_builtin_bound(&infcx, param_env,
                                                                 self, bound, span);
@@ -5276,11 +5298,11 @@ impl<'tcx> ctxt<'tcx> {
     }
 
     pub fn node_id_to_type_opt(&self, id: ast::NodeId) -> Option<Ty<'tcx>> {
-        self.node_types.borrow().get(&id).cloned()
+        self.tables.borrow().node_types.get(&id).cloned()
     }
 
     pub fn node_id_item_substs(&self, id: ast::NodeId) -> ItemSubsts<'tcx> {
-        match self.item_substs.borrow().get(&id) {
+        match self.tables.borrow().item_substs.get(&id) {
             None => ItemSubsts::empty(),
             Some(ts) => ts.clone(),
         }
@@ -5325,9 +5347,9 @@ impl<'tcx> ctxt<'tcx> {
     pub fn expr_ty_adjusted(&self, expr: &ast::Expr) -> Ty<'tcx> {
         self.expr_ty(expr)
             .adjust(self, expr.span, expr.id,
-                    self.adjustments.borrow().get(&expr.id),
+                    self.tables.borrow().adjustments.get(&expr.id),
                     |method_call| {
-            self.method_map.borrow().get(&method_call).map(|method| method.ty)
+            self.tables.borrow().method_map.get(&method_call).map(|method| method.ty)
         })
     }
 
@@ -6671,11 +6693,11 @@ impl<'tcx> ctxt<'tcx> {
     }
 
     pub fn is_method_call(&self, expr_id: ast::NodeId) -> bool {
-        self.method_map.borrow().contains_key(&MethodCall::expr(expr_id))
+        self.tables.borrow().method_map.contains_key(&MethodCall::expr(expr_id))
     }
 
     pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
-        Some(self.upvar_capture_map.borrow().get(&upvar_id).unwrap().clone())
+        Some(self.tables.borrow().upvar_capture_map.get(&upvar_id).unwrap().clone())
     }
 }
 
@@ -6689,17 +6711,21 @@ impl<'a,'tcx> Typer<'tcx> for ParameterEnvironment<'a,'tcx> {
     }
 
     fn node_method_ty(&self, method_call: ty::MethodCall) -> Option<Ty<'tcx>> {
-        self.tcx.method_map.borrow().get(&method_call).map(|method| method.ty)
+        self.tcx.tables.borrow().method_map.get(&method_call).map(|method| method.ty)
     }
 
     fn node_method_origin(&self, method_call: ty::MethodCall)
                           -> Option<ty::MethodOrigin<'tcx>>
     {
-        self.tcx.method_map.borrow().get(&method_call).map(|method| method.origin.clone())
+        self.tcx.tables.borrow().method_map.get(&method_call).map(|method| method.origin.clone())
     }
 
-    fn adjustments(&self) -> &RefCell<NodeMap<ty::AutoAdjustment<'tcx>>> {
-        &self.tcx.adjustments
+    fn adjustments(&self) -> Ref<NodeMap<ty::AutoAdjustment<'tcx>>> {
+        fn projection<'a, 'tcx>(tables: &'a Tables<'tcx>) -> &'a NodeMap<ty::AutoAdjustment<'tcx>> {
+            &tables.adjustments
+        }
+
+        Ref::map(self.tcx.tables.borrow(), projection)
     }
 
     fn is_method_call(&self, id: ast::NodeId) -> bool {
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index dcdf457965e..de2f33e8a4a 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -688,7 +688,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
             TyStr => write!(f, "str"),
             TyClosure(ref did, substs) => ty::tls::with(|tcx| {
                 try!(write!(f, "[closure"));
-                let closure_tys = tcx.closure_tys.borrow();
+                let closure_tys = &tcx.tables.borrow().closure_tys;
                 try!(closure_tys.get(did).map(|cty| &cty.sig).and_then(|sig| {
                     tcx.lift(&substs).map(|substs| sig.subst(tcx, substs))
                 }).map(|sig| {
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 1ad3f53c328..80c4fc28703 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -602,7 +602,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session,
                                                make_glob_map: resolve::MakeGlobMap,
                                                f: F)
                                                -> (Session, R)
-                                               where F: FnOnce(&ty::ctxt<'tcx>,
+                                               where F: for<'a> FnOnce(&'a ty::ctxt<'tcx>,
                                                                ty::CrateAnalysis) -> R
 {
     let time_passes = sess.time_passes();
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 5ec6e293684..fb2f6b2b08d 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -140,7 +140,7 @@ fn test_env<F>(source_string: &str,
                                lang_items,
                                stability::Index::new(krate),
                                |tcx| {
-        let infcx = infer::new_infer_ctxt(tcx);
+        let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
         body(Env { infcx: &infcx });
         let free_regions = FreeRegionMap::new();
         infcx.resolve_regions_and_report_errors(&free_regions, ast::CRATE_NODE_ID);
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 8fe07da1579..db48608823d 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -1446,7 +1446,7 @@ impl LintPass for UnusedAllocation {
             _ => return
         }
 
-        if let Some(adjustment) = cx.tcx.adjustments.borrow().get(&e.id) {
+        if let Some(adjustment) = cx.tcx.tables.borrow().adjustments.get(&e.id) {
             if let ty::AdjustDerefRef(ty::AutoDerefRef { ref autoref, .. }) = *adjustment {
                 match autoref {
                     &Some(ty::AutoPtr(_, ast::MutImmutable)) => {
@@ -1984,7 +1984,7 @@ impl LintPass for UnconditionalRecursion {
                                           method_id: ast::NodeId,
                                           method_name: ast::Ident,
                                           id: ast::NodeId) -> bool {
-            let did = match tcx.method_map.borrow().get(&ty::MethodCall::expr(id)) {
+            let did = match tcx.tables.borrow().method_map.get(&ty::MethodCall::expr(id)) {
                 None => return false,
                 Some(m) => match m.origin {
                     // There's no way to know if a method call via a
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 24803562fa3..239141df9e8 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -904,7 +904,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
             }
             ast::ExprMethodCall(ident, _, _) => {
                 let method_call = MethodCall::expr(expr.id);
-                match self.tcx.method_map.borrow().get(&method_call) {
+                match self.tcx.tables.borrow().method_map.get(&method_call) {
                     None => {
                         self.tcx.sess.span_bug(expr.span,
                                                 "method call not in \
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index bb7e95cd4ae..dc692b0e765 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -43,6 +43,7 @@
 #![feature(unicode)]
 #![feature(unicode)]
 #![feature(vec_push_all)]
+#![feature(cell_extras)]
 
 #![allow(trivial_casts)]
 
diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs
index 5ddad0e1947..d86242f39ce 100644
--- a/src/librustc_trans/save/dump_csv.rs
+++ b/src/librustc_trans/save/dump_csv.rs
@@ -886,7 +886,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
     fn process_method_call(&mut self,
                            ex: &ast::Expr,
                            args: &Vec<P<ast::Expr>>) {
-        let method_map = self.tcx.method_map.borrow();
+        let method_map = &self.tcx.tables.borrow().method_map;
         let method_callee = method_map.get(&ty::MethodCall::expr(ex.id)).unwrap();
         let (def_id, decl_id) = match method_callee.origin {
             ty::MethodStatic(def_id) |
diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs
index f035b32e359..0cd6bbad03a 100644
--- a/src/librustc_trans/trans/base.rs
+++ b/src/librustc_trans/trans/base.rs
@@ -212,7 +212,7 @@ pub fn self_type_for_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 }
 
 pub fn kind_for_closure(ccx: &CrateContext, closure_id: ast::DefId) -> ty::ClosureKind {
-    *ccx.tcx().closure_kinds.borrow().get(&closure_id).unwrap()
+    *ccx.tcx().tables.borrow().closure_kinds.get(&closure_id).unwrap()
 }
 
 pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId,
diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs
index 24abe0ed3fd..dfe807d6c91 100644
--- a/src/librustc_trans/trans/callee.rs
+++ b/src/librustc_trans/trans/callee.rs
@@ -518,7 +518,7 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>(
             let ref_ty = match node {
                 ExprId(id) => tcx.node_id_to_type(id),
                 MethodCallKey(method_call) => {
-                    tcx.method_map.borrow().get(&method_call).unwrap().ty
+                    tcx.tables.borrow().method_map.get(&method_call).unwrap().ty
                 }
             };
             let ref_ty = monomorphize::apply_param_substs(tcx,
@@ -610,7 +610,7 @@ pub fn trans_method_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let _icx = push_ctxt("trans_method_call");
     debug!("trans_method_call(call_expr={:?})", call_expr);
     let method_call = MethodCall::expr(call_expr.id);
-    let method_ty = match bcx.tcx().method_map.borrow().get(&method_call) {
+    let method_ty = match bcx.tcx().tables.borrow().method_map.get(&method_call) {
         Some(method) => match method.origin {
             ty::MethodTraitObject(_) => match method.ty.sty {
                 ty::TyBareFn(_, ref fty) => {
diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs
index cb30bcdbf53..b6378062855 100644
--- a/src/librustc_trans/trans/closure.rs
+++ b/src/librustc_trans/trans/closure.rs
@@ -130,7 +130,7 @@ pub fn get_or_create_declaration_if_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tc
                                                       closure_id: ast::DefId,
                                                       substs: &Substs<'tcx>)
                                                       -> Option<Datum<'tcx, Rvalue>> {
-    if !ccx.tcx().closure_kinds.borrow().contains_key(&closure_id) {
+    if !ccx.tcx().tables.borrow().closure_kinds.contains_key(&closure_id) {
         // Not a closure.
         return None
     }
diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs
index 777b61f25f0..483d82f508f 100644
--- a/src/librustc_trans/trans/common.rs
+++ b/src/librustc_trans/trans/common.rs
@@ -47,7 +47,7 @@ use util::nodemap::{FnvHashMap, NodeMap};
 use arena::TypedArena;
 use libc::{c_uint, c_char};
 use std::ffi::CString;
-use std::cell::{Cell, RefCell};
+use std::cell::{Cell, RefCell, Ref};
 use std::result::Result as StdResult;
 use std::vec::Vec;
 use syntax::ast;
@@ -353,7 +353,7 @@ pub struct FunctionContext<'a, 'tcx: 'a> {
     // section of the executable we're generating.
     pub llfn: ValueRef,
 
-    // always an empty parameter-environment
+    // always an empty parameter-environment NOTE: @jroesch another use of ParamEnv
     pub param_env: ty::ParameterEnvironment<'a, 'tcx>,
 
     // The environment argument in a closure.
@@ -630,8 +630,9 @@ impl<'blk, 'tcx> mc::Typer<'tcx> for BlockS<'blk, 'tcx> {
 
     fn node_method_ty(&self, method_call: ty::MethodCall) -> Option<Ty<'tcx>> {
         self.tcx()
-            .method_map
+            .tables
             .borrow()
+            .method_map
             .get(&method_call)
             .map(|method| monomorphize_type(self, method.ty))
     }
@@ -640,18 +641,26 @@ impl<'blk, 'tcx> mc::Typer<'tcx> for BlockS<'blk, 'tcx> {
                           -> Option<ty::MethodOrigin<'tcx>>
     {
         self.tcx()
-            .method_map
+            .tables
             .borrow()
+            .method_map
             .get(&method_call)
             .map(|method| method.origin.clone())
     }
 
-    fn adjustments<'a>(&'a self) -> &'a RefCell<NodeMap<ty::AutoAdjustment<'tcx>>> {
-        &self.tcx().adjustments
+    fn adjustments<'a>(&'a self) -> Ref<NodeMap<ty::AutoAdjustment<'tcx>>> {
+        // FIXME (@jroesch): this is becuase we currently have a HR inference problem
+        // in the snapshot that causes this code not to work.
+        fn project_adjustments<'a, 'tcx>(tables: &'a ty::Tables<'tcx>) ->
+            &'a NodeMap<ty::AutoAdjustment<'tcx>> {
+            &tables.adjustments
+        }
+
+        Ref::map(self.tcx().tables.borrow(), project_adjustments)
     }
 
     fn is_method_call(&self, id: ast::NodeId) -> bool {
-        self.tcx().method_map.borrow().contains_key(&ty::MethodCall::expr(id))
+        self.tcx().tables.borrow().method_map.contains_key(&ty::MethodCall::expr(id))
     }
 
     fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<region::CodeExtent> {
@@ -659,7 +668,7 @@ impl<'blk, 'tcx> mc::Typer<'tcx> for BlockS<'blk, 'tcx> {
     }
 
     fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
-        Some(self.tcx().upvar_capture_map.borrow().get(&upvar_id).unwrap().clone())
+        Some(self.tcx().tables.borrow().upvar_capture_map.get(&upvar_id).unwrap().clone())
     }
 
     fn type_moves_by_default(&self, ty: Ty<'tcx>, span: Span) -> bool {
@@ -991,7 +1000,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
            trait_ref, trait_ref.def_id());
 
     tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id());
-    let infcx = infer::new_infer_ctxt(tcx);
+    let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
 
     // Do the initial selection for the obligation. This yields the
     // shallow result we are looking for -- that is, what specific impl.
@@ -1053,7 +1062,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
            predicates);
 
     let tcx = ccx.tcx();
-    let infcx = infer::new_infer_ctxt(tcx);
+    let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
     let typer = NormalizingClosureTyper::new(tcx);
     let mut selcx = traits::SelectionContext::new(&infcx, &typer);
     let mut fulfill_cx = traits::FulfillmentContext::new(false);
@@ -1070,6 +1079,10 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     drain_fulfillment_cx(&infcx, &mut fulfill_cx, &()).is_ok()
 }
 
+// NOTE: here is another use of parameter environment without an InferCtxt,
+// this is obviously related to the typer interface requiring a parameter env.
+// We should pay attention to this when refactoring
+// - @jroesch
 pub struct NormalizingClosureTyper<'a,'tcx:'a> {
     param_env: ty::ParameterEnvironment<'a, 'tcx>
 }
@@ -1191,7 +1204,7 @@ pub fn node_id_substs<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             tcx.node_id_item_substs(id).substs
         }
         MethodCallKey(method_call) => {
-            tcx.method_map.borrow().get(&method_call).unwrap().substs.clone()
+            tcx.tables.borrow().method_map.get(&method_call).unwrap().substs.clone()
         }
     };
 
diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs
index 8ec60000ee8..57af688ef60 100644
--- a/src/librustc_trans/trans/consts.rs
+++ b/src/librustc_trans/trans/consts.rs
@@ -228,7 +228,7 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             let def = ccx.tcx().def_map.borrow().get(&expr.id).unwrap().full_def();
             match def {
                 def::DefConst(def_id) | def::DefAssociatedConst(def_id, _) => {
-                    if !ccx.tcx().adjustments.borrow().contains_key(&expr.id) {
+                    if !ccx.tcx().tables.borrow().adjustments.contains_key(&expr.id) {
                         debug!("get_const_expr_as_global ({:?}): found const {:?}",
                                expr.id, def_id);
                         return get_const_val(ccx, def_id, expr);
@@ -281,7 +281,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     let mut llconst = llconst;
     let mut ety_adjusted = monomorphize::apply_param_substs(cx.tcx(), param_substs,
                                                             &cx.tcx().expr_ty_adjusted(e));
-    let opt_adj = cx.tcx().adjustments.borrow().get(&e.id).cloned();
+    let opt_adj = cx.tcx().tables.borrow().adjustments.get(&e.id).cloned();
     match opt_adj {
         Some(ty::AdjustReifyFnPointer) => {
             // FIXME(#19925) once fn item types are
@@ -894,7 +894,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
           ast::ExprMethodCall(_, _, ref args) => {
               let arg_vals = map_list(args);
               let method_call = ty::MethodCall::expr(e.id);
-              let method_did = match cx.tcx().method_map.borrow()[&method_call].origin {
+              let method_did = match cx.tcx().tables.borrow().method_map[&method_call].origin {
                   ty::MethodStatic(did) => did,
                   _ => cx.sess().span_bug(e.span, "expected a const method def")
               };
diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs
index 8fd88055b8e..045cc69bf95 100644
--- a/src/librustc_trans/trans/expr.rs
+++ b/src/librustc_trans/trans/expr.rs
@@ -117,7 +117,7 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
 
-    if bcx.tcx().adjustments.borrow().contains_key(&expr.id) {
+    if bcx.tcx().tables.borrow().adjustments.contains_key(&expr.id) {
         // use trans, which may be less efficient but
         // which will perform the adjustments:
         let datum = unpack_datum!(bcx, trans(bcx, expr));
@@ -345,7 +345,7 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 {
     let mut bcx = bcx;
     let mut datum = datum;
-    let adjustment = match bcx.tcx().adjustments.borrow().get(&expr.id).cloned() {
+    let adjustment = match bcx.tcx().tables.borrow().adjustments.get(&expr.id).cloned() {
         None => {
             return DatumBlock::new(bcx, datum);
         }
@@ -372,7 +372,7 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                     // Don't skip a conversion from Box<T> to &T, etc.
                     ty::TyRef(..) => {
                         let method_call = MethodCall::autoderef(expr.id, 0);
-                        if bcx.tcx().method_map.borrow().contains_key(&method_call) {
+                        if bcx.tcx().tables.borrow().method_map.contains_key(&method_call) {
                             // Don't skip an overloaded deref.
                             0
                         } else {
@@ -774,8 +774,9 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     // Check for overloaded index.
     let method_ty = ccx.tcx()
-                       .method_map
+                       .tables
                        .borrow()
+                       .method_map
                        .get(&method_call)
                        .map(|method| method.ty);
     let elt_datum = match method_ty {
@@ -1617,7 +1618,7 @@ fn trans_unary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     // Otherwise, we should be in the RvalueDpsExpr path.
     assert!(
         op == ast::UnDeref ||
-        !ccx.tcx().method_map.borrow().contains_key(&method_call));
+        !ccx.tcx().tables.borrow().method_map.contains_key(&method_call));
 
     let un_ty = expr_ty(bcx, expr);
 
@@ -1910,7 +1911,7 @@ fn trans_binary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let ccx = bcx.ccx();
 
     // if overloaded, would be RvalueDpsExpr
-    assert!(!ccx.tcx().method_map.borrow().contains_key(&MethodCall::expr(expr.id)));
+    assert!(!ccx.tcx().tables.borrow().method_map.contains_key(&MethodCall::expr(expr.id)));
 
     match op.node {
         ast::BiAnd => {
@@ -1950,7 +1951,12 @@ fn trans_overloaded_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                    dest: Option<Dest>,
                                    autoref: bool)
                                    -> Result<'blk, 'tcx> {
-    let method_ty = bcx.tcx().method_map.borrow().get(&method_call).unwrap().ty;
+    let method_ty = bcx.tcx()
+                       .tables
+                       .borrow()
+                       .method_map
+                       .get(&method_call).unwrap().ty;
+
     callee::trans_call_inner(bcx,
                              expr.debug_loc(),
                              monomorphize_type(bcx, method_ty),
@@ -1973,8 +1979,9 @@ fn trans_overloaded_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
     debug!("trans_overloaded_call {}", expr.id);
     let method_call = MethodCall::expr(expr.id);
     let method_type = bcx.tcx()
-                         .method_map
+                         .tables
                          .borrow()
+                         .method_map
                          .get(&method_call)
                          .unwrap()
                          .ty;
@@ -2154,7 +2161,7 @@ fn trans_assign_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     debug!("trans_assign_op(expr={:?})", expr);
 
     // User-defined operator methods cannot be used with `+=` etc right now
-    assert!(!bcx.tcx().method_map.borrow().contains_key(&MethodCall::expr(expr.id)));
+    assert!(!bcx.tcx().tables.borrow().method_map.contains_key(&MethodCall::expr(expr.id)));
 
     // Evaluate LHS (destination), which should be an lvalue
     let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op"));
@@ -2229,8 +2236,12 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let mut bcx = bcx;
 
     // Check for overloaded deref.
-    let method_ty = ccx.tcx().method_map.borrow()
+    let method_ty = ccx.tcx()
+                       .tables
+                       .borrow()
+                       .method_map
                        .get(&method_call).map(|method| method.ty);
+
     let datum = match method_ty {
         Some(method_ty) => {
             let method_ty = monomorphize_type(bcx, method_ty);
@@ -2615,7 +2626,7 @@ enum ExprKind {
 }
 
 fn expr_kind(tcx: &ty::ctxt, expr: &ast::Expr) -> ExprKind {
-    if tcx.method_map.borrow().contains_key(&MethodCall::expr(expr.id)) {
+    if tcx.tables.borrow().method_map.contains_key(&MethodCall::expr(expr.id)) {
         // Overloaded operations are generally calls, and hence they are
         // generated via DPS, but there are a few exceptions:
         return match expr.node {
diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs
index a3e5b640fd0..e46c3b5fab1 100644
--- a/src/librustc_trans/trans/meth.rs
+++ b/src/librustc_trans/trans/meth.rs
@@ -109,11 +109,13 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let _icx = push_ctxt("meth::trans_method_callee");
 
     let (origin, method_ty) =
-        bcx.tcx().method_map
-                 .borrow()
-                 .get(&method_call)
-                 .map(|method| (method.origin.clone(), method.ty))
-                 .unwrap();
+        bcx.tcx()
+           .tables
+           .borrow()
+           .method_map
+           .get(&method_call)
+           .map(|method| (method.origin.clone(), method.ty))
+           .unwrap();
 
     match origin {
         ty::MethodStatic(did) |
diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs
index cae810c9082..67ccf64621a 100644
--- a/src/librustc_trans/trans/monomorphize.rs
+++ b/src/librustc_trans/trans/monomorphize.rs
@@ -322,8 +322,9 @@ pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
     }
 
     // FIXME(#20304) -- cache
-
-    let infcx = infer::new_infer_ctxt(tcx);
+    // NOTE: @jroesch
+    // Here is of an example where we do not use a param_env but use a typer instead.
+    let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
     let typer = NormalizingClosureTyper::new(tcx);
     let mut selcx = traits::SelectionContext::new(&infcx, &typer);
     let cause = traits::ObligationCause::dummy();
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 7109e45b552..d29c0494572 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -137,9 +137,9 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             // Check whether this is a call to a closure where we
             // haven't yet decided on whether the closure is fn vs
             // fnmut vs fnonce. If so, we have to defer further processing.
-            if fcx.closure_kind(def_id).is_none() {
+            if fcx.infcx().closure_kind(def_id).is_none() {
                 let closure_ty =
-                    fcx.closure_type(def_id, substs);
+                    fcx.infcx().closure_type(def_id, substs);
                 let fn_sig =
                     fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
                                                                           infer::FnCall,
@@ -324,7 +324,7 @@ fn write_overloaded_call_method_map<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                              call_expr: &ast::Expr,
                                              method_callee: ty::MethodCallee<'tcx>) {
     let method_call = ty::MethodCall::expr(call_expr.id);
-    fcx.inh.method_map.borrow_mut().insert(method_call, method_callee);
+    fcx.inh.tables.borrow_mut().method_map.insert(method_call, method_callee);
 }
 
 #[derive(Debug)]
@@ -344,7 +344,7 @@ impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> {
 
         // we should not be invoked until the closure kind has been
         // determined by upvar inference
-        assert!(fcx.closure_kind(self.closure_def_id).is_some());
+        assert!(fcx.infcx().closure_kind(self.closure_def_id).is_some());
 
         // We may now know enough to figure out fn vs fnmut etc.
         match try_overloaded_call_traits(fcx, self.call_expr, self.callee_expr,
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index d431c0fda98..b5ee46ece94 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -61,7 +61,7 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
         expected_sig);
 
     let closure_type = fcx.ccx.tcx.mk_closure(expr_def_id,
-        fcx.ccx.tcx.mk_substs(fcx.inh.param_env.free_substs.clone()));
+        fcx.ccx.tcx.mk_substs(fcx.inh.infcx.parameter_environment.free_substs.clone()));
 
     fcx.write_ty(expr.id, closure_type);
 
@@ -86,9 +86,9 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
            fn_ty.sig,
            opt_kind);
 
-    fcx.inh.closure_tys.borrow_mut().insert(expr_def_id, fn_ty);
+    fcx.inh.tables.borrow_mut().closure_tys.insert(expr_def_id, fn_ty);
     match opt_kind {
-        Some(kind) => { fcx.inh.closure_kinds.borrow_mut().insert(expr_def_id, kind); }
+        Some(kind) => { fcx.inh.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); }
         None => { }
     }
 }
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 73b9a16d1eb..b38b6884a98 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -273,7 +273,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         };
         let source = source.adjust_for_autoref(self.tcx(), reborrow);
 
-        let mut selcx = traits::SelectionContext::new(self.fcx.infcx(), self.fcx);
+        let mut selcx = traits::SelectionContext::new(self.fcx.infcx(), self.fcx.infcx());
 
         // Use a FIFO queue for this custom fulfillment procedure.
         let mut queue = VecDeque::new();
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 349d1a8bb65..f62411e8582 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -43,7 +43,7 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
     debug!("compare_impl_method: impl_trait_ref (liberated) = {:?}",
            impl_trait_ref);
 
-    let infcx = infer::new_infer_ctxt(tcx);
+    let mut infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
     let mut fulfillment_cx = traits::FulfillmentContext::new(true);
 
     let trait_to_impl_substs = &impl_trait_ref.substs;
@@ -240,11 +240,13 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
     let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.into_vec());
     let trait_param_env = traits::normalize_param_env_or_error(trait_param_env,
                                                                normalize_cause.clone());
+    // FIXME(@jroesch) this seems ugly, but is a temporary change
+    infcx.parameter_environment = trait_param_env;
 
     debug!("compare_impl_method: trait_bounds={:?}",
-        trait_param_env.caller_bounds);
+        infcx.parameter_environment.caller_bounds);
 
-    let mut selcx = traits::SelectionContext::new(&infcx, &trait_param_env);
+    let mut selcx = traits::SelectionContext::new(&infcx, &infcx.parameter_environment);
 
     for predicate in impl_pred.fns {
         let traits::Normalized { value: predicate, .. } =
@@ -345,7 +347,7 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
 
     // Check that all obligations are satisfied by the implementation's
     // version.
-    match fulfillment_cx.select_all_or_error(&infcx, &trait_param_env) {
+    match fulfillment_cx.select_all_or_error(&infcx, &infcx.parameter_environment) {
         Err(ref errors) => { traits::report_fulfillment_errors(&infcx, errors) }
         Ok(_) => {}
     }
@@ -360,7 +362,8 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
     // anyway, so it shouldn't be needed there either. Anyway, we can
     // always add more relations later (it's backwards compat).
     let mut free_regions = FreeRegionMap::new();
-    free_regions.relate_free_regions_from_predicates(tcx, &trait_param_env.caller_bounds);
+    free_regions.relate_free_regions_from_predicates(tcx,
+                                                     &infcx.parameter_environment.caller_bounds);
 
     infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id);
 
@@ -416,7 +419,7 @@ pub fn compare_const_impl<'tcx>(tcx: &ty::ctxt<'tcx>,
     debug!("compare_const_impl(impl_trait_ref={:?})",
            impl_trait_ref);
 
-    let infcx = infer::new_infer_ctxt(tcx);
+    let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
     let mut fulfillment_cx = traits::FulfillmentContext::new(true);
 
     // 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 a48cffb4472..6f0fbfebf46 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -93,7 +93,8 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
                          ty: named_type } =
         tcx.lookup_item_type(self_type_did);
 
-    let infcx = infer::new_infer_ctxt(tcx);
+    let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
+
     infcx.commit_if_ok(|snapshot| {
         let (named_type_to_skolem, skol_map) =
             infcx.construct_skolemized_subst(named_type_generics, snapshot);
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 5f7a78ec611..9c2d1c4a34d 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -488,8 +488,9 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
             // Count autoderefs.
             let autoderef_count = match self.fcx
                                             .inh
-                                            .adjustments
+                                            .tables
                                             .borrow()
+                                            .adjustments
                                             .get(&expr.id) {
                 Some(&ty::AdjustDerefRef(ref adj)) => adj.autoderefs,
                 Some(_) | None => 0,
@@ -527,7 +528,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                         // expects. This is annoying and horrible. We
                         // ought to recode this routine so it doesn't
                         // (ab)use the normal type checking paths.
-                        let adj = self.fcx.inh.adjustments.borrow().get(&base_expr.id).cloned();
+                        let adj = self.fcx.inh.tables.borrow().adjustments.get(&base_expr.id)
+                                                                          .cloned();
                         let (autoderefs, unsize) = match adj {
                             Some(ty::AdjustDerefRef(adr)) => match adr.autoref {
                                 None => {
@@ -589,7 +591,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                         // if this is an overloaded deref, then re-evaluate with
                         // a preference for mut
                         let method_call = MethodCall::expr(expr.id);
-                        if self.fcx.inh.method_map.borrow().contains_key(&method_call) {
+                        if self.fcx.inh.tables.borrow().method_map.contains_key(&method_call) {
                             check::try_overloaded_deref(
                                 self.fcx,
                                 expr.span,
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index 0f8048f27a0..f312db9c4dc 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -195,7 +195,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                               poly_trait_ref.to_predicate());
 
     // Now we want to know if this can be matched
-    let mut selcx = traits::SelectionContext::new(fcx.infcx(), fcx);
+    let mut selcx = traits::SelectionContext::new(fcx.infcx(), fcx.infcx());
     if !selcx.evaluate_obligation(&obligation) {
         debug!("--> Cannot match obligation");
         return None; // Cannot be matched, no such method resolution is possible.
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 8026fce69ec..94a2050829d 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -421,7 +421,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
         // We can't use normalize_associated_types_in as it will pollute the
         // fcx's fulfillment context after this probe is over.
         let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
-        let mut selcx = &mut traits::SelectionContext::new(self.fcx.infcx(), self.fcx);
+        let mut selcx = &mut traits::SelectionContext::new(self.fcx.infcx(), self.fcx.infcx());
         let traits::Normalized { value: xform_self_ty, obligations } =
             traits::normalize(selcx, cause, &xform_self_ty);
         debug!("assemble_inherent_impl_probe: xform_self_ty = {:?}",
@@ -477,7 +477,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
         // FIXME -- Do we want to commit to this behavior for param bounds?
 
         let bounds: Vec<_> =
-            self.fcx.inh.param_env.caller_bounds
+            self.fcx.inh.infcx.parameter_environment.caller_bounds
             .iter()
             .filter_map(|predicate| {
                 match *predicate {
@@ -681,7 +681,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
             // as it will pollute the fcx's fulfillment context after this probe
             // is over.
             let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
-            let mut selcx = &mut traits::SelectionContext::new(self.fcx.infcx(), self.fcx);
+            let mut selcx = &mut traits::SelectionContext::new(self.fcx.infcx(), self.fcx.infcx());
             let traits::Normalized { value: xform_self_ty, obligations } =
                 traits::normalize(selcx, cause, &xform_self_ty);
 
@@ -742,7 +742,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
                 _ => continue,
             };
 
-            let closure_kinds = self.fcx.inh.closure_kinds.borrow();
+            let closure_kinds = &self.fcx.inh.tables.borrow().closure_kinds;
             let closure_kind = match closure_kinds.get(&closure_def_id) {
                 Some(&k) => k,
                 None => {
@@ -845,7 +845,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
         debug!("assemble_where_clause_candidates(trait_def_id={:?})",
                trait_def_id);
 
-        let caller_predicates = self.fcx.inh.param_env.caller_bounds.clone();
+        let caller_predicates = self.fcx.inh.infcx.parameter_environment.caller_bounds.clone();
         for poly_bound in traits::elaborate_predicates(self.tcx(), caller_predicates)
                           .filter_map(|p| p.to_opt_poly_trait_ref())
                           .filter(|b| b.def_id() == trait_def_id)
@@ -1076,7 +1076,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
             match probe.kind {
                 InherentImplCandidate(impl_def_id, ref substs, ref ref_obligations) |
                 ExtensionImplCandidate(impl_def_id, _, ref substs, _, ref ref_obligations) => {
-                    let selcx = &mut traits::SelectionContext::new(self.infcx(), self.fcx);
+                    let selcx = &mut traits::SelectionContext::new(self.infcx(), self.fcx.infcx());
                     let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
 
                     // Check whether the impl imposes obligations we have to worry about.
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index b193ddcb213..b81b672e684 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -102,7 +102,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                             let obligation = Obligation::misc(span,
                                                               fcx.body_id,
                                                               poly_trait_ref.to_predicate());
-                            let mut selcx = SelectionContext::new(infcx, fcx);
+                            let mut selcx = SelectionContext::new(infcx, fcx.infcx());
 
                             if selcx.evaluate_obligation(&obligation) {
                                 span_stored_function();
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 299ccd579cc..7e87dc6540e 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -87,8 +87,6 @@ use fmt_macros::{Parser, Piece, Position};
 use middle::astconv_util::{check_path_args, NO_TPS, NO_REGIONS};
 use middle::def;
 use middle::infer;
-use middle::mem_categorization as mc;
-use middle::mem_categorization::McResult;
 use middle::pat_util::{self, pat_id_map};
 use middle::privacy::{AllPublic, LastMod};
 use middle::region::{self, CodeExtent};
@@ -97,7 +95,7 @@ use middle::traits::{self, report_fulfillment_errors};
 use middle::ty::{FnSig, GenericPredicates, TypeScheme};
 use middle::ty::{Disr, ParamTy, ParameterEnvironment};
 use middle::ty::{self, HasTypeFlags, RegionEscape, ToPolyTraitRef, Ty};
-use middle::ty::{MethodCall, MethodCallee, MethodMap};
+use middle::ty::{MethodCall, MethodCallee};
 use middle::ty_fold::{TypeFolder, TypeFoldable};
 use rscope::RegionScope;
 use session::Session;
@@ -152,16 +150,8 @@ mod op;
 pub struct Inherited<'a, 'tcx: 'a> {
     infcx: infer::InferCtxt<'a, 'tcx>,
     locals: RefCell<NodeMap<Ty<'tcx>>>,
-    param_env: ty::ParameterEnvironment<'a, 'tcx>,
 
-    // Temporary tables:
-    node_types: RefCell<NodeMap<Ty<'tcx>>>,
-    item_substs: RefCell<NodeMap<ty::ItemSubsts<'tcx>>>,
-    adjustments: RefCell<NodeMap<ty::AutoAdjustment<'tcx>>>,
-    method_map: MethodMap<'tcx>,
-    upvar_capture_map: RefCell<ty::UpvarCaptureMap>,
-    closure_tys: RefCell<DefIdMap<ty::ClosureTy<'tcx>>>,
-    closure_kinds: RefCell<DefIdMap<ty::ClosureKind>>,
+    tables: &'a RefCell<ty::Tables<'tcx>>,
 
     // A mapping from each fn's id to its signature, with all bound
     // regions replaced with free ones. Unlike the other tables, this
@@ -298,90 +288,16 @@ pub struct FnCtxt<'a, 'tcx: 'a> {
     ccx: &'a CrateCtxt<'a, 'tcx>,
 }
 
-impl<'a, 'tcx> mc::Typer<'tcx> for FnCtxt<'a, 'tcx> {
-    fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>> {
-        let ty = self.node_ty(id);
-        self.resolve_type_vars_or_error(&ty)
-    }
-    fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult<Ty<'tcx>> {
-        let ty = self.adjust_expr_ty(expr, self.inh.adjustments.borrow().get(&expr.id));
-        self.resolve_type_vars_or_error(&ty)
-    }
-    fn type_moves_by_default(&self, ty: Ty<'tcx>, span: Span) -> bool {
-        let ty = self.infcx().resolve_type_vars_if_possible(&ty);
-        !traits::type_known_to_meet_builtin_bound(self.infcx(), self, ty, ty::BoundCopy, span)
-    }
-    fn node_method_ty(&self, method_call: ty::MethodCall)
-                      -> Option<Ty<'tcx>> {
-        self.inh.method_map.borrow()
-                           .get(&method_call)
-                           .map(|method| method.ty)
-                           .map(|ty| self.infcx().resolve_type_vars_if_possible(&ty))
-    }
-    fn node_method_origin(&self, method_call: ty::MethodCall)
-                          -> Option<ty::MethodOrigin<'tcx>>
-    {
-        self.inh.method_map.borrow()
-                           .get(&method_call)
-                           .map(|method| method.origin.clone())
-    }
-    fn adjustments(&self) -> &RefCell<NodeMap<ty::AutoAdjustment<'tcx>>> {
-        &self.inh.adjustments
-    }
-    fn is_method_call(&self, id: ast::NodeId) -> bool {
-        self.inh.method_map.borrow().contains_key(&ty::MethodCall::expr(id))
-    }
-    fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<CodeExtent> {
-        self.param_env().temporary_scope(rvalue_id)
-    }
-    fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
-        self.inh.upvar_capture_map.borrow().get(&upvar_id).cloned()
-    }
-}
-
-impl<'a, 'tcx> ty::ClosureTyper<'tcx> for FnCtxt<'a, 'tcx> {
-    fn param_env<'b>(&'b self) -> &'b ty::ParameterEnvironment<'b,'tcx> {
-        &self.inh.param_env
-    }
-
-    fn closure_kind(&self,
-                    def_id: ast::DefId)
-                    -> Option<ty::ClosureKind>
-    {
-        self.inh.closure_kinds.borrow().get(&def_id).cloned()
-    }
-
-    fn closure_type(&self,
-                    def_id: ast::DefId,
-                    substs: &subst::Substs<'tcx>)
-                    -> ty::ClosureTy<'tcx>
-    {
-        self.inh.closure_tys.borrow().get(&def_id).unwrap().subst(self.tcx(), substs)
-    }
-
-    fn closure_upvars(&self,
-                      def_id: ast::DefId,
-                      substs: &Substs<'tcx>)
-                      -> Option<Vec<ty::ClosureUpvar<'tcx>>> {
-        ty::ctxt::closure_upvars(self, def_id, substs)
-    }
-}
-
 impl<'a, 'tcx> Inherited<'a, 'tcx> {
     fn new(tcx: &'a ty::ctxt<'tcx>,
+           tables: &'a RefCell<ty::Tables<'tcx>>,
            param_env: ty::ParameterEnvironment<'a, 'tcx>)
            -> Inherited<'a, 'tcx> {
+
         Inherited {
-            infcx: infer::new_infer_ctxt(tcx),
+            infcx: infer::new_infer_ctxt(tcx, tables, Some(param_env)),
             locals: RefCell::new(NodeMap()),
-            param_env: param_env,
-            node_types: RefCell::new(NodeMap()),
-            item_substs: RefCell::new(NodeMap()),
-            adjustments: RefCell::new(NodeMap()),
-            method_map: RefCell::new(FnvHashMap()),
-            upvar_capture_map: RefCell::new(FnvHashMap()),
-            closure_tys: RefCell::new(DefIdMap()),
-            closure_kinds: RefCell::new(DefIdMap()),
+            tables: tables,
             fn_sig_map: RefCell::new(NodeMap()),
             fulfillment_cx: RefCell::new(traits::FulfillmentContext::new(true)),
             deferred_call_resolutions: RefCell::new(DefIdMap()),
@@ -424,12 +340,13 @@ pub fn blank_fn_ctxt<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
     }
 }
 
-fn static_inherited_fields<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>)
+fn static_inherited_fields<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
+                                     tables: &'a RefCell<ty::Tables<'tcx>>)
                                     -> Inherited<'a, 'tcx> {
     // It's kind of a kludge to manufacture a fake function context
     // and statement context, but we might as well do write the code only once
     let param_env = ccx.tcx.empty_parameter_environment();
-    Inherited::new(ccx.tcx, param_env)
+    Inherited::new(ccx.tcx, &tables, param_env)
 }
 
 struct CheckItemTypesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> }
@@ -504,16 +421,20 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 {
     match raw_fty.sty {
         ty::TyBareFn(_, ref fn_ty) => {
-            let inh = Inherited::new(ccx.tcx, param_env);
+            let tables = RefCell::new(ty::Tables::empty());
+            let inh = Inherited::new(ccx.tcx, &tables, param_env);
 
             // Compute the fty from point of view of inside fn.
             let fn_sig =
-                fn_ty.sig.subst(ccx.tcx, &inh.param_env.free_substs);
+                fn_ty.sig.subst(ccx.tcx, &inh.infcx.parameter_environment.free_substs);
             let fn_sig =
                 ccx.tcx.liberate_late_bound_regions(region::DestructionScopeData::new(body.id),
                                                     &fn_sig);
             let fn_sig =
-                inh.normalize_associated_types_in(&inh.param_env, body.span, body.id, &fn_sig);
+                inh.normalize_associated_types_in(&inh.infcx.parameter_environment,
+                                                  body.span,
+                                                  body.id,
+                                                  &fn_sig);
 
             let fcx = check_fn(ccx, fn_ty.unsafety, fn_id, &fn_sig,
                                decl, fn_id, body, &inh);
@@ -1198,7 +1119,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
     }
 
     fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
-        Some(&self.inh.param_env.free_substs)
+        Some(&self.inh.infcx.parameter_environment.free_substs)
     }
 
     fn get_type_parameter_bounds(&self,
@@ -1207,7 +1128,8 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
                                  -> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>
     {
         let def = self.tcx().type_parameter_def(node_id);
-        let r = self.inh.param_env.caller_bounds
+        let r = self.inh.infcx.parameter_environment
+                                  .caller_bounds
                                   .iter()
                                   .filter_map(|predicate| {
                                       match *predicate {
@@ -1273,7 +1195,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     pub fn param_env(&self) -> &ty::ParameterEnvironment<'a,'tcx> {
-        &self.inh.param_env
+        &self.inh.infcx.parameter_environment
     }
 
     pub fn sess(&self) -> &Session {
@@ -1322,16 +1244,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ty
     }
 
-    /// Resolves all type variables in `t` and then, if any were left
-    /// unresolved, substitutes an error type. This is used after the
-    /// main checking when doing a second pass before writeback. The
-    /// justification is that writeback will produce an error for
-    /// these unconstrained type variables.
-    fn resolve_type_vars_or_error(&self, ty: &Ty<'tcx>) -> mc::McResult<Ty<'tcx>> {
-        let ty = self.infcx().resolve_type_vars_if_possible(ty);
-        if ty.has_infer_types() || ty.references_error() { Err(()) } else { Ok(ty) }
-    }
-
     fn record_deferred_call_resolution(&self,
                                        closure_def_id: ast::DefId,
                                        r: DeferredCallResolutionHandler<'tcx>) {
@@ -1368,7 +1280,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// ! gets replaced with (), unconstrained ints with i32, and unconstrained floats with f64.
     pub fn default_type_parameters(&self) {
         use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither};
-        for (_, &mut ref ty) in &mut *self.inh.node_types.borrow_mut() {
+        for (_, &mut ref ty) in &mut self.inh.tables.borrow_mut().node_types {
             let resolved = self.infcx().resolve_type_vars_if_possible(ty);
             if self.infcx().type_var_diverges(resolved) {
                 demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil());
@@ -1390,7 +1302,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) {
         debug!("write_ty({}, {:?}) in fcx {}",
                node_id, ty, self.tag());
-        self.inh.node_types.borrow_mut().insert(node_id, ty);
+        self.inh.tables.borrow_mut().node_types.insert(node_id, ty);
     }
 
     pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) {
@@ -1400,7 +1312,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                    substs,
                    self.tag());
 
-            self.inh.item_substs.borrow_mut().insert(node_id, substs);
+            self.inh.tables.borrow_mut().item_substs.insert(node_id, substs);
         }
     }
 
@@ -1426,7 +1338,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return;
         }
 
-        self.inh.adjustments.borrow_mut().insert(node_id, adj);
+        self.inh.tables.borrow_mut().adjustments.insert(node_id, adj);
     }
 
     /// Basically whenever we are converting from a type scheme into
@@ -1465,7 +1377,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
         where T : TypeFoldable<'tcx> + HasTypeFlags
     {
-        self.inh.normalize_associated_types_in(self, span, self.body_id, value)
+        self.inh.normalize_associated_types_in(self.infcx(), span, self.body_id, value)
     }
 
     fn normalize_associated_type(&self,
@@ -1480,7 +1392,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.inh.fulfillment_cx
             .borrow_mut()
             .normalize_projection_type(self.infcx(),
-                                       self,
+                                       self.infcx(),
                                        ty::ProjectionTy {
                                            trait_ref: trait_ref,
                                            item_name: item_name,
@@ -1627,7 +1539,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     pub fn expr_ty(&self, ex: &ast::Expr) -> Ty<'tcx> {
-        match self.inh.node_types.borrow().get(&ex.id) {
+        match self.inh.tables.borrow().node_types.get(&ex.id) {
             Some(&t) => t,
             None => {
                 self.tcx().sess.bug(&format!("no type for expr in fcx {}",
@@ -1646,13 +1558,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let raw_ty = self.infcx().shallow_resolve(raw_ty);
         let resolve_ty = |ty: Ty<'tcx>| self.infcx().resolve_type_vars_if_possible(&ty);
         raw_ty.adjust(self.tcx(), expr.span, expr.id, adjustment, |method_call| {
-            self.inh.method_map.borrow().get(&method_call)
+            self.inh.tables.borrow().method_map.get(&method_call)
                                         .map(|method| resolve_ty(method.ty))
         })
     }
 
     pub fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx> {
-        match self.inh.node_types.borrow().get(&id) {
+        match self.inh.tables.borrow().node_types.get(&id) {
             Some(&t) => t,
             None if self.err_count_since_creation() != 0 => self.tcx().types.err,
             None => {
@@ -1665,7 +1577,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     pub fn item_substs(&self) -> Ref<NodeMap<ty::ItemSubsts<'tcx>>> {
-        self.inh.item_substs.borrow()
+        // 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.inh.tables.borrow(), project_item_susbts)
     }
 
     pub fn opt_node_ty_substs<F>(&self,
@@ -1673,7 +1592,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                  f: F) where
         F: FnOnce(&ty::ItemSubsts<'tcx>),
     {
-        match self.inh.item_substs.borrow().get(&id) {
+        match self.inh.tables.borrow().item_substs.get(&id) {
             Some(s) => { f(s) }
             None => { }
         }
@@ -1829,7 +1748,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         self.select_all_obligations_and_apply_defaults();
         let mut fulfillment_cx = self.inh.fulfillment_cx.borrow_mut();
-        match fulfillment_cx.select_all_or_error(self.infcx(), self) {
+        match fulfillment_cx.select_all_or_error(self.infcx(), self.infcx()) {
             Ok(()) => { }
             Err(errors) => { report_fulfillment_errors(self.infcx(), &errors); }
         }
@@ -1840,7 +1759,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         match
             self.inh.fulfillment_cx
             .borrow_mut()
-            .select_where_possible(self.infcx(), self)
+            .select_where_possible(self.infcx(), self.infcx())
         {
             Ok(()) => { }
             Err(errors) => { report_fulfillment_errors(self.infcx(), &errors); }
@@ -1855,7 +1774,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         match
             self.inh.fulfillment_cx
             .borrow_mut()
-            .select_new_obligations(self.infcx(), self)
+            .select_new_obligations(self.infcx(), self.infcx())
         {
             Ok(()) => { }
             Err(errors) => { report_fulfillment_errors(self.infcx(), &errors); }
@@ -2039,7 +1958,7 @@ fn make_overloaded_lvalue_return_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             let ret_ty = fcx.tcx().no_late_bound_regions(&ret_ty).unwrap().unwrap();
 
             if let Some(method_call) = method_call {
-                fcx.inh.method_map.borrow_mut().insert(method_call, method);
+                fcx.inh.tables.borrow_mut().method_map.insert(method_call, method);
             }
 
             // method returns &T, but the type as visible to user is T, so deref
@@ -2640,7 +2559,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
             Ok(method) => {
                 let method_ty = method.ty;
                 let method_call = MethodCall::expr(expr.id);
-                fcx.inh.method_map.borrow_mut().insert(method_call, method);
+                fcx.inh.tables.borrow_mut().method_map.insert(method_call, method);
                 method_ty
             }
             Err(error) => {
@@ -4074,7 +3993,8 @@ fn check_block_with_expected<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 fn check_const_in_type<'a,'tcx>(ccx: &'a CrateCtxt<'a,'tcx>,
                                 expr: &'tcx ast::Expr,
                                 expected_type: Ty<'tcx>) {
-    let inh = static_inherited_fields(ccx);
+    let tables = RefCell::new(ty::Tables::empty());
+    let inh = static_inherited_fields(ccx, &tables);
     let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(expected_type), expr.id);
     check_const_with_ty(&fcx, expr.span, expr, expected_type);
 }
@@ -4083,7 +4003,8 @@ fn check_const<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                         sp: Span,
                         e: &'tcx ast::Expr,
                         id: ast::NodeId) {
-    let inh = static_inherited_fields(ccx);
+    let tables = RefCell::new(ty::Tables::empty());
+    let inh = static_inherited_fields(ccx, &tables);
     let rty = ccx.tcx.node_id_to_type(id);
     let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), e.id);
     let declty = fcx.ccx.tcx.tcache.borrow().get(&local_def(id)).unwrap().ty;
@@ -4235,7 +4156,8 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
         let rty = ccx.tcx.node_id_to_type(id);
         let mut disr_vals: Vec<ty::Disr> = Vec::new();
 
-        let inh = static_inherited_fields(ccx);
+        let tables = RefCell::new(ty::Tables::empty());
+        let inh = static_inherited_fields(ccx, &tables);
         let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), id);
 
         let (_, repr_type_ty) = ccx.tcx.enum_repr_type(Some(&hint));
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index 5a114c81119..c419a986f95 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -330,7 +330,7 @@ fn lookup_op_method<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
 
             // HACK(eddyb) Fully qualified path to work around a resolve bug.
             let method_call = ::middle::ty::MethodCall::expr(expr.id);
-            fcx.inh.method_map.borrow_mut().insert(method_call, method);
+            fcx.inh.tables.borrow_mut().method_map.insert(method_call, method);
 
             // extract return type for method; all late bound regions
             // should have been instantiated by now
@@ -454,4 +454,3 @@ fn is_builtin_binop<'tcx>(cx: &ty::ctxt<'tcx>,
         }
     }
 }
-
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 13961834aeb..a8630190738 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -86,6 +86,7 @@ use astconv::AstConv;
 use check::dropck;
 use check::FnCtxt;
 use middle::free_region::FreeRegionMap;
+use middle::infer::InferCtxt;
 use middle::implicator;
 use middle::mem_categorization as mc;
 use middle::region::CodeExtent;
@@ -124,7 +125,8 @@ pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) {
 pub fn regionck_item(fcx: &FnCtxt, item: &ast::Item) {
     let mut rcx = Rcx::new(fcx, RepeatingScope(item.id), item.id, Subject(item.id));
     let tcx = fcx.tcx();
-    rcx.free_region_map.relate_free_regions_from_predicates(tcx, &fcx.inh.param_env.caller_bounds);
+    rcx.free_region_map
+       .relate_free_regions_from_predicates(tcx, &fcx.infcx().parameter_environment.caller_bounds);
     rcx.visit_region_obligations(item.id);
     rcx.resolve_regions_and_report_errors();
 }
@@ -143,7 +145,8 @@ pub fn regionck_fn(fcx: &FnCtxt,
     }
 
     let tcx = fcx.tcx();
-    rcx.free_region_map.relate_free_regions_from_predicates(tcx, &fcx.inh.param_env.caller_bounds);
+    rcx.free_region_map
+       .relate_free_regions_from_predicates(tcx, &fcx.infcx().parameter_environment.caller_bounds);
 
     rcx.resolve_regions_and_report_errors();
 
@@ -254,7 +257,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
     }
 
     fn resolve_method_type(&self, method_call: MethodCall) -> Option<Ty<'tcx>> {
-        let method_ty = self.fcx.inh.method_map.borrow()
+        let method_ty = self.fcx.inh.tables.borrow().method_map
                             .get(&method_call).map(|method| method.ty);
         method_ty.map(|method_ty| self.resolve_type(method_ty))
     }
@@ -267,7 +270,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
         } else {
             ty_unadjusted.adjust(
                 self.fcx.tcx(), expr.span, expr.id,
-                self.fcx.inh.adjustments.borrow().get(&expr.id),
+                self.fcx.inh.tables.borrow().adjustments.get(&expr.id),
                 |method_call| self.resolve_method_type(method_call))
         }
     }
@@ -353,7 +356,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
             debug!("relate_free_regions(t={:?})", ty);
             let body_scope = CodeExtent::from_node_id(body_id);
             let body_scope = ty::ReScope(body_scope);
-            let implications = implicator::implications(self.fcx.infcx(), self.fcx, body_id,
+            let implications = implicator::implications(self.fcx.infcx(), self.fcx.infcx(), body_id,
                                                         ty, body_scope, span);
 
             // Record any relations between free regions that we observe into the free-region-map.
@@ -511,12 +514,13 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
                       expr_ty, ty::ReScope(CodeExtent::from_node_id(expr.id)));
 
     let method_call = MethodCall::expr(expr.id);
-    let has_method_map = rcx.fcx.inh.method_map.borrow().contains_key(&method_call);
+    let has_method_map = rcx.fcx.inh.tables.borrow().method_map.contains_key(&method_call);
 
     // Check any autoderefs or autorefs that appear.
-    if let Some(adjustment) = rcx.fcx.inh.adjustments.borrow().get(&expr.id) {
+    let adjustment = rcx.fcx.inh.tables.borrow().adjustments.get(&expr.id).map(|a| a.clone());
+    if let Some(adjustment) = adjustment {
         debug!("adjustment={:?}", adjustment);
-        match *adjustment {
+        match adjustment {
             ty::AdjustDerefRef(ty::AutoDerefRef {autoderefs, ref autoref, ..}) => {
                 let expr_ty = rcx.resolve_node_type(expr.id);
                 constrain_autoderefs(rcx, expr, autoderefs, expr_ty);
@@ -548,7 +552,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
         // If necessary, constrain destructors in the unadjusted form of this
         // expression.
         let cmt_result = {
-            let mc = mc::MemCategorizationContext::new(rcx.fcx);
+            let mc = mc::MemCategorizationContext::new(rcx.fcx.infcx());
             mc.cat_expr_unadjusted(expr)
         };
         match cmt_result {
@@ -567,7 +571,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
     // If necessary, constrain destructors in this expression. This will be
     // the adjusted form if there is an adjustment.
     let cmt_result = {
-        let mc = mc::MemCategorizationContext::new(rcx.fcx);
+        let mc = mc::MemCategorizationContext::new(rcx.fcx.infcx());
         mc.cat_expr(expr)
     };
     match cmt_result {
@@ -657,7 +661,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
         ast::ExprUnary(ast::UnDeref, ref base) => {
             // For *a, the lifetime of a must enclose the deref
             let method_call = MethodCall::expr(expr.id);
-            let base_ty = match rcx.fcx.inh.method_map.borrow().get(&method_call) {
+            let base_ty = match rcx.fcx.inh.tables.borrow().method_map.get(&method_call) {
                 Some(method) => {
                     constrain_call(rcx, expr, Some(&**base),
                                    None::<ast::Expr>.iter(), true);
@@ -884,7 +888,9 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
         let method_call = MethodCall::autoderef(deref_expr.id, i as u32);
         debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs);
 
-        derefd_ty = match rcx.fcx.inh.method_map.borrow().get(&method_call) {
+        let method = rcx.fcx.inh.tables.borrow().method_map.get(&method_call).map(|m| m.clone());
+
+        derefd_ty = match method {
             Some(method) => {
                 debug!("constrain_autoderefs: #{} is overloaded, method={:?}",
                        i, method);
@@ -909,7 +915,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
                        r, m);
 
                 {
-                    let mc = mc::MemCategorizationContext::new(rcx.fcx);
+                    let mc = mc::MemCategorizationContext::new(rcx.fcx.infcx());
                     let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
                     debug!("constrain_autoderefs: self_cmt={:?}",
                            self_cmt);
@@ -1018,7 +1024,7 @@ fn type_of_node_must_outlive<'a, 'tcx>(
     // report errors later on in the writeback phase.
     let ty0 = rcx.resolve_node_type(id);
     let ty = ty0.adjust(tcx, origin.span(), id,
-                        rcx.fcx.inh.adjustments.borrow().get(&id),
+                        rcx.fcx.inh.tables.borrow().adjustments.get(&id),
                         |method_call| rcx.resolve_method_type(method_call));
     debug!("constrain_regions_in_type_of_node(\
             ty={}, ty0={}, id={}, minimum_lifetime={:?})",
@@ -1034,7 +1040,7 @@ fn link_addr_of(rcx: &mut Rcx, expr: &ast::Expr,
     debug!("link_addr_of(expr={:?}, base={:?})", expr, base);
 
     let cmt = {
-        let mc = mc::MemCategorizationContext::new(rcx.fcx);
+        let mc = mc::MemCategorizationContext::new(rcx.fcx.infcx());
         ignore_err!(mc.cat_expr(base))
     };
 
@@ -1052,7 +1058,7 @@ fn link_local(rcx: &Rcx, local: &ast::Local) {
         None => { return; }
         Some(ref expr) => &**expr,
     };
-    let mc = mc::MemCategorizationContext::new(rcx.fcx);
+    let mc = mc::MemCategorizationContext::new(rcx.fcx.infcx());
     let discr_cmt = ignore_err!(mc.cat_expr(init_expr));
     link_pattern(rcx, mc, discr_cmt, &*local.pat);
 }
@@ -1062,7 +1068,7 @@ fn link_local(rcx: &Rcx, local: &ast::Local) {
 /// linked to the lifetime of its guarantor (if any).
 fn link_match(rcx: &Rcx, discr: &ast::Expr, arms: &[ast::Arm]) {
     debug!("regionck::for_match()");
-    let mc = mc::MemCategorizationContext::new(rcx.fcx);
+    let mc = mc::MemCategorizationContext::new(rcx.fcx.infcx());
     let discr_cmt = ignore_err!(mc.cat_expr(discr));
     debug!("discr_cmt={:?}", discr_cmt);
     for arm in arms {
@@ -1077,7 +1083,7 @@ fn link_match(rcx: &Rcx, discr: &ast::Expr, arms: &[ast::Arm]) {
 /// linked to the lifetime of its guarantor (if any).
 fn link_fn_args(rcx: &Rcx, body_scope: CodeExtent, args: &[ast::Arg]) {
     debug!("regionck::link_fn_args(body_scope={:?})", body_scope);
-    let mc = mc::MemCategorizationContext::new(rcx.fcx);
+    let mc = mc::MemCategorizationContext::new(rcx.fcx.infcx());
     for arg in args {
         let arg_ty = rcx.fcx.node_ty(arg.id);
         let re_scope = ty::ReScope(body_scope);
@@ -1092,7 +1098,7 @@ fn link_fn_args(rcx: &Rcx, body_scope: CodeExtent, args: &[ast::Arg]) {
 /// Link lifetimes of any ref bindings in `root_pat` to the pointers found in the discriminant, if
 /// needed.
 fn link_pattern<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
-                          mc: mc::MemCategorizationContext<FnCtxt<'a, 'tcx>>,
+                          mc: mc::MemCategorizationContext<InferCtxt<'a, 'tcx>>,
                           discr_cmt: mc::cmt<'tcx>,
                           root_pat: &ast::Pat) {
     debug!("link_pattern(discr_cmt={:?}, root_pat={:?})",
@@ -1131,7 +1137,7 @@ fn link_autoref(rcx: &Rcx,
                 autoref: &ty::AutoRef)
 {
     debug!("link_autoref(autoref={:?})", autoref);
-    let mc = mc::MemCategorizationContext::new(rcx.fcx);
+    let mc = mc::MemCategorizationContext::new(rcx.fcx.infcx());
     let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs));
     debug!("expr_cmt={:?}", expr_cmt);
 
@@ -1155,7 +1161,7 @@ fn link_by_ref(rcx: &Rcx,
                callee_scope: CodeExtent) {
     debug!("link_by_ref(expr={:?}, callee_scope={:?})",
            expr, callee_scope);
-    let mc = mc::MemCategorizationContext::new(rcx.fcx);
+    let mc = mc::MemCategorizationContext::new(rcx.fcx.infcx());
     let expr_cmt = ignore_err!(mc.cat_expr(expr));
     let borrow_region = ty::ReScope(callee_scope);
     link_region(rcx, expr.span, &borrow_region, ty::ImmBorrow, expr_cmt);
@@ -1292,7 +1298,7 @@ fn link_reborrowed_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
     // Detect by-ref upvar `x`:
     let cause = match note {
         mc::NoteUpvarRef(ref upvar_id) => {
-            let upvar_capture_map = rcx.fcx.inh.upvar_capture_map.borrow_mut();
+            let upvar_capture_map = &rcx.fcx.inh.tables.borrow_mut().upvar_capture_map;
             match upvar_capture_map.get(upvar_id) {
                 Some(&ty::UpvarCapture::ByRef(ref upvar_borrow)) => {
                     // The mutability of the upvar may have been modified
@@ -1399,7 +1405,7 @@ pub fn type_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
            ty,
            region);
 
-    let implications = implicator::implications(rcx.fcx.infcx(), rcx.fcx, rcx.body_id,
+    let implications = implicator::implications(rcx.fcx.infcx(), rcx.fcx.infcx(), rcx.body_id,
                                                 ty, region, origin.span());
     for implication in implications {
         debug!("implication: {:?}", implication);
@@ -1440,7 +1446,7 @@ fn closure_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
     debug!("closure_must_outlive(region={:?}, def_id={:?}, substs={:?})",
            region, def_id, substs);
 
-    let upvars = rcx.fcx.closure_upvars(def_id, substs).unwrap();
+    let upvars = rcx.fcx.infcx().closure_upvars(def_id, substs).unwrap();
     for upvar in upvars {
         let var_id = upvar.def.def_id().local_id();
         type_must_outlive(
@@ -1453,7 +1459,7 @@ fn generic_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
                                   origin: infer::SubregionOrigin<'tcx>,
                                   region: ty::Region,
                                   generic: &GenericKind<'tcx>) {
-    let param_env = &rcx.fcx.inh.param_env;
+    let param_env = &rcx.fcx.inh.infcx.parameter_environment;
 
     debug!("param_must_outlive(region={:?}, generic={:?})",
            region,
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index 1345f322476..c7f084e27cd 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -129,9 +129,10 @@ impl<'a,'tcx> SeedBorrowKind<'a,'tcx> {
                      _body: &ast::Block)
     {
         let closure_def_id = ast_util::local_def(expr.id);
-        if !self.fcx.inh.closure_kinds.borrow().contains_key(&closure_def_id) {
+        if !self.fcx.inh.tables.borrow().closure_kinds.contains_key(&closure_def_id) {
             self.closures_with_inferred_kinds.insert(expr.id);
-            self.fcx.inh.closure_kinds.borrow_mut().insert(closure_def_id, ty::FnClosureKind);
+            self.fcx.inh.tables.borrow_mut().closure_kinds
+                                            .insert(closure_def_id, ty::FnClosureKind);
             debug!("check_closure: adding closure_id={:?} to closures_with_inferred_kinds",
                    closure_def_id);
         }
@@ -156,7 +157,7 @@ impl<'a,'tcx> SeedBorrowKind<'a,'tcx> {
                     }
                 };
 
-                self.fcx.inh.upvar_capture_map.borrow_mut().insert(upvar_id, capture_kind);
+                self.fcx.inh.tables.borrow_mut().upvar_capture_map.insert(upvar_id, capture_kind);
             }
         });
     }
@@ -186,7 +187,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
 
         debug!("analyzing closure `{}` with fn body id `{}`", id, body.id);
 
-        let mut euv = euv::ExprUseVisitor::new(self, self.fcx);
+        let mut euv = euv::ExprUseVisitor::new(self, self.fcx.infcx());
         euv.walk_fn(decl, body);
 
         // If we had not yet settled on a closure kind for this closure,
@@ -267,7 +268,10 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
                         // to move out of an upvar, this must be a FnOnce closure
                         self.adjust_closure_kind(upvar_id.closure_expr_id, ty::FnOnceClosureKind);
 
-                        let mut upvar_capture_map = self.fcx.inh.upvar_capture_map.borrow_mut();
+                        let upvar_capture_map = &mut self.fcx
+                                                         .inh
+                                                         .tables.borrow_mut()
+                                                         .upvar_capture_map;
                         upvar_capture_map.insert(upvar_id, ty::UpvarCapture::ByValue);
                     }
                     mc::NoteClosureEnv(upvar_id) => {
@@ -374,9 +378,11 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
                 // upvar, then we need to modify the
                 // borrow_kind of the upvar to make sure it
                 // is inferred to mutable if necessary
-                let mut upvar_capture_map = self.fcx.inh.upvar_capture_map.borrow_mut();
-                let ub = upvar_capture_map.get_mut(&upvar_id).unwrap();
-                self.adjust_upvar_borrow_kind(upvar_id, ub, borrow_kind);
+                {
+                    let upvar_capture_map = &mut self.fcx.inh.tables.borrow_mut().upvar_capture_map;
+                    let ub = upvar_capture_map.get_mut(&upvar_id).unwrap();
+                    self.adjust_upvar_borrow_kind(upvar_id, ub, borrow_kind);
+                }
 
                 // also need to be in an FnMut closure since this is not an ImmBorrow
                 self.adjust_closure_kind(upvar_id.closure_expr_id, ty::FnMutClosureKind);
@@ -442,7 +448,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
         }
 
         let closure_def_id = ast_util::local_def(closure_id);
-        let mut closure_kinds = self.fcx.inh.closure_kinds.borrow_mut();
+        let closure_kinds = &mut self.fcx.inh.tables.borrow_mut().closure_kinds;
         let existing_kind = *closure_kinds.get(&closure_def_id).unwrap();
 
         debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}",
diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs
index 00bbbafd5cd..df01b99fd9b 100644
--- a/src/librustc_typeck/check/wf.rs
+++ b/src/librustc_typeck/check/wf.rs
@@ -18,6 +18,7 @@ use middle::traits;
 use middle::ty::{self, Ty};
 use middle::ty_fold::{TypeFolder, TypeFoldable, super_fold_ty};
 
+use std::cell::RefCell;
 use std::collections::HashSet;
 use syntax::ast;
 use syntax::ast_util::local_def;
@@ -143,7 +144,8 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
                                                                 &type_scheme.generics,
                                                                 &type_predicates,
                                                                 item.id);
-        let inh = Inherited::new(ccx.tcx, param_env);
+        let tables = RefCell::new(ty::Tables::empty());
+        let inh = Inherited::new(ccx.tcx, &tables, param_env);
         let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(type_scheme.ty), item.id);
         f(self, &fcx);
         fcx.select_all_obligations_or_error();
@@ -199,7 +201,10 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
 
             let type_scheme = fcx.tcx().lookup_item_type(local_def(item.id));
             let item_ty = fcx.instantiate_type_scheme(item.span,
-                                                      &fcx.inh.param_env.free_substs,
+                                                      &fcx.inh
+                                                          .infcx
+                                                          .parameter_environment
+                                                          .free_substs,
                                                       &type_scheme.ty);
 
             bounds_checker.check_traits_in_ty(item_ty, item.span);
@@ -220,7 +225,10 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
             // to free.
             let self_ty = fcx.tcx().node_id_to_type(item.id);
             let self_ty = fcx.instantiate_type_scheme(item.span,
-                                                      &fcx.inh.param_env.free_substs,
+                                                      &fcx.inh
+                                                          .infcx
+                                                          .parameter_environment
+                                                          .free_substs,
                                                       &self_ty);
 
             bounds_checker.check_traits_in_ty(self_ty, item.span);
@@ -233,7 +241,10 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
             };
 
             let trait_ref = fcx.instantiate_type_scheme(item.span,
-                                                        &fcx.inh.param_env.free_substs,
+                                                        &fcx.inh
+                                                            .infcx
+                                                            .parameter_environment
+                                                            .free_substs,
                                                         &trait_ref);
 
             // We are stricter on the trait-ref in an impl than the
@@ -257,7 +268,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
             let predicates = fcx.tcx().lookup_super_predicates(poly_trait_ref.def_id());
             let predicates = predicates.instantiate_supertrait(fcx.tcx(), &poly_trait_ref);
             let predicates = {
-                let selcx = &mut traits::SelectionContext::new(fcx.infcx(), fcx);
+                let selcx = &mut traits::SelectionContext::new(fcx.infcx(), fcx.infcx());
                 traits::normalize(selcx, cause.clone(), &predicates)
             };
             for predicate in predicates.value.predicates {
@@ -635,7 +646,10 @@ fn struct_variant<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         .map(|field| {
             let field_ty = fcx.tcx().node_id_to_type(field.node.id);
             let field_ty = fcx.instantiate_type_scheme(field.span,
-                                                       &fcx.inh.param_env.free_substs,
+                                                       &fcx.inh
+                                                           .infcx
+                                                           .parameter_environment
+                                                           .free_substs,
                                                        &field_ty);
             AdtField { ty: field_ty, span: field.span }
         })
@@ -660,7 +674,10 @@ fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                             let arg_ty = arg_tys[index];
                             let arg_ty =
                                 fcx.instantiate_type_scheme(variant.span,
-                                                            &fcx.inh.param_env.free_substs,
+                                                            &fcx.inh
+                                                                .infcx
+                                                                .parameter_environment
+                                                                .free_substs,
                                                             &arg_ty);
                             AdtField {
                                 ty: arg_ty,
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 29119f3b594..1fc7224737d 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -96,14 +96,14 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
             let rhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&rhs_ty);
 
             if lhs_ty.is_scalar() && rhs_ty.is_scalar() {
-                self.fcx.inh.method_map.borrow_mut().remove(&MethodCall::expr(e.id));
+                self.fcx.inh.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id));
 
                 // weird but true: the by-ref binops put an
                 // adjustment on the lhs but not the rhs; the
                 // adjustment for rhs is kind of baked into the
                 // system.
                 if !ast_util::is_by_value_binop(op.node) {
-                    self.fcx.inh.adjustments.borrow_mut().remove(&lhs.id);
+                    self.fcx.inh.tables.borrow_mut().adjustments.remove(&lhs.id);
                 }
             }
         }
@@ -204,7 +204,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
             return;
         }
 
-        for (upvar_id, upvar_capture) in self.fcx.inh.upvar_capture_map.borrow().iter() {
+        for (upvar_id, upvar_capture) in self.fcx.inh.tables.borrow().upvar_capture_map.iter() {
             let new_upvar_capture = match *upvar_capture {
                 ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue,
                 ty::UpvarCapture::ByRef(ref upvar_borrow) => {
@@ -217,7 +217,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
             debug!("Upvar capture for {:?} resolved to {:?}",
                    upvar_id,
                    new_upvar_capture);
-            self.fcx.tcx().upvar_capture_map.borrow_mut().insert(*upvar_id, new_upvar_capture);
+            self.fcx.tcx()
+                    .tables
+                    .borrow_mut()
+                    .upvar_capture_map
+                    .insert(*upvar_id, new_upvar_capture);
         }
     }
 
@@ -226,13 +230,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
             return
         }
 
-        for (def_id, closure_ty) in self.fcx.inh.closure_tys.borrow().iter() {
+        for (def_id, closure_ty) in self.fcx.inh.tables.borrow().closure_tys.iter() {
             let closure_ty = self.resolve(closure_ty, ResolvingClosure(*def_id));
-            self.fcx.tcx().closure_tys.borrow_mut().insert(*def_id, closure_ty);
+            self.fcx.tcx().tables.borrow_mut().closure_tys.insert(*def_id, closure_ty);
         }
 
-        for (def_id, &closure_kind) in self.fcx.inh.closure_kinds.borrow().iter() {
-            self.fcx.tcx().closure_kinds.borrow_mut().insert(*def_id, closure_kind);
+        for (def_id, &closure_kind) in self.fcx.inh.tables.borrow().closure_kinds.iter() {
+            self.fcx.tcx().tables.borrow_mut().closure_kinds.insert(*def_id, closure_kind);
         }
     }
 
@@ -254,7 +258,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
     }
 
     fn visit_adjustments(&self, reason: ResolveReason, id: ast::NodeId) {
-        match self.fcx.inh.adjustments.borrow_mut().remove(&id) {
+        let adjustments = self.fcx.inh.tables.borrow_mut().adjustments.remove(&id);
+        match adjustments {
             None => {
                 debug!("No adjustments for node {}", id);
             }
@@ -281,7 +286,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
                     }
                 };
                 debug!("Adjustments for node {}: {:?}", id, resolved_adjustment);
-                self.tcx().adjustments.borrow_mut().insert(
+                self.tcx().tables.borrow_mut().adjustments.insert(
                     id, resolved_adjustment);
             }
         }
@@ -291,7 +296,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
                               reason: ResolveReason,
                               method_call: MethodCall) {
         // Resolve any method map entry
-        match self.fcx.inh.method_map.borrow_mut().remove(&method_call) {
+        let new_method = match self.fcx.inh.tables.borrow_mut().method_map.remove(&method_call) {
             Some(method) => {
                 debug!("writeback::resolve_method_map_entry(call={:?}, entry={:?})",
                        method_call,
@@ -302,9 +307,17 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
                     substs: self.resolve(&method.substs, reason),
                 };
 
-                self.tcx().method_map.borrow_mut().insert(
+                Some(new_method)
+            }
+            None => None
+        };
+
+        //NB(jroesch): We need to match twice to avoid a double borrow which would cause an ICE
+        match new_method {
+            Some(method) => {
+                self.tcx().tables.borrow_mut().method_map.insert(
                     method_call,
-                    new_method);
+                    method);
             }
             None => {}
         }
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 06bd572ac12..fbabc287342 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -448,7 +448,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
             debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (free)",
                    source, target);
 
-            let infcx = new_infer_ctxt(tcx);
+            let infcx = new_infer_ctxt(tcx, &tcx.tables, Some(param_env));
 
             let check_mutbl = |mt_a: ty::mt<'tcx>, mt_b: ty::mt<'tcx>,
                                mk_ptr: &Fn(Ty<'tcx>) -> Ty<'tcx>| {
@@ -540,13 +540,15 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
             fulfill_cx.register_predicate_obligation(&infcx, predicate);
 
             // Check that all transitive obligations are satisfied.
-            if let Err(errors) = fulfill_cx.select_all_or_error(&infcx, &param_env) {
+            if let Err(errors) = fulfill_cx.select_all_or_error(&infcx,
+                                                                &infcx.parameter_environment) {
                 traits::report_fulfillment_errors(&infcx, &errors);
             }
 
             // Finally, resolve all regions.
             let mut free_regions = FreeRegionMap::new();
-            free_regions.relate_free_regions_from_predicates(tcx, &param_env.caller_bounds);
+            free_regions.relate_free_regions_from_predicates(tcx, &infcx.parameter_environment
+                                                                        .caller_bounds);
             infcx.resolve_regions_and_report_errors(&free_regions, impl_did.node);
 
             if let Some(kind) = kind {
@@ -630,7 +632,7 @@ fn subst_receiver_types_in_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
 pub fn check_coherence(crate_context: &CrateCtxt) {
     CoherenceChecker {
         crate_context: crate_context,
-        inference_context: new_infer_ctxt(crate_context.tcx),
+        inference_context: new_infer_ctxt(crate_context.tcx, &crate_context.tcx.tables, None),
         inherent_impls: RefCell::new(FnvHashMap()),
     }.check(crate_context.tcx.map.krate());
     unsafety::check(crate_context.tcx);
diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs
index b4ad55ef2e4..3495714fcc7 100644
--- a/src/librustc_typeck/coherence/overlap.rs
+++ b/src/librustc_typeck/coherence/overlap.rs
@@ -133,7 +133,7 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
                    impl1_def_id,
                    impl2_def_id);
 
-            let infcx = infer::new_infer_ctxt(self.tcx);
+            let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None);
             if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) {
                 self.report_overlap_error(trait_def_id, impl1_def_id, impl2_def_id);
             }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index e43a3542b6e..ef9dcd56a57 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -2204,7 +2204,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
                base_type,
                base_type_free);
 
-        let infcx = infer::new_infer_ctxt(tcx);
+        let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
         drop(::require_same_types(tcx,
                                   Some(&infcx),
                                   false,
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index fc825c198e7..48a64675c70 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -88,6 +88,7 @@ This API is completely unstable and subject to change.
 #![feature(slice_extras)]
 #![feature(staged_api)]
 #![feature(vec_push_all)]
+#![feature(cell_extras)]
 
 #[macro_use] extern crate log;
 #[macro_use] extern crate syntax;
@@ -162,7 +163,7 @@ fn write_substs_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>,
 
         assert!(!item_substs.substs.types.needs_infer());
 
-        tcx.item_substs.borrow_mut().insert(node_id, item_substs);
+        tcx.tables.borrow_mut().item_substs.insert(node_id, item_substs);
     }
 }
 
@@ -187,7 +188,7 @@ fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>,
 {
     let result = match maybe_infcx {
         None => {
-            let infcx = infer::new_infer_ctxt(tcx);
+            let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
             infer::mk_eqty(&infcx, t1_is_expected, infer::Misc(span), t1, t2)
         }
         Some(infcx) => {