about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/infer/mod.rs238
-rw-r--r--src/librustc/lint/context.rs50
-rw-r--r--src/librustc/middle/expr_use_visitor.rs82
-rw-r--r--src/librustc/middle/mem_categorization.rs208
-rw-r--r--src/librustc/traits/error_reporting.rs29
-rw-r--r--src/librustc/traits/mod.rs4
-rw-r--r--src/librustc/traits/specialize/mod.rs4
-rw-r--r--src/librustc/traits/specialize/specialization_graph.rs2
-rw-r--r--src/librustc/traits/trans/mod.rs2
-rw-r--r--src/librustc/ty/context.rs4
-rw-r--r--src/librustc/ty/util.rs8
-rw-r--r--src/librustc_borrowck/borrowck/check_loans.rs4
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/mod.rs9
-rw-r--r--src/librustc_const_eval/check_match.rs17
-rw-r--r--src/librustc_const_eval/eval.rs2
-rw-r--r--src/librustc_driver/test.rs2
-rw-r--r--src/librustc_lint/builtin.rs21
-rw-r--r--src/librustc_lint/types.rs2
-rw-r--r--src/librustc_mir/build/mod.rs11
-rw-r--r--src/librustc_mir/hair/cx/expr.rs10
-rw-r--r--src/librustc_mir/hair/cx/mod.rs6
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs2
-rw-r--r--src/librustc_mir/transform/type_check.rs2
-rw-r--r--src/librustc_passes/consts.rs16
-rw-r--r--src/librustc_typeck/check/compare_method.rs4
-rw-r--r--src/librustc_typeck/check/dropck.rs2
-rw-r--r--src/librustc_typeck/check/mod.rs51
-rw-r--r--src/librustc_typeck/check/regionck.rs60
-rw-r--r--src/librustc_typeck/check/upvar.rs207
-rw-r--r--src/librustc_typeck/coherence/builtin.rs2
-rw-r--r--src/librustc_typeck/coherence/inherent_impls_overlap.rs2
-rw-r--r--src/librustc_typeck/lib.rs2
32 files changed, 440 insertions, 625 deletions
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index f5869b8a20f..4bc0005d568 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -19,11 +19,8 @@ pub use self::freshen::TypeFreshener;
 pub use self::region_inference::{GenericKind, VerifyBound};
 
 use hir::def_id::DefId;
-use hir;
 use middle::free_region::{FreeRegionMap, RegionRelations};
 use middle::region::RegionMaps;
-use middle::mem_categorization as mc;
-use middle::mem_categorization::McResult;
 use middle::lang_items;
 use mir::tcx::LvalueTy;
 use ty::subst::{Kind, Subst, Substs};
@@ -34,9 +31,8 @@ use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use ty::relate::RelateResult;
 use traits::{self, ObligationCause, PredicateObligations, Reveal};
 use rustc_data_structures::unify::{self, UnificationTable};
-use std::cell::{Cell, RefCell, Ref, RefMut};
+use std::cell::{Cell, RefCell, Ref};
 use std::fmt;
-use std::ops::Deref;
 use syntax::ast;
 use errors::DiagnosticBuilder;
 use syntax_pos::{self, Span, DUMMY_SP};
@@ -76,71 +72,14 @@ pub type Bound<T> = Option<T>;
 pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
 pub type FixupResult<T> = Result<T, FixupError>; // "fixup result"
 
-/// A version of &ty::TypeckTables which can be `Missing` (not needed),
-/// `InProgress` (during typeck) or `Interned` (result of typeck).
-/// Only the `InProgress` version supports `borrow_mut`.
-#[derive(Copy, Clone)]
-pub enum InferTables<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    Interned(&'a ty::TypeckTables<'gcx>),
-    InProgress(&'a RefCell<ty::TypeckTables<'tcx>>),
-    Missing
-}
-
-pub enum InferTablesRef<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    Interned(&'a ty::TypeckTables<'gcx>),
-    InProgress(Ref<'a, ty::TypeckTables<'tcx>>)
-}
-
-impl<'a, 'gcx, 'tcx> Deref for InferTablesRef<'a, 'gcx, 'tcx> {
-    type Target = ty::TypeckTables<'tcx>;
-    fn deref(&self) -> &Self::Target {
-        match *self {
-            InferTablesRef::Interned(tables) => tables,
-            InferTablesRef::InProgress(ref tables) => tables
-        }
-    }
-}
-
-impl<'a, 'gcx, 'tcx> InferTables<'a, 'gcx, 'tcx> {
-    pub fn borrow(self) -> InferTablesRef<'a, 'gcx, 'tcx> {
-        match self {
-            InferTables::Interned(tables) => InferTablesRef::Interned(tables),
-            InferTables::InProgress(tables) => InferTablesRef::InProgress(tables.borrow()),
-            InferTables::Missing => {
-                bug!("InferTables: infcx.tables.borrow() with no tables")
-            }
-        }
-    }
-
-    pub fn expect_interned(self) -> &'a ty::TypeckTables<'gcx> {
-        match self {
-            InferTables::Interned(tables) => tables,
-            InferTables::InProgress(_) => {
-                bug!("InferTables: infcx.tables.expect_interned() during type-checking");
-            }
-            InferTables::Missing => {
-                bug!("InferTables: infcx.tables.expect_interned() with no tables")
-            }
-        }
-    }
-
-    pub fn borrow_mut(self) -> RefMut<'a, ty::TypeckTables<'tcx>> {
-        match self {
-            InferTables::Interned(_) => {
-                bug!("InferTables: infcx.tables.borrow_mut() outside of type-checking");
-            }
-            InferTables::InProgress(tables) => tables.borrow_mut(),
-            InferTables::Missing => {
-                bug!("InferTables: infcx.tables.borrow_mut() with no tables")
-            }
-        }
-    }
-}
-
 pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
 
-    pub tables: InferTables<'a, 'gcx, 'tcx>,
+    /// During type-checking/inference of a body, `in_progress_tables`
+    /// contains a reference to the tables being built up, which are
+    /// used for reading closure kinds/signatures as they are inferred,
+    /// and for error reporting logic to read arbitrary node types.
+    pub in_progress_tables: Option<&'a RefCell<ty::TypeckTables<'tcx>>>,
 
     // Cache for projections. This cache is snapshotted along with the
     // infcx.
@@ -396,91 +335,33 @@ impl fmt::Display for FixupError {
     }
 }
 
-pub trait InferEnv<'a, 'tcx> {
-    fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                -> (Option<&'a ty::TypeckTables<'tcx>>,
-                    Option<ty::TypeckTables<'tcx>>);
-}
-
-impl<'a, 'tcx> InferEnv<'a, 'tcx> for () {
-    fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
-                -> (Option<&'a ty::TypeckTables<'tcx>>,
-                    Option<ty::TypeckTables<'tcx>>) {
-        (None, None)
-    }
-}
-
-impl<'a, 'tcx> InferEnv<'a, 'tcx> for &'a ty::TypeckTables<'tcx> {
-    fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
-                -> (Option<&'a ty::TypeckTables<'tcx>>,
-                    Option<ty::TypeckTables<'tcx>>) {
-        (Some(self), None)
-    }
-}
-
-impl<'a, 'tcx> InferEnv<'a, 'tcx> for ty::TypeckTables<'tcx> {
-    fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
-                -> (Option<&'a ty::TypeckTables<'tcx>>,
-                    Option<ty::TypeckTables<'tcx>>) {
-        (None, Some(self))
-    }
-}
-
-impl<'a, 'tcx> InferEnv<'a, 'tcx> for hir::BodyId {
-    fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                -> (Option<&'a ty::TypeckTables<'tcx>>,
-                    Option<ty::TypeckTables<'tcx>>) {
-        let def_id = tcx.hir.body_owner_def_id(self);
-        (Some(tcx.typeck_tables_of(def_id)), None)
-    }
-}
-
-/// Helper type of a temporary returned by tcx.infer_ctxt(...).
+/// Helper type of a temporary returned by tcx.infer_ctxt().
 /// Necessary because we can't write the following bound:
 /// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(InferCtxt<'b, 'gcx, 'tcx>).
 pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     global_tcx: TyCtxt<'a, 'gcx, 'gcx>,
     arena: DroplessArena,
     fresh_tables: Option<RefCell<ty::TypeckTables<'tcx>>>,
-    tables: Option<&'a ty::TypeckTables<'gcx>>,
 }
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
-    pub fn infer_ctxt<E: InferEnv<'a, 'gcx>>(self, env: E) -> InferCtxtBuilder<'a, 'gcx, 'tcx> {
-        let (tables, fresh_tables) = env.to_parts(self);
+    pub fn infer_ctxt(self) -> InferCtxtBuilder<'a, 'gcx, 'tcx> {
         InferCtxtBuilder {
             global_tcx: self,
             arena: DroplessArena::new(),
-            fresh_tables: fresh_tables.map(RefCell::new),
-            tables: tables,
-        }
-    }
-
-    /// Fake InferCtxt with the global tcx. Used by pre-MIR borrowck
-    /// for MemCategorizationContext/ExprUseVisitor.
-    /// If any inference functionality is used, ICEs will occur.
-    pub fn borrowck_fake_infer_ctxt(self, body: hir::BodyId)
-                                    -> InferCtxt<'a, 'gcx, 'gcx> {
-        let (tables, _) = body.to_parts(self);
-        InferCtxt {
-            tcx: self,
-            tables: InferTables::Interned(tables.unwrap()),
-            type_variables: RefCell::new(type_variable::TypeVariableTable::new()),
-            int_unification_table: RefCell::new(UnificationTable::new()),
-            float_unification_table: RefCell::new(UnificationTable::new()),
-            region_vars: RegionVarBindings::new(self),
-            selection_cache: traits::SelectionCache::new(),
-            evaluation_cache: traits::EvaluationCache::new(),
-            projection_cache: RefCell::new(traits::ProjectionCache::new()),
-            reported_trait_errors: RefCell::new(FxHashSet()),
-            tainted_by_errors_flag: Cell::new(false),
-            err_count_on_creation: self.sess.err_count(),
-            in_snapshot: Cell::new(false),
+            fresh_tables: None,
         }
     }
 }
 
 impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
+    /// Used only by `rustc_typeck` during body type-checking/inference,
+    /// will initialize `in_progress_tables` with fresh `TypeckTables`.
+    pub fn with_fresh_in_progress_tables(mut self) -> Self {
+        self.fresh_tables = Some(RefCell::new(ty::TypeckTables::empty()));
+        self
+    }
+
     pub fn enter<F, R>(&'tcx mut self, f: F) -> R
         where F: for<'b> FnOnce(InferCtxt<'b, 'gcx, 'tcx>) -> R
     {
@@ -488,14 +369,11 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
             global_tcx,
             ref arena,
             ref fresh_tables,
-            tables,
         } = *self;
-        let tables = tables.map(InferTables::Interned).unwrap_or_else(|| {
-            fresh_tables.as_ref().map_or(InferTables::Missing, InferTables::InProgress)
-        });
+        let in_progress_tables = fresh_tables.as_ref();
         global_tcx.enter_local(arena, |tcx| f(InferCtxt {
-            tcx: tcx,
-            tables: tables,
+            tcx,
+            in_progress_tables,
             projection_cache: RefCell::new(traits::ProjectionCache::new()),
             type_variables: RefCell::new(type_variable::TypeVariableTable::new()),
             int_unification_table: RefCell::new(UnificationTable::new()),
@@ -618,7 +496,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
             return value;
         }
 
-        self.infer_ctxt(()).enter(|infcx| {
+        self.infer_ctxt().enter(|infcx| {
             value.trans_normalize(&infcx, param_env)
         })
     }
@@ -640,7 +518,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
             return value;
         }
 
-        self.infer_ctxt(()).enter(|infcx| {
+        self.infer_ctxt().enter(|infcx| {
             value.trans_normalize(&infcx, env.reveal_all())
        })
     }
@@ -844,10 +722,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             was_in_snapshot: in_snapshot,
             // Borrow tables "in progress" (i.e. during typeck)
             // to ban writes from within a snapshot to them.
-            _in_progress_tables: match self.tables {
-                InferTables::InProgress(ref tables) => tables.try_borrow().ok(),
-                _ => None
-            }
+            _in_progress_tables: self.in_progress_tables.map(|tables| {
+                tables.borrow()
+            })
         }
     }
 
@@ -1190,28 +1067,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         self.tainted_by_errors_flag.set(true)
     }
 
-    pub fn node_type(&self, id: ast::NodeId) -> Ty<'tcx> {
-        match self.tables.borrow().node_types.get(&id) {
-            Some(&t) => t,
-            // FIXME
-            None if self.is_tainted_by_errors() =>
-                self.tcx.types.err,
-            None => {
-                bug!("no type for node {}: {} in fcx",
-                     id, self.tcx.hir.node_to_string(id));
-            }
-        }
-    }
-
-    pub fn expr_ty(&self, ex: &hir::Expr) -> Ty<'tcx> {
-        match self.tables.borrow().node_types.get(&ex.id) {
-            Some(&t) => t,
-            None => {
-                bug!("no type for expr in fcx");
-            }
-        }
-    }
-
     pub fn resolve_regions_and_report_errors(&self,
                                              region_context: DefId,
                                              region_map: &RegionMaps,
@@ -1310,21 +1165,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, '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.references_error() || ty.is_ty_var() {
-            debug!("resolve_type_vars_or_error: error from {:?}", ty);
-            Err(())
-        } else {
-            Ok(ty)
-        }
-    }
-
     pub fn fully_resolve<T:TypeFoldable<'tcx>>(&self, value: &T) -> FixupResult<T> {
         /*!
          * Attempts to resolve all type/region variables in
@@ -1484,30 +1324,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         self.region_vars.verify_generic_bound(origin, kind, a, bound);
     }
 
-    pub fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>> {
-        let ty = self.node_type(id);
-        self.resolve_type_vars_or_error(&ty)
-    }
-
-    pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult<Ty<'tcx>> {
-        let ty = self.tables.borrow().expr_ty_adjusted(expr);
-        self.resolve_type_vars_or_error(&ty)
-    }
-
     pub fn type_moves_by_default(&self,
                                  param_env: ty::ParamEnv<'tcx>,
                                  ty: Ty<'tcx>,
                                  span: Span)
                                  -> bool {
         let ty = self.resolve_type_vars_if_possible(&ty);
-        if let Some((param_env, ty)) = self.tcx.lift_to_global(&(param_env, ty)) {
-            // Even if the type may have no inference variables, during
-            // type-checking closure types are in local tables only.
-            let local_closures = match self.tables {
-                InferTables::InProgress(_) => ty.has_closure_types(),
-                _ => false
-            };
-            if !local_closures {
+        // Even if the type may have no inference variables, during
+        // type-checking closure types are in local tables only.
+        if !self.in_progress_tables.is_some() || !ty.has_closure_types() {
+            if let Some((param_env, ty)) = self.tcx.lift_to_global(&(param_env, ty)) {
                 return ty.moves_by_default(self.tcx.global_tcx(), param_env, span);
             }
         }
@@ -1521,15 +1347,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         !traits::type_known_to_meet_bound(self, param_env, ty, copy_def_id, span)
     }
 
-    pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture<'tcx>> {
-        self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned()
-    }
-
     pub fn closure_kind(&self,
                         def_id: DefId)
                         -> Option<ty::ClosureKind>
     {
-        if let InferTables::InProgress(tables) = self.tables {
+        if let Some(tables) = self.in_progress_tables {
             if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
                 return tables.borrow()
                              .closure_kinds
@@ -1547,7 +1369,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn closure_type(&self, def_id: DefId) -> ty::PolyFnSig<'tcx> {
-        if let InferTables::InProgress(tables) = self.tables {
+        if let Some(tables) = self.in_progress_tables {
             if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
                 if let Some(&ty) = tables.borrow().closure_tys.get(&id) {
                     return ty;
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 2022565d533..40734469718 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -27,6 +27,7 @@ use self::TargetLint::*;
 
 use dep_graph::DepNode;
 use middle::privacy::AccessLevels;
+use traits::Reveal;
 use ty::{self, TyCtxt};
 use session::{config, early_error, Session};
 use lint::{Level, LevelSource, Lint, LintId, LintPass, LintSource};
@@ -411,8 +412,8 @@ pub struct LateContext<'a, 'tcx: 'a> {
     /// Side-tables for the body we are in.
     pub tables: &'a ty::TypeckTables<'tcx>,
 
-    /// The crate being checked.
-    pub krate: &'a hir::Crate,
+    /// Parameter environment for the item we are in.
+    pub param_env: ty::ParamEnv<'tcx>,
 
     /// Items accessible from the crate being checked.
     pub access_levels: &'a AccessLevels,
@@ -869,6 +870,17 @@ impl<'a> LintContext<'a> for EarlyContext<'a> {
     }
 }
 
+impl<'a, 'tcx> LateContext<'a, 'tcx> {
+    fn with_param_env<F>(&mut self, id: ast::NodeId, f: F)
+        where F: FnOnce(&mut Self),
+    {
+        let old_param_env = self.param_env;
+        self.param_env = self.tcx.param_env(self.tcx.hir.local_def_id(id));
+        f(self);
+        self.param_env = old_param_env;
+    }
+}
+
 impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
     /// Because lints are scoped lexically, we want to walk nested
     /// items in the context of the outer item, so enable
@@ -902,17 +914,21 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
 
     fn visit_item(&mut self, it: &'tcx hir::Item) {
         self.with_lint_attrs(&it.attrs, |cx| {
-            run_lints!(cx, check_item, late_passes, it);
-            hir_visit::walk_item(cx, it);
-            run_lints!(cx, check_item_post, late_passes, it);
+            cx.with_param_env(it.id, |cx| {
+                run_lints!(cx, check_item, late_passes, it);
+                hir_visit::walk_item(cx, it);
+                run_lints!(cx, check_item_post, late_passes, it);
+            });
         })
     }
 
     fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem) {
         self.with_lint_attrs(&it.attrs, |cx| {
-            run_lints!(cx, check_foreign_item, late_passes, it);
-            hir_visit::walk_foreign_item(cx, it);
-            run_lints!(cx, check_foreign_item_post, late_passes, it);
+            cx.with_param_env(it.id, |cx| {
+                run_lints!(cx, check_foreign_item, late_passes, it);
+                hir_visit::walk_foreign_item(cx, it);
+                run_lints!(cx, check_foreign_item_post, late_passes, it);
+            });
         })
     }
 
@@ -1026,17 +1042,21 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
 
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
         self.with_lint_attrs(&trait_item.attrs, |cx| {
-            run_lints!(cx, check_trait_item, late_passes, trait_item);
-            hir_visit::walk_trait_item(cx, trait_item);
-            run_lints!(cx, check_trait_item_post, late_passes, trait_item);
+            cx.with_param_env(trait_item.id, |cx| {
+                run_lints!(cx, check_trait_item, late_passes, trait_item);
+                hir_visit::walk_trait_item(cx, trait_item);
+                run_lints!(cx, check_trait_item_post, late_passes, trait_item);
+            });
         });
     }
 
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
         self.with_lint_attrs(&impl_item.attrs, |cx| {
-            run_lints!(cx, check_impl_item, late_passes, impl_item);
-            hir_visit::walk_impl_item(cx, impl_item);
-            run_lints!(cx, check_impl_item_post, late_passes, impl_item);
+            cx.with_param_env(impl_item.id, |cx| {
+                run_lints!(cx, check_impl_item, late_passes, impl_item);
+                hir_visit::walk_impl_item(cx, impl_item);
+                run_lints!(cx, check_impl_item_post, late_passes, impl_item);
+            });
         });
     }
 
@@ -1330,7 +1350,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     let mut cx = LateContext {
         tcx: tcx,
         tables: &ty::TypeckTables::empty(),
-        krate: krate,
+        param_env: ty::ParamEnv::empty(Reveal::UserFacing),
         access_levels: access_levels,
         lint_sess: LintSession::new(&tcx.sess.lint_store),
     };
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 0b2652c7488..58e77f40d98 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -235,17 +235,14 @@ impl OverloadedCallType {
 ///////////////////////////////////////////////////////////////////////////
 // The ExprUseVisitor type
 //
-// This is the code that actually walks the tree. Like
-// mem_categorization, it requires a TYPER, which is a type that
-// supplies types from the tree. After type checking is complete, you
-// can just use the tcx as the typer.
+// This is the code that actually walks the tree.
 pub struct ExprUseVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     mc: mc::MemCategorizationContext<'a, 'gcx, 'tcx>,
     delegate: &'a mut Delegate<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
 }
 
-// If the TYPER results in an error, it's because the type check
+// If the MC results in an error, it's because the type check
 // failed (or will fail, when the error is uncovered and reported
 // during writeback). In this case, we just ignore this part of the
 // code.
@@ -264,29 +261,32 @@ macro_rules! return_if_err {
     )
 }
 
-impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
+impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx, 'tcx> {
     pub fn new(delegate: &'a mut (Delegate<'tcx>+'a),
+               tcx: TyCtxt<'a, 'tcx, 'tcx>,
+               param_env: ty::ParamEnv<'tcx>,
                region_maps: &'a RegionMaps,
-               infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
-               param_env: ty::ParamEnv<'tcx>)
+               tables: &'a ty::TypeckTables<'tcx>)
                -> Self
     {
-        ExprUseVisitor::with_options(delegate,
-                                     infcx,
-                                     param_env,
-                                     region_maps,
-                                     mc::MemCategorizationOptions::default())
+        ExprUseVisitor {
+            mc: mc::MemCategorizationContext::new(tcx, region_maps, tables),
+            delegate,
+            param_env,
+        }
     }
+}
 
-    pub fn with_options(delegate: &'a mut (Delegate<'tcx>+'a),
-                        infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
-                        param_env: ty::ParamEnv<'tcx>,
-                        region_maps: &'a RegionMaps,
-                        options: mc::MemCategorizationOptions)
-               -> Self
+impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
+    pub fn with_infer(delegate: &'a mut (Delegate<'tcx>+'a),
+                      infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+                      param_env: ty::ParamEnv<'tcx>,
+                      region_maps: &'a RegionMaps,
+                      tables: &'a ty::TypeckTables<'tcx>)
+                      -> Self
     {
         ExprUseVisitor {
-            mc: mc::MemCategorizationContext::with_options(infcx, region_maps, options),
+            mc: mc::MemCategorizationContext::with_infer(infcx, region_maps, tables),
             delegate,
             param_env,
         }
@@ -296,7 +296,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
         debug!("consume_body(body={:?})", body);
 
         for arg in &body.arguments {
-            let arg_ty = return_if_err!(self.mc.infcx.node_ty(arg.pat.id));
+            let arg_ty = return_if_err!(self.mc.node_ty(arg.pat.id));
 
             let fn_body_scope_r = self.tcx().node_scope_region(body.value.id);
             let arg_cmt = self.mc.cat_rvalue(
@@ -312,7 +312,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
     }
 
     fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
-        self.mc.infcx.tcx
+        self.mc.tcx
     }
 
     fn delegate_consume(&mut self,
@@ -322,7 +322,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
         debug!("delegate_consume(consume_id={}, cmt={:?})",
                consume_id, cmt);
 
-        let mode = copy_or_move(self.mc.infcx, self.param_env, &cmt, DirectRefMove);
+        let mode = copy_or_move(&self.mc, self.param_env, &cmt, DirectRefMove);
         self.delegate.consume(consume_id, consume_span, cmt, mode);
     }
 
@@ -441,7 +441,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
             hir::ExprAddrOf(m, ref base) => {   // &base
                 // make sure that the thing we are pointing out stays valid
                 // for the lifetime `scope_r` of the resulting ptr:
-                let expr_ty = return_if_err!(self.mc.infcx.node_ty(expr.id));
+                let expr_ty = return_if_err!(self.mc.expr_ty(expr));
                 if let ty::TyRef(r, _) = expr_ty.sty {
                     let bk = ty::BorrowKind::from_mutbl(m);
                     self.borrow_expr(&base, r, bk, AddrOf);
@@ -505,7 +505,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
             }
 
             hir::ExprAssignOp(_, ref lhs, ref rhs) => {
-                if self.mc.infcx.tables.borrow().is_method_call(expr) {
+                if self.mc.tables.is_method_call(expr) {
                     self.consume_expr(lhs);
                 } else {
                     self.mutate_expr(expr, &lhs, MutateMode::WriteAndRead);
@@ -528,7 +528,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
     }
 
     fn walk_callee(&mut self, call: &hir::Expr, callee: &hir::Expr) {
-        let callee_ty = return_if_err!(self.mc.infcx.expr_ty_adjusted(callee));
+        let callee_ty = return_if_err!(self.mc.expr_ty_adjusted(callee));
         debug!("walk_callee: callee={:?} callee_ty={:?}",
                callee, callee_ty);
         match callee_ty.sty {
@@ -537,7 +537,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
             }
             ty::TyError => { }
             _ => {
-                let def_id = self.mc.infcx.tables.borrow().type_dependent_defs[&call.id].def_id();
+                let def_id = self.mc.tables.type_dependent_defs[&call.id].def_id();
                 match OverloadedCallType::from_method_id(self.tcx(), def_id) {
                     FnMutOverloadedCall => {
                         let call_scope_r = self.tcx().node_scope_region(call.id);
@@ -678,8 +678,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
     // consumed or borrowed as part of the automatic adjustment
     // process.
     fn walk_adjustment(&mut self, expr: &hir::Expr) {
-        //NOTE(@jroesch): mixed RefCell borrow causes crash
-        let adjustments = self.mc.infcx.tables.borrow().expr_adjustments(expr).to_vec();
+        let adjustments = self.mc.tables.expr_adjustments(expr);
         let mut cmt = return_if_err!(self.mc.cat_expr_unadjusted(expr));
         for adjustment in adjustments {
             debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
@@ -796,12 +795,12 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                                mode: &mut TrackMatchMode) {
         debug!("determine_pat_move_mode cmt_discr={:?} pat={:?}", cmt_discr,
                pat);
-        return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |_mc, cmt_pat, pat| {
+        return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |cmt_pat, pat| {
             match pat.node {
                 PatKind::Binding(hir::BindByRef(..), ..) =>
                     mode.lub(BorrowingMatch),
                 PatKind::Binding(hir::BindByValue(..), ..) => {
-                    match copy_or_move(self.mc.infcx, self.param_env, &cmt_pat, PatBindingMove) {
+                    match copy_or_move(&self.mc, self.param_env, &cmt_pat, PatBindingMove) {
                         Copy => mode.lub(CopyingMatch),
                         Move(..) => mode.lub(MovingMatch),
                     }
@@ -818,14 +817,13 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
         debug!("walk_pat cmt_discr={:?} pat={:?}", cmt_discr, pat);
 
         let tcx = self.tcx();
-        let infcx = self.mc.infcx;
         let ExprUseVisitor { ref mc, ref mut delegate, param_env } = *self;
-        return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| {
+        return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |cmt_pat, pat| {
             if let PatKind::Binding(bmode, def_id, ..) = pat.node {
                 debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", cmt_pat, pat, match_mode);
 
                 // pat_ty: the type of the binding being produced.
-                let pat_ty = return_if_err!(infcx.node_ty(pat.id));
+                let pat_ty = return_if_err!(mc.node_ty(pat.id));
 
                 // Each match binding is effectively an assignment to the
                 // binding being produced.
@@ -843,7 +841,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                         }
                     }
                     hir::BindByValue(..) => {
-                        let mode = copy_or_move(infcx, param_env, &cmt_pat, PatBindingMove);
+                        let mode = copy_or_move(mc, param_env, &cmt_pat, PatBindingMove);
                         debug!("walk_pat binding consuming pat");
                         delegate.consume_pat(pat, cmt_pat, mode);
                     }
@@ -855,14 +853,14 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
         // the interior nodes (enum variants and structs), as opposed
         // to the above loop's visit of than the bindings that form
         // the leaves of the pattern tree structure.
-        return_if_err!(mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| {
+        return_if_err!(mc.cat_pattern(cmt_discr, pat, |cmt_pat, pat| {
             let qpath = match pat.node {
                 PatKind::Path(ref qpath) |
                 PatKind::TupleStruct(ref qpath, ..) |
                 PatKind::Struct(ref qpath, ..) => qpath,
                 _ => return
             };
-            let def = infcx.tables.borrow().qpath_def(qpath, pat.id);
+            let def = mc.tables.qpath_def(qpath, pat.id);
             match def {
                 Def::Variant(variant_did) |
                 Def::VariantCtor(variant_did, ..) => {
@@ -896,13 +894,13 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                 let id_var = self.tcx().hir.as_local_node_id(def_id).unwrap();
                 let upvar_id = ty::UpvarId { var_id: id_var,
                                              closure_expr_id: closure_expr.id };
-                let upvar_capture = self.mc.infcx.upvar_capture(upvar_id).unwrap();
+                let upvar_capture = self.mc.tables.upvar_capture(upvar_id);
                 let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.id,
                                                                    fn_decl_span,
                                                                    freevar.def));
                 match upvar_capture {
                     ty::UpvarCapture::ByValue => {
-                        let mode = copy_or_move(self.mc.infcx,
+                        let mode = copy_or_move(&self.mc,
                                                 self.param_env,
                                                 &cmt_var,
                                                 CaptureMove);
@@ -929,18 +927,18 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
         // Create the cmt for the variable being borrowed, from the
         // caller's perspective
         let var_id = self.tcx().hir.as_local_node_id(upvar_def.def_id()).unwrap();
-        let var_ty = self.mc.infcx.node_ty(var_id)?;
+        let var_ty = self.mc.node_ty(var_id)?;
         self.mc.cat_def(closure_id, closure_span, var_ty, upvar_def)
     }
 }
 
-fn copy_or_move<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+fn copy_or_move<'a, 'gcx, 'tcx>(mc: &mc::MemCategorizationContext<'a, 'gcx, 'tcx>,
                                 param_env: ty::ParamEnv<'tcx>,
                                 cmt: &mc::cmt<'tcx>,
                                 move_reason: MoveReason)
                                 -> ConsumeMode
 {
-    if infcx.type_moves_by_default(param_env, cmt.ty, cmt.span) {
+    if mc.type_moves_by_default(param_env, cmt.ty, cmt.span) {
         Move(move_reason)
     } else {
         Copy
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index c114aa1d7a8..259079cf160 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -76,6 +76,7 @@ use infer::InferCtxt;
 use hir::def::{Def, CtorKind};
 use ty::adjustment;
 use ty::{self, Ty, TyCtxt};
+use ty::fold::TypeFoldable;
 
 use hir::{MutImmutable, MutMutable, PatKind};
 use hir::pat_util::EnumerateAndAdjustIterator;
@@ -281,20 +282,10 @@ impl ast_node for hir::Pat {
 
 #[derive(Clone)]
 pub struct MemCategorizationContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+    pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
     pub region_maps: &'a RegionMaps,
-    options: MemCategorizationOptions,
-}
-
-#[derive(Copy, Clone, Default)]
-pub struct MemCategorizationOptions {
-    // If true, then when analyzing a closure upvar, if the closure
-    // has a missing kind, we treat it like a Fn closure. When false,
-    // we ICE if the closure has a missing kind. Should be false
-    // except during closure kind inference. It is used by the
-    // mem-categorization code to be able to have stricter assertions
-    // (which are always true except during upvar inference).
-    pub during_closure_kind_inference: bool,
+    pub tables: &'a ty::TypeckTables<'tcx>,
+    infcx: Option<&'a InferCtxt<'a, 'gcx, 'tcx>>,
 }
 
 pub type McResult<T> = Result<T, ()>;
@@ -395,51 +386,90 @@ impl MutabilityCategory {
     }
 }
 
-impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
-    /// Context should be the `DefId` we use to fetch region-maps.
-    pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
-               region_maps: &'a RegionMaps)
-               -> MemCategorizationContext<'a, 'gcx, 'tcx> {
-        MemCategorizationContext::with_options(infcx,
-                                               region_maps,
-                                               MemCategorizationOptions::default())
+impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx, 'tcx> {
+    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+               region_maps: &'a RegionMaps,
+               tables: &'a ty::TypeckTables<'tcx>)
+               -> MemCategorizationContext<'a, 'tcx, 'tcx> {
+        MemCategorizationContext { tcx, region_maps, tables, infcx: None }
     }
+}
 
-    pub fn with_options(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
-                        region_maps: &'a RegionMaps,
-                        options: MemCategorizationOptions)
-                        -> MemCategorizationContext<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
+    pub fn with_infer(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+                      region_maps: &'a RegionMaps,
+                      tables: &'a ty::TypeckTables<'tcx>)
+                      -> MemCategorizationContext<'a, 'gcx, 'tcx> {
         MemCategorizationContext {
-            infcx: infcx,
-            region_maps: region_maps,
-            options: options,
+            tcx: infcx.tcx,
+            region_maps,
+            tables,
+            infcx: Some(infcx),
         }
     }
 
-    fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
-        self.infcx.tcx
+    pub fn type_moves_by_default(&self,
+                                 param_env: ty::ParamEnv<'tcx>,
+                                 ty: Ty<'tcx>,
+                                 span: Span)
+                                 -> bool {
+        self.infcx.map(|infcx| infcx.type_moves_by_default(param_env, ty, span))
+            .or_else(|| {
+                self.tcx.lift_to_global(&(param_env, ty)).map(|(param_env, ty)| {
+                    ty.moves_by_default(self.tcx.global_tcx(), param_env, span)
+                })
+            })
+            .unwrap_or(true)
     }
 
-    fn expr_ty(&self, expr: &hir::Expr) -> McResult<Ty<'tcx>> {
-        match self.infcx.node_ty(expr.id) {
-            Ok(t) => Ok(t),
-            Err(()) => {
-                debug!("expr_ty({:?}) yielded Err", expr);
-                Err(())
+    fn resolve_type_vars_if_possible<T>(&self, value: &T) -> T
+        where T: TypeFoldable<'tcx>
+    {
+        self.infcx.map(|infcx| infcx.resolve_type_vars_if_possible(value))
+            .unwrap_or_else(|| value.clone())
+    }
+
+    fn is_tainted_by_errors(&self) -> bool {
+        self.infcx.map_or(false, |infcx| infcx.is_tainted_by_errors())
+    }
+
+    fn resolve_type_vars_or_error(&self,
+                                  id: ast::NodeId,
+                                  ty: Option<Ty<'tcx>>)
+                                  -> McResult<Ty<'tcx>> {
+        match ty {
+            Some(ty) => {
+                let ty = self.resolve_type_vars_if_possible(&ty);
+                if ty.references_error() || ty.is_ty_var() {
+                    debug!("resolve_type_vars_or_error: error from {:?}", ty);
+                    Err(())
+                } else {
+                    Ok(ty)
+                }
+            }
+            // FIXME
+            None if self.is_tainted_by_errors() => Err(()),
+            None => {
+                bug!("no type for node {}: {} in mem_categorization",
+                     id, self.tcx.hir.node_to_string(id));
             }
         }
     }
 
-    fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult<Ty<'tcx>> {
-        self.infcx.expr_ty_adjusted(expr)
+    pub fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>> {
+        self.resolve_type_vars_or_error(id, self.tables.node_id_to_type_opt(id))
     }
 
-    fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>> {
-        self.infcx.node_ty(id)
+    pub fn expr_ty(&self, expr: &hir::Expr) -> McResult<Ty<'tcx>> {
+        self.resolve_type_vars_or_error(expr.id, self.tables.expr_ty_opt(expr))
+    }
+
+    pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult<Ty<'tcx>> {
+        self.resolve_type_vars_or_error(expr.id, self.tables.expr_ty_adjusted_opt(expr))
     }
 
     fn pat_ty(&self, pat: &hir::Pat) -> McResult<Ty<'tcx>> {
-        let base_ty = self.infcx.node_ty(pat.id)?;
+        let base_ty = self.node_ty(pat.id)?;
         // FIXME (Issue #18207): This code detects whether we are
         // looking at a `ref x`, and if so, figures out what the type
         // *being borrowed* is.  But ideally we would put in a more
@@ -479,7 +509,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             }
         }
 
-        helper(self, expr, self.infcx.tables.borrow().expr_adjustments(expr))
+        helper(self, expr, self.tables.expr_adjustments(expr))
     }
 
     pub fn cat_expr_adjusted(&self, expr: &hir::Expr,
@@ -496,12 +526,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
         where F: FnOnce() -> McResult<cmt<'tcx>>
     {
         debug!("cat_expr_adjusted_with({:?}): {:?}", adjustment, expr);
-        let target = self.infcx.resolve_type_vars_if_possible(&adjustment.target);
+        let target = self.resolve_type_vars_if_possible(&adjustment.target);
         match adjustment.kind {
             adjustment::Adjust::Deref(overloaded) => {
                 // Equivalent to *expr or something similar.
                 let base = if let Some(deref) = overloaded {
-                    let ref_ty = self.tcx().mk_ref(deref.region, ty::TypeAndMut {
+                    let ref_ty = self.tcx.mk_ref(deref.region, ty::TypeAndMut {
                         ty: target,
                         mutbl: deref.mutbl,
                     });
@@ -531,7 +561,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
         let expr_ty = self.expr_ty(expr)?;
         match expr.node {
           hir::ExprUnary(hir::UnDeref, ref e_base) => {
-            if self.infcx.tables.borrow().is_method_call(expr) {
+            if self.tables.is_method_call(expr) {
                 self.cat_overloaded_lvalue(expr, e_base, false)
             } else {
                 let base_cmt = self.cat_expr(&e_base)?;
@@ -554,7 +584,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
           }
 
           hir::ExprIndex(ref base, _) => {
-            if self.infcx.tables.borrow().is_method_call(expr) {
+            if self.tables.is_method_call(expr) {
                 // If this is an index implemented by a method call, then it
                 // will include an implicit deref of the result.
                 // The call to index() returns a `&T` value, which
@@ -568,7 +598,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
           }
 
           hir::ExprPath(ref qpath) => {
-            let def = self.infcx.tables.borrow().qpath_def(qpath, expr.id);
+            let def = self.tables.qpath_def(qpath, expr.id);
             self.cat_def(expr.id, expr.span, expr_ty, def)
           }
 
@@ -619,49 +649,17 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
           }
 
           Def::Upvar(def_id, _, fn_node_id) => {
-              let var_id = self.tcx().hir.as_local_node_id(def_id).unwrap();
-              let ty = self.node_ty(fn_node_id)?;
-              match ty.sty {
-                  ty::TyClosure(closure_id, _) => {
-                      match self.infcx.closure_kind(closure_id) {
-                          Some(kind) => {
-                              self.cat_upvar(id, span, var_id, fn_node_id, kind)
-                          }
-                          None => {
-                              if !self.options.during_closure_kind_inference {
-                                  span_bug!(
-                                      span,
-                                      "No closure kind for {:?}",
-                                      closure_id);
-                              }
-
-                              // during closure kind inference, we
-                              // don't know the closure kind yet, but
-                              // it's ok because we detect that we are
-                              // accessing an upvar and handle that
-                              // case specially anyhow. Use Fn
-                              // arbitrarily.
-                              self.cat_upvar(id, span, var_id, fn_node_id, ty::ClosureKind::Fn)
-                          }
-                      }
-                  }
-                  _ => {
-                      span_bug!(
-                          span,
-                          "Upvar of non-closure {} - {:?}",
-                          fn_node_id,
-                          ty);
-                  }
-              }
+              let var_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
+              self.cat_upvar(id, span, var_id, fn_node_id)
           }
 
           Def::Local(def_id) => {
-            let vid = self.tcx().hir.as_local_node_id(def_id).unwrap();
+            let vid = self.tcx.hir.as_local_node_id(def_id).unwrap();
             Ok(Rc::new(cmt_ {
                 id: id,
                 span: span,
                 cat: Categorization::Local(vid),
-                mutbl: MutabilityCategory::from_local(self.tcx(), vid),
+                mutbl: MutabilityCategory::from_local(self.tcx, vid),
                 ty: expr_ty,
                 note: NoteNone
             }))
@@ -677,8 +675,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
                  id: ast::NodeId,
                  span: Span,
                  var_id: ast::NodeId,
-                 fn_node_id: ast::NodeId,
-                 kind: ty::ClosureKind)
+                 fn_node_id: ast::NodeId)
                  -> McResult<cmt<'tcx>>
     {
         // An upvar can have up to 3 components. We translate first to a
@@ -704,12 +701,17 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
         // FnMut          | copied -> &'env mut  | upvar -> &'env mut -> &'up bk
         // FnOnce         | copied               | upvar -> &'up bk
 
+        let kind = match self.tables.closure_kinds.get(&fn_node_id) {
+            Some(&(kind, _)) => kind,
+            None => span_bug!(span, "missing closure kind")
+        };
+
         let upvar_id = ty::UpvarId { var_id: var_id,
                                      closure_expr_id: fn_node_id };
         let var_ty = self.node_ty(var_id)?;
 
         // Mutability of original variable itself
-        let var_mutbl = MutabilityCategory::from_local(self.tcx(), var_id);
+        let var_mutbl = MutabilityCategory::from_local(self.tcx, var_id);
 
         // Construct the upvar. This represents access to the field
         // from the environment (perhaps we should eventually desugar
@@ -743,7 +745,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
         // for that.
         let upvar_id = ty::UpvarId { var_id: var_id,
                                      closure_expr_id: fn_node_id };
-        let upvar_capture = self.infcx.upvar_capture(upvar_id).unwrap();
+        let upvar_capture = self.tables.upvar_capture(upvar_id);
         let cmt_result = match upvar_capture {
             ty::UpvarCapture::ByValue => {
                 cmt_result
@@ -776,11 +778,11 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
                  -> cmt_<'tcx>
     {
         // Region of environment pointer
-        let env_region = self.tcx().mk_region(ty::ReFree(ty::FreeRegion {
+        let env_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
             // The environment of a closure is guaranteed to
             // outlive any bindings introduced in the body of the
             // closure itself.
-            scope: self.tcx().hir.local_def_id(upvar_id.closure_expr_id),
+            scope: self.tcx.hir.local_def_id(upvar_id.closure_expr_id),
             bound_region: ty::BrEnv
         }));
 
@@ -797,7 +799,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
         // one.
         let cmt_result = cmt_ {
             mutbl: McImmutable,
-            ty: self.tcx().types.err,
+            ty: self.tcx.types.err,
             ..cmt_result
         };
 
@@ -829,7 +831,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
     pub fn temporary_scope(&self, id: ast::NodeId) -> ty::Region<'tcx>
     {
         let scope = self.region_maps.temporary_scope(id);
-        self.tcx().mk_region(match scope {
+        self.tcx.mk_region(match scope {
             Some(scope) => ty::ReScope(scope),
             None => ty::ReStatic
         })
@@ -840,20 +842,20 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
                            span: Span,
                            expr_ty: Ty<'tcx>)
                            -> cmt<'tcx> {
-        let promotable = self.tcx().rvalue_promotable_to_static.borrow().get(&id).cloned()
+        let promotable = self.tcx.rvalue_promotable_to_static.borrow().get(&id).cloned()
                                    .unwrap_or(false);
 
         // When the corresponding feature isn't toggled, only promote `[T; 0]`.
         let promotable = match expr_ty.sty {
             ty::TyArray(_, 0) => true,
-            _ => promotable && self.tcx().sess.features.borrow().rvalue_static_promotion,
+            _ => promotable && self.tcx.sess.features.borrow().rvalue_static_promotion,
         };
 
         // Compute maximum lifetime of this rvalue. This is 'static if
         // we can promote to a constant, otherwise equal to enclosing temp
         // lifetime.
         let re = if promotable {
-            self.tcx().types.re_static
+            self.tcx.types.re_static
         } else {
             self.temporary_scope(id)
         };
@@ -934,7 +936,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
                 span_bug!(expr.span, "cat_overloaded_lvalue: base is not a reference")
             }
         };
-        let ref_ty = self.tcx().mk_ref(region, ty::TypeAndMut {
+        let ref_ty = self.tcx.mk_ref(region, ty::TypeAndMut {
             ty: lvalue_ty,
             mutbl,
         });
@@ -1049,14 +1051,14 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
     }
 
     pub fn cat_pattern<F>(&self, cmt: cmt<'tcx>, pat: &hir::Pat, mut op: F) -> McResult<()>
-        where F: FnMut(&MemCategorizationContext<'a, 'gcx, 'tcx>, cmt<'tcx>, &hir::Pat),
+        where F: FnMut(cmt<'tcx>, &hir::Pat),
     {
         self.cat_pattern_(cmt, pat, &mut op)
     }
 
     // FIXME(#19596) This is a workaround, but there should be a better way to do this
     fn cat_pattern_<F>(&self, cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McResult<()>
-        where F : FnMut(&MemCategorizationContext<'a, 'gcx, 'tcx>, cmt<'tcx>, &hir::Pat)
+        where F : FnMut(cmt<'tcx>, &hir::Pat)
     {
         // Here, `cmt` is the categorization for the value being
         // matched and pat is the pattern it is being matched against.
@@ -1105,7 +1107,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
 
         debug!("cat_pattern: {:?} cmt={:?}", pat, cmt);
 
-        op(self, cmt.clone(), pat);
+        op(cmt.clone(), pat);
 
         // Note: This goes up here (rather than within the PatKind::TupleStruct arm
         // alone) because PatKind::Struct can also refer to variants.
@@ -1121,8 +1123,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
                     Def::Variant(variant_did) |
                     Def::VariantCtor(variant_did, ..) => {
                         // univariant enums do not need downcasts
-                        let enum_did = self.tcx().parent_def_id(variant_did).unwrap();
-                        if !self.tcx().adt_def(enum_did).is_univariant() {
+                        let enum_did = self.tcx.parent_def_id(variant_did).unwrap();
+                        if !self.tcx.adt_def(enum_did).is_univariant() {
                             self.cat_downcast(pat, cmt.clone(), cmt.ty, variant_did)
                         } else {
                             cmt
@@ -1136,11 +1138,11 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
 
         match pat.node {
           PatKind::TupleStruct(ref qpath, ref subpats, ddpos) => {
-            let def = self.infcx.tables.borrow().qpath_def(qpath, pat.id);
+            let def = self.tables.qpath_def(qpath, pat.id);
             let expected_len = match def {
                 Def::VariantCtor(def_id, CtorKind::Fn) => {
-                    let enum_def = self.tcx().parent_def_id(def_id).unwrap();
-                    self.tcx().adt_def(enum_def).variant_with_id(def_id).fields.len()
+                    let enum_def = self.tcx.parent_def_id(def_id).unwrap();
+                    self.tcx.adt_def(enum_def).variant_with_id(def_id).fields.len()
                 }
                 Def::StructCtor(_, CtorKind::Fn) => {
                     match self.pat_ty(&pat)?.sty {
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index c8e99c0354a..64438f586d7 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -29,7 +29,7 @@ use hir::{self, intravisit, Local, Pat, Body};
 use hir::intravisit::{Visitor, NestedVisitorMap};
 use hir::map::NodeExpr;
 use hir::def_id::DefId;
-use infer::{self, InferCtxt, InferTables, InferTablesRef};
+use infer::{self, InferCtxt};
 use infer::type_variable::TypeVariableOrigin;
 use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL;
 use std::fmt;
@@ -72,9 +72,12 @@ struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
 }
 
 impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
-    fn node_matches_type(&mut self, node_id: &'gcx NodeId) -> bool {
-        match self.infcx.tables.borrow().node_types.get(node_id) {
-            Some(&ty) => {
+    fn node_matches_type(&mut self, node_id: NodeId) -> bool {
+        let ty_opt = self.infcx.in_progress_tables.and_then(|tables| {
+            tables.borrow().node_id_to_type_opt(node_id)
+        });
+        match ty_opt {
+            Some(ty) => {
                 let ty = self.infcx.resolve_type_vars_if_possible(&ty);
                 ty.walk().any(|inner_ty| {
                     inner_ty == *self.target_ty || match (&inner_ty.sty, &self.target_ty.sty) {
@@ -88,7 +91,7 @@ impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
                     }
                 })
             }
-            _ => false,
+            None => false,
         }
     }
 }
@@ -99,7 +102,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
     }
 
     fn visit_local(&mut self, local: &'gcx Local) {
-        if self.found_local_pattern.is_none() && self.node_matches_type(&local.id) {
+        if self.found_local_pattern.is_none() && self.node_matches_type(local.id) {
             self.found_local_pattern = Some(&*local.pat);
         }
         intravisit::walk_local(self, local);
@@ -107,7 +110,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
 
     fn visit_body(&mut self, body: &'gcx Body) {
         for argument in &body.arguments {
-            if self.found_arg_pattern.is_none() && self.node_matches_type(&argument.id) {
+            if self.found_arg_pattern.is_none() && self.node_matches_type(argument.id) {
                 self.found_arg_pattern = Some(&*argument.pat);
             }
         }
@@ -652,18 +655,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                             obligation.cause.span,
                             format!("the requirement to implement `{}` derives from here", kind));
 
-                        let infer_tables = match self.tables {
-                            InferTables::Interned(tables) =>
-                                Some(InferTablesRef::Interned(tables)),
-                            InferTables::InProgress(tables) =>
-                                Some(InferTablesRef::InProgress(tables.borrow())),
-                            InferTables::Missing => None,
-                        };
-
                         // Additional context information explaining why the closure only implements
                         // a particular trait.
-                        if let Some(tables) = infer_tables {
-                            match tables.closure_kinds.get(&node_id) {
+                        if let Some(tables) = self.in_progress_tables {
+                            match tables.borrow().closure_kinds.get(&node_id) {
                                 Some(&(ty::ClosureKind::FnOnce, Some((span, name)))) => {
                                     err.span_note(span, &format!(
                                         "closure is `FnOnce` because it moves the \
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index c51974e6e67..3ce7ee847cc 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -484,7 +484,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let elaborated_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates),
                                            unnormalized_env.reveal);
 
-    tcx.infer_ctxt(()).enter(|infcx| {
+    tcx.infer_ctxt().enter(|infcx| {
         let predicates = match fully_normalize(
             &infcx,
             cause,
@@ -598,7 +598,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     debug!("normalize_and_test_predicates(predicates={:?})",
            predicates);
 
-    tcx.infer_ctxt(()).enter(|infcx| {
+    tcx.infer_ctxt().enter(|infcx| {
         let param_env = ty::ParamEnv::empty(Reveal::All);
         let mut selcx = SelectionContext::new(&infcx);
         let mut fulfill_cx = FulfillmentContext::new();
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index 689f06a3597..18734e2dbc3 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -125,7 +125,7 @@ pub fn find_associated_item<'a, 'tcx>(
     let ancestors = trait_def.ancestors(tcx, impl_data.impl_def_id);
     match ancestors.defs(tcx, item.name, item.kind).next() {
         Some(node_item) => {
-            let substs = tcx.infer_ctxt(()).enter(|infcx| {
+            let substs = tcx.infer_ctxt().enter(|infcx| {
                 let param_env = ty::ParamEnv::empty(Reveal::All);
                 let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
                 let substs = translate_substs(&infcx, param_env, impl_data.impl_def_id,
@@ -188,7 +188,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
 
     // Create a infcx, taking the predicates of impl1 as assumptions:
-    let result = tcx.infer_ctxt(()).enter(|infcx| {
+    let result = tcx.infer_ctxt().enter(|infcx| {
         // Normalize the trait reference. The WF rules ought to ensure
         // that this always succeeds.
         let impl1_trait_ref =
diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs
index 702c5035a18..f80caeec460 100644
--- a/src/librustc/traits/specialize/specialization_graph.rs
+++ b/src/librustc/traits/specialize/specialization_graph.rs
@@ -109,7 +109,7 @@ impl<'a, 'gcx, 'tcx> Children {
             let possible_sibling = *slot;
 
             let tcx = tcx.global_tcx();
-            let (le, ge) = tcx.infer_ctxt(()).enter(|infcx| {
+            let (le, ge) = tcx.infer_ctxt().enter(|infcx| {
                 let overlap = traits::overlapping_impls(&infcx,
                                                         possible_sibling,
                                                         impl_def_id);
diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs
index 7ad2ef90f0d..734ba2a2d39 100644
--- a/src/librustc/traits/trans/mod.rs
+++ b/src/librustc/traits/trans/mod.rs
@@ -46,7 +46,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
 
             // Do the initial selection for the obligation. This yields the
             // shallow result we are looking for -- that is, what specific impl.
-            self.infer_ctxt(()).enter(|infcx| {
+            self.infer_ctxt().enter(|infcx| {
                 let mut selcx = SelectionContext::new(&infcx);
 
                 let param_env = ty::ParamEnv::empty(Reveal::All);
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 2bbb71610ad..2d81606329e 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -376,8 +376,8 @@ impl<'tcx> TypeckTables<'tcx> {
         }
     }
 
-    pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture<'tcx>> {
-        Some(self.upvar_capture_map.get(&upvar_id).unwrap().clone())
+    pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> ty::UpvarCapture<'tcx> {
+        self.upvar_capture_map[&upvar_id]
     }
 }
 
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index ec4ca54d6f5..a7029ac5fa9 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -175,7 +175,7 @@ impl<'tcx> ty::ParamEnv<'tcx> {
                                        self_type: Ty<'tcx>, span: Span)
                                        -> Result<(), CopyImplementationError<'tcx>> {
         // FIXME: (@jroesch) float this code up
-        tcx.infer_ctxt(()).enter(|infcx| {
+        tcx.infer_ctxt().enter(|infcx| {
             let (adt, substs) = match self_type.sty {
                 ty::TyAdt(adt, substs) => (adt, substs),
                 _ => return Err(CopyImplementationError::NotAnAdt),
@@ -977,7 +977,7 @@ fn is_copy_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 {
     let (param_env, ty) = query.into_parts();
     let trait_def_id = tcx.require_lang_item(lang_items::CopyTraitLangItem);
-    tcx.infer_ctxt(())
+    tcx.infer_ctxt()
        .enter(|infcx| traits::type_known_to_meet_bound(&infcx,
                                                        param_env,
                                                        ty,
@@ -991,7 +991,7 @@ fn is_sized_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 {
     let (param_env, ty) = query.into_parts();
     let trait_def_id = tcx.require_lang_item(lang_items::SizedTraitLangItem);
-    tcx.infer_ctxt(())
+    tcx.infer_ctxt()
        .enter(|infcx| traits::type_known_to_meet_bound(&infcx,
                                                        param_env,
                                                        ty,
@@ -1005,7 +1005,7 @@ fn is_freeze_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 {
     let (param_env, ty) = query.into_parts();
     let trait_def_id = tcx.require_lang_item(lang_items::FreezeTraitLangItem);
-    tcx.infer_ctxt(())
+    tcx.infer_ctxt()
        .enter(|infcx| traits::type_known_to_meet_bound(&infcx,
                                                        param_env,
                                                        ty,
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index 122a37ee32a..ae2be28c198 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -192,7 +192,6 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
     debug!("check_loans(body id={})", body.value.id);
 
     let def_id = bccx.tcx.hir.body_owner_def_id(body.id());
-    let infcx = bccx.tcx.borrowck_fake_infer_ctxt(body.id());
     let param_env = bccx.tcx.param_env(def_id);
     let mut clcx = CheckLoanCtxt {
         bccx: bccx,
@@ -201,7 +200,8 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
         all_loans: all_loans,
         param_env,
     };
-    euv::ExprUseVisitor::new(&mut clcx, &bccx.region_maps, &infcx, param_env).consume_body(body);
+    euv::ExprUseVisitor::new(&mut clcx, bccx.tcx, param_env, &bccx.region_maps, bccx.tables)
+        .consume_body(body);
 }
 
 #[derive(PartialEq)]
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index 85a09969ac8..7dcb6ce76a4 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -18,7 +18,6 @@
 
 use borrowck::*;
 use borrowck::move_data::MoveData;
-use rustc::infer::InferCtxt;
 use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::mem_categorization as mc;
 use rustc::middle::mem_categorization::Categorization;
@@ -40,11 +39,9 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                     body: hir::BodyId)
                                     -> (Vec<Loan<'tcx>>, move_data::MoveData<'tcx>) {
     let def_id = bccx.tcx.hir.body_owner_def_id(body);
-    let infcx = bccx.tcx.borrowck_fake_infer_ctxt(body);
     let param_env = bccx.tcx.param_env(def_id);
     let mut glcx = GatherLoanCtxt {
         bccx: bccx,
-        infcx: &infcx,
         all_loans: Vec::new(),
         item_ub: region::CodeExtent::Misc(body.node_id),
         move_data: MoveData::new(),
@@ -52,7 +49,8 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
     };
 
     let body = glcx.bccx.tcx.hir.body(body);
-    euv::ExprUseVisitor::new(&mut glcx, &bccx.region_maps, &infcx, param_env).consume_body(body);
+    euv::ExprUseVisitor::new(&mut glcx, bccx.tcx, param_env, &bccx.region_maps, bccx.tables)
+        .consume_body(body);
 
     glcx.report_potential_errors();
     let GatherLoanCtxt { all_loans, move_data, .. } = glcx;
@@ -61,7 +59,6 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
 
 struct GatherLoanCtxt<'a, 'tcx: 'a> {
     bccx: &'a BorrowckCtxt<'a, 'tcx>,
-    infcx: &'a InferCtxt<'a, 'tcx, 'tcx>,
     move_data: move_data::MoveData<'tcx>,
     move_error_collector: move_error::MoveErrorCollector<'tcx>,
     all_loans: Vec<Loan<'tcx>>,
@@ -158,7 +155,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> {
     }
 
     fn decl_without_init(&mut self, id: ast::NodeId, _span: Span) {
-        let ty = self.infcx.tables.borrow().node_id_to_type(id);
+        let ty = self.bccx.tables.node_id_to_type(id);
         gather_moves::gather_decl(self.bccx, &self.move_data, id, ty);
     }
 }
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index 7c3076fda4f..fcdabf89e3c 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -493,19 +493,18 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
 ///
 /// FIXME: this should be done by borrowck.
 fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) {
-    cx.tcx.infer_ctxt(cx.tables).enter(|infcx| {
-        let mut checker = MutationChecker {
-            cx: cx,
-        };
-        ExprUseVisitor::new(&mut checker, cx.region_maps, &infcx, cx.param_env).walk_expr(guard);
-    });
+    let mut checker = MutationChecker {
+        cx: cx,
+    };
+    ExprUseVisitor::new(&mut checker, cx.tcx, cx.param_env, cx.region_maps, cx.tables)
+        .walk_expr(guard);
 }
 
-struct MutationChecker<'a, 'gcx: 'a> {
-    cx: &'a MatchVisitor<'a, 'gcx>,
+struct MutationChecker<'a, 'tcx: 'a> {
+    cx: &'a MatchVisitor<'a, 'tcx>,
 }
 
-impl<'a, 'gcx, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'gcx> {
+impl<'a, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'tcx> {
     fn matched_pat(&mut self, _: &Pat, _: cmt, _: euv::MatchMode) {}
     fn consume(&mut self, _: ast::NodeId, _: Span, _: cmt, _: ConsumeMode) {}
     fn consume_pat(&mut self, _: &Pat, _: cmt, _: ConsumeMode) {}
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 3d07ffc2bc7..ec7510546a0 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -483,7 +483,7 @@ fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     debug!("resolve_trait_associated_const: trait_ref={:?}",
            trait_ref);
 
-    tcx.infer_ctxt(()).enter(|infcx| {
+    tcx.infer_ctxt().enter(|infcx| {
         let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
         let mut selcx = traits::SelectionContext::new(&infcx);
         let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 2b74d0a812b..62e20a90f8a 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -154,7 +154,7 @@ fn test_env<F>(source_string: &str,
                              index,
                              "test_crate",
                              |tcx| {
-        tcx.infer_ctxt(()).enter(|infcx| {
+        tcx.infer_ctxt().enter(|infcx| {
             let mut region_maps = RegionMaps::new();
             body(Env {
                 infcx: &infcx,
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 3a4729e6454..9800012917c 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -32,7 +32,7 @@ use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
 use rustc::cfg;
 use rustc::ty::subst::Substs;
-use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::{self, Ty};
 use rustc::traits::{self, Reveal};
 use rustc::hir::map as hir_map;
 use util::nodemap::NodeSet;
@@ -893,7 +893,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
             for adjustment in cx.tables.expr_adjustments(expr) {
                 if let Adjust::Deref(Some(deref)) = adjustment.kind {
                     let (def_id, substs) = deref.method_call(cx.tcx, source);
-                    if method_call_refers_to_method(cx.tcx, method, def_id, substs, id) {
+                    if method_call_refers_to_method(cx, method, def_id, substs, id) {
                         return true;
                     }
                 }
@@ -904,7 +904,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
             if cx.tables.is_method_call(expr) {
                 let def_id = cx.tables.type_dependent_defs[&id].def_id();
                 let substs = cx.tables.node_substs(id);
-                if method_call_refers_to_method(cx.tcx, method, def_id, substs, id) {
+                if method_call_refers_to_method(cx, method, def_id, substs, id) {
                     return true;
                 }
             }
@@ -920,8 +920,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
                     match def {
                         Def::Method(def_id) => {
                             let substs = cx.tables.node_substs(callee.id);
-                            method_call_refers_to_method(
-                                cx.tcx, method, def_id, substs, id)
+                            method_call_refers_to_method(cx, method, def_id, substs, id)
                         }
                         _ => false,
                     }
@@ -932,12 +931,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
 
         // Check if the method call to the method with the ID `callee_id`
         // and instantiated with `callee_substs` refers to method `method`.
-        fn method_call_refers_to_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+        fn method_call_refers_to_method<'a, 'tcx>(cx: &LateContext<'a, 'tcx>,
                                                   method: &ty::AssociatedItem,
                                                   callee_id: DefId,
                                                   callee_substs: &Substs<'tcx>,
                                                   expr_id: ast::NodeId)
                                                   -> bool {
+            let tcx = cx.tcx;
             let callee_item = tcx.associated_item(callee_id);
 
             match callee_item.container {
@@ -951,13 +951,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
                     let trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, callee_substs);
                     let trait_ref = ty::Binder(trait_ref);
                     let span = tcx.hir.span(expr_id);
-                    let param_env = tcx.param_env(method.def_id);
                     let obligation =
                         traits::Obligation::new(traits::ObligationCause::misc(span, expr_id),
-                                                param_env,
+                                                cx.param_env,
                                                 trait_ref.to_poly_trait_predicate());
 
-                    tcx.infer_ctxt(()).enter(|infcx| {
+                    tcx.infer_ctxt().enter(|infcx| {
                         let mut selcx = traits::SelectionContext::new(&infcx);
                         match selcx.select(&obligation) {
                             // The method comes from a `T: Trait` bound.
@@ -1224,11 +1223,9 @@ impl LintPass for UnionsWithDropFields {
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnionsWithDropFields {
     fn check_item(&mut self, ctx: &LateContext, item: &hir::Item) {
         if let hir::ItemUnion(ref vdata, _) = item.node {
-            let item_def_id = ctx.tcx.hir.local_def_id(item.id);
-            let param_env = ctx.tcx.param_env(item_def_id);
             for field in vdata.fields() {
                 let field_ty = ctx.tcx.type_of(ctx.tcx.hir.local_def_id(field.id));
-                if field_ty.needs_drop(ctx.tcx, param_env) {
+                if field_ty.needs_drop(ctx.tcx, ctx.param_env) {
                     ctx.span_lint(UNIONS_WITH_DROP_FIELDS,
                                   field.span,
                                   "union contains a field with possibly non-trivial drop code, \
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 3019165bfbf..32bde42b526 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -725,7 +725,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
                 // sizes only make sense for non-generic types
                 let item_def_id = cx.tcx.hir.local_def_id(it.id);
                 let t = cx.tcx.type_of(item_def_id);
-                let param_env = cx.tcx.param_env(item_def_id).reveal_all();
+                let param_env = cx.param_env.reveal_all();
                 let ty = cx.tcx.erase_regions(&t);
                 let layout = ty.layout(cx.tcx, param_env).unwrap_or_else(|e| {
                     bug!("failed to get layout for `{}`: {}", t, e)
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 08a5cb37e57..56c0e18d6f9 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -83,7 +83,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t
     };
 
     let src = MirSource::from_node(tcx, id);
-    tcx.infer_ctxt(body_id).enter(|infcx| {
+    tcx.infer_ctxt().enter(|infcx| {
         let cx = Cx::new(&infcx, src);
         let mut mir = if cx.tables().tainted_by_errors {
             build::construct_error(cx, body_id)
@@ -171,7 +171,7 @@ fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 {
     let span = tcx.hir.span(ctor_id);
     if let hir::VariantData::Tuple(ref fields, ctor_id) = *v {
-        tcx.infer_ctxt(()).enter(|infcx| {
+        tcx.infer_ctxt().enter(|infcx| {
             let (mut mir, src) =
                 shim::build_adt_ctor(&infcx, ctor_id, fields, span);
 
@@ -365,13 +365,14 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
     let upvar_decls: Vec<_> = tcx.with_freevars(fn_id, |freevars| {
         freevars.iter().map(|fv| {
             let var_id = tcx.hir.as_local_node_id(fv.def.def_id()).unwrap();
-            let by_ref = hir.tables().upvar_capture(ty::UpvarId {
+            let capture = hir.tables().upvar_capture(ty::UpvarId {
                 var_id: var_id,
                 closure_expr_id: fn_id
-            }).map_or(false, |capture| match capture {
+            });
+            let by_ref = match capture {
                 ty::UpvarCapture::ByValue => false,
                 ty::UpvarCapture::ByRef(..) => true
-            });
+            };
             let mut decl = UpvarDecl {
                 debug_name: keywords::Invalid.name(),
                 by_ref: by_ref
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 8cfeecdafb5..474feefabbb 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -758,13 +758,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 var_id: id_var,
                 closure_expr_id: closure_expr_id,
             };
-            let upvar_capture = match cx.tables().upvar_capture(upvar_id) {
-                Some(c) => c,
-                None => {
-                    span_bug!(expr.span, "no upvar_capture for {:?}", upvar_id);
-                }
-            };
-            match upvar_capture {
+            match cx.tables().upvar_capture(upvar_id) {
                 ty::UpvarCapture::ByValue => field_kind,
                 ty::UpvarCapture::ByRef(borrow) => {
                     ExprKind::Deref {
@@ -878,7 +872,7 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         var_id: id_var,
         closure_expr_id: closure_expr.id,
     };
-    let upvar_capture = cx.tables().upvar_capture(upvar_id).unwrap();
+    let upvar_capture = cx.tables().upvar_capture(upvar_id);
     let temp_lifetime = cx.region_maps.temporary_scope(closure_expr.id);
     let var_ty = cx.tables().node_id_to_type(id_var);
     let captured_var = Expr {
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 5b7b52a72b0..2bb6b39966a 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -37,6 +37,7 @@ pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
     pub param_env: ty::ParamEnv<'tcx>,
     pub region_maps: Rc<RegionMaps>,
+    pub tables: &'a ty::TypeckTables<'gcx>,
 
     /// This is `Constness::Const` if we are compiling a `static`,
     /// `const`, or the body of a `const fn`.
@@ -67,6 +68,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
 
         let param_env = tcx.param_env(src_def_id);
         let region_maps = tcx.region_maps(src_def_id);
+        let tables = tcx.typeck_tables_of(src_def_id);
 
         let attrs = tcx.hir.attrs(src_id);
 
@@ -82,7 +84,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
         // Constants and const fn's always need overflow checks.
         check_overflow |= constness == hir::Constness::Const;
 
-        Cx { tcx, infcx, param_env, region_maps, constness, src, check_overflow }
+        Cx { tcx, infcx, param_env, region_maps, tables, constness, src, check_overflow }
     }
 }
 
@@ -184,7 +186,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
     }
 
     pub fn tables(&self) -> &'a ty::TypeckTables<'gcx> {
-        self.infcx.tables.expect_interned()
+        self.tables
     }
 
     pub fn check_overflow(&self) -> bool {
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 793cffdec89..d60e761bc0b 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -998,7 +998,7 @@ impl MirPass for QualifyAndPromoteConstants {
         // Statics must be Sync.
         if mode == Mode::Static {
             let ty = mir.return_ty;
-            tcx.infer_ctxt(()).enter(|infcx| {
+            tcx.infer_ctxt().enter(|infcx| {
                 let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
                 let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic);
                 let mut fulfillment_cx = traits::FulfillmentContext::new();
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index da8e3b5a42b..e23f0705b6a 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -759,7 +759,7 @@ impl MirPass for TypeckMir {
             return;
         }
         let param_env = tcx.param_env(def_id);
-        tcx.infer_ctxt(()).enter(|infcx| {
+        tcx.infer_ctxt().enter(|infcx| {
             let mut checker = TypeChecker::new(&infcx, item_id, param_env);
             {
                 let mut verifier = TypeVerifier::new(&mut checker, mir);
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 65a9334bbae..e539cc1ae8b 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -51,7 +51,6 @@ use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 
 use std::collections::hash_map::Entry;
 use std::cmp::Ordering;
-use std::mem;
 
 struct CheckCrateVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -138,13 +137,14 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
             self.check_const_eval(&body.value);
         }
 
-        let outer_penv = self.tcx.infer_ctxt(body_id).enter(|infcx| {
-            let param_env = self.tcx.param_env(item_def_id);
-            let outer_penv = mem::replace(&mut self.param_env, param_env);
-            let region_maps = &self.tcx.region_maps(item_def_id);
-            euv::ExprUseVisitor::new(self, region_maps, &infcx, param_env).consume_body(body);
-            outer_penv
-        });
+        let outer_penv = self.param_env;
+        self.param_env = self.tcx.param_env(item_def_id);
+
+        let tcx = self.tcx;
+        let param_env = self.param_env;
+        let region_maps = self.tcx.region_maps(item_def_id);
+        euv::ExprUseVisitor::new(self, tcx, param_env, &region_maps, self.tables)
+            .consume_body(body);
 
         self.visit_body(body);
 
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 8b76431fd2e..29742469f84 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -219,7 +219,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                          param_env,
                                                          normalize_cause.clone());
 
-    tcx.infer_ctxt(()).enter(|infcx| {
+    tcx.infer_ctxt().enter(|infcx| {
         let inh = Inherited::new(infcx, impl_m.def_id);
         let infcx = &inh.infcx;
 
@@ -726,7 +726,7 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                     impl_trait_ref: ty::TraitRef<'tcx>) {
     debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
 
-    tcx.infer_ctxt(()).enter(|infcx| {
+    tcx.infer_ctxt().enter(|infcx| {
         let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
         let inh = Inherited::new(infcx, impl_c.def_id);
         let infcx = &inh.infcx;
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index bff9289de50..93057f91997 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -79,7 +79,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
 
     // check that the impl type can be made to match the trait type.
 
-    tcx.infer_ctxt(()).enter(|ref infcx| {
+    tcx.infer_ctxt().enter(|ref infcx| {
         let impl_param_env = tcx.param_env(self_type_did);
         let tcx = infcx.tcx;
         let mut fulfillment_cx = traits::FulfillmentContext::new();
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 04469dcaf2b..844065cb334 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -108,7 +108,7 @@ use lint;
 use util::common::{ErrorReported, indenter};
 use util::nodemap::{DefIdMap, FxHashMap, NodeMap};
 
-use std::cell::{Cell, RefCell};
+use std::cell::{Cell, RefCell, Ref, RefMut};
 use std::collections::hash_map::Entry;
 use std::cmp;
 use std::mem::replace;
@@ -147,6 +147,33 @@ mod compare_method;
 mod intrinsic;
 mod op;
 
+/// A wrapper for InferCtxt's `in_progress_tables` field.
+#[derive(Copy, Clone)]
+struct MaybeInProgressTables<'a, 'tcx: 'a> {
+    maybe_tables: Option<&'a RefCell<ty::TypeckTables<'tcx>>>,
+}
+
+impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> {
+    fn borrow(self) -> Ref<'a, ty::TypeckTables<'tcx>> {
+        match self.maybe_tables {
+            Some(tables) => tables.borrow(),
+            None => {
+                bug!("MaybeInProgressTables: inh/fcx.tables.borrow() with no tables")
+            }
+        }
+    }
+
+    fn borrow_mut(self) -> RefMut<'a, ty::TypeckTables<'tcx>> {
+        match self.maybe_tables {
+            Some(tables) => tables.borrow_mut(),
+            None => {
+                bug!("MaybeInProgressTables: inh/fcx.tables.borrow_mut() with no tables")
+            }
+        }
+    }
+}
+
+
 /// closures defined within the function.  For example:
 ///
 ///     fn foo() {
@@ -159,6 +186,8 @@ mod op;
 pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     infcx: InferCtxt<'a, 'gcx, 'tcx>,
 
+    tables: MaybeInProgressTables<'a, 'tcx>,
+
     locals: RefCell<NodeMap<Ty<'tcx>>>,
 
     fulfillment_cx: RefCell<traits::FulfillmentContext<'tcx>>,
@@ -535,9 +564,8 @@ pub struct InheritedBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
     pub fn build(tcx: TyCtxt<'a, 'gcx, 'gcx>, def_id: DefId)
                  -> InheritedBuilder<'a, 'gcx, 'tcx> {
-        let tables = ty::TypeckTables::empty();
         InheritedBuilder {
-            infcx: tcx.infer_ctxt(tables),
+            infcx: tcx.infer_ctxt().with_fresh_in_progress_tables(),
             def_id,
         }
     }
@@ -562,6 +590,9 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
         });
 
         Inherited {
+            tables: MaybeInProgressTables {
+                maybe_tables: infcx.in_progress_tables,
+            },
             infcx: infcx,
             fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
             locals: RefCell::new(NodeMap()),
@@ -3302,14 +3333,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.check_expr_has_type(base_expr, struct_ty);
             match struct_ty.sty {
                 ty::TyAdt(adt, substs) if adt.is_struct() => {
-                    self.tables.borrow_mut().fru_field_types.insert(
-                        expr.id,
-                        adt.struct_variant().fields.iter().map(|f| {
-                            self.normalize_associated_types_in(
-                                expr.span, &f.ty(self.tcx, substs)
-                            )
-                        }).collect()
-                    );
+                    let fru_field_types = adt.struct_variant().fields.iter().map(|f| {
+                        self.normalize_associated_types_in(expr.span, &f.ty(self.tcx, substs))
+                    }).collect();
+                    self.tables.borrow_mut().fru_field_types.insert(expr.id, fru_field_types);
                 }
                 _ => {
                     span_err!(self.tcx.sess, base_expr.span, E0436,
@@ -4186,7 +4213,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             hir::StmtSemi(ref e, _) => e,
             _ => return,
         };
-        let last_expr_ty = self.expr_ty(last_expr);
+        let last_expr_ty = self.node_ty(last_expr.id);
         if self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err() {
             return;
         }
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index b66e311f04c..952321c946b 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -824,18 +824,24 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
+    /// Create a temporary `MemCategorizationContext` and pass it to the closure.
+    fn with_mc<F, R>(&self, f: F) -> R
+        where F: for<'b> FnOnce(mc::MemCategorizationContext<'b, 'gcx, 'tcx>) -> R
+    {
+        f(mc::MemCategorizationContext::with_infer(&self.infcx,
+                                                   &self.region_maps,
+                                                   &self.tables.borrow()))
+    }
+
     /// Invoked on any adjustments that occur. Checks that if this is a region pointer being
     /// dereferenced, the lifetime of the pointer includes the deref expr.
     fn constrain_adjustments(&mut self, expr: &hir::Expr) -> mc::McResult<mc::cmt<'tcx>> {
         debug!("constrain_adjustments(expr={:?})", expr);
 
-        let mut cmt = {
-            let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
-            mc.cat_expr_unadjusted(expr)?
-        };
+        let mut cmt = self.with_mc(|mc| mc.cat_expr_unadjusted(expr))?;
 
-        //NOTE(@jroesch): mixed RefCell borrow causes crash
-        let adjustments = self.tables.borrow().expr_adjustments(&expr).to_vec();
+        let tables = self.tables.borrow();
+        let adjustments = tables.expr_adjustments(&expr);
         if adjustments.is_empty() {
             return Ok(cmt);
         }
@@ -886,10 +892,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
                                                expr.id, expr_region);
             }
 
-            {
-                let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
-                cmt = mc.cat_expr_adjusted(expr, cmt, &adjustment)?;
-            }
+            cmt = self.with_mc(|mc| mc.cat_expr_adjusted(expr, cmt, &adjustment))?;
 
             if let Categorization::Deref(_, mc::BorrowedPtr(_, r_ptr)) = cmt.cat {
                 self.mk_subregion_due_to_dereference(expr.span,
@@ -981,10 +984,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
                     mutability: hir::Mutability, base: &hir::Expr) {
         debug!("link_addr_of(expr={:?}, base={:?})", expr, base);
 
-        let cmt = {
-            let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
-            ignore_err!(mc.cat_expr(base))
-        };
+        let cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(base)));
 
         debug!("link_addr_of: cmt={:?}", cmt);
 
@@ -1000,9 +1000,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
             None => { return; }
             Some(ref expr) => &**expr,
         };
-        let mc = &mc::MemCategorizationContext::new(self, &self.region_maps);
-        let discr_cmt = ignore_err!(mc.cat_expr(init_expr));
-        self.link_pattern(mc, discr_cmt, &local.pat);
+        let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(init_expr)));
+        self.link_pattern(discr_cmt, &local.pat);
     }
 
     /// Computes the guarantors for any ref bindings in a match and
@@ -1010,12 +1009,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     /// linked to the lifetime of its guarantor (if any).
     fn link_match(&self, discr: &hir::Expr, arms: &[hir::Arm]) {
         debug!("regionck::for_match()");
-        let mc = &mc::MemCategorizationContext::new(self, &self.region_maps);
-        let discr_cmt = ignore_err!(mc.cat_expr(discr));
+        let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(discr)));
         debug!("discr_cmt={:?}", discr_cmt);
         for arm in arms {
             for root_pat in &arm.pats {
-                self.link_pattern(mc, discr_cmt.clone(), &root_pat);
+                self.link_pattern(discr_cmt.clone(), &root_pat);
             }
         }
     }
@@ -1025,30 +1023,28 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     /// linked to the lifetime of its guarantor (if any).
     fn link_fn_args(&self, body_scope: CodeExtent, args: &[hir::Arg]) {
         debug!("regionck::link_fn_args(body_scope={:?})", body_scope);
-        let mc = &mc::MemCategorizationContext::new(self, &self.region_maps);
         for arg in args {
             let arg_ty = self.node_ty(arg.id);
             let re_scope = self.tcx.mk_region(ty::ReScope(body_scope));
-            let arg_cmt = mc.cat_rvalue(
-                arg.id, arg.pat.span, re_scope, arg_ty);
+            let arg_cmt = self.with_mc(|mc| {
+                mc.cat_rvalue(arg.id, arg.pat.span, re_scope, arg_ty)
+            });
             debug!("arg_ty={:?} arg_cmt={:?} arg={:?}",
                    arg_ty,
                    arg_cmt,
                    arg);
-            self.link_pattern(mc, arg_cmt, &arg.pat);
+            self.link_pattern(arg_cmt, &arg.pat);
         }
     }
 
     /// Link lifetimes of any ref bindings in `root_pat` to the pointers found
     /// in the discriminant, if needed.
-    fn link_pattern<'t>(&self,
-                        mc: &mc::MemCategorizationContext<'a, 'gcx, 'tcx>,
-                        discr_cmt: mc::cmt<'tcx>,
-                        root_pat: &hir::Pat) {
+    fn link_pattern(&self, discr_cmt: mc::cmt<'tcx>, root_pat: &hir::Pat) {
         debug!("link_pattern(discr_cmt={:?}, root_pat={:?})",
                discr_cmt,
                root_pat);
-        let _ = mc.cat_pattern(discr_cmt, root_pat, |_, sub_cmt, sub_pat| {
+        let _ = self.with_mc(|mc| {
+            mc.cat_pattern(discr_cmt, root_pat, |sub_cmt, sub_pat| {
                 match sub_pat.node {
                     // `ref x` pattern
                     PatKind::Binding(hir::BindByRef(mutbl), ..) => {
@@ -1057,7 +1053,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
                     }
                     _ => {}
                 }
-            });
+            })
+        });
     }
 
     /// Link lifetime of borrowed pointer resulting from autoref to lifetimes in the value being
@@ -1215,8 +1212,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         // Detect by-ref upvar `x`:
         let cause = match note {
             mc::NoteUpvarRef(ref upvar_id) => {
-                let upvar_capture_map = &self.tables.borrow_mut().upvar_capture_map;
-                match upvar_capture_map.get(upvar_id) {
+                match self.tables.borrow().upvar_capture_map.get(upvar_id) {
                     Some(&ty::UpvarCapture::ByRef(ref upvar_borrow)) => {
                         // The mutability of the upvar may have been modified
                         // by the above adjustment, so update our local variable.
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index 25f5418bea9..59ca896b347 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -53,31 +53,22 @@ use rustc::hir;
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::util::nodemap::NodeMap;
 
-///////////////////////////////////////////////////////////////////////////
-// PUBLIC ENTRY POINTS
+use std::collections::hash_map::Entry;
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn closure_analyze(&self, body: &'gcx hir::Body) {
-        let mut seed = SeedBorrowKind::new(self);
-        seed.visit_body(body);
-
-        let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds);
-        adjust.visit_body(body);
+        InferBorrowKindVisitor { fcx: self }.visit_body(body);
 
         // it's our job to process these.
         assert!(self.deferred_call_resolutions.borrow().is_empty());
     }
 }
 
-///////////////////////////////////////////////////////////////////////////
-// SEED BORROW KIND
-
-struct SeedBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+struct InferBorrowKindVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
-    temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>,
 }
 
-impl<'a, 'gcx, 'tcx> Visitor<'gcx> for SeedBorrowKind<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> Visitor<'gcx> for InferBorrowKindVisitor<'a, 'gcx, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
         NestedVisitorMap::None
     }
@@ -87,7 +78,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for SeedBorrowKind<'a, 'gcx, 'tcx> {
             hir::ExprClosure(cc, _, body_id, _) => {
                 let body = self.fcx.tcx.hir.body(body_id);
                 self.visit_body(body);
-                self.check_closure(expr, cc);
+                self.fcx.analyze_closure(expr.id, expr.span, body, cc);
             }
 
             _ => { }
@@ -97,26 +88,33 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for SeedBorrowKind<'a, 'gcx, 'tcx> {
     }
 }
 
-impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> {
-    fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>) -> SeedBorrowKind<'a, 'gcx, 'tcx> {
-        SeedBorrowKind { fcx: fcx, temp_closure_kinds: NodeMap() }
-    }
+impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
+    fn analyze_closure(&self,
+                       id: ast::NodeId,
+                       span: Span,
+                       body: &hir::Body,
+                       capture_clause: hir::CaptureClause) {
+        /*!
+         * Analysis starting point.
+         */
 
-    fn check_closure(&mut self,
-                     expr: &hir::Expr,
-                     capture_clause: hir::CaptureClause)
-    {
-        if !self.fcx.tables.borrow().closure_kinds.contains_key(&expr.id) {
-            self.temp_closure_kinds.insert(expr.id, (ty::ClosureKind::Fn, None));
-            debug!("check_closure: adding closure {:?} as Fn", expr.id);
-        }
+        debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id());
 
-        self.fcx.tcx.with_freevars(expr.id, |freevars| {
+        let infer_kind = match self.tables.borrow_mut().closure_kinds.entry(id) {
+            Entry::Occupied(_) => false,
+            Entry::Vacant(entry) => {
+                debug!("check_closure: adding closure {:?} as Fn", id);
+                entry.insert((ty::ClosureKind::Fn, None));
+                true
+            }
+        };
+
+        self.tcx.with_freevars(id, |freevars| {
             for freevar in freevars {
                 let def_id = freevar.def.def_id();
-                let var_node_id = self.fcx.tcx.hir.as_local_node_id(def_id).unwrap();
+                let var_node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
                 let upvar_id = ty::UpvarId { var_id: var_node_id,
-                                             closure_expr_id: expr.id };
+                                             closure_expr_id: id };
                 debug!("seed upvar_id {:?}", upvar_id);
 
                 let capture_kind = match capture_clause {
@@ -124,58 +122,41 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> {
                         ty::UpvarCapture::ByValue
                     }
                     hir::CaptureByRef => {
-                        let origin = UpvarRegion(upvar_id, expr.span);
-                        let freevar_region = self.fcx.next_region_var(origin);
+                        let origin = UpvarRegion(upvar_id, span);
+                        let freevar_region = self.next_region_var(origin);
                         let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow,
                                                              region: freevar_region };
                         ty::UpvarCapture::ByRef(upvar_borrow)
                     }
                 };
 
-                self.fcx.tables.borrow_mut().upvar_capture_map.insert(upvar_id, capture_kind);
+                self.tables.borrow_mut().upvar_capture_map.insert(upvar_id, capture_kind);
             }
         });
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////
-// ADJUST BORROW KIND
-
-struct AdjustBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
-    temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>,
-}
-
-impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
-    fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
-           temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>)
-           -> AdjustBorrowKind<'a, 'gcx, 'tcx> {
-        AdjustBorrowKind { fcx: fcx, temp_closure_kinds: temp_closure_kinds }
-    }
-
-    fn analyze_closure(&mut self,
-                       id: ast::NodeId,
-                       span: Span,
-                       body: &hir::Body) {
-        /*!
-         * Analysis starting point.
-         */
-
-        debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id());
 
         {
-            let body_owner_def_id = self.fcx.tcx.hir.body_owner_def_id(body.id());
-            let region_maps = &self.fcx.tcx.region_maps(body_owner_def_id);
-            let param_env = self.fcx.param_env;
-            let mut euv =
-                euv::ExprUseVisitor::with_options(self,
-                                                  self.fcx,
-                                                  param_env,
-                                                  region_maps,
-                                                  mc::MemCategorizationOptions {
-                                                      during_closure_kind_inference: true
-                                                  });
-            euv.consume_body(body);
+            let body_owner_def_id = self.tcx.hir.body_owner_def_id(body.id());
+            let region_maps = &self.tcx.region_maps(body_owner_def_id);
+            let mut delegate = InferBorrowKind {
+                fcx: self,
+                adjust_closure_kinds: NodeMap(),
+                adjust_upvar_captures: ty::UpvarCaptureMap::default(),
+            };
+            euv::ExprUseVisitor::with_infer(&mut delegate,
+                                            &self.infcx,
+                                            self.param_env,
+                                            region_maps,
+                                            &self.tables.borrow())
+                .consume_body(body);
+
+            // Write the adjusted values back into the main tables.
+            if infer_kind {
+                if let Some(kind) = delegate.adjust_closure_kinds.remove(&id) {
+                    self.tables.borrow_mut().closure_kinds.insert(id, kind);
+                }
+            }
+            self.tables.borrow_mut().upvar_capture_map.extend(
+                delegate.adjust_upvar_captures);
         }
 
         // Now that we've analyzed the closure, we know how each
@@ -191,7 +172,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
         // inference algorithm will reject it).
 
         // Extract the type variables UV0...UVn.
-        let (def_id, closure_substs) = match self.fcx.node_ty(id).sty {
+        let (def_id, closure_substs) = match self.node_ty(id).sty {
             ty::TyClosure(def_id, substs) => (def_id, substs),
             ref t => {
                 span_bug!(
@@ -206,44 +187,41 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
         debug!("analyze_closure: id={:?} closure_substs={:?} final_upvar_tys={:?}",
                id, closure_substs, final_upvar_tys);
         for (upvar_ty, final_upvar_ty) in
-            closure_substs.upvar_tys(def_id, self.fcx.tcx).zip(final_upvar_tys)
+            closure_substs.upvar_tys(def_id, self.tcx).zip(final_upvar_tys)
         {
-            self.fcx.demand_eqtype(span, final_upvar_ty, upvar_ty);
+            self.demand_eqtype(span, final_upvar_ty, upvar_ty);
         }
 
-        // If we are also inferred the closure kind here, update the
-        // main table and process any deferred resolutions.
-        if let Some(&(kind, context)) = self.temp_closure_kinds.get(&id) {
-            self.fcx.tables.borrow_mut().closure_kinds.insert(id, (kind, context));
-            let closure_def_id = self.fcx.tcx.hir.local_def_id(id);
-            debug!("closure_kind({:?}) = {:?}", closure_def_id, kind);
-
+        // If we are also inferred the closure kind here,
+        // process any deferred resolutions.
+        if infer_kind {
+            let closure_def_id = self.tcx.hir.local_def_id(id);
             let deferred_call_resolutions =
-                self.fcx.remove_deferred_call_resolutions(closure_def_id);
+                self.remove_deferred_call_resolutions(closure_def_id);
             for deferred_call_resolution in deferred_call_resolutions {
-                deferred_call_resolution.resolve(self.fcx);
+                deferred_call_resolution.resolve(self);
             }
         }
     }
 
     // Returns a list of `ClosureUpvar`s for each upvar.
-    fn final_upvar_tys(&mut self, closure_id: ast::NodeId) -> Vec<Ty<'tcx>> {
+    fn final_upvar_tys(&self, closure_id: ast::NodeId) -> Vec<Ty<'tcx>> {
         // Presently an unboxed closure type cannot "escape" out of a
         // function, so we will only encounter ones that originated in the
         // local crate or were inlined into it along with some function.
         // This may change if abstract return types of some sort are
         // implemented.
-        let tcx = self.fcx.tcx;
+        let tcx = self.tcx;
         tcx.with_freevars(closure_id, |freevars| {
             freevars.iter().map(|freevar| {
                 let def_id = freevar.def.def_id();
                 let var_id = tcx.hir.as_local_node_id(def_id).unwrap();
-                let freevar_ty = self.fcx.node_ty(var_id);
+                let freevar_ty = self.node_ty(var_id);
                 let upvar_id = ty::UpvarId {
                     var_id: var_id,
                     closure_expr_id: closure_id
                 };
-                let capture = self.fcx.upvar_capture(upvar_id).unwrap();
+                let capture = self.tables.borrow().upvar_capture(upvar_id);
 
                 debug!("var_id={:?} freevar_ty={:?} capture={:?}",
                        var_id, freevar_ty, capture);
@@ -260,7 +238,15 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
             }).collect()
         })
     }
+}
 
+struct InferBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+    fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
+    adjust_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>,
+    adjust_upvar_captures: ty::UpvarCaptureMap<'tcx>,
+}
+
+impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
     fn adjust_upvar_borrow_kind_for_consume(&mut self,
                                             cmt: mc::cmt<'tcx>,
                                             mode: euv::ConsumeMode)
@@ -297,9 +283,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
                                                  guarantor.span,
                                                  tcx.hir.name(upvar_id.var_id));
 
-                        let upvar_capture_map =
-                            &mut self.fcx.tables.borrow_mut().upvar_capture_map;
-                        upvar_capture_map.insert(upvar_id, ty::UpvarCapture::ByValue);
+                        self.adjust_upvar_captures.insert(upvar_id, ty::UpvarCapture::ByValue);
                     }
                     mc::NoteClosureEnv(upvar_id) => {
                         // we get just a closureenv ref if this is a
@@ -410,11 +394,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
                 // upvar, then we need to modify the
                 // borrow_kind of the upvar to make sure it
                 // is inferred to mutable if necessary
-                {
-                    let upvar_capture_map = &mut self.fcx.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);
-                }
+                self.adjust_upvar_borrow_kind(upvar_id, 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,
@@ -448,22 +428,25 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
     /// some particular use.
     fn adjust_upvar_borrow_kind(&mut self,
                                 upvar_id: ty::UpvarId,
-                                upvar_capture: &mut ty::UpvarCapture,
                                 kind: ty::BorrowKind) {
+        let upvar_capture = self.adjust_upvar_captures.get(&upvar_id).cloned()
+            .unwrap_or_else(|| self.fcx.tables.borrow().upvar_capture(upvar_id));
         debug!("adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})",
                upvar_id, upvar_capture, kind);
 
-        match *upvar_capture {
+        match upvar_capture {
             ty::UpvarCapture::ByValue => {
                 // Upvar is already by-value, the strongest criteria.
             }
-            ty::UpvarCapture::ByRef(ref mut upvar_borrow) => {
+            ty::UpvarCapture::ByRef(mut upvar_borrow) => {
                 match (upvar_borrow.kind, kind) {
                     // Take RHS:
                     (ty::ImmBorrow, ty::UniqueImmBorrow) |
                     (ty::ImmBorrow, ty::MutBorrow) |
                     (ty::UniqueImmBorrow, ty::MutBorrow) => {
                         upvar_borrow.kind = kind;
+                        self.adjust_upvar_captures.insert(upvar_id,
+                            ty::UpvarCapture::ByRef(upvar_borrow));
                     }
                     // Take LHS:
                     (ty::ImmBorrow, ty::ImmBorrow) |
@@ -484,7 +467,9 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
         debug!("adjust_closure_kind(closure_id={}, new_kind={:?}, upvar_span={:?}, var_name={})",
                closure_id, new_kind, upvar_span, var_name);
 
-        if let Some(&(existing_kind, _)) = self.temp_closure_kinds.get(&closure_id) {
+        let closure_kind = self.adjust_closure_kinds.get(&closure_id).cloned()
+            .or_else(|| self.fcx.tables.borrow().closure_kinds.get(&closure_id).cloned());
+        if let Some((existing_kind, _)) = closure_kind {
             debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}",
                    closure_id, existing_kind, new_kind);
 
@@ -500,7 +485,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
                 (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
                 (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
                     // new kind is stronger than the old kind
-                    self.temp_closure_kinds.insert(
+                    self.adjust_closure_kinds.insert(
                         closure_id,
                         (new_kind, Some((upvar_span, var_name)))
                     );
@@ -510,27 +495,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
     }
 }
 
-impl<'a, 'gcx, 'tcx> Visitor<'gcx> for AdjustBorrowKind<'a, 'gcx, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
-        NestedVisitorMap::None
-    }
-
-    fn visit_fn(&mut self,
-                fn_kind: intravisit::FnKind<'gcx>,
-                decl: &'gcx hir::FnDecl,
-                body: hir::BodyId,
-                span: Span,
-                id: ast::NodeId)
-    {
-        intravisit::walk_fn(self, fn_kind, decl, body, span, id);
-
-        let body = self.fcx.tcx.hir.body(body);
-        self.visit_body(body);
-        self.analyze_closure(id, span, body);
-    }
-}
-
-impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for AdjustBorrowKind<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'gcx, 'tcx> {
     fn consume(&mut self,
                _consume_id: ast::NodeId,
                _consume_span: Span,
diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs
index 377b7b069d3..ccbc0299041 100644
--- a/src/librustc_typeck/coherence/builtin.rs
+++ b/src/librustc_typeck/coherence/builtin.rs
@@ -208,7 +208,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
            source,
            target);
 
-    tcx.infer_ctxt(()).enter(|infcx| {
+    tcx.infer_ctxt().enter(|infcx| {
         let cause = ObligationCause::misc(span, impl_node_id);
         let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
                            mt_b: ty::TypeAndMut<'tcx>,
diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs
index afeb85a7a06..078ae34bc52 100644
--- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs
+++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs
@@ -70,7 +70,7 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
 
         for (i, &impl1_def_id) in impls.iter().enumerate() {
             for &impl2_def_id in &impls[(i + 1)..] {
-                self.tcx.infer_ctxt(()).enter(|infcx| {
+                self.tcx.infer_ctxt().enter(|infcx| {
                     if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
                         self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
                     }
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 06cb9f948c9..26ea3ab3a33 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -155,7 +155,7 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                 expected: Ty<'tcx>,
                                 actual: Ty<'tcx>)
                                 -> bool {
-    tcx.infer_ctxt(()).enter(|ref infcx| {
+    tcx.infer_ctxt().enter(|ref infcx| {
         let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
         let mut fulfill_cx = FulfillmentContext::new();
         match infcx.at(&cause, param_env).eq(expected, actual) {