about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduard Burtescu <edy.burt@gmail.com>2016-05-11 04:14:41 +0300
committerEduard Burtescu <edy.burt@gmail.com>2016-05-11 04:14:58 +0300
commita1c170fc355947f54129a97aedcb8dea3d555f71 (patch)
treec9a14d32948bcde76d6872b17c491cbbcebf2fd8
parent31a07b0ce662e95119a76cce8dcfc29d2055f738 (diff)
downloadrust-a1c170fc355947f54129a97aedcb8dea3d555f71.tar.gz
rust-a1c170fc355947f54129a97aedcb8dea3d555f71.zip
rustc: Split local type contexts interners from the global one.
-rw-r--r--src/librustc/infer/mod.rs247
-rw-r--r--src/librustc/middle/intrinsicck.rs14
-rw-r--r--src/librustc/middle/liveness.rs5
-rw-r--r--src/librustc/mir/tcx.rs18
-rw-r--r--src/librustc/traits/coherence.rs16
-rw-r--r--src/librustc/traits/mod.rs15
-rw-r--r--src/librustc/traits/specialize/mod.rs11
-rw-r--r--src/librustc/traits/specialize/specialization_graph.rs5
-rw-r--r--src/librustc/traits/structural_impls.rs52
-rw-r--r--src/librustc/ty/context.rs405
-rw-r--r--src/librustc/ty/flags.rs15
-rw-r--r--src/librustc/ty/layout.rs50
-rw-r--r--src/librustc/ty/mod.rs37
-rw-r--r--src/librustc/ty/structural_impls.rs35
-rw-r--r--src/librustc/ty/util.rs37
-rw-r--r--src/librustc/util/ppaux.rs22
-rw-r--r--src/librustc_borrowck/borrowck/check_loans.rs22
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/mod.rs36
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs6
-rw-r--r--src/librustc_const_eval/check_match.rs15
-rw-r--r--src/librustc_const_eval/eval.rs3
-rw-r--r--src/librustc_driver/test.rs10
-rw-r--r--src/librustc_lint/builtin.rs3
-rw-r--r--src/librustc_mir/build/block.rs2
-rw-r--r--src/librustc_mir/build/expr/as_constant.rs2
-rw-r--r--src/librustc_mir/build/expr/as_lvalue.rs2
-rw-r--r--src/librustc_mir/build/expr/as_operand.rs2
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs2
-rw-r--r--src/librustc_mir/build/expr/as_temp.rs2
-rw-r--r--src/librustc_mir/build/expr/into.rs2
-rw-r--r--src/librustc_mir/build/expr/stmt.rs2
-rw-r--r--src/librustc_mir/build/into.rs32
-rw-r--r--src/librustc_mir/build/matches/mod.rs4
-rw-r--r--src/librustc_mir/build/matches/simplify.rs2
-rw-r--r--src/librustc_mir/build/matches/test.rs2
-rw-r--r--src/librustc_mir/build/matches/util.rs2
-rw-r--r--src/librustc_mir/build/misc.rs2
-rw-r--r--src/librustc_mir/build/mod.rs34
-rw-r--r--src/librustc_mir/build/scope.rs28
-rw-r--r--src/librustc_mir/hair/cx/block.rs16
-rw-r--r--src/librustc_mir/hair/cx/expr.rs81
-rw-r--r--src/librustc_mir/hair/cx/mod.rs25
-rw-r--r--src/librustc_mir/hair/cx/pattern.rs23
-rw-r--r--src/librustc_mir/hair/mod.rs12
-rw-r--r--src/librustc_mir/mir_map.rs125
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs3
-rw-r--r--src/librustc_mir/transform/type_check.rs18
-rw-r--r--src/librustc_passes/consts.rs13
-rw-r--r--src/librustc_passes/rvalues.rs20
-rw-r--r--src/librustc_trans/_match.rs3
-rw-r--r--src/librustc_trans/closure.rs8
-rw-r--r--src/librustc_trans/collector.rs10
-rw-r--r--src/librustc_trans/common.rs14
-rw-r--r--src/librustc_trans/glue.rs20
-rw-r--r--src/librustc_trans/meth.rs11
-rw-r--r--src/librustc_trans/mir/constant.rs3
-rw-r--r--src/librustc_trans/monomorphize.rs3
-rw-r--r--src/librustc_trans/type_of.rs3
-rw-r--r--src/librustc_typeck/check/compare_method.rs39
-rw-r--r--src/librustc_typeck/check/dropck.rs5
-rw-r--r--src/librustc_typeck/check/mod.rs45
-rw-r--r--src/librustc_typeck/check/wfcheck.rs120
-rw-r--r--src/librustc_typeck/coherence/mod.rs14
-rw-r--r--src/librustc_typeck/coherence/overlap.rs3
-rw-r--r--src/librustc_typeck/lib.rs4
65 files changed, 1142 insertions, 700 deletions
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index e6d9db20ece..fe9e128d8a6 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -24,6 +24,7 @@ use middle::free_region::FreeRegionMap;
 use middle::mem_categorization as mc;
 use middle::mem_categorization::McResult;
 use middle::region::CodeExtent;
+use mir::tcx::LvalueTy;
 use ty::subst;
 use ty::subst::Substs;
 use ty::subst::Subst;
@@ -35,7 +36,7 @@ use ty::fold::TypeFoldable;
 use ty::relate::{Relate, RelateResult, TypeRelation};
 use traits::{self, PredicateObligations, ProjectionMode};
 use rustc_data_structures::unify::{self, UnificationTable};
-use std::cell::{Cell, RefCell, Ref};
+use std::cell::{Cell, RefCell, Ref, RefMut};
 use std::fmt;
 use syntax::ast;
 use syntax::codemap;
@@ -72,10 +73,36 @@ pub type Bound<T> = Option<T>;
 pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
 pub type FixupResult<T> = Result<T, FixupError>; // "fixup result"
 
+/// A version of &ty::Tables which can be global or local.
+/// Only the local version supports borrow_mut.
+#[derive(Copy, Clone)]
+pub enum InferTables<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+    Global(&'a RefCell<ty::Tables<'gcx>>),
+    Local(&'a RefCell<ty::Tables<'tcx>>)
+}
+
+impl<'a, 'gcx, 'tcx> InferTables<'a, 'gcx, 'tcx> {
+    pub fn borrow(self) -> Ref<'a, ty::Tables<'tcx>> {
+        match self {
+            InferTables::Global(tables) => tables.borrow(),
+            InferTables::Local(tables) => tables.borrow()
+        }
+    }
+
+    pub fn borrow_mut(self) -> RefMut<'a, ty::Tables<'tcx>> {
+        match self {
+            InferTables::Global(_) => {
+                bug!("InferTables: infcx.tables.borrow_mut() outside of type-checking");
+            }
+            InferTables::Local(tables) => tables.borrow_mut()
+        }
+    }
+}
+
 pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
 
-    pub tables: &'a RefCell<ty::Tables<'tcx>>,
+    pub tables: InferTables<'a, 'gcx, 'tcx>,
 
     // We instantiate UnificationTable with bounds<Ty> because the
     // types that might instantiate a general type variable have an
@@ -390,48 +417,106 @@ impl fmt::Display for FixupError {
     }
 }
 
-impl<'a, 'tcx> InferCtxt<'a, 'tcx, 'tcx> {
-    pub fn enter<F, R>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                       tables: Option<ty::Tables<'tcx>>,
-                       param_env: Option<ty::ParameterEnvironment<'tcx>>,
-                       projection_mode: ProjectionMode,
-                       f: F) -> R
-        where F: for<'b> FnOnce(InferCtxt<'b, 'tcx, 'tcx>) -> R
+/// 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>,
+    arenas: ty::CtxtArenas<'tcx>,
+    tables: Option<RefCell<ty::Tables<'tcx>>>,
+    param_env: Option<ty::ParameterEnvironment<'gcx>>,
+    projection_mode: ProjectionMode,
+    normalize: bool
+}
+
+impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
+    pub fn infer_ctxt(self,
+                      tables: Option<ty::Tables<'tcx>>,
+                      param_env: Option<ty::ParameterEnvironment<'gcx>>,
+                      projection_mode: ProjectionMode)
+                      -> InferCtxtBuilder<'a, 'gcx, 'tcx> {
+        InferCtxtBuilder {
+            global_tcx: self,
+            arenas: ty::CtxtArenas::new(),
+            tables: tables.map(RefCell::new),
+            param_env: param_env,
+            projection_mode: projection_mode,
+            normalize: false
+        }
+    }
+
+    pub fn normalizing_infer_ctxt(self, projection_mode: ProjectionMode)
+                                  -> InferCtxtBuilder<'a, 'gcx, 'tcx> {
+        InferCtxtBuilder {
+            global_tcx: self,
+            arenas: ty::CtxtArenas::new(),
+            tables: None,
+            param_env: None,
+            projection_mode: projection_mode,
+            normalize: false
+        }
+    }
+
+    /// Fake InferCtxt with the global tcx. Used by pre-MIR borrowck
+    /// for MemCategorizationContext/ExprUseVisitor.
+    /// If any inference functionality is used, ICEs will occur.
+    pub fn borrowck_fake_infer_ctxt(self, param_env: ty::ParameterEnvironment<'gcx>)
+                                    -> InferCtxt<'a, 'gcx, 'gcx> {
+        InferCtxt {
+            tcx: self,
+            tables: InferTables::Global(&self.tables),
+            type_variables: RefCell::new(type_variable::TypeVariableTable::new()),
+            int_unification_table: RefCell::new(UnificationTable::new()),
+            float_unification_table: RefCell::new(UnificationTable::new()),
+            region_vars: RegionVarBindings::new(self),
+            parameter_environment: param_env,
+            selection_cache: traits::SelectionCache::new(),
+            evaluation_cache: traits::EvaluationCache::new(),
+            reported_trait_errors: RefCell::new(FnvHashSet()),
+            normalize: false,
+            projection_mode: ProjectionMode::AnyFinal,
+            tainted_by_errors_flag: Cell::new(false),
+            err_count_on_creation: self.sess.err_count()
+        }
+    }
+}
+
+impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
+    pub fn enter<F, R>(&'tcx mut self, f: F) -> R
+        where F: for<'b> FnOnce(InferCtxt<'b, 'gcx, 'tcx>) -> R
     {
-        let new_tables;
-        let tables = if let Some(tables) = tables {
-            new_tables = RefCell::new(tables);
-            &new_tables
+        let InferCtxtBuilder {
+            global_tcx,
+            ref arenas,
+            ref tables,
+            ref mut param_env,
+            projection_mode,
+            normalize
+        } = *self;
+        let tables = if let Some(ref tables) = *tables {
+            InferTables::Local(tables)
         } else {
-            &tcx.tables
+            InferTables::Global(&global_tcx.tables)
         };
-        f(InferCtxt {
+        let param_env = param_env.take().unwrap_or_else(|| {
+            global_tcx.empty_parameter_environment()
+        });
+        global_tcx.enter_local(arenas, |tcx| f(InferCtxt {
             tcx: tcx,
             tables: tables,
             type_variables: RefCell::new(type_variable::TypeVariableTable::new()),
             int_unification_table: RefCell::new(UnificationTable::new()),
             float_unification_table: RefCell::new(UnificationTable::new()),
             region_vars: RegionVarBindings::new(tcx),
-            parameter_environment: param_env.unwrap_or(tcx.empty_parameter_environment()),
+            parameter_environment: param_env,
             selection_cache: traits::SelectionCache::new(),
             evaluation_cache: traits::EvaluationCache::new(),
             reported_trait_errors: RefCell::new(FnvHashSet()),
-            normalize: false,
+            normalize: normalize,
             projection_mode: projection_mode,
-        tainted_by_errors_flag: Cell::new(false),
+            tainted_by_errors_flag: Cell::new(false),
             err_count_on_creation: tcx.sess.err_count()
-        })
-    }
-
-    pub fn enter_normalizing<F, R>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                   projection_mode: ProjectionMode,
-                                   f: F) -> R
-        where F: for<'b> FnOnce(InferCtxt<'b, 'tcx, 'tcx>) -> R
-    {
-        InferCtxt::enter(tcx, None, None, projection_mode, |mut infcx| {
-            infcx.normalize = true;
-            f(infcx)
-        })
+        }))
     }
 }
 
@@ -459,10 +544,54 @@ pub struct CombinedSnapshot {
     region_vars_snapshot: RegionSnapshot,
 }
 
+/// Helper trait for shortening the lifetimes inside a
+/// value for post-type-checking normalization.
+pub trait TransNormalize<'gcx>: TypeFoldable<'gcx> {
+    fn trans_normalize<'a, 'tcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Self;
+}
+
+macro_rules! items { ($($item:item)+) => ($($item)+) }
+macro_rules! impl_trans_normalize {
+    ($lt_gcx:tt, $($ty:ty),+) => {
+        items!($(impl<$lt_gcx> TransNormalize<$lt_gcx> for $ty {
+            fn trans_normalize<'a, 'tcx>(&self,
+                                         infcx: &InferCtxt<'a, $lt_gcx, 'tcx>)
+                                         -> Self {
+                infcx.normalize_projections_in(self)
+            }
+        })+);
+    }
+}
+
+impl_trans_normalize!('gcx,
+    Ty<'gcx>,
+    &'gcx Substs<'gcx>,
+    ty::FnSig<'gcx>,
+    ty::FnOutput<'gcx>,
+    &'gcx ty::BareFnTy<'gcx>,
+    ty::ClosureSubsts<'gcx>,
+    ty::PolyTraitRef<'gcx>
+);
+
+impl<'gcx> TransNormalize<'gcx> for LvalueTy<'gcx> {
+    fn trans_normalize<'a, 'tcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Self {
+        match *self {
+            LvalueTy::Ty { ty } => LvalueTy::Ty { ty: ty.trans_normalize(infcx) },
+            LvalueTy::Downcast { adt_def, substs, variant_index } => {
+                LvalueTy::Downcast {
+                    adt_def: adt_def,
+                    substs: substs.trans_normalize(infcx),
+                    variant_index: variant_index
+                }
+            }
+        }
+    }
+}
+
 // NOTE: Callable from trans only!
 impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
     pub fn normalize_associated_type<T>(self, value: &T) -> T
-        where T : TypeFoldable<'tcx>
+        where T: TransNormalize<'tcx>
     {
         debug!("normalize_associated_type(t={:?})", value);
 
@@ -472,15 +601,15 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
             return value;
         }
 
-        InferCtxt::enter(self, None, None, ProjectionMode::Any, |infcx| {
-            infcx.normalize_projections_in(&value)
+        self.infer_ctxt(None, None, ProjectionMode::Any).enter(|infcx| {
+            value.trans_normalize(&infcx)
         })
     }
 }
 
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
-    fn normalize_projections_in<T>(&self, value: &T) -> T
-        where T : TypeFoldable<'tcx>
+    fn normalize_projections_in<T>(&self, value: &T) -> T::Lifted
+        where T: TypeFoldable<'tcx> + ty::Lift<'gcx>
     {
         let mut selcx = traits::SelectionContext::new(self);
         let cause = traits::ObligationCause::dummy();
@@ -503,16 +632,21 @@ pub fn drain_fulfillment_cx_or_panic<T>(&self,
                                         span: Span,
                                         fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
                                         result: &T)
-                                        -> T
-    where T : TypeFoldable<'tcx>
+                                        -> T::Lifted
+    where T: TypeFoldable<'tcx> + ty::Lift<'gcx>
 {
-    match self.drain_fulfillment_cx(fulfill_cx, result) {
+    let when = "resolving bounds after type-checking";
+    let v = match self.drain_fulfillment_cx(fulfill_cx, result) {
         Ok(v) => v,
         Err(errors) => {
-            span_bug!(
-                span,
-                "Encountered errors `{:?}` fulfilling during trans",
-                errors);
+            span_bug!(span, "Encountered errors `{:?}` {}", errors, when);
+        }
+    };
+
+    match self.tcx.lift_to_global(&v) {
+        Some(v) => v,
+        None => {
+            span_bug!(span, "Uninferred types/regions in `{:?}` {}", v, when);
         }
     }
 }
@@ -1449,18 +1583,16 @@ pub fn drain_fulfillment_cx<T>(&self,
         self.resolve_type_vars_or_error(&ty)
     }
 
-    pub fn tables_are_tcx_tables(&self) -> bool {
-        let tables: &RefCell<ty::Tables> = &self.tables;
-        let tcx_tables: &RefCell<ty::Tables> = &self.tcx.tables;
-        tables as *const _ as usize == tcx_tables as *const _ as usize
-    }
-
     pub fn type_moves_by_default(&self, ty: Ty<'tcx>, span: Span) -> bool {
         let ty = self.resolve_type_vars_if_possible(&ty);
         if let Some(ty) = self.tcx.lift_to_global(&ty) {
-            // HACK(eddyb) Temporarily handle infer type in the global tcx.
-            if !ty.needs_infer() &&
-               !(ty.has_closure_types() && !self.tables_are_tcx_tables()) {
+            // Even if the type may have no inference variables, during
+            // type-checking closure types are in local tables only.
+            let local_closures = match self.tables {
+                InferTables::Local(_) => ty.has_closure_types(),
+                InferTables::Global(_) => false
+            };
+            if !local_closures {
                 return ty.moves_by_default(self.tcx.global_tcx(), self.param_env(), span);
             }
         }
@@ -1527,7 +1659,7 @@ pub fn drain_fulfillment_cx<T>(&self,
             // during trans, we see closure ids from other traits.
             // That may require loading the closure data out of the
             // cstore.
-            Some(ty::Tables::closure_kind(&self.tables, self.tcx, def_id))
+            Some(self.tcx.closure_kind(def_id))
         }
     }
 
@@ -1536,12 +1668,13 @@ pub fn drain_fulfillment_cx<T>(&self,
                         substs: ty::ClosureSubsts<'tcx>)
                         -> ty::ClosureTy<'tcx>
     {
-        let closure_ty =
-            ty::Tables::closure_type(self.tables,
-                                     self.tcx,
-                                     def_id,
-                                     substs);
+        if let InferTables::Local(tables) = self.tables {
+            if let Some(ty) = tables.borrow().closure_tys.get(&def_id) {
+                return ty.subst(self.tcx, substs.func_substs);
+            }
+        }
 
+        let closure_ty = self.tcx.closure_type(def_id, substs);
         if self.normalize {
             let closure_ty = self.tcx.erase_regions(&closure_ty);
 
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index e45d3331a02..07e69d85ff4 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -36,7 +36,7 @@ struct ItemVisitor<'a, 'tcx: 'a> {
 impl<'a, 'tcx> ItemVisitor<'a, 'tcx> {
     fn visit_const(&mut self, item_id: ast::NodeId, expr: &hir::Expr) {
         let param_env = ty::ParameterEnvironment::for_item(self.tcx, item_id);
-        InferCtxt::enter(self.tcx, None, Some(param_env), ProjectionMode::Any, |infcx| {
+        self.tcx.infer_ctxt(None, Some(param_env), ProjectionMode::Any).enter(|infcx| {
             let mut visitor = ExprVisitor {
                 infcx: &infcx
             };
@@ -49,7 +49,7 @@ struct ExprVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>
 }
 
-impl<'a, 'tcx> ExprVisitor<'a, 'tcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> {
     fn def_id_is_transmute(&self, def_id: DefId) -> bool {
         let intrinsic = match self.infcx.tcx.lookup_item_type(def_id).ty.sty {
             ty::TyFnDef(_, _, ref bfty) => bfty.abi == RustIntrinsic,
@@ -58,7 +58,7 @@ impl<'a, 'tcx> ExprVisitor<'a, 'tcx, 'tcx> {
         intrinsic && self.infcx.tcx.item_name(def_id).as_str() == "transmute"
     }
 
-    fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>, id: ast::NodeId) {
+    fn check_transmute(&self, span: Span, from: Ty<'gcx>, to: Ty<'gcx>, id: ast::NodeId) {
         let sk_from = SizeSkeleton::compute(from, self.infcx);
         let sk_to = SizeSkeleton::compute(to, self.infcx);
 
@@ -84,7 +84,7 @@ impl<'a, 'tcx> ExprVisitor<'a, 'tcx, 'tcx> {
         }
 
         // Try to display a sensible error with as much information as possible.
-        let skeleton_string = |ty: Ty<'tcx>, sk| {
+        let skeleton_string = |ty: Ty<'gcx>, sk| {
             match sk {
                 Ok(SizeSkeleton::Known(size)) => {
                     format!("{} bits", size.bits())
@@ -114,7 +114,7 @@ impl<'a, 'tcx> ExprVisitor<'a, 'tcx, 'tcx> {
 impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> {
     // const, static and N in [T; N].
     fn visit_expr(&mut self, expr: &hir::Expr) {
-        InferCtxt::enter(self.tcx, None, None, ProjectionMode::Any, |infcx| {
+        self.tcx.infer_ctxt(None, None, ProjectionMode::Any).enter(|infcx| {
             let mut visitor = ExprVisitor {
                 infcx: &infcx
             };
@@ -144,7 +144,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> {
             span_bug!(s, "intrinsicck: closure outside of function")
         }
         let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
-        InferCtxt::enter(self.tcx, None, Some(param_env), ProjectionMode::Any, |infcx| {
+        self.tcx.infer_ctxt(None, Some(param_env), ProjectionMode::Any).enter(|infcx| {
             let mut visitor = ExprVisitor {
                 infcx: &infcx
             };
@@ -153,7 +153,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for ExprVisitor<'a, 'tcx, 'tcx> {
+impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for ExprVisitor<'a, 'gcx, 'tcx> {
     fn visit_expr(&mut self, expr: &hir::Expr) {
         if let hir::ExprPath(..) = expr.node {
             match self.infcx.tcx.resolve_expr(expr) {
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index de38c51aabe..473fd7d9be6 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -114,7 +114,6 @@ use hir::def::*;
 use hir::pat_util;
 use ty::{self, TyCtxt, ParameterEnvironment};
 use traits::{self, ProjectionMode};
-use infer::InferCtxt;
 use ty::subst::Subst;
 use lint;
 use util::nodemap::NodeMap;
@@ -1488,8 +1487,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
                 let param_env = ParameterEnvironment::for_item(self.ir.tcx, id);
                 let t_ret_subst = t_ret.subst(self.ir.tcx, &param_env.free_substs);
-                let is_nil = InferCtxt::enter(self.ir.tcx, None, Some(param_env),
-                                              ProjectionMode::Any, |infcx| {
+                let is_nil = self.ir.tcx.infer_ctxt(None, Some(param_env),
+                                                    ProjectionMode::Any).enter(|infcx| {
                     let cause = traits::ObligationCause::dummy();
                     traits::fully_normalize(&infcx, cause, &t_ret_subst).unwrap().is_nil()
                 });
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index 7041945a873..a1c0d92f60c 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -30,12 +30,12 @@ pub enum LvalueTy<'tcx> {
                variant_index: usize },
 }
 
-impl<'a, 'tcx> LvalueTy<'tcx> {
+impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> {
     pub fn from_ty(ty: Ty<'tcx>) -> LvalueTy<'tcx> {
         LvalueTy::Ty { ty: ty }
     }
 
-    pub fn to_ty(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {
+    pub fn to_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
         match *self {
             LvalueTy::Ty { ty } =>
                 ty,
@@ -44,7 +44,7 @@ impl<'a, 'tcx> LvalueTy<'tcx> {
         }
     }
 
-    pub fn projection_ty(self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    pub fn projection_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
                          elem: &LvalueElem<'tcx>)
                          -> LvalueTy<'tcx>
     {
@@ -99,8 +99,8 @@ impl<'tcx> TypeFoldable<'tcx> for LvalueTy<'tcx> {
     }
 }
 
-impl<'a, 'tcx> Mir<'tcx> {
-    pub fn operand_ty(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+impl<'a, 'gcx, 'tcx> Mir<'tcx> {
+    pub fn operand_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
                       operand: &Operand<'tcx>)
                       -> Ty<'tcx>
     {
@@ -110,7 +110,7 @@ impl<'a, 'tcx> Mir<'tcx> {
         }
     }
 
-    pub fn binop_ty(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    pub fn binop_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
                     op: BinOp,
                     lhs_ty: Ty<'tcx>,
                     rhs_ty: Ty<'tcx>)
@@ -134,7 +134,7 @@ impl<'a, 'tcx> Mir<'tcx> {
         }
     }
 
-    pub fn lvalue_ty(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    pub fn lvalue_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
                      lvalue: &Lvalue<'tcx>)
                      -> LvalueTy<'tcx>
     {
@@ -154,7 +154,7 @@ impl<'a, 'tcx> Mir<'tcx> {
         }
     }
 
-    pub fn rvalue_ty(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    pub fn rvalue_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
                      rvalue: &Rvalue<'tcx>)
                      -> Option<Ty<'tcx>>
     {
@@ -205,7 +205,7 @@ impl<'a, 'tcx> Mir<'tcx> {
                         ))
                     }
                     AggregateKind::Adt(def, _, substs) => {
-                        Some(def.type_scheme(tcx).ty.subst(tcx, substs))
+                        Some(tcx.lookup_item_type(def.did).ty.subst(tcx, substs))
                     }
                     AggregateKind::Closure(did, substs) => {
                         Some(tcx.mk_closure_from_closure_substs(did, substs))
diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs
index 74e6a97daf8..414b9fa70c3 100644
--- a/src/librustc/traits/coherence.rs
+++ b/src/librustc/traits/coherence.rs
@@ -24,10 +24,10 @@ struct InferIsLocal(bool);
 
 /// If there are types that satisfy both impls, returns a suitably-freshened
 /// `ImplHeader` with those types substituted
-pub fn overlapping_impls<'cx, 'tcx>(infcx: &InferCtxt<'cx, 'tcx, 'tcx>,
-                                    impl1_def_id: DefId,
-                                    impl2_def_id: DefId)
-                                    -> Option<ty::ImplHeader<'tcx>>
+pub fn overlapping_impls<'cx, 'gcx, 'tcx>(infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
+                                          impl1_def_id: DefId,
+                                          impl2_def_id: DefId)
+                                          -> Option<ty::ImplHeader<'tcx>>
 {
     debug!("impl_can_satisfy(\
            impl1_def_id={:?}, \
@@ -41,10 +41,10 @@ pub fn overlapping_impls<'cx, 'tcx>(infcx: &InferCtxt<'cx, 'tcx, 'tcx>,
 
 /// Can both impl `a` and impl `b` be satisfied by a common type (including
 /// `where` clauses)? If so, returns an `ImplHeader` that unifies the two impls.
-fn overlap<'cx, 'tcx>(selcx: &mut SelectionContext<'cx, 'tcx, 'tcx>,
-                      a_def_id: DefId,
-                      b_def_id: DefId)
-                      -> Option<ty::ImplHeader<'tcx>>
+fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
+                            a_def_id: DefId,
+                            b_def_id: DefId)
+                            -> Option<ty::ImplHeader<'tcx>>
 {
     debug!("overlap(a_def_id={:?}, b_def_id={:?})",
            a_def_id,
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index f9b5c0b139c..f606d73a549 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -422,7 +422,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     let elaborated_env = unnormalized_env.with_caller_bounds(predicates);
 
-    InferCtxt::enter(tcx, None, Some(elaborated_env), ProjectionMode::AnyFinal, |infcx| {
+    tcx.infer_ctxt(None, Some(elaborated_env), ProjectionMode::AnyFinal).enter(|infcx| {
         let predicates = match fully_normalize(&infcx, cause,
                                                &infcx.parameter_environment.caller_bounds) {
             Ok(predicates) => predicates,
@@ -454,6 +454,11 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             }
         };
 
+        let predicates = match tcx.lift_to_global(&predicates) {
+            Some(predicates) => predicates,
+            None => return infcx.parameter_environment
+        };
+
         debug!("normalize_param_env_or_error: resolved predicates={:?}",
             predicates);
 
@@ -461,10 +466,10 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     })
 }
 
-pub fn fully_normalize<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx, 'tcx>,
-                                  cause: ObligationCause<'tcx>,
-                                  value: &T)
-                                  -> Result<T, Vec<FulfillmentError<'tcx>>>
+pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+                                          cause: ObligationCause<'tcx>,
+                                          value: &T)
+                                          -> Result<T, Vec<FulfillmentError<'tcx>>>
     where T : TypeFoldable<'tcx>
 {
     debug!("fully_normalize(value={:?})", value);
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index 9212c54eb7d..d43d2de1f1f 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -146,14 +146,21 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              .unwrap()
                              .subst(tcx, &penv.free_substs);
 
-    InferCtxt::enter_normalizing(tcx, ProjectionMode::Topmost, |mut infcx| {
+    tcx.normalizing_infer_ctxt(ProjectionMode::Topmost).enter(|mut infcx| {
         // Normalize the trait reference, adding any obligations
         // that arise into the impl1 assumptions.
         let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = {
             let selcx = &mut SelectionContext::new(&infcx);
             traits::normalize(selcx, ObligationCause::dummy(), &impl1_trait_ref)
         };
-        penv.caller_bounds.extend(normalization_obligations.into_iter().map(|o| o.predicate));
+        penv.caller_bounds.extend(normalization_obligations.into_iter().map(|o| {
+            match tcx.lift_to_global(&o.predicate) {
+                Some(predicate) => predicate,
+                None => {
+                    bug!("specializes: obligation `{:?}` has inference types/regions", o);
+                }
+            }
+        }));
 
         // Install the parameter environment, taking the predicates of impl1 as assumptions:
         infcx.parameter_environment = penv;
diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs
index 8c359c0c7a2..ae7deb48f86 100644
--- a/src/librustc/traits/specialize/specialization_graph.rs
+++ b/src/librustc/traits/specialize/specialization_graph.rs
@@ -14,7 +14,6 @@ use std::rc::Rc;
 use super::{OverlapError, specializes};
 
 use hir::def_id::DefId;
-use infer::InferCtxt;
 use traits::{self, ProjectionMode};
 use ty::{self, TyCtxt, ImplOrTraitItem, TraitDef, TypeFoldable};
 use ty::fast_reject::{self, SimplifiedType};
@@ -112,8 +111,8 @@ impl<'a, 'gcx, 'tcx> Children {
             let possible_sibling = *slot;
 
             let tcx = tcx.global_tcx();
-            let (le, ge) = InferCtxt::enter(tcx, None, None,
-                                            ProjectionMode::Topmost, |infcx| {
+            let (le, ge) = tcx.infer_ctxt(None, None,
+                                          ProjectionMode::Topmost).enter(|infcx| {
                 let overlap = traits::overlapping_impls(&infcx,
                                                         possible_sibling,
                                                         impl_def_id);
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index 8d3f7fab38f..1495ae72ab3 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -153,6 +153,58 @@ impl<'a, 'tcx> Lift<'tcx> for traits::SelectionError<'a> {
     }
 }
 
+// For trans only.
+impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> {
+    type Lifted = traits::Vtable<'tcx, ()>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
+        match self.clone() {
+            traits::VtableImpl(traits::VtableImplData {
+                impl_def_id,
+                substs,
+                nested
+            }) => {
+                tcx.lift(&substs).map(|substs| {
+                    traits::VtableImpl(traits::VtableImplData {
+                        impl_def_id: impl_def_id,
+                        substs: substs,
+                        nested: nested
+                    })
+                })
+            }
+            traits::VtableDefaultImpl(t) => Some(traits::VtableDefaultImpl(t)),
+            traits::VtableClosure(traits::VtableClosureData {
+                closure_def_id,
+                substs,
+                nested
+            }) => {
+                tcx.lift(&substs).map(|substs| {
+                    traits::VtableClosure(traits::VtableClosureData {
+                        closure_def_id: closure_def_id,
+                        substs: substs,
+                        nested: nested
+                    })
+                })
+            }
+            traits::VtableFnPointer(ty) => {
+                tcx.lift(&ty).map(traits::VtableFnPointer)
+            }
+            traits::VtableParam(n) => Some(traits::VtableParam(n)),
+            traits::VtableBuiltin(d) => Some(traits::VtableBuiltin(d)),
+            traits::VtableObject(traits::VtableObjectData {
+                upcast_trait_ref,
+                vtable_base
+            }) => {
+                tcx.lift(&upcast_trait_ref).map(|trait_ref| {
+                    traits::VtableObject(traits::VtableObjectData {
+                        upcast_trait_ref: trait_ref,
+                        vtable_base: vtable_base
+                    })
+                })
+            }
+        }
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // TypeFoldable implementations.
 
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index f5610de062f..39fe744c67d 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -22,7 +22,7 @@ use middle::free_region::FreeRegionMap;
 use middle::region::RegionMaps;
 use middle::resolve_lifetime;
 use middle::stability;
-use ty::subst::{self, Subst, Substs};
+use ty::subst::{self, Substs};
 use traits;
 use ty::{self, TraitRef, Ty, TypeAndMut};
 use ty::{TyS, TypeVariants};
@@ -41,6 +41,7 @@ use arena::TypedArena;
 use std::borrow::Borrow;
 use std::cell::{Cell, RefCell, Ref};
 use std::hash::{Hash, Hasher};
+use std::mem;
 use std::ops::Deref;
 use std::rc::Rc;
 use syntax::ast::{self, Name, NodeId};
@@ -82,22 +83,22 @@ impl<'tcx> CtxtArenas<'tcx> {
     }
 }
 
-struct CtxtInterners<'tcx> {
+pub struct CtxtInterners<'tcx> {
     /// The arenas that types etc are allocated from.
     arenas: &'tcx CtxtArenas<'tcx>,
 
     /// Specifically use a speedy hash algorithm for these hash sets,
     /// they're accessed quite often.
-    type_: RefCell<FnvHashSet<InternedTy<'tcx>>>,
-    type_list: RefCell<FnvHashSet<InternedTyList<'tcx>>>,
-    substs: RefCell<FnvHashSet<InternedSubsts<'tcx>>>,
-    bare_fn: RefCell<FnvHashSet<&'tcx BareFnTy<'tcx>>>,
-    region: RefCell<FnvHashSet<InternedRegion<'tcx>>>,
+    type_: RefCell<FnvHashSet<Interned<'tcx, TyS<'tcx>>>>,
+    type_list: RefCell<FnvHashSet<Interned<'tcx, [Ty<'tcx>]>>>,
+    substs: RefCell<FnvHashSet<Interned<'tcx, Substs<'tcx>>>>,
+    bare_fn: RefCell<FnvHashSet<Interned<'tcx, BareFnTy<'tcx>>>>,
+    region: RefCell<FnvHashSet<Interned<'tcx, Region>>>,
     stability: RefCell<FnvHashSet<&'tcx attr::Stability>>,
     layout: RefCell<FnvHashSet<&'tcx Layout>>,
 }
 
-impl<'tcx> CtxtInterners<'tcx> {
+impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
     fn new(arenas: &'tcx CtxtArenas<'tcx>) -> CtxtInterners<'tcx> {
         CtxtInterners {
             arenas: arenas,
@@ -111,24 +112,58 @@ impl<'tcx> CtxtInterners<'tcx> {
         }
     }
 
-    fn intern_ty(&self, st: TypeVariants<'tcx>) -> Ty<'tcx> {
+    /// Intern a type. global_interners is Some only if this is
+    /// a local interner and global_interners is its counterpart.
+    fn intern_ty(&self, st: TypeVariants<'tcx>,
+                 global_interners: Option<&CtxtInterners<'gcx>>)
+                 -> Ty<'tcx> {
         let ty = {
             let mut interner = self.type_.borrow_mut();
-            match interner.get(&st) {
-                Some(&InternedTy { ty }) => return ty,
-                None => ()
+            let global_interner = global_interners.map(|interners| {
+                interners.type_.borrow_mut()
+            });
+            if let Some(&Interned(ty)) = interner.get(&st) {
+                return ty;
+            }
+            if let Some(ref interner) = global_interner {
+                if let Some(&Interned(ty)) = interner.get(&st) {
+                    return ty;
+                }
             }
 
             let flags = super::flags::FlagComputation::for_sty(&st);
-
-            // Don't be &mut TyS.
-            let ty: Ty = self.arenas.type_.alloc(TyS {
+            let ty_struct = TyS {
                 sty: st,
                 flags: Cell::new(flags.flags),
                 region_depth: flags.depth,
-            });
+            };
+
+            // HACK(eddyb) Depend on flags being accurate to
+            // determine that all contents are in the global tcx.
+            // See comments on Lift for why we can't use that.
+            if !flags.flags.intersects(ty::TypeFlags::KEEP_IN_LOCAL_TCX) {
+                if let Some(interner) = global_interners {
+                    let ty_struct: TyS<'gcx> = unsafe {
+                        mem::transmute(ty_struct)
+                    };
+                    let ty: Ty<'gcx> = interner.arenas.type_.alloc(ty_struct);
+                    global_interner.unwrap().insert(Interned(ty));
+                    return ty;
+                }
+            } else {
+                // Make sure we don't end up with inference
+                // types/regions in the global tcx.
+                if global_interners.is_none() {
+                    drop(interner);
+                    bug!("Attempted to intern `{:?}` which contains \
+                          inference types/regions in the global type context",
+                         &ty_struct);
+                }
+            }
 
-            interner.insert(InternedTy { ty: ty });
+            // Don't be &mut TyS.
+            let ty: Ty<'tcx> = self.arenas.type_.alloc(ty_struct);
+            interner.insert(Interned(ty));
             ty
         };
 
@@ -212,45 +247,11 @@ impl<'a, 'gcx, 'tcx> Tables<'tcx> {
             fru_field_types: NodeMap()
         }
     }
-
-    pub fn closure_kind(this: &RefCell<Self>,
-                        tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                        def_id: DefId)
-                        -> ty::ClosureKind {
-        // If this is a local def-id, it should be inserted into the
-        // tables by typeck; else, it will be retreived from
-        // the external crate metadata.
-        if let Some(&kind) = this.borrow().closure_kinds.get(&def_id) {
-            return kind;
-        }
-
-        let kind = tcx.sess.cstore.closure_kind(def_id);
-        this.borrow_mut().closure_kinds.insert(def_id, kind);
-        kind
-    }
-
-    pub fn closure_type(this: &RefCell<Self>,
-                        tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                        def_id: DefId,
-                        substs: ClosureSubsts<'tcx>)
-                        -> ty::ClosureTy<'tcx>
-    {
-        // If this is a local def-id, it should be inserted into the
-        // tables by typeck; else, it will be retreived from
-        // the external crate metadata.
-        if let Some(ty) = this.borrow().closure_tys.get(&def_id) {
-            return ty.subst(tcx, substs.func_substs);
-        }
-
-        let ty = tcx.sess.cstore.closure_ty(tcx.global_tcx(), def_id);
-        this.borrow_mut().closure_tys.insert(def_id, ty.clone());
-        ty.subst(tcx, substs.func_substs)
-    }
 }
 
 impl<'tcx> CommonTypes<'tcx> {
     fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
-        let mk = |sty| interners.intern_ty(sty);
+        let mk = |sty| interners.intern_ty(sty, None);
         CommonTypes {
             bool: mk(TyBool),
             char: mk(TyChar),
@@ -558,13 +559,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         interned
     }
 
-    pub fn intern_stability(self, stab: attr::Stability) -> &'tcx attr::Stability {
-        if let Some(st) = self.interners.stability.borrow().get(&stab) {
+    pub fn intern_stability(self, stab: attr::Stability) -> &'gcx attr::Stability {
+        if let Some(st) = self.global_interners.stability.borrow().get(&stab) {
             return st;
         }
 
-        let interned = self.interners.arenas.stability.alloc(stab);
-        if let Some(prev) = self.interners.stability
+        let interned = self.global_interners.arenas.stability.alloc(stab);
+        if let Some(prev) = self.global_interners.stability
                                 .borrow_mut()
                                 .replace(interned) {
             bug!("Tried to overwrite interned Stability: {:?}", prev)
@@ -572,13 +573,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         interned
     }
 
-    pub fn intern_layout(self, layout: Layout) -> &'tcx Layout {
-        if let Some(layout) = self.interners.layout.borrow().get(&layout) {
+    pub fn intern_layout(self, layout: Layout) -> &'gcx Layout {
+        if let Some(layout) = self.global_interners.layout.borrow().get(&layout) {
             return layout;
         }
 
-        let interned = self.interners.arenas.layout.alloc(layout);
-        if let Some(prev) = self.interners.layout
+        let interned = self.global_interners.arenas.layout.alloc(layout);
+        if let Some(prev) = self.global_interners.layout
                                 .borrow_mut()
                                 .replace(interned) {
             bug!("Tried to overwrite interned Layout: {:?}", prev)
@@ -635,7 +636,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         let common_types = CommonTypes::new(&interners);
         let dep_graph = map.dep_graph.clone();
         let fulfilled_predicates = traits::GlobalFulfilledPredicates::new(dep_graph.clone());
-        tls::enter(GlobalCtxt {
+        tls::enter_global(GlobalCtxt {
             global_interners: interners,
             dep_graph: dep_graph.clone(),
             types: common_types,
@@ -690,11 +691,27 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 }
 
+impl<'gcx: 'tcx, 'tcx> GlobalCtxt<'gcx> {
+    /// Call the closure with a local `TyCtxt` using the given arenas.
+    pub fn enter_local<F, R>(&self, arenas: &'tcx CtxtArenas<'tcx>, f: F) -> R
+        where F: for<'a> FnOnce(TyCtxt<'a, 'gcx, 'tcx>) -> R
+    {
+        let interners = CtxtInterners::new(arenas);
+        tls::enter(self, &interners, f)
+    }
+}
+
 /// A trait implemented for all X<'a> types which can be safely and
 /// efficiently converted to X<'tcx> as long as they are part of the
 /// provided TyCtxt<'tcx>.
 /// This can be done, for example, for Ty<'tcx> or &'tcx Substs<'tcx>
 /// by looking them up in their respective interners.
+///
+/// However, this is still not the best implementation as it does
+/// need to compare the components, even for interned values.
+/// It would be more efficient if TypedArena provided a way to
+/// determine whether the address is in the allocated range.
+///
 /// None is returned if the value or one of the components is not part
 /// of the provided context.
 /// For Ty, None can be returned if either the type interner doesn't
@@ -709,7 +726,7 @@ pub trait Lift<'tcx> {
 impl<'a, 'tcx> Lift<'tcx> for Ty<'a> {
     type Lifted = Ty<'tcx>;
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Ty<'tcx>> {
-        if let Some(&InternedTy { ty }) = tcx.interners.type_.borrow().get(&self.sty) {
+        if let Some(&Interned(ty)) = tcx.interners.type_.borrow().get(&self.sty) {
             if *self as *const _ == ty as *const _ {
                 return Some(ty);
             }
@@ -726,7 +743,7 @@ impl<'a, 'tcx> Lift<'tcx> for Ty<'a> {
 impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
     type Lifted = &'tcx Substs<'tcx>;
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Substs<'tcx>> {
-        if let Some(&InternedSubsts { substs }) = tcx.interners.substs.borrow().get(*self) {
+        if let Some(&Interned(substs)) = tcx.interners.substs.borrow().get(*self) {
             if *self as *const _ == substs as *const _ {
                 return Some(substs);
             }
@@ -743,7 +760,7 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
 impl<'a, 'tcx> Lift<'tcx> for &'a Region {
     type Lifted = &'tcx Region;
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Region> {
-        if let Some(&InternedRegion { region }) = tcx.interners.region.borrow().get(*self) {
+        if let Some(&Interned(region)) = tcx.interners.region.borrow().get(*self) {
             if *self as *const _ == region as *const _ {
                 return Some(region);
             }
@@ -760,7 +777,7 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Region {
 impl<'a, 'tcx> Lift<'tcx> for &'a [Ty<'a>] {
     type Lifted = &'tcx [Ty<'tcx>];
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx [Ty<'tcx>]> {
-        if let Some(&InternedTyList { list }) = tcx.interners.type_list.borrow().get(*self) {
+        if let Some(&Interned(list)) = tcx.interners.type_list.borrow().get(*self) {
             if *self as *const _ == list as *const _ {
                 return Some(list);
             }
@@ -774,21 +791,41 @@ impl<'a, 'tcx> Lift<'tcx> for &'a [Ty<'a>] {
     }
 }
 
+impl<'a, 'tcx> Lift<'tcx> for &'a BareFnTy<'a> {
+    type Lifted = &'tcx BareFnTy<'tcx>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
+                             -> Option<&'tcx BareFnTy<'tcx>> {
+        if let Some(&Interned(fty)) = tcx.interners.bare_fn.borrow().get(*self) {
+            if *self as *const _ == fty as *const _ {
+                return Some(fty);
+            }
+        }
+        // Also try in the global tcx if we're not that.
+        if !tcx.is_global() {
+            self.lift_to_tcx(tcx.global_tcx())
+        } else {
+            None
+        }
+    }
+}
+
 
 pub mod tls {
-    use super::{GlobalCtxt, TyCtxt};
+    use super::{CtxtInterners, GlobalCtxt, TyCtxt};
 
     use std::cell::Cell;
     use std::fmt;
     use syntax::codemap;
 
-    /// Marker type used for the scoped TLS slot.
+    /// Marker types used for the scoped TLS slot.
     /// The type context cannot be used directly because the scoped TLS
     /// in libstd doesn't allow types generic over lifetimes.
     enum ThreadLocalGlobalCtxt {}
+    enum ThreadLocalInterners {}
 
     thread_local! {
-        static TLS_TCX: Cell<Option<*const ThreadLocalGlobalCtxt>> = Cell::new(None)
+        static TLS_TCX: Cell<Option<(*const ThreadLocalGlobalCtxt,
+                                     *const ThreadLocalInterners)>> = Cell::new(None)
     }
 
     fn span_debug(span: codemap::Span, f: &mut fmt::Formatter) -> fmt::Result {
@@ -797,42 +834,55 @@ pub mod tls {
         })
     }
 
-    pub fn enter<'tcx, F, R>(gcx: GlobalCtxt<'tcx>, f: F) -> R
-        where F: for<'a> FnOnce(TyCtxt<'a, 'tcx, 'tcx>) -> R
+    pub fn enter_global<'gcx, F, R>(gcx: GlobalCtxt<'gcx>, f: F) -> R
+        where F: for<'a> FnOnce(TyCtxt<'a, 'gcx, 'gcx>) -> R
     {
         codemap::SPAN_DEBUG.with(|span_dbg| {
             let original_span_debug = span_dbg.get();
             span_dbg.set(span_debug);
-            let tls_ptr = &gcx as *const _ as *const ThreadLocalGlobalCtxt;
-            let result = TLS_TCX.with(|tls| {
-                let prev = tls.get();
-                tls.set(Some(tls_ptr));
-                let ret = f(gcx.global_tcx());
-                tls.set(prev);
-                ret
-            });
+            let result = enter(&gcx, &gcx.global_interners, f);
             span_dbg.set(original_span_debug);
             result
         })
     }
 
+    pub fn enter<'a, 'gcx: 'tcx, 'tcx, F, R>(gcx: &'a GlobalCtxt<'gcx>,
+                                             interners: &'a CtxtInterners<'tcx>,
+                                             f: F) -> R
+        where F: FnOnce(TyCtxt<'a, 'gcx, 'tcx>) -> R
+    {
+        let gcx_ptr = gcx as *const _ as *const ThreadLocalGlobalCtxt;
+        let interners_ptr = interners as *const _ as *const ThreadLocalInterners;
+        TLS_TCX.with(|tls| {
+            let prev = tls.get();
+            tls.set(Some((gcx_ptr, interners_ptr)));
+            let ret = f(TyCtxt {
+                gcx: gcx,
+                interners: interners
+            });
+            tls.set(prev);
+            ret
+        })
+    }
+
     pub fn with<F, R>(f: F) -> R
-        where F: for<'a, 'tcx> FnOnce(TyCtxt<'a, 'tcx, 'tcx>) -> R
+        where F: for<'a, 'gcx, 'tcx> FnOnce(TyCtxt<'a, 'gcx, 'tcx>) -> R
     {
-        TLS_TCX.with(|gcx| {
-            let gcx = gcx.get().unwrap();
+        TLS_TCX.with(|tcx| {
+            let (gcx, interners) = tcx.get().unwrap();
             let gcx = unsafe { &*(gcx as *const GlobalCtxt) };
+            let interners = unsafe { &*(interners as *const CtxtInterners) };
             f(TyCtxt {
                 gcx: gcx,
-                interners: &gcx.global_interners
+                interners: interners
             })
         })
     }
 
     pub fn with_opt<F, R>(f: F) -> R
-        where F: for<'a, 'tcx> FnOnce(Option<TyCtxt<'a, 'tcx, 'tcx>>) -> R
+        where F: for<'a, 'gcx, 'tcx> FnOnce(Option<TyCtxt<'a, 'gcx, 'tcx>>) -> R
     {
-        if TLS_TCX.with(|gcx| gcx.get().is_some()) {
+        if TLS_TCX.with(|tcx| tcx.get().is_some()) {
             with(|v| f(Some(v)))
         } else {
             f(None)
@@ -847,7 +897,7 @@ macro_rules! sty_debug_print {
         #[allow(non_snake_case)]
         mod inner {
             use ty::{self, TyCtxt};
-            use ty::context::InternedTy;
+            use ty::context::Interned;
 
             #[derive(Copy, Clone)]
             struct DebugStat {
@@ -865,7 +915,7 @@ macro_rules! sty_debug_print {
                 $(let mut $variant = total;)*
 
 
-                for &InternedTy { ty: t } in tcx.interners.type_.borrow().iter() {
+                for &Interned(t) in tcx.interners.type_.borrow().iter() {
                     let variant = match t.sty {
                         ty::TyBool | ty::TyChar | ty::TyInt(..) | ty::TyUint(..) |
                             ty::TyFloat(..) | ty::TyStr => continue,
@@ -920,100 +970,134 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
 }
 
 
-/// An entry in the type interner.
-struct InternedTy<'tcx> {
-    ty: Ty<'tcx>
-}
+/// An entry in an interner.
+struct Interned<'tcx, T: 'tcx+?Sized>(&'tcx T);
 
-// NB: An InternedTy compares and hashes as a sty.
-impl<'tcx> PartialEq for InternedTy<'tcx> {
-    fn eq(&self, other: &InternedTy<'tcx>) -> bool {
-        self.ty.sty == other.ty.sty
+// NB: An Interned<Ty> compares and hashes as a sty.
+impl<'tcx> PartialEq for Interned<'tcx, TyS<'tcx>> {
+    fn eq(&self, other: &Interned<'tcx, TyS<'tcx>>) -> bool {
+        self.0.sty == other.0.sty
     }
 }
 
-impl<'tcx> Eq for InternedTy<'tcx> {}
+impl<'tcx> Eq for Interned<'tcx, TyS<'tcx>> {}
 
-impl<'tcx> Hash for InternedTy<'tcx> {
+impl<'tcx> Hash for Interned<'tcx, TyS<'tcx>> {
     fn hash<H: Hasher>(&self, s: &mut H) {
-        self.ty.sty.hash(s)
+        self.0.sty.hash(s)
     }
 }
 
-impl<'tcx: 'lcx, 'lcx> Borrow<TypeVariants<'lcx>> for InternedTy<'tcx> {
+impl<'tcx: 'lcx, 'lcx> Borrow<TypeVariants<'lcx>> for Interned<'tcx, TyS<'tcx>> {
     fn borrow<'a>(&'a self) -> &'a TypeVariants<'lcx> {
-        &self.ty.sty
+        &self.0.sty
     }
 }
 
-/// An entry in the type list interner.
-#[derive(PartialEq, Eq, Hash)]
-struct InternedTyList<'tcx> {
-    list: &'tcx [Ty<'tcx>]
-}
-
-impl<'tcx: 'lcx, 'lcx> Borrow<[Ty<'lcx>]> for InternedTyList<'tcx> {
+impl<'tcx: 'lcx, 'lcx> Borrow<[Ty<'lcx>]> for Interned<'tcx, [Ty<'tcx>]> {
     fn borrow<'a>(&'a self) -> &'a [Ty<'lcx>] {
-        self.list
+        self.0
     }
 }
 
-/// An entry in the substs interner.
-#[derive(PartialEq, Eq, Hash)]
-struct InternedSubsts<'tcx> {
-    substs: &'tcx Substs<'tcx>
-}
-
-impl<'tcx: 'lcx, 'lcx> Borrow<Substs<'lcx>> for InternedSubsts<'tcx> {
+impl<'tcx: 'lcx, 'lcx> Borrow<Substs<'lcx>> for Interned<'tcx, Substs<'tcx>> {
     fn borrow<'a>(&'a self) -> &'a Substs<'lcx> {
-        self.substs
+        self.0
     }
 }
 
-/// An entry in the region interner.
-#[derive(PartialEq, Eq, Hash)]
-struct InternedRegion<'tcx> {
-    region: &'tcx Region
+impl<'tcx: 'lcx, 'lcx> Borrow<BareFnTy<'lcx>> for Interned<'tcx, BareFnTy<'tcx>> {
+    fn borrow<'a>(&'a self) -> &'a BareFnTy<'lcx> {
+        self.0
+    }
 }
 
-impl<'tcx> Borrow<Region> for InternedRegion<'tcx> {
+impl<'tcx> Borrow<Region> for Interned<'tcx, Region> {
     fn borrow<'a>(&'a self) -> &'a Region {
-        self.region
+        self.0
     }
 }
 
-fn bound_list_is_sorted(bounds: &[ty::PolyProjectionPredicate]) -> bool {
-    bounds.is_empty() ||
-        bounds[1..].iter().enumerate().all(
-            |(index, bound)| bounds[index].sort_key() <= bound.sort_key())
-}
-
-impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
-    pub fn mk_type_list(self, list: Vec<Ty<'tcx>>) -> &'tcx [Ty<'tcx>] {
-        if let Some(interned) = self.interners.type_list.borrow().get(&list[..]) {
-            return interned.list;
+macro_rules! items { ($($item:item)+) => ($($item)+) }
+macro_rules! impl_interners {
+    ($lt_tcx:tt, $($name:ident: $method:ident($alloc:ty, $needs_infer:expr)-> $ty:ty),+) => {
+        items!($(impl<$lt_tcx> PartialEq for Interned<$lt_tcx, $ty> {
+            fn eq(&self, other: &Self) -> bool {
+                self.0 == other.0
+            }
         }
 
-        let list = self.interners.arenas.type_list.alloc(list);
-        self.interners.type_list.borrow_mut().insert(InternedTyList {
-            list: list
-        });
-        list
-    }
+        impl<$lt_tcx> Eq for Interned<$lt_tcx, $ty> {}
 
-    // Type constructors
-    pub fn mk_substs(self, substs: Substs<'tcx>) -> &'tcx Substs<'tcx> {
-        if let Some(interned) = self.interners.substs.borrow().get(&substs) {
-            return interned.substs;
+        impl<$lt_tcx> Hash for Interned<$lt_tcx, $ty> {
+            fn hash<H: Hasher>(&self, s: &mut H) {
+                self.0.hash(s)
+            }
         }
 
-        let substs = self.interners.arenas.substs.alloc(substs);
-        self.interners.substs.borrow_mut().insert(InternedSubsts {
-            substs: substs
-        });
-        substs
+        impl<'a, 'gcx, $lt_tcx> TyCtxt<'a, 'gcx, $lt_tcx> {
+            pub fn $method(self, v: $alloc) -> &$lt_tcx $ty {
+                if let Some(i) = self.interners.$name.borrow().get::<$ty>(&v) {
+                    return i.0;
+                }
+                if !self.is_global() {
+                    if let Some(i) = self.global_interners.$name.borrow().get::<$ty>(&v) {
+                        return i.0;
+                    }
+                }
+
+                // HACK(eddyb) Depend on flags being accurate to
+                // determine that all contents are in the global tcx.
+                // See comments on Lift for why we can't use that.
+                if !($needs_infer)(&v) {
+                    if !self.is_global() {
+                        let v = unsafe {
+                            mem::transmute(v)
+                        };
+                        let i = self.global_interners.arenas.$name.alloc(v);
+                        self.global_interners.$name.borrow_mut().insert(Interned(i));
+                        return i;
+                    }
+                } else {
+                    // Make sure we don't end up with inference
+                    // types/regions in the global tcx.
+                    if self.is_global() {
+                        bug!("Attempted to intern `{:?}` which contains \
+                              inference types/regions in the global type context",
+                             v);
+                    }
+                }
+
+                let i = self.interners.arenas.$name.alloc(v);
+                self.interners.$name.borrow_mut().insert(Interned(i));
+                i
+            }
+        })+);
     }
+}
+
+fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool {
+    x.has_type_flags(ty::TypeFlags::KEEP_IN_LOCAL_TCX)
+}
 
+impl_interners!('tcx,
+    type_list: mk_type_list(Vec<Ty<'tcx>>, keep_local) -> [Ty<'tcx>],
+    substs: mk_substs(Substs<'tcx>, |substs: &Substs| {
+        keep_local(&substs.types) || keep_local(&substs.regions)
+    }) -> Substs<'tcx>,
+    bare_fn: mk_bare_fn(BareFnTy<'tcx>, |fty: &BareFnTy| {
+        keep_local(&fty.sig)
+    }) -> BareFnTy<'tcx>,
+    region: mk_region(Region, keep_local) -> Region
+);
+
+fn bound_list_is_sorted(bounds: &[ty::PolyProjectionPredicate]) -> bool {
+    bounds.is_empty() ||
+        bounds[1..].iter().enumerate().all(
+            |(index, bound)| bounds[index].sort_key() <= bound.sort_key())
+}
+
+impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// Create an unsafe fn ty based on a safe fn ty.
     pub fn safe_to_unsafe_fn_ty(self, bare_fn: &BareFnTy<'tcx>) -> Ty<'tcx> {
         assert_eq!(bare_fn.unsafety, hir::Unsafety::Normal);
@@ -1024,32 +1108,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }))
     }
 
-    pub fn mk_bare_fn(self, bare_fn: BareFnTy<'tcx>) -> &'tcx BareFnTy<'tcx> {
-        if let Some(bare_fn) = self.interners.bare_fn.borrow().get(&bare_fn) {
-            return *bare_fn;
-        }
-
-        let bare_fn = self.interners.arenas.bare_fn.alloc(bare_fn);
-        self.interners.bare_fn.borrow_mut().insert(bare_fn);
-        bare_fn
-    }
-
-    pub fn mk_region(self, region: Region) -> &'tcx Region {
-        if let Some(interned) = self.interners.region.borrow().get(&region) {
-            return interned.region;
-        }
-
-        let region = self.interners.arenas.region.alloc(region);
-        self.interners.region.borrow_mut().insert(InternedRegion {
-            region: region
-        });
-        region
-    }
-
     // Interns a type/name combination, stores the resulting box in cx.interners,
     // and returns the box as cast to an unsafe ptr (see comments for Ty above).
     pub fn mk_ty(self, st: TypeVariants<'tcx>) -> Ty<'tcx> {
-        self.interners.intern_ty(st)
+        let global_interners = if !self.is_global() {
+            Some(&self.global_interners)
+        } else {
+            None
+        };
+        self.interners.intern_ty(st, global_interners)
     }
 
     pub fn mk_mach_int(self, tm: ast::IntTy) -> Ty<'tcx> {
diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs
index f3dcccedc59..a1da3017fcd 100644
--- a/src/librustc/ty/flags.rs
+++ b/src/librustc/ty/flags.rs
@@ -90,9 +90,15 @@ impl FlagComputation {
                 self.add_tys(&substs.upvar_tys);
             }
 
-            &ty::TyInfer(_) => {
+            &ty::TyInfer(infer) => {
                 self.add_flags(TypeFlags::HAS_LOCAL_NAMES); // it might, right?
-                self.add_flags(TypeFlags::HAS_TY_INFER)
+                self.add_flags(TypeFlags::HAS_TY_INFER);
+                match infer {
+                    ty::FreshTy(_) |
+                    ty::FreshIntTy(_) |
+                    ty::FreshFloatTy(_) => {}
+                    _ => self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX)
+                }
             }
 
             &ty::TyEnum(_, substs) | &ty::TyStruct(_, substs) => {
@@ -171,7 +177,10 @@ impl FlagComputation {
     fn add_region(&mut self, r: ty::Region) {
         match r {
             ty::ReVar(..) |
-            ty::ReSkolemized(..) => { self.add_flags(TypeFlags::HAS_RE_INFER); }
+            ty::ReSkolemized(..) => {
+                self.add_flags(TypeFlags::HAS_RE_INFER);
+                self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX);
+            }
             ty::ReLateBound(debruijn, _) => { self.add_depth(debruijn.depth); }
             ty::ReEarlyBound(..) => { self.add_flags(TypeFlags::HAS_RE_EARLY_BOUND); }
             ty::ReStatic => {}
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 35656fb0c2d..82a3b0b8db2 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -466,7 +466,7 @@ pub struct Struct {
     pub offset_after_field: Vec<Size>
 }
 
-impl<'a, 'tcx> Struct {
+impl<'a, 'gcx, 'tcx> Struct {
     pub fn new(dl: &TargetDataLayout, packed: bool) -> Struct {
         Struct {
             align: if packed { dl.i8_align } else { dl.aggregate_align },
@@ -479,9 +479,9 @@ impl<'a, 'tcx> Struct {
     /// Extend the Struct with more fields.
     pub fn extend<I>(&mut self, dl: &TargetDataLayout,
                      fields: I,
-                     scapegoat: Ty<'tcx>)
-                     -> Result<(), LayoutError<'tcx>>
-    where I: Iterator<Item=Result<&'a Layout, LayoutError<'tcx>>> {
+                     scapegoat: Ty<'gcx>)
+                     -> Result<(), LayoutError<'gcx>>
+    where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
         self.offset_after_field.reserve(fields.size_hint().0);
 
         for field in fields {
@@ -528,8 +528,8 @@ impl<'a, 'tcx> Struct {
 
     /// Determine whether a structure would be zero-sized, given its fields.
     pub fn would_be_zero_sized<I>(dl: &TargetDataLayout, fields: I)
-                                  -> Result<bool, LayoutError<'tcx>>
-    where I: Iterator<Item=Result<&'a Layout, LayoutError<'tcx>>> {
+                                  -> Result<bool, LayoutError<'gcx>>
+    where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
         for field in fields {
             let field = field?;
             if field.is_unsized() || field.size(dl).bytes() > 0 {
@@ -542,10 +542,10 @@ impl<'a, 'tcx> Struct {
     /// Find the path leading to a non-zero leaf field, starting from
     /// the given type and recursing through aggregates.
     // FIXME(eddyb) track value ranges and traverse already optimized enums.
-    pub fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'tcx, 'tcx>,
-                                  ty: Ty<'tcx>)
-                                  -> Result<Option<FieldPath>, LayoutError<'tcx>> {
-        let tcx = infcx.tcx;
+    pub fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+                                  ty: Ty<'gcx>)
+                                  -> Result<Option<FieldPath>, LayoutError<'gcx>> {
+        let tcx = infcx.tcx.global_tcx();
         match (ty.layout(infcx)?, &ty.sty) {
             (&Scalar { non_zero: true, .. }, _) => Ok(Some(vec![])),
             (&FatPointer { non_zero: true, .. }, _) => {
@@ -600,10 +600,10 @@ impl<'a, 'tcx> Struct {
 
     /// Find the path leading to a non-zero leaf field, starting from
     /// the given set of fields and recursing through aggregates.
-    pub fn non_zero_field_path<I>(infcx: &InferCtxt<'a, 'tcx, 'tcx>,
+    pub fn non_zero_field_path<I>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                   fields: I)
-                                  -> Result<Option<FieldPath>, LayoutError<'tcx>>
-    where I: Iterator<Item=Ty<'tcx>> {
+                                  -> Result<Option<FieldPath>, LayoutError<'gcx>>
+    where I: Iterator<Item=Ty<'gcx>> {
         for (i, ty) in fields.enumerate() {
             if let Some(mut path) = Struct::non_zero_field_in_type(infcx, ty)? {
                 path.push(i as u32);
@@ -736,9 +736,9 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
 }
 
 /// Helper function for normalizing associated types in an inference context.
-fn normalize_associated_type<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx, 'tcx>,
-                                       ty: Ty<'tcx>)
-                                       -> Ty<'tcx> {
+fn normalize_associated_type<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+                                             ty: Ty<'gcx>)
+                                             -> Ty<'gcx> {
     if !ty.has_projection_types() {
         return ty;
     }
@@ -757,11 +757,11 @@ fn normalize_associated_type<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx, 'tcx>,
     infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result)
 }
 
-impl<'a, 'tcx> Layout {
-    pub fn compute_uncached(ty: Ty<'tcx>,
-                            infcx: &InferCtxt<'a, 'tcx, 'tcx>)
-                            -> Result<Layout, LayoutError<'tcx>> {
-        let tcx = infcx.tcx;
+impl<'a, 'gcx, 'tcx> Layout {
+    pub fn compute_uncached(ty: Ty<'gcx>,
+                            infcx: &InferCtxt<'a, 'gcx, 'tcx>)
+                            -> Result<Layout, LayoutError<'gcx>> {
+        let tcx = infcx.tcx.global_tcx();
         let dl = &tcx.data_layout;
         assert!(!ty.has_infer_types());
 
@@ -1220,10 +1220,10 @@ pub enum SizeSkeleton<'tcx> {
     }
 }
 
-impl<'a, 'tcx> SizeSkeleton<'tcx> {
-    pub fn compute(ty: Ty<'tcx>, infcx: &InferCtxt<'a, 'tcx, 'tcx>)
-                   -> Result<SizeSkeleton<'tcx>, LayoutError<'tcx>> {
-        let tcx = infcx.tcx;
+impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> {
+    pub fn compute(ty: Ty<'gcx>, infcx: &InferCtxt<'a, 'gcx, 'tcx>)
+                   -> Result<SizeSkeleton<'gcx>, LayoutError<'gcx>> {
+        let tcx = infcx.tcx.global_tcx();
         assert!(!ty.has_infer_types());
 
         // First try computing a static layout.
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 7bede488964..005d83da38d 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -165,8 +165,8 @@ pub struct ImplHeader<'tcx> {
     pub predicates: Vec<Predicate<'tcx>>,
 }
 
-impl<'a, 'tcx> ImplHeader<'tcx> {
-    pub fn with_fresh_ty_vars(selcx: &mut traits::SelectionContext<'a, 'tcx, 'tcx>,
+impl<'a, 'gcx, 'tcx> ImplHeader<'tcx> {
+    pub fn with_fresh_ty_vars(selcx: &mut traits::SelectionContext<'a, 'gcx, 'tcx>,
                               impl_def_id: DefId)
                               -> ImplHeader<'tcx>
     {
@@ -524,6 +524,10 @@ bitflags! {
         // that are local to a particular fn
         const HAS_LOCAL_NAMES   = 1 << 9,
 
+        // Present if the type belongs in a local type context.
+        // Only set for TyInfer other than Fresh.
+        const KEEP_IN_LOCAL_TCX = 1 << 10,
+
         const NEEDS_SUBST        = TypeFlags::HAS_PARAMS.bits |
                                    TypeFlags::HAS_SELF.bits |
                                    TypeFlags::HAS_RE_EARLY_BOUND.bits,
@@ -540,7 +544,8 @@ bitflags! {
                                   TypeFlags::HAS_TY_ERR.bits |
                                   TypeFlags::HAS_PROJECTION.bits |
                                   TypeFlags::HAS_TY_CLOSURE.bits |
-                                  TypeFlags::HAS_LOCAL_NAMES.bits,
+                                  TypeFlags::HAS_LOCAL_NAMES.bits |
+                                  TypeFlags::KEEP_IN_LOCAL_TCX.bits,
 
         // Caches for type_is_sized, type_moves_by_default
         const SIZEDNESS_CACHED  = 1 << 16,
@@ -2715,15 +2720,33 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn closure_kind(self, def_id: DefId) -> ty::ClosureKind {
-        Tables::closure_kind(&self.tables, self.global_tcx(), def_id)
+        // If this is a local def-id, it should be inserted into the
+        // tables by typeck; else, it will be retreived from
+        // the external crate metadata.
+        if let Some(&kind) = self.tables.borrow().closure_kinds.get(&def_id) {
+            return kind;
+        }
+
+        let kind = self.sess.cstore.closure_kind(def_id);
+        self.tables.borrow_mut().closure_kinds.insert(def_id, kind);
+        kind
     }
 
     pub fn closure_type(self,
                         def_id: DefId,
-                        substs: ClosureSubsts<'gcx>)
-                        -> ty::ClosureTy<'gcx>
+                        substs: ClosureSubsts<'tcx>)
+                        -> ty::ClosureTy<'tcx>
     {
-        Tables::closure_type(&self.tables, self.global_tcx(), def_id, substs)
+        // If this is a local def-id, it should be inserted into the
+        // tables by typeck; else, it will be retreived from
+        // the external crate metadata.
+        if let Some(ty) = self.tables.borrow().closure_tys.get(&def_id) {
+            return ty.subst(self, substs.func_substs);
+        }
+
+        let ty = self.sess.cstore.closure_ty(self.global_tcx(), def_id);
+        self.tables.borrow_mut().closure_tys.insert(def_id, ty.clone());
+        ty.subst(self, substs.func_substs)
     }
 
     /// Given the def_id of an impl, return the def_id of the trait it implements.
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 284019ed6a2..77e980ff319 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -131,6 +131,41 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionPredicate<'a> {
     }
 }
 
+impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> {
+    type Lifted = ty::Predicate<'tcx>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
+        match *self {
+            ty::Predicate::Trait(ref binder) => {
+                tcx.lift(binder).map(ty::Predicate::Trait)
+            }
+            ty::Predicate::Equate(ref binder) => {
+                tcx.lift(binder).map(ty::Predicate::Equate)
+            }
+            ty::Predicate::RegionOutlives(ref binder) => {
+                tcx.lift(binder).map(ty::Predicate::RegionOutlives)
+            }
+            ty::Predicate::TypeOutlives(ref binder) => {
+                tcx.lift(binder).map(ty::Predicate::TypeOutlives)
+            }
+            ty::Predicate::Projection(ref binder) => {
+                tcx.lift(binder).map(ty::Predicate::Projection)
+            }
+            ty::Predicate::WellFormed(ty) => {
+                tcx.lift(&ty).map(ty::Predicate::WellFormed)
+            }
+            ty::Predicate::Rfc1592(box ref a) => {
+                tcx.lift(a).map(|a| ty::Predicate::Rfc1592(Box::new(a)))
+            }
+            ty::Predicate::ClosureKind(closure_def_id, kind) => {
+                Some(ty::Predicate::ClosureKind(closure_def_id, kind))
+            }
+            ty::Predicate::ObjectSafe(trait_def_id) => {
+                Some(ty::Predicate::ObjectSafe(trait_def_id))
+            }
+        }
+    }
+}
+
 impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<T> {
     type Lifted = ty::Binder<T::Lifted>;
     fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted> {
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 4b96527cbe1..08909861d3f 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -134,9 +134,9 @@ impl<'tcx> ParameterEnvironment<'tcx> {
                                        self_type: Ty<'tcx>, span: Span)
                                        -> Result<(),CopyImplementationError> {
         // FIXME: (@jroesch) float this code up
-        let adt = InferCtxt::enter(tcx, None, Some(self.clone()),
-                                   ProjectionMode::Topmost, |infcx| {
-            match self_type.sty {
+        tcx.infer_ctxt(None, Some(self.clone()),
+                       ProjectionMode::Topmost).enter(|infcx| {
+            let adt = match self_type.sty {
                 ty::TyStruct(struct_def, substs) => {
                     for field in struct_def.all_fields() {
                         let field_ty = field.ty(tcx, substs);
@@ -145,7 +145,7 @@ impl<'tcx> ParameterEnvironment<'tcx> {
                                 field.name))
                         }
                     }
-                    Ok(struct_def)
+                    struct_def
                 }
                 ty::TyEnum(enum_def, substs) => {
                     for variant in &enum_def.variants {
@@ -157,17 +157,17 @@ impl<'tcx> ParameterEnvironment<'tcx> {
                             }
                         }
                     }
-                    Ok(enum_def)
+                    enum_def
                 }
-                _ => Err(CopyImplementationError::NotAnAdt)
-            }
-        })?;
+                _ => return Err(CopyImplementationError::NotAnAdt)
+            };
 
-        if adt.has_dtor() {
-            return Err(CopyImplementationError::HasDestructor)
-        }
+            if adt.has_dtor() {
+                return Err(CopyImplementationError::HasDestructor);
+            }
 
-        Ok(())
+            Ok(())
+        })
     }
 }
 
@@ -513,7 +513,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
                    param_env: &ParameterEnvironment<'tcx>,
                    bound: ty::BuiltinBound, span: Span) -> bool
     {
-        InferCtxt::enter(tcx, None, Some(param_env.clone()), ProjectionMode::Topmost, |infcx| {
+        tcx.infer_ctxt(None, Some(param_env.clone()), ProjectionMode::Topmost).enter(|infcx| {
             traits::type_known_to_meet_builtin_bound(&infcx, self, bound, span)
         })
     }
@@ -596,19 +596,20 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
     }
 
     #[inline]
-    pub fn layout(&'tcx self, infcx: &InferCtxt<'a, 'tcx, 'tcx>)
-                  -> Result<&'tcx Layout, LayoutError<'tcx>> {
+    pub fn layout<'lcx>(&'tcx self, infcx: &InferCtxt<'a, 'tcx, 'lcx>)
+                        -> Result<&'tcx Layout, LayoutError<'tcx>> {
+        let tcx = infcx.tcx.global_tcx();
         let can_cache = !self.has_param_types() && !self.has_self_ty();
         if can_cache {
-            if let Some(&cached) = infcx.tcx.layout_cache.borrow().get(&self) {
+            if let Some(&cached) = tcx.layout_cache.borrow().get(&self) {
                 return Ok(cached);
             }
         }
 
         let layout = Layout::compute_uncached(self, infcx)?;
-        let layout = infcx.tcx.intern_layout(layout);
+        let layout = tcx.intern_layout(layout);
         if can_cache {
-            infcx.tcx.layout_cache.borrow_mut().insert(self, layout);
+            tcx.layout_cache.borrow_mut().insert(self, layout);
         }
         Ok(layout)
     }
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index ff22db4ccda..1a802064b61 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -69,12 +69,12 @@ pub enum Ns {
     Value
 }
 
-fn number_of_supplied_defaults<'a, 'tcx, GG>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                             substs: &subst::Substs,
-                                             space: subst::ParamSpace,
-                                             get_generics: GG)
-                                             -> usize
-    where GG: FnOnce(TyCtxt<'a, 'tcx, 'tcx>) -> ty::Generics<'tcx>
+fn number_of_supplied_defaults<'a, 'gcx, 'tcx, GG>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                                                   substs: &subst::Substs,
+                                                   space: subst::ParamSpace,
+                                                   get_generics: GG)
+                                                   -> usize
+    where GG: FnOnce(TyCtxt<'a, 'gcx, 'tcx>) -> ty::Generics<'tcx>
 {
     let generics = get_generics(tcx);
 
@@ -115,7 +115,7 @@ pub fn parameterized<GG>(f: &mut fmt::Formatter,
                          projections: &[ty::ProjectionPredicate],
                          get_generics: GG)
                          -> fmt::Result
-    where GG: for<'a, 'tcx> FnOnce(TyCtxt<'a, 'tcx, 'tcx>) -> ty::Generics<'tcx>
+    where GG: for<'a, 'gcx, 'tcx> FnOnce(TyCtxt<'a, 'gcx, 'tcx>) -> ty::Generics<'tcx>
 {
     if let (Ns::Value, Some(self_ty)) = (ns, substs.self_ty()) {
         write!(f, "<{} as ", self_ty)?;
@@ -231,10 +231,10 @@ pub fn parameterized<GG>(f: &mut fmt::Formatter,
     Ok(())
 }
 
-fn in_binder<'a, 'tcx, T, U>(f: &mut fmt::Formatter,
-                             tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                             original: &ty::Binder<T>,
-                             lifted: Option<ty::Binder<U>>) -> fmt::Result
+fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter,
+                                   tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                                   original: &ty::Binder<T>,
+                                   lifted: Option<ty::Binder<U>>) -> fmt::Result
     where T: fmt::Display, U: fmt::Display + TypeFoldable<'tcx>
 {
     // Replace any anonymous late-bound regions with named
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index c5fe4366621..bf5bce8fc3b 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -22,12 +22,10 @@ use borrowck::*;
 use borrowck::InteriorKind::{InteriorElement, InteriorField};
 use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::expr_use_visitor::MutateMode;
-use rustc::infer::InferCtxt;
 use rustc::middle::mem_categorization as mc;
 use rustc::middle::mem_categorization::Categorization;
 use rustc::middle::region;
 use rustc::ty::{self, TyCtxt};
-use rustc::traits::ProjectionMode;
 use syntax::ast;
 use syntax::codemap::Span;
 use rustc::hir;
@@ -203,17 +201,15 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
     debug!("check_loans(body id={})", body.id);
 
     let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);
-    InferCtxt::enter(bccx.tcx, None, Some(param_env), ProjectionMode::AnyFinal, |infcx| {
-        let mut clcx = CheckLoanCtxt {
-            bccx: bccx,
-            dfcx_loans: dfcx_loans,
-            move_data: move_data,
-            all_loans: all_loans,
-            param_env: &infcx.parameter_environment
-        };
-        let mut euv = euv::ExprUseVisitor::new(&mut clcx, &infcx);
-        euv.walk_fn(decl, body);
-    });
+    let infcx = bccx.tcx.borrowck_fake_infer_ctxt(param_env);
+    let mut clcx = CheckLoanCtxt {
+        bccx: bccx,
+        dfcx_loans: dfcx_loans,
+        move_data: move_data,
+        all_loans: all_loans,
+        param_env: &infcx.parameter_environment
+    };
+    euv::ExprUseVisitor::new(&mut clcx, &infcx).walk_fn(decl, body);
 }
 
 #[derive(PartialEq)]
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index b4d7ca6627e..7d4f02bfe11 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -19,12 +19,10 @@
 use borrowck::*;
 use borrowck::move_data::MoveData;
 use rustc::middle::expr_use_visitor as euv;
-use rustc::infer::InferCtxt;
 use rustc::middle::mem_categorization as mc;
 use rustc::middle::mem_categorization::Categorization;
 use rustc::middle::region;
 use rustc::ty::{self, TyCtxt};
-use rustc::traits::ProjectionMode;
 
 use syntax::ast;
 use syntax::codemap::Span;
@@ -56,10 +54,8 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
     };
 
     let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);
-    InferCtxt::enter(bccx.tcx, None, Some(param_env), ProjectionMode::AnyFinal, |infcx| {
-        let mut euv = euv::ExprUseVisitor::new(&mut glcx, &infcx);
-        euv.walk_fn(decl, body);
-    });
+    let infcx = bccx.tcx.borrowck_fake_infer_ctxt(param_env);
+    euv::ExprUseVisitor::new(&mut glcx, &infcx).walk_fn(decl, body);
 
     glcx.report_potential_errors();
     let GatherLoanCtxt { all_loans, move_data, .. } = glcx;
@@ -520,21 +516,22 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
 /// sure the loans being taken are sound.
 struct StaticInitializerCtxt<'a, 'tcx: 'a> {
     bccx: &'a BorrowckCtxt<'a, 'tcx>,
+    item_id: ast::NodeId
 }
 
 impl<'a, 'tcx, 'v> Visitor<'v> for StaticInitializerCtxt<'a, 'tcx> {
     fn visit_expr(&mut self, ex: &Expr) {
         if let hir::ExprAddrOf(mutbl, ref base) = ex.node {
-            let err = InferCtxt::enter(self.bccx.tcx, None, None,
-                                       ProjectionMode::AnyFinal, |infcx| {
-                let mc = mc::MemCategorizationContext::new(&infcx);
-                let base_cmt = mc.cat_expr(&base).unwrap();
-                let borrow_kind = ty::BorrowKind::from_mutbl(mutbl);
-                // Check that we don't allow borrows of unsafe static items.
-                check_aliasability(self.bccx, ex.span,
-                                   BorrowViolation(euv::AddrOf),
-                                   base_cmt, borrow_kind).is_err()
-            });
+            let param_env = ty::ParameterEnvironment::for_item(self.bccx.tcx,
+                                                               self.item_id);
+            let infcx = self.bccx.tcx.borrowck_fake_infer_ctxt(param_env);
+            let mc = mc::MemCategorizationContext::new(&infcx);
+            let base_cmt = mc.cat_expr(&base).unwrap();
+            let borrow_kind = ty::BorrowKind::from_mutbl(mutbl);
+            // Check that we don't allow borrows of unsafe static items.
+            let err = check_aliasability(self.bccx, ex.span,
+                                         BorrowViolation(euv::AddrOf),
+                                         base_cmt, borrow_kind).is_err();
             if err {
                 return; // reported an error, no sense in reporting more.
             }
@@ -544,12 +541,15 @@ impl<'a, 'tcx, 'v> Visitor<'v> for StaticInitializerCtxt<'a, 'tcx> {
     }
 }
 
-pub fn gather_loans_in_static_initializer(bccx: &mut BorrowckCtxt, expr: &hir::Expr) {
+pub fn gather_loans_in_static_initializer(bccx: &mut BorrowckCtxt,
+                                          item_id: ast::NodeId,
+                                          expr: &hir::Expr) {
 
     debug!("gather_loans_in_static_initializer(expr={:?})", expr);
 
     let mut sicx = StaticInitializerCtxt {
-        bccx: bccx
+        bccx: bccx,
+        item_id: item_id
     };
 
     sicx.visit_expr(expr);
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index ca6d00a2baf..f0ea69c8a6b 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -87,14 +87,14 @@ impl<'a, 'tcx, 'v> Visitor<'v> for BorrowckCtxt<'a, 'tcx> {
 
     fn visit_trait_item(&mut self, ti: &hir::TraitItem) {
         if let hir::ConstTraitItem(_, Some(ref expr)) = ti.node {
-            gather_loans::gather_loans_in_static_initializer(self, &expr);
+            gather_loans::gather_loans_in_static_initializer(self, ti.id, &expr);
         }
         intravisit::walk_trait_item(self, ti);
     }
 
     fn visit_impl_item(&mut self, ii: &hir::ImplItem) {
         if let hir::ImplItemKind::Const(_, ref expr) = ii.node {
-            gather_loans::gather_loans_in_static_initializer(self, &expr);
+            gather_loans::gather_loans_in_static_initializer(self, ii.id, &expr);
         }
         intravisit::walk_impl_item(self, ii);
     }
@@ -142,7 +142,7 @@ fn borrowck_item(this: &mut BorrowckCtxt, item: &hir::Item) {
     match item.node {
         hir::ItemStatic(_, _, ref ex) |
         hir::ItemConst(_, ref ex) => {
-            gather_loans::gather_loans_in_static_initializer(this, &ex);
+            gather_loans::gather_loans_in_static_initializer(this, item.id, &ex);
         }
         _ => { }
     }
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index d7c1c877c8b..61d2408d5bf 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -22,7 +22,6 @@ use rustc::hir::def_id::{DefId};
 use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
 use rustc::middle::expr_use_visitor::{LoanCause, MutateMode};
 use rustc::middle::expr_use_visitor as euv;
-use rustc::infer::InferCtxt;
 use rustc::middle::mem_categorization::{cmt};
 use rustc::hir::pat_util::*;
 use rustc::traits::ProjectionMode;
@@ -1123,8 +1122,8 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
                     PatKind::Ident(hir::BindByValue(_), _, ref sub) => {
                         let pat_ty = tcx.node_id_to_type(p.id);
                         //FIXME: (@jroesch) this code should be floated up as well
-                        InferCtxt::enter(cx.tcx, None, Some(cx.param_env.clone()),
-                                         ProjectionMode::AnyFinal, |infcx| {
+                        cx.tcx.infer_ctxt(None, Some(cx.param_env.clone()),
+                                          ProjectionMode::AnyFinal).enter(|infcx| {
                             if infcx.type_moves_by_default(pat_ty, pat.span) {
                                 check_move(p, sub.as_ref().map(|p| &**p));
                             }
@@ -1150,8 +1149,8 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
 /// assign.
 fn check_for_mutation_in_guard<'a, 'tcx>(cx: &'a MatchCheckCtxt<'a, 'tcx>,
                                          guard: &hir::Expr) {
-    InferCtxt::enter(cx.tcx, None, Some(cx.param_env.clone()),
-                     ProjectionMode::AnyFinal, |infcx| {
+    cx.tcx.infer_ctxt(None, Some(cx.param_env.clone()),
+                      ProjectionMode::AnyFinal).enter(|infcx| {
         let mut checker = MutationChecker {
             cx: cx,
         };
@@ -1160,11 +1159,11 @@ fn check_for_mutation_in_guard<'a, 'tcx>(cx: &'a MatchCheckCtxt<'a, 'tcx>,
     });
 }
 
-struct MutationChecker<'a, 'tcx: 'a> {
-    cx: &'a MatchCheckCtxt<'a, 'tcx>,
+struct MutationChecker<'a, 'gcx: 'a> {
+    cx: &'a MatchCheckCtxt<'a, 'gcx>,
 }
 
-impl<'a, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'tcx> {
+impl<'a, 'gcx, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'gcx> {
     fn matched_pat(&mut self, _: &Pat, _: cmt, _: euv::MatchMode) {}
     fn consume(&mut self, _: 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 22ffebc081b..9db24fa4770 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -19,7 +19,6 @@ use rustc::hir::map as ast_map;
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::middle::cstore::{self, InlinedItem};
 use rustc::traits;
-use rustc::infer::InferCtxt;
 use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
 use rustc::hir::pat_util::def_to_path;
@@ -1014,7 +1013,7 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
            trait_ref);
 
     tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id());
-    InferCtxt::enter(tcx, None, None, ProjectionMode::AnyFinal, |infcx| {
+    tcx.infer_ctxt(None, None, ProjectionMode::AnyFinal).enter(|infcx| {
         let mut selcx = traits::SelectionContext::new(&infcx);
         let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
                                                  trait_ref.to_poly_trait_predicate());
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index fc44f808e4b..9bbf250b971 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -42,8 +42,8 @@ use syntax::feature_gate::UnstableFeatures;
 
 use rustc::hir;
 
-struct Env<'a, 'tcx: 'a> {
-    infcx: &'a infer::InferCtxt<'a, 'tcx, 'tcx>,
+struct Env<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+    infcx: &'a infer::InferCtxt<'a, 'gcx, 'tcx>,
 }
 
 struct RH<'a> {
@@ -149,7 +149,7 @@ fn test_env<F>(source_string: &str,
                              index,
                              "test_crate",
                              |tcx| {
-        InferCtxt::enter(tcx, None, None, ProjectionMode::AnyFinal, |infcx| {
+        tcx.infer_ctxt(None, None, ProjectionMode::AnyFinal).enter(|infcx| {
 
             body(Env { infcx: &infcx });
             let free_regions = FreeRegionMap::new();
@@ -159,8 +159,8 @@ fn test_env<F>(source_string: &str,
     });
 }
 
-impl<'a, 'tcx> Env<'a, 'tcx> {
-    pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
+    pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
         self.infcx.tcx
     }
 
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 13cfa2a604d..d1eba5b3f4a 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -32,7 +32,6 @@ use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
 use middle::stability;
 use rustc::cfg;
-use rustc::infer::InferCtxt;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::adjustment;
@@ -866,7 +865,7 @@ impl LateLintPass for UnconditionalRecursion {
                     let node_id = tcx.map.as_local_node_id(method.def_id).unwrap();
 
                     let param_env = Some(ty::ParameterEnvironment::for_item(tcx, node_id));
-                    InferCtxt::enter(tcx, None, param_env, ProjectionMode::AnyFinal, |infcx| {
+                    tcx.infer_ctxt(None, param_env, ProjectionMode::AnyFinal).enter(|infcx| {
                         let mut selcx = traits::SelectionContext::new(&infcx);
                         match selcx.select(&obligation) {
                             // The method comes from a `T: Trait` bound.
diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs
index 3bfea614919..c1626b93f0c 100644
--- a/src/librustc_mir/build/block.rs
+++ b/src/librustc_mir/build/block.rs
@@ -13,7 +13,7 @@ use hair::*;
 use rustc::mir::repr::*;
 use rustc::hir;
 
-impl<'a,'tcx> Builder<'a,'tcx> {
+impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     pub fn ast_block(&mut self,
                      destination: &Lvalue<'tcx>,
                      // FIXME(#32959): temporary measure for the issue
diff --git a/src/librustc_mir/build/expr/as_constant.rs b/src/librustc_mir/build/expr/as_constant.rs
index d97245a5fc2..a08d14d9e20 100644
--- a/src/librustc_mir/build/expr/as_constant.rs
+++ b/src/librustc_mir/build/expr/as_constant.rs
@@ -14,7 +14,7 @@ use build::Builder;
 use hair::*;
 use rustc::mir::repr::*;
 
-impl<'a,'tcx> Builder<'a,'tcx> {
+impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// Compile `expr`, yielding a compile-time constant. Assumes that
     /// `expr` is a valid compile-time constant!
     pub fn as_constant<M>(&mut self, expr: M) -> Constant<'tcx>
diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs
index 0c9323f4af3..15ea3f0e6e8 100644
--- a/src/librustc_mir/build/expr/as_lvalue.rs
+++ b/src/librustc_mir/build/expr/as_lvalue.rs
@@ -15,7 +15,7 @@ use build::expr::category::Category;
 use hair::*;
 use rustc::mir::repr::*;
 
-impl<'a,'tcx> Builder<'a,'tcx> {
+impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// Compile `expr`, yielding an lvalue that we can move from etc.
     pub fn as_lvalue<M>(&mut self,
                         block: BasicBlock,
diff --git a/src/librustc_mir/build/expr/as_operand.rs b/src/librustc_mir/build/expr/as_operand.rs
index 661d01ce989..a059f2bdde9 100644
--- a/src/librustc_mir/build/expr/as_operand.rs
+++ b/src/librustc_mir/build/expr/as_operand.rs
@@ -15,7 +15,7 @@ use build::expr::category::Category;
 use hair::*;
 use rustc::mir::repr::*;
 
-impl<'a,'tcx> Builder<'a,'tcx> {
+impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// Compile `expr` into a value that can be used as an operand.
     /// If `expr` is an lvalue like `x`, this will introduce a
     /// temporary `tmp = x`, so that we capture the value of `x` at
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 88757c6873c..2a733462408 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -17,7 +17,7 @@ use build::expr::category::{Category, RvalueFunc};
 use hair::*;
 use rustc::mir::repr::*;
 
-impl<'a,'tcx> Builder<'a,'tcx> {
+impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// Compile `expr`, yielding an rvalue.
     pub fn as_rvalue<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Rvalue<'tcx>>
         where M: Mirror<'tcx, Output = Expr<'tcx>>
diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs
index a4f4e44b1b1..38d32ec6777 100644
--- a/src/librustc_mir/build/expr/as_temp.rs
+++ b/src/librustc_mir/build/expr/as_temp.rs
@@ -15,7 +15,7 @@ use build::expr::category::Category;
 use hair::*;
 use rustc::mir::repr::*;
 
-impl<'a,'tcx> Builder<'a,'tcx> {
+impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// Compile `expr` into a fresh temporary. This is used when building
     /// up rvalues so as to freeze the value that will be consumed.
     pub fn as_temp<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Lvalue<'tcx>>
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index efffde91910..41610c90377 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -16,7 +16,7 @@ use hair::*;
 use rustc::ty;
 use rustc::mir::repr::*;
 
-impl<'a,'tcx> Builder<'a,'tcx> {
+impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// Compile `expr`, storing the result into `destination`, which
     /// is assumed to be uninitialized.
     pub fn into_expr(&mut self,
diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs
index 3c1672b9197..9629396f48b 100644
--- a/src/librustc_mir/build/expr/stmt.rs
+++ b/src/librustc_mir/build/expr/stmt.rs
@@ -15,7 +15,7 @@ use rustc::middle::region::CodeExtent;
 use rustc::mir::repr::*;
 use syntax::codemap::Span;
 
-impl<'a,'tcx> Builder<'a,'tcx> {
+impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
     pub fn stmt_expr(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd<()> {
         let this = self;
diff --git a/src/librustc_mir/build/into.rs b/src/librustc_mir/build/into.rs
index 77d9d926328..17ccb701c2b 100644
--- a/src/librustc_mir/build/into.rs
+++ b/src/librustc_mir/build/into.rs
@@ -19,14 +19,14 @@ use hair::*;
 use rustc::mir::repr::*;
 
 pub trait EvalInto<'tcx> {
-    fn eval_into<'a>(self,
-                     builder: &mut Builder<'a, 'tcx>,
-                     destination: &Lvalue<'tcx>,
-                     block: BasicBlock)
-                     -> BlockAnd<()>;
+    fn eval_into<'a, 'gcx>(self,
+                           builder: &mut Builder<'a, 'gcx, 'tcx>,
+                           destination: &Lvalue<'tcx>,
+                           block: BasicBlock)
+                           -> BlockAnd<()>;
 }
 
-impl<'a,'tcx> Builder<'a,'tcx> {
+impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     pub fn into<E>(&mut self,
                    destination: &Lvalue<'tcx>,
                    block: BasicBlock,
@@ -39,22 +39,22 @@ impl<'a,'tcx> Builder<'a,'tcx> {
 }
 
 impl<'tcx> EvalInto<'tcx> for ExprRef<'tcx> {
-    fn eval_into<'a>(self,
-                     builder: &mut Builder<'a, 'tcx>,
-                     destination: &Lvalue<'tcx>,
-                     block: BasicBlock)
-                     -> BlockAnd<()> {
+    fn eval_into<'a, 'gcx>(self,
+                           builder: &mut Builder<'a, 'gcx, 'tcx>,
+                           destination: &Lvalue<'tcx>,
+                           block: BasicBlock)
+                           -> BlockAnd<()> {
         let expr = builder.hir.mirror(self);
         builder.into_expr(destination, block, expr)
     }
 }
 
 impl<'tcx> EvalInto<'tcx> for Expr<'tcx> {
-    fn eval_into<'a>(self,
-                     builder: &mut Builder<'a, 'tcx>,
-                     destination: &Lvalue<'tcx>,
-                     block: BasicBlock)
-                     -> BlockAnd<()> {
+    fn eval_into<'a, 'gcx>(self,
+                           builder: &mut Builder<'a, 'gcx, 'tcx>,
+                           destination: &Lvalue<'tcx>,
+                           block: BasicBlock)
+                           -> BlockAnd<()> {
         builder.into_expr(destination, block, self)
     }
 }
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 080183ae1da..c1a0e1f9a69 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -27,7 +27,7 @@ mod simplify;
 mod test;
 mod util;
 
-impl<'a,'tcx> Builder<'a,'tcx> {
+impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     pub fn match_expr(&mut self,
                       destination: &Lvalue<'tcx>,
                       span: Span,
@@ -304,7 +304,7 @@ pub struct Test<'tcx> {
 ///////////////////////////////////////////////////////////////////////////
 // Main matching algorithm
 
-impl<'a,'tcx> Builder<'a,'tcx> {
+impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// The main match algorithm. It begins with a set of candidates
     /// `candidates` and has the job of generating code to determine
     /// which of these candidates, if any, is the correct one. The
diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs
index a3337badf88..c707bb8a27b 100644
--- a/src/librustc_mir/build/matches/simplify.rs
+++ b/src/librustc_mir/build/matches/simplify.rs
@@ -29,7 +29,7 @@ use rustc::mir::repr::*;
 
 use std::mem;
 
-impl<'a,'tcx> Builder<'a,'tcx> {
+impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     pub fn simplify_candidate<'pat>(&mut self,
                                     mut block: BasicBlock,
                                     candidate: &mut Candidate<'pat, 'tcx>)
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index f70d4321a49..e53584a3f8b 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -24,7 +24,7 @@ use rustc::ty::{self, Ty};
 use rustc::mir::repr::*;
 use syntax::codemap::Span;
 
-impl<'a,'tcx> Builder<'a,'tcx> {
+impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// Identifies what test is needed to decide if `match_pair` is applicable.
     ///
     /// It is a bug to call this with a simplifyable pattern.
diff --git a/src/librustc_mir/build/matches/util.rs b/src/librustc_mir/build/matches/util.rs
index e5f2c754378..5eb58f7612d 100644
--- a/src/librustc_mir/build/matches/util.rs
+++ b/src/librustc_mir/build/matches/util.rs
@@ -14,7 +14,7 @@ use hair::*;
 use rustc::mir::repr::*;
 use std::u32;
 
-impl<'a,'tcx> Builder<'a,'tcx> {
+impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     pub fn field_match_pairs<'pat>(&mut self,
                                    lvalue: Lvalue<'tcx>,
                                    subpatterns: &'pat [FieldPattern<'tcx>])
diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs
index 5daaf37d878..7317c6f9b31 100644
--- a/src/librustc_mir/build/misc.rs
+++ b/src/librustc_mir/build/misc.rs
@@ -17,7 +17,7 @@ use rustc::mir::repr::*;
 use std::u32;
 use syntax::codemap::Span;
 
-impl<'a,'tcx> Builder<'a,'tcx> {
+impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// Add a new temporary value of type `ty` storing the result of
     /// evaluating `expr`.
     ///
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index ac64d1eb65b..77499a0f96c 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -21,8 +21,8 @@ use syntax::ast;
 use syntax::codemap::Span;
 use syntax::parse::token::keywords;
 
-pub struct Builder<'a, 'tcx: 'a> {
-    hir: Cx<'a, 'tcx, 'tcx>,
+pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+    hir: Cx<'a, 'gcx, 'tcx>,
     cfg: CFG<'tcx>,
 
     fn_span: Span,
@@ -160,13 +160,13 @@ macro_rules! unpack {
 ///////////////////////////////////////////////////////////////////////////
 /// the main entry point for building MIR for a function
 
-pub fn construct_fn<'a, 'tcx, A>(hir: Cx<'a, 'tcx, 'tcx>,
-                                 fn_id: ast::NodeId,
-                                 arguments: A,
-                                 return_ty: ty::FnOutput<'tcx>,
-                                 ast_block: &'tcx hir::Block)
-                                 -> (Mir<'tcx>, ScopeAuxiliaryVec)
-    where A: Iterator<Item=(Ty<'tcx>, Option<&'tcx hir::Pat>)>
+pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
+                                       fn_id: ast::NodeId,
+                                       arguments: A,
+                                       return_ty: ty::FnOutput<'gcx>,
+                                       ast_block: &'gcx hir::Block)
+                                       -> (Mir<'tcx>, ScopeAuxiliaryVec)
+    where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
 {
     let tcx = hir.tcx();
     let span = tcx.map.span(fn_id);
@@ -232,10 +232,10 @@ pub fn construct_fn<'a, 'tcx, A>(hir: Cx<'a, 'tcx, 'tcx>,
     builder.finish(upvar_decls, arg_decls, return_ty)
 }
 
-pub fn construct_const<'a, 'tcx>(hir: Cx<'a, 'tcx, 'tcx>,
-                                 item_id: ast::NodeId,
-                                 ast_expr: &'tcx hir::Expr)
-                                 -> (Mir<'tcx>, ScopeAuxiliaryVec) {
+pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
+                                       item_id: ast::NodeId,
+                                       ast_expr: &'tcx hir::Expr)
+                                       -> (Mir<'tcx>, ScopeAuxiliaryVec) {
     let tcx = hir.tcx();
     let span = tcx.map.span(item_id);
     let mut builder = Builder::new(hir, span);
@@ -259,8 +259,8 @@ pub fn construct_const<'a, 'tcx>(hir: Cx<'a, 'tcx, 'tcx>,
     builder.finish(vec![], vec![], ty::FnConverging(ty))
 }
 
-impl<'a,'tcx> Builder<'a,'tcx> {
-    fn new(hir: Cx<'a, 'tcx, 'tcx>, span: Span) -> Builder<'a, 'tcx> {
+impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
+    fn new(hir: Cx<'a, 'gcx, 'tcx>, span: Span) -> Builder<'a, 'gcx, 'tcx> {
         let mut builder = Builder {
             hir: hir,
             cfg: CFG { basic_blocks: vec![] },
@@ -311,9 +311,9 @@ impl<'a,'tcx> Builder<'a,'tcx> {
                         return_ty: ty::FnOutput<'tcx>,
                         arguments: A,
                         argument_scope_id: ScopeId,
-                        ast_block: &'tcx hir::Block)
+                        ast_block: &'gcx hir::Block)
                         -> BlockAnd<Vec<ArgDecl<'tcx>>>
-        where A: Iterator<Item=(Ty<'tcx>, Option<&'tcx hir::Pat>)>
+        where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
     {
         // to start, translate the argument patterns and collect the argument types.
         let arg_decls = arguments.enumerate().map(|(index, (ty, pattern))| {
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index d07a58b981b..071c8d618c8 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -206,7 +206,7 @@ impl<'tcx> Scope<'tcx> {
     }
 }
 
-impl<'a,'tcx> Builder<'a,'tcx> {
+impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     // Adding and removing scopes
     // ==========================
     /// Start a loop scope, which tracks where `continue` and `break`
@@ -218,7 +218,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
                                break_block: BasicBlock,
                                f: F)
                                -> bool
-        where F: FnOnce(&mut Builder<'a, 'tcx>)
+        where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>)
     {
         let extent = self.extent_of_innermost_scope();
         let loop_scope = LoopScope {
@@ -237,7 +237,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
     /// Convenience wrapper that pushes a scope and then executes `f`
     /// to build its contents, popping the scope afterwards.
     pub fn in_scope<F, R>(&mut self, extent: CodeExtent, mut block: BasicBlock, f: F) -> BlockAnd<R>
-        where F: FnOnce(&mut Builder<'a, 'tcx>, ScopeId) -> BlockAnd<R>
+        where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>, ScopeId) -> BlockAnd<R>
     {
         debug!("in_scope(extent={:?}, block={:?})", extent, block);
         let id = self.push_scope(extent, block);
@@ -662,12 +662,12 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
     block.unit()
 }
 
-fn build_diverge_scope<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                 cfg: &mut CFG<'tcx>,
-                                 unit_temp: &Lvalue<'tcx>,
-                                 scope: &mut Scope<'tcx>,
-                                 mut target: BasicBlock)
-                                 -> BasicBlock
+fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                                       cfg: &mut CFG<'tcx>,
+                                       unit_temp: &Lvalue<'tcx>,
+                                       scope: &mut Scope<'tcx>,
+                                       mut target: BasicBlock)
+                                       -> BasicBlock
 {
     // Build up the drops in **reverse** order. The end result will
     // look like:
@@ -721,11 +721,11 @@ fn build_diverge_scope<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     target
 }
 
-fn build_free<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                        unit_temp: &Lvalue<'tcx>,
-                        data: &FreeData<'tcx>,
-                        target: BasicBlock)
-                        -> TerminatorKind<'tcx> {
+fn build_free<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                              unit_temp: &Lvalue<'tcx>,
+                              data: &FreeData<'tcx>,
+                              target: BasicBlock)
+                              -> TerminatorKind<'tcx> {
     let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem)
                        .unwrap_or_else(|e| tcx.sess.fatal(&e));
     let substs = tcx.mk_substs(Substs::new(
diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs
index fd568aebea4..52d54f2cc85 100644
--- a/src/librustc_mir/hair/cx/block.rs
+++ b/src/librustc_mir/hair/cx/block.rs
@@ -18,7 +18,7 @@ use syntax::ast;
 impl<'tcx> Mirror<'tcx> for &'tcx hir::Block {
     type Output = Block<'tcx>;
 
-    fn make_mirror<'a>(self, cx: &mut Cx<'a, 'tcx, 'tcx>) -> Block<'tcx> {
+    fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Block<'tcx> {
         // We have to eagerly translate the "spine" of the statements
         // in order to get the lexical scoping correctly.
         let stmts = mirror_stmts(cx, self.id, &*self.stmts);
@@ -31,10 +31,10 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Block {
     }
 }
 
-fn mirror_stmts<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
-                          block_id: ast::NodeId,
-                          stmts: &'tcx [hir::Stmt])
-                          -> Vec<StmtRef<'tcx>>
+fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
+                                block_id: ast::NodeId,
+                                stmts: &'tcx [hir::Stmt])
+                                -> Vec<StmtRef<'tcx>>
 {
     let mut result = vec![];
     for (index, stmt) in stmts.iter().enumerate() {
@@ -74,9 +74,9 @@ fn mirror_stmts<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
     return result;
 }
 
-pub fn to_expr_ref<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
-                             block: &'tcx hir::Block)
-                             -> ExprRef<'tcx> {
+pub fn to_expr_ref<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
+                                   block: &'tcx hir::Block)
+                                   -> ExprRef<'tcx> {
     let block_ty = cx.tcx.node_id_to_type(block.id);
     let temp_lifetime = cx.tcx.region_maps.temporary_scope(block.id);
     let expr = Expr {
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 39e9ace5432..1e7164a62c0 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -29,7 +29,7 @@ use syntax::ptr::P;
 impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
     type Output = Expr<'tcx>;
 
-    fn make_mirror<'a>(self, cx: &mut Cx<'a, 'tcx, 'tcx>) -> Expr<'tcx> {
+    fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> {
         let temp_lifetime = cx.tcx.region_maps.temporary_scope(self.id);
         let expr_extent = cx.tcx.region_maps.node_extent(self.id);
 
@@ -202,9 +202,9 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
     }
 }
 
-fn make_mirror_unadjusted<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
-                                    expr: &'tcx hir::Expr)
-                                    -> Expr<'tcx> {
+fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
+                                          expr: &'tcx hir::Expr)
+                                          -> Expr<'tcx> {
     let expr_ty = cx.tcx.expr_ty(expr);
     let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
 
@@ -545,7 +545,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
             count: TypedConstVal {
                 ty: cx.tcx.expr_ty(c),
                 span: c.span,
-                value: match const_eval::eval_const_expr(cx.tcx, c) {
+                value: match const_eval::eval_const_expr(cx.tcx.global_tcx(), c) {
                     ConstVal::Integral(ConstInt::Usize(u)) => u,
                     other => bug!("constant evaluation of repeat count yielded {:?}", other),
                 },
@@ -622,10 +622,10 @@ fn make_mirror_unadjusted<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
     }
 }
 
-fn method_callee<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
-                           expr: &hir::Expr,
-                           method_call: ty::MethodCall)
-                           -> Expr<'tcx> {
+fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
+                                 expr: &hir::Expr,
+                                 method_call: ty::MethodCall)
+                                 -> Expr<'tcx> {
     let tables = cx.tcx.tables.borrow();
     let callee = &tables.method_map[&method_call];
     let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
@@ -649,8 +649,8 @@ fn to_borrow_kind(m: hir::Mutability) -> BorrowKind {
     }
 }
 
-fn convert_arm<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
-                         arm: &'tcx hir::Arm) -> Arm<'tcx> {
+fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
+                               arm: &'tcx hir::Arm) -> Arm<'tcx> {
     let mut map;
     let opt_map = if arm.pats.len() == 1 {
         None
@@ -669,9 +669,9 @@ fn convert_arm<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
     }
 }
 
-fn convert_path_expr<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
-                               expr: &'tcx hir::Expr)
-                               -> ExprKind<'tcx> {
+fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
+                                     expr: &'tcx hir::Expr)
+                                     -> ExprKind<'tcx> {
     let substs = cx.tcx.node_id_item_substs(expr.id).substs;
     // Otherwise there may be def_map borrow conflicts
     let def = cx.tcx.def_map.borrow()[&expr.id].full_def();
@@ -714,7 +714,8 @@ fn convert_path_expr<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
         Def::Const(def_id) |
         Def::AssociatedConst(def_id) => {
             let substs = Some(cx.tcx.node_id_item_substs(expr.id).substs);
-            if let Some((e, _)) = const_eval::lookup_const_by_id(cx.tcx, def_id, substs) {
+            let tcx = cx.tcx.global_tcx();
+            if let Some((e, _)) = const_eval::lookup_const_by_id(tcx, def_id, substs) {
                 // FIXME ConstVal can't be yet used with adjustments, as they would be lost.
                 if !cx.tcx.tables.borrow().adjustments.contains_key(&e.id) {
                     if let Some(v) = cx.try_const_eval_literal(e) {
@@ -743,10 +744,10 @@ fn convert_path_expr<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
     }
 }
 
-fn convert_var<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
-                         expr: &'tcx hir::Expr,
-                         def: Def)
-                         -> ExprKind<'tcx> {
+fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
+                               expr: &'tcx hir::Expr,
+                               def: Def)
+                               -> ExprKind<'tcx> {
     let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
 
     match def {
@@ -908,13 +909,13 @@ enum PassArgs {
     ByRef,
 }
 
-fn overloaded_operator<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
-                                 expr: &'tcx hir::Expr,
-                                 method_call: ty::MethodCall,
-                                 pass_args: PassArgs,
-                                 receiver: ExprRef<'tcx>,
-                                 args: Vec<&'tcx P<hir::Expr>>)
-                                 -> ExprKind<'tcx> {
+fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
+                                       expr: &'tcx hir::Expr,
+                                       method_call: ty::MethodCall,
+                                       pass_args: PassArgs,
+                                       receiver: ExprRef<'tcx>,
+                                       args: Vec<&'tcx P<hir::Expr>>)
+                                       -> ExprKind<'tcx> {
     // the receiver has all the adjustments that are needed, so we can
     // just push a reference to it
     let mut argrefs = vec![receiver];
@@ -959,13 +960,13 @@ fn overloaded_operator<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
     }
 }
 
-fn overloaded_lvalue<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
-                               expr: &'tcx hir::Expr,
-                               method_call: ty::MethodCall,
-                               pass_args: PassArgs,
-                               receiver: ExprRef<'tcx>,
-                               args: Vec<&'tcx P<hir::Expr>>)
-                               -> ExprKind<'tcx> {
+fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
+                                     expr: &'tcx hir::Expr,
+                                     method_call: ty::MethodCall,
+                                     pass_args: PassArgs,
+                                     receiver: ExprRef<'tcx>,
+                                     args: Vec<&'tcx P<hir::Expr>>)
+                                     -> ExprKind<'tcx> {
     // For an overloaded *x or x[y] expression of type T, the method
     // call returns an &T and we must add the deref so that the types
     // line up (this is because `*x` and `x[y]` represent lvalues):
@@ -994,11 +995,11 @@ fn overloaded_lvalue<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
     ExprKind::Deref { arg: ref_expr.to_ref() }
 }
 
-fn capture_freevar<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
-                             closure_expr: &'tcx hir::Expr,
-                             freevar: &hir::Freevar,
-                             freevar_ty: Ty<'tcx>)
-                             -> ExprRef<'tcx> {
+fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
+                                   closure_expr: &'tcx hir::Expr,
+                                   freevar: &hir::Freevar,
+                                   freevar_ty: Ty<'tcx>)
+                                   -> ExprRef<'tcx> {
     let id_var = freevar.def.var_id();
     let upvar_id = ty::UpvarId {
         var_id: id_var,
@@ -1035,8 +1036,8 @@ fn capture_freevar<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
     }
 }
 
-fn loop_label<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
-                        expr: &'tcx hir::Expr) -> CodeExtent {
+fn loop_label<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
+                              expr: &'tcx hir::Expr) -> CodeExtent {
     match cx.tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def()) {
         Some(Def::Label(loop_id)) => cx.tcx.region_maps.node_extent(loop_id),
         d => {
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 8f79b6e68ee..fad6cfb7ae1 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -35,10 +35,10 @@ pub struct Cx<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     constness: hir::Constness
 }
 
-impl<'a, 'tcx> Cx<'a, 'tcx, 'tcx> {
-    pub fn new(infcx: &'a InferCtxt<'a, 'tcx, 'tcx>,
+impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
+    pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
                constness: hir::Constness)
-               -> Cx<'a, 'tcx, 'tcx> {
+               -> Cx<'a, 'gcx, 'tcx> {
         Cx {
             tcx: infcx.tcx,
             infcx: infcx,
@@ -47,7 +47,7 @@ impl<'a, 'tcx> Cx<'a, 'tcx, 'tcx> {
     }
 }
 
-impl<'a, 'tcx: 'a> Cx<'a, 'tcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
     /// Normalizes `ast` into the appropriate `mirror` type.
     pub fn mirror<M: Mirror<'tcx>>(&mut self, ast: M) -> M::Output {
         ast.make_mirror(self)
@@ -85,12 +85,15 @@ impl<'a, 'tcx: 'a> Cx<'a, 'tcx, 'tcx> {
     }
 
     pub fn const_eval_literal(&mut self, e: &hir::Expr) -> Literal<'tcx> {
-        Literal::Value { value: const_eval::eval_const_expr(self.tcx, e) }
+        Literal::Value {
+            value: const_eval::eval_const_expr(self.tcx.global_tcx(), e)
+        }
     }
 
     pub fn try_const_eval_literal(&mut self, e: &hir::Expr) -> Option<Literal<'tcx>> {
         let hint = const_eval::EvalHint::ExprTypeChecked;
-        const_eval::eval_const_expr_partial(self.tcx, e, hint, None).ok().and_then(|v| {
+        let tcx = self.tcx.global_tcx();
+        const_eval::eval_const_expr_partial(tcx, e, hint, None).ok().and_then(|v| {
             match v {
                 // All of these contain local IDs, unsuitable for storing in MIR.
                 ConstVal::Struct(_) | ConstVal::Tuple(_) |
@@ -130,21 +133,25 @@ impl<'a, 'tcx: 'a> Cx<'a, 'tcx, 'tcx> {
         bug!("found no method `{}` in `{:?}`", method_name, trait_def_id);
     }
 
-    pub fn num_variants(&mut self, adt_def: ty::AdtDef<'tcx>) -> usize {
+    pub fn num_variants(&mut self, adt_def: ty::AdtDef) -> usize {
         adt_def.variants.len()
     }
 
-    pub fn all_fields(&mut self, adt_def: ty::AdtDef<'tcx>, variant_index: usize) -> Vec<Field> {
+    pub fn all_fields(&mut self, adt_def: ty::AdtDef, variant_index: usize) -> Vec<Field> {
         (0..adt_def.variants[variant_index].fields.len())
             .map(Field::new)
             .collect()
     }
 
     pub fn needs_drop(&mut self, ty: Ty<'tcx>) -> bool {
+        let ty = self.tcx.lift_to_global(&ty).unwrap_or_else(|| {
+            bug!("MIR: Cx::needs_drop({}) got \
+                  type with inference types/regions", ty);
+        });
         self.tcx.type_needs_drop_given_env(ty, &self.infcx.parameter_environment)
     }
 
-    pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
+    pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
         self.tcx
     }
 }
diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs
index 3fbfead0c08..9e08e7b62d3 100644
--- a/src/librustc_mir/hair/cx/pattern.rs
+++ b/src/librustc_mir/hair/cx/pattern.rs
@@ -34,12 +34,12 @@ use syntax::ptr::P;
 ///    _ => { ... }
 /// }
 /// ```
-struct PatCx<'patcx, 'cx: 'patcx, 'tcx: 'cx> {
-    cx: &'patcx mut Cx<'cx, 'tcx, 'tcx>,
+struct PatCx<'patcx, 'cx: 'patcx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
+    cx: &'patcx mut Cx<'cx, 'gcx, 'tcx>,
     binding_map: Option<&'patcx FnvHashMap<ast::Name, ast::NodeId>>,
 }
 
-impl<'cx, 'tcx> Cx<'cx, 'tcx, 'tcx> {
+impl<'cx, 'gcx, 'tcx> Cx<'cx, 'gcx, 'tcx> {
     pub fn irrefutable_pat(&mut self, pat: &hir::Pat) -> Pattern<'tcx> {
         PatCx::new(self, None).to_pattern(pat)
     }
@@ -52,10 +52,10 @@ impl<'cx, 'tcx> Cx<'cx, 'tcx, 'tcx> {
     }
 }
 
-impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> {
-    fn new(cx: &'patcx mut Cx<'cx, 'tcx, 'tcx>,
+impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
+    fn new(cx: &'patcx mut Cx<'cx, 'gcx, 'tcx>,
                binding_map: Option<&'patcx FnvHashMap<ast::Name, ast::NodeId>>)
-               -> PatCx<'patcx, 'cx, 'tcx> {
+               -> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
         PatCx {
             cx: cx,
             binding_map: binding_map,
@@ -69,14 +69,14 @@ impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> {
             PatKind::Wild => PatternKind::Wild,
 
             PatKind::Lit(ref value) => {
-                let value = const_eval::eval_const_expr(self.cx.tcx, value);
+                let value = const_eval::eval_const_expr(self.cx.tcx.global_tcx(), value);
                 PatternKind::Constant { value: value }
             }
 
             PatKind::Range(ref lo, ref hi) => {
-                let lo = const_eval::eval_const_expr(self.cx.tcx, lo);
+                let lo = const_eval::eval_const_expr(self.cx.tcx.global_tcx(), lo);
                 let lo = Literal::Value { value: lo };
-                let hi = const_eval::eval_const_expr(self.cx.tcx, hi);
+                let hi = const_eval::eval_const_expr(self.cx.tcx.global_tcx(), hi);
                 let hi = Literal::Value { value: hi };
                 PatternKind::Range { lo: lo, hi: hi }
             },
@@ -87,10 +87,11 @@ impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> {
                 let def = self.cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
                 match def {
                     Def::Const(def_id) | Def::AssociatedConst(def_id) => {
+                        let tcx = self.cx.tcx.global_tcx();
                         let substs = Some(self.cx.tcx.node_id_item_substs(pat.id).substs);
-                        match const_eval::lookup_const_by_id(self.cx.tcx, def_id, substs) {
+                        match const_eval::lookup_const_by_id(tcx, def_id, substs) {
                             Some((const_expr, _const_ty)) => {
-                                match const_eval::const_expr_to_pat(self.cx.tcx,
+                                match const_eval::const_expr_to_pat(tcx,
                                                                     const_expr,
                                                                     pat.id,
                                                                     pat.span) {
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index 1cdf077ffac..020fbb6fcd1 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -358,13 +358,13 @@ pub struct FieldPattern<'tcx> {
 pub trait Mirror<'tcx> {
     type Output;
 
-    fn make_mirror<'a>(self, cx: &mut Cx<'a, 'tcx, 'tcx>) -> Self::Output;
+    fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Self::Output;
 }
 
 impl<'tcx> Mirror<'tcx> for Expr<'tcx> {
     type Output = Expr<'tcx>;
 
-    fn make_mirror<'a>(self, _: &mut Cx<'a, 'tcx, 'tcx>) -> Expr<'tcx> {
+    fn make_mirror<'a, 'gcx>(self, _: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> {
         self
     }
 }
@@ -372,7 +372,7 @@ impl<'tcx> Mirror<'tcx> for Expr<'tcx> {
 impl<'tcx> Mirror<'tcx> for ExprRef<'tcx> {
     type Output = Expr<'tcx>;
 
-    fn make_mirror<'a>(self, hir: &mut Cx<'a, 'tcx, 'tcx>) -> Expr<'tcx> {
+    fn make_mirror<'a, 'gcx>(self, hir: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> {
         match self {
             ExprRef::Hair(h) => h.make_mirror(hir),
             ExprRef::Mirror(m) => *m,
@@ -383,7 +383,7 @@ impl<'tcx> Mirror<'tcx> for ExprRef<'tcx> {
 impl<'tcx> Mirror<'tcx> for Stmt<'tcx> {
     type Output = Stmt<'tcx>;
 
-    fn make_mirror<'a>(self, _: &mut Cx<'a, 'tcx, 'tcx>) -> Stmt<'tcx> {
+    fn make_mirror<'a, 'gcx>(self, _: &mut Cx<'a, 'gcx, 'tcx>) -> Stmt<'tcx> {
         self
     }
 }
@@ -391,7 +391,7 @@ impl<'tcx> Mirror<'tcx> for Stmt<'tcx> {
 impl<'tcx> Mirror<'tcx> for StmtRef<'tcx> {
     type Output = Stmt<'tcx>;
 
-    fn make_mirror<'a>(self, _: &mut Cx<'a, 'tcx, 'tcx>) -> Stmt<'tcx> {
+    fn make_mirror<'a, 'gcx>(self, _: &mut Cx<'a, 'gcx, 'tcx>) -> Stmt<'tcx> {
         match self {
             StmtRef::Mirror(m) => *m,
         }
@@ -401,7 +401,7 @@ impl<'tcx> Mirror<'tcx> for StmtRef<'tcx> {
 impl<'tcx> Mirror<'tcx> for Block<'tcx> {
     type Output = Block<'tcx>;
 
-    fn make_mirror<'a>(self, _: &mut Cx<'a, 'tcx, 'tcx>) -> Block<'tcx> {
+    fn make_mirror<'a, 'gcx>(self, _: &mut Cx<'a, 'gcx, 'tcx>) -> Block<'tcx> {
         self
     }
 }
diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs
index 3874224e054..73cfdeda74a 100644
--- a/src/librustc_mir/mir_map.rs
+++ b/src/librustc_mir/mir_map.rs
@@ -20,13 +20,15 @@ use build;
 use rustc::dep_graph::DepNode;
 use rustc::mir::repr::Mir;
 use rustc::mir::transform::MirSource;
+use rustc::mir::visit::MutVisitor;
 use pretty;
 use hair::cx::Cx;
 
 use rustc::mir::mir_map::MirMap;
-use rustc::infer::InferCtxt;
+use rustc::infer::InferCtxtBuilder;
 use rustc::traits::ProjectionMode;
 use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::subst::Substs;
 use rustc::util::nodemap::NodeMap;
 use rustc::hir;
 use rustc::hir::intravisit::{self, FnKind, Visitor};
@@ -34,6 +36,8 @@ use rustc::hir::map::blocks::FnLikeNode;
 use syntax::ast;
 use syntax::codemap::Span;
 
+use std::mem;
+
 pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MirMap<'tcx> {
     let mut map = MirMap {
         map: NodeMap(),
@@ -48,6 +52,36 @@ pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MirMap<'tcx
     map
 }
 
+/// A pass to lift all the types and substitutions in a Mir
+/// to the global tcx. Sadly, we don't have a "folder" that
+/// can change 'tcx so we have to transmute afterwards.
+struct GlobalizeMir<'a, 'gcx: 'a> {
+    tcx: TyCtxt<'a, 'gcx, 'gcx>,
+    span: Span
+}
+
+impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> {
+    fn visit_ty(&mut self, ty: &mut Ty<'tcx>) {
+        if let Some(lifted) = self.tcx.lift(ty) {
+            *ty = lifted;
+        } else {
+            span_bug!(self.span,
+                      "found type `{:?}` with inference types/regions in MIR",
+                      ty);
+        }
+    }
+
+    fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>) {
+        if let Some(lifted) = self.tcx.lift(substs) {
+            *substs = lifted;
+        } else {
+            span_bug!(self.span,
+                      "found substs `{:?}` with inference types/regions in MIR",
+                      substs);
+        }
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // BuildMir -- walks a crate, looking for fn items and methods to build MIR from
 
@@ -56,36 +90,69 @@ struct BuildMir<'a, 'tcx: 'a> {
     map: &'a mut MirMap<'tcx>,
 }
 
-impl<'a, 'tcx> BuildMir<'a, 'tcx> {
-    fn build<F>(&mut self, src: MirSource, f: F)
-        where F: for<'b> FnOnce(Cx<'b, 'tcx, 'tcx>) -> (Mir<'tcx>, build::ScopeAuxiliaryVec)
+/// Helper type of a temporary returned by BuildMir::cx(...).
+/// Necessary because we can't write the following bound:
+/// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(Cx<'b, 'gcx, 'tcx>).
+struct CxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+    src: MirSource,
+    infcx: InferCtxtBuilder<'a, 'gcx, 'tcx>,
+    map: &'a mut MirMap<'gcx>,
+}
+
+impl<'a, 'gcx, 'tcx> BuildMir<'a, 'gcx> {
+    fn cx<'b>(&'b mut self, src: MirSource) -> CxBuilder<'b, 'gcx, 'tcx> {
+        let param_env = ty::ParameterEnvironment::for_item(self.tcx, src.item_id());
+        CxBuilder {
+            src: src,
+            infcx: self.tcx.infer_ctxt(None, Some(param_env), ProjectionMode::AnyFinal),
+            map: self.map
+        }
+    }
+}
+
+impl<'a, 'gcx, 'tcx> CxBuilder<'a, 'gcx, 'tcx> {
+    fn build<F>(&'tcx mut self, f: F)
+        where F: for<'b> FnOnce(Cx<'b, 'gcx, 'tcx>) -> (Mir<'tcx>, build::ScopeAuxiliaryVec)
     {
-        let constness = match src {
-            MirSource::Const(_) |
-            MirSource::Static(..) => hir::Constness::Const,
-            MirSource::Fn(id) => {
-                let fn_like = FnLikeNode::from_node(self.tcx.map.get(id));
-                match fn_like.map(|f| f.kind()) {
-                    Some(FnKind::ItemFn(_, _, _, c, _, _, _)) => c,
-                    Some(FnKind::Method(_, m, _, _)) => m.constness,
-                    _ => hir::Constness::NotConst
+        let src = self.src;
+        let mir = self.infcx.enter(|infcx| {
+            let constness = match src {
+                MirSource::Const(_) |
+                MirSource::Static(..) => hir::Constness::Const,
+                MirSource::Fn(id) => {
+                    let fn_like = FnLikeNode::from_node(infcx.tcx.map.get(id));
+                    match fn_like.map(|f| f.kind()) {
+                        Some(FnKind::ItemFn(_, _, _, c, _, _, _)) => c,
+                        Some(FnKind::Method(_, m, _, _)) => m.constness,
+                        _ => hir::Constness::NotConst
+                    }
                 }
-            }
-            MirSource::Promoted(..) => bug!()
-        };
+                MirSource::Promoted(..) => bug!()
+            };
+            let (mut mir, scope_auxiliary) = f(Cx::new(&infcx, constness));
+
+            // Convert the Mir to global types.
+            let mut globalizer = GlobalizeMir {
+                tcx: infcx.tcx.global_tcx(),
+                span: mir.span
+            };
+            globalizer.visit_mir(&mut mir);
+            let mir = unsafe {
+                mem::transmute::<Mir, Mir<'gcx>>(mir)
+            };
+
+            pretty::dump_mir(infcx.tcx.global_tcx(), "mir_map", &0,
+                             src, &mir, Some(&scope_auxiliary));
 
-        let param_env = ty::ParameterEnvironment::for_item(self.tcx, src.item_id());
-        let mir = InferCtxt::enter(self.tcx, None, Some(param_env),
-                                   ProjectionMode::AnyFinal, |infcx| {
-            let (mir, scope_auxiliary) = f(Cx::new(&infcx, constness));
-            pretty::dump_mir(self.tcx, "mir_map", &0, src, &mir, Some(&scope_auxiliary));
             mir
         });
 
         assert!(self.map.map.insert(src.item_id(), mir).is_none())
     }
+}
 
-    fn build_const_integer(&mut self, expr: &'tcx hir::Expr) {
+impl<'a, 'gcx> BuildMir<'a, 'gcx> {
+    fn build_const_integer(&mut self, expr: &'gcx hir::Expr) {
         // FIXME(eddyb) Closures should have separate
         // function definition IDs and expression IDs.
         // Type-checking should not let closures get
@@ -93,7 +160,7 @@ impl<'a, 'tcx> BuildMir<'a, 'tcx> {
         if let hir::ExprClosure(..) = expr.node {
             return;
         }
-        self.build(MirSource::Const(expr.id), |cx| {
+        self.cx(MirSource::Const(expr.id)).build(|cx| {
             build::construct_const(cx, expr.id, expr)
         });
     }
@@ -104,12 +171,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         match item.node {
             hir::ItemConst(_, ref expr) => {
-                self.build(MirSource::Const(item.id), |cx| {
+                self.cx(MirSource::Const(item.id)).build(|cx| {
                     build::construct_const(cx, item.id, expr)
                 });
             }
             hir::ItemStatic(_, m, ref expr) => {
-                self.build(MirSource::Static(item.id, m), |cx| {
+                self.cx(MirSource::Static(item.id, m)).build(|cx| {
                     build::construct_const(cx, item.id, expr)
                 });
             }
@@ -121,7 +188,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
     // Trait associated const defaults.
     fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
         if let hir::ConstTraitItem(_, Some(ref expr)) = item.node {
-            self.build(MirSource::Const(item.id), |cx| {
+            self.cx(MirSource::Const(item.id)).build(|cx| {
                 build::construct_const(cx, item.id, expr)
             });
         }
@@ -131,7 +198,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
     // Impl associated const.
     fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
         if let hir::ImplItemKind::Const(_, ref expr) = item.node {
-            self.build(MirSource::Const(item.id), |cx| {
+            self.cx(MirSource::Const(item.id)).build(|cx| {
                 build::construct_const(cx, item.id, expr)
             });
         }
@@ -192,8 +259,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
                     (fn_sig.inputs[index], Some(&*arg.pat))
                 });
 
-        self.build(MirSource::Fn(id), |cx| {
-            let arguments = implicit_argument.into_iter().chain(explicit_arguments);
+        let arguments = implicit_argument.into_iter().chain(explicit_arguments);
+        self.cx(MirSource::Fn(id)).build(|cx| {
             build::construct_fn(cx, id, arguments, fn_sig.output, body)
         });
 
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index eb7cc7559e6..54ac04bea9c 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -19,7 +19,6 @@ use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit::FnKind;
 use rustc::hir::map::blocks::FnLikeNode;
-use rustc::infer::InferCtxt;
 use rustc::traits::{self, ProjectionMode};
 use rustc::ty::{self, TyCtxt, Ty};
 use rustc::ty::cast::CastTy;
@@ -1019,7 +1018,7 @@ impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants {
             // Statics must be Sync.
             if mode == Mode::Static {
                 let ty = mir.return_ty.unwrap();
-                InferCtxt::enter(tcx, None, None, ProjectionMode::AnyFinal, |infcx| {
+                tcx.infer_ctxt(None, None, ProjectionMode::AnyFinal).enter(|infcx| {
                     let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic);
                     let mut fulfillment_cx = traits::FulfillmentContext::new();
                     fulfillment_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause);
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index 9ad06e85c4f..40157aa934c 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -61,7 +61,7 @@ struct TypeVerifier<'a, 'b: 'a, 'gcx: 'b+'tcx, 'tcx: 'b> {
     errors_reported: bool
 }
 
-impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx, 'tcx> {
+impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
     fn visit_span(&mut self, span: &Span) {
         if *span != DUMMY_SP {
             self.last_span = *span;
@@ -104,8 +104,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx, 'tcx> {
     }
 }
 
-impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx, 'tcx> {
-    fn new(cx: &'a mut TypeChecker<'b, 'tcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self {
+impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
+    fn new(cx: &'a mut TypeChecker<'b, 'gcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self {
         TypeVerifier {
             cx: cx,
             mir: mir,
@@ -114,11 +114,11 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx, 'tcx> {
         }
     }
 
-    fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
         self.cx.infcx.tcx
     }
 
-    fn infcx(&self) -> &'a InferCtxt<'a, 'tcx, 'tcx> {
+    fn infcx(&self) -> &'a InferCtxt<'a, 'gcx, 'tcx> {
         self.cx.infcx
     }
 
@@ -324,8 +324,8 @@ pub struct TypeChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     last_span: Span
 }
 
-impl<'a, 'tcx> TypeChecker<'a, 'tcx, 'tcx> {
-    fn new(infcx: &'a InferCtxt<'a, 'tcx, 'tcx>) -> Self {
+impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
+    fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> Self {
         TypeChecker {
             infcx: infcx,
             fulfillment_cx: traits::FulfillmentContext::new(),
@@ -349,7 +349,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx, 'tcx> {
             .map(|InferOk { obligations, .. }| assert!(obligations.is_empty()))
     }
 
-    fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
         self.infcx.tcx
     }
 
@@ -584,7 +584,7 @@ impl<'tcx> MirPass<'tcx> for TypeckMir {
             return;
         }
         let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id());
-        InferCtxt::enter(tcx, None, Some(param_env), ProjectionMode::AnyFinal, |infcx| {
+        tcx.infer_ctxt(None, Some(param_env), ProjectionMode::AnyFinal).enter(|infcx| {
             let mut checker = TypeChecker::new(&infcx);
             {
                 let mut verifier = TypeVerifier::new(&mut checker, mir);
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 80a4e421e34..b1bb48aacee 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -36,7 +36,6 @@ use rustc_const_math::{ConstMathErr, Op};
 use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
 use rustc::middle::expr_use_visitor as euv;
-use rustc::infer::InferCtxt;
 use rustc::middle::mem_categorization as mc;
 use rustc::middle::mem_categorization::Categorization;
 use rustc::ty::{self, Ty, TyCtxt};
@@ -74,9 +73,9 @@ struct CheckCrateVisitor<'a, 'tcx: 'a> {
     rvalue_borrows: NodeMap<hir::Mutability>
 }
 
-impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
+impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
     fn with_mode<F, R>(&mut self, mode: Mode, f: F) -> R where
-        F: FnOnce(&mut CheckCrateVisitor<'a, 'tcx>) -> R,
+        F: FnOnce(&mut CheckCrateVisitor<'a, 'gcx>) -> R,
     {
         let (old_mode, old_qualif) = (self.mode, self.qualif);
         self.mode = mode;
@@ -88,14 +87,14 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
     }
 
     fn with_euv<F, R>(&mut self, item_id: Option<ast::NodeId>, f: F) -> R where
-        F: for<'b> FnOnce(&mut euv::ExprUseVisitor<'b, 'tcx, 'tcx>) -> R,
+        F: for<'b, 'tcx> FnOnce(&mut euv::ExprUseVisitor<'b, 'gcx, 'tcx>) -> R,
     {
         let param_env = match item_id {
             Some(item_id) => ty::ParameterEnvironment::for_item(self.tcx, item_id),
             None => self.tcx.empty_parameter_environment()
         };
 
-        InferCtxt::enter(self.tcx, None, Some(param_env), ProjectionMode::AnyFinal, |infcx| {
+        self.tcx.infer_ctxt(None, Some(param_env), ProjectionMode::AnyFinal).enter(|infcx| {
             f(&mut euv::ExprUseVisitor::new(self, &infcx))
         })
     }
@@ -178,7 +177,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
     fn handle_const_fn_call(&mut self,
                             _expr: &hir::Expr,
                             def_id: DefId,
-                            ret_ty: Ty<'tcx>)
+                            ret_ty: Ty<'gcx>)
                             -> bool {
         if let Some(fn_like) = lookup_const_fn_by_id(self.tcx, def_id) {
             let qualif = self.fn_like(fn_like.kind(),
@@ -672,7 +671,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     tcx.sess.abort_if_errors();
 }
 
-impl<'a, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'tcx> {
+impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> {
     fn consume(&mut self,
                _consume_id: ast::NodeId,
                _consume_span: Span,
diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs
index 441154b7bf0..137a50642fc 100644
--- a/src/librustc_passes/rvalues.rs
+++ b/src/librustc_passes/rvalues.rs
@@ -13,7 +13,6 @@
 
 use rustc::dep_graph::DepNode;
 use rustc::middle::expr_use_visitor as euv;
-use rustc::infer::InferCtxt;
 use rustc::middle::mem_categorization as mc;
 use rustc::ty::{self, TyCtxt, ParameterEnvironment};
 use rustc::traits::ProjectionMode;
@@ -41,10 +40,10 @@ impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for RvalueContext<'a, 'tcx> {
                 fn_id: ast::NodeId) {
         // FIXME (@jroesch) change this to be an inference context
         let param_env = ParameterEnvironment::for_item(self.tcx, fn_id);
-        InferCtxt::enter(self.tcx, None, Some(param_env.clone()),
-                         ProjectionMode::AnyFinal, |infcx| {
+        self.tcx.infer_ctxt(None, Some(param_env.clone()),
+                            ProjectionMode::AnyFinal).enter(|infcx| {
             let mut delegate = RvalueContextDelegate {
-                tcx: self.tcx,
+                tcx: infcx.tcx,
                 param_env: &param_env
             };
             let mut euv = euv::ExprUseVisitor::new(&mut delegate, &infcx);
@@ -54,22 +53,23 @@ impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for RvalueContext<'a, 'tcx> {
     }
 }
 
-struct RvalueContextDelegate<'a, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    param_env: &'a ty::ParameterEnvironment<'tcx>,
+struct RvalueContextDelegate<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'gcx, 'tcx>,
+    param_env: &'a ty::ParameterEnvironment<'gcx>,
 }
 
-impl<'a, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'tcx> {
+impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'gcx, 'tcx> {
     fn consume(&mut self,
                _: ast::NodeId,
                span: Span,
                cmt: mc::cmt<'tcx>,
                _: euv::ConsumeMode) {
         debug!("consume; cmt: {:?}; type: {:?}", *cmt, cmt.ty);
-        if !cmt.ty.is_sized(self.tcx, self.param_env, span) {
+        let ty = self.tcx.lift_to_global(&cmt.ty).unwrap();
+        if !ty.is_sized(self.tcx.global_tcx(), self.param_env, span) {
             span_err!(self.tcx.sess, span, E0161,
                 "cannot move a value of type {0}: the size of {0} cannot be statically determined",
-                cmt.ty);
+                ty);
         }
     }
 
diff --git a/src/librustc_trans/_match.rs b/src/librustc_trans/_match.rs
index 4b656544bc4..6df308d5e62 100644
--- a/src/librustc_trans/_match.rs
+++ b/src/librustc_trans/_match.rs
@@ -194,7 +194,6 @@ use rustc_const_eval::{compare_lit_exprs, eval_const_expr};
 use rustc::hir::def::{Def, DefMap};
 use rustc::hir::def_id::DefId;
 use middle::expr_use_visitor as euv;
-use rustc::infer::InferCtxt;
 use middle::lang_items::StrEqFnLangItem;
 use middle::mem_categorization as mc;
 use middle::mem_categorization::Categorization;
@@ -1466,7 +1465,7 @@ fn is_discr_reassigned(bcx: Block, discr: &hir::Expr, body: &hir::Expr) -> bool
         field: field,
         reassigned: false
     };
-    InferCtxt::enter_normalizing(bcx.tcx(), ProjectionMode::Any, |infcx| {
+    bcx.tcx().normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
         let mut visitor = euv::ExprUseVisitor::new(&mut rc, &infcx);
         visitor.walk_expr(body);
     });
diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs
index 04f5e71497c..1c393f8091e 100644
--- a/src/librustc_trans/closure.rs
+++ b/src/librustc_trans/closure.rs
@@ -153,7 +153,7 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let symbol = symbol_names::exported_name(ccx, &instance);
 
     // Compute the rust-call form of the closure call method.
-    let sig = &ty::Tables::closure_type(&tcx.tables, tcx, closure_id, substs).sig;
+    let sig = &tcx.closure_type(closure_id, substs).sig;
     let sig = tcx.erase_late_bound_regions(sig);
     let sig = tcx.normalize_associated_type(&sig);
     let closure_type = tcx.mk_closure_from_closure_substs(closure_id, substs);
@@ -217,9 +217,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
     // this function (`trans_closure`) is invoked at the point
     // of the closure expression.
 
-    let sig = &ty::Tables::closure_type(&tcx.tables, tcx,
-                                        closure_def_id,
-                                        closure_substs).sig;
+    let sig = &tcx.closure_type(closure_def_id, closure_substs).sig;
     let sig = tcx.erase_late_bound_regions(sig);
     let sig = tcx.normalize_associated_type(&sig);
 
@@ -349,7 +347,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
 
     // Make a version with the type of by-ref closure.
     let ty::ClosureTy { unsafety, abi, mut sig } =
-        ty::Tables::closure_type(&tcx.tables, tcx, closure_def_id, substs);
+        tcx.closure_type(closure_def_id, substs);
     sig.0.inputs.insert(0, ref_closure_ty); // sig has no self type as of yet
     let llref_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
         unsafety: unsafety,
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index 05ed5abce14..dfab2bdbf64 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -530,7 +530,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
                 let exchange_malloc_fn_trans_item =
                     create_fn_trans_item(self.scx.tcx(),
                                          exchange_malloc_fn_def_id,
-                                         self.ccx.tcx().mk_substs(Substs::empty()),
+                                         self.scx.tcx().mk_substs(Substs::empty()),
                                          self.param_substs);
 
                 self.output.push(exchange_malloc_fn_trans_item);
@@ -670,8 +670,8 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
         let exchange_free_fn_trans_item =
             create_fn_trans_item(scx.tcx(),
                                  exchange_free_fn_def_id,
-                                 ccx.tcx().mk_substs(Substs::empty()),
-                                 ccx.tcx().mk_substs(Substs::empty()));
+                                 scx.tcx().mk_substs(Substs::empty()),
+                                 scx.tcx().mk_substs(Substs::empty()));
 
         output.push(exchange_free_fn_trans_item);
     }
@@ -709,7 +709,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
             let trans_item = create_fn_trans_item(scx.tcx(),
                                                   destructor_did,
                                                   substs,
-                                                  ccx.tcx().mk_substs(Substs::empty()));
+                                                  scx.tcx().mk_substs(Substs::empty()));
             output.push(trans_item);
         }
 
@@ -1014,7 +1014,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a,
                                 Some(create_fn_trans_item(scx.tcx(),
                                     impl_method.method.def_id,
                                     impl_method.substs,
-                                    ccx.tcx().mk_substs(Substs::empty())))
+                                    scx.tcx().mk_substs(Substs::empty())))
                             } else {
                                 None
                             }
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index f46ab825736..c1685e6a749 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -19,7 +19,7 @@ use llvm::{True, False, Bool, OperandBundleDef};
 use rustc::cfg;
 use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
-use rustc::infer::InferCtxt;
+use rustc::infer::TransNormalize;
 use rustc::util::common::MemoizationMap;
 use middle::lang_items::LangItem;
 use rustc::ty::subst::Substs;
@@ -428,7 +428,7 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
     }
 
     pub fn monomorphize<T>(&self, value: &T) -> T
-        where T : TypeFoldable<'tcx>
+        where T: TransNormalize<'tcx>
     {
         monomorphize::apply_param_substs(self.ccx.tcx(),
                                          self.param_substs,
@@ -603,7 +603,7 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> {
     }
 
     pub fn monomorphize<T>(&self, value: &T) -> T
-        where T : TypeFoldable<'tcx>
+        where T: TransNormalize<'tcx>
     {
         monomorphize::apply_param_substs(self.tcx(),
                                          self.fcx.param_substs,
@@ -710,7 +710,7 @@ impl<'blk, 'tcx> BlockAndBuilder<'blk, 'tcx> {
     }
 
     pub fn monomorphize<T>(&self, value: &T) -> T
-        where T: TypeFoldable<'tcx>
+        where T: TransNormalize<'tcx>
     {
         self.bcx.monomorphize(value)
     }
@@ -1066,7 +1066,7 @@ pub fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
 
         // Do the initial selection for the obligation. This yields the
         // shallow result we are looking for -- that is, what specific impl.
-        let vtable = InferCtxt::enter_normalizing(tcx, ProjectionMode::Any, |infcx| {
+        tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
             let mut selcx = SelectionContext::new(&infcx);
 
             let obligation_cause = traits::ObligationCause::misc(span,
@@ -1108,7 +1108,7 @@ pub fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
             info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
             vtable
         })
-    });
+    })
 }
 
 /// Normalizes the predicates and checks whether they hold.  If this
@@ -1122,7 +1122,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     debug!("normalize_and_test_predicates(predicates={:?})",
            predicates);
 
-    InferCtxt::enter_normalizing(tcx, ProjectionMode::Any, |infcx| {
+    tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
         let mut selcx = SelectionContext::new(&infcx);
         let mut fulfill_cx = traits::FulfillmentContext::new();
         let cause = traits::ObligationCause::dummy();
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index 4574c590a62..a29ff95851d 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -18,7 +18,6 @@ use back::symbol_names;
 use llvm;
 use llvm::{ValueRef, get_param};
 use middle::lang_items::ExchangeFreeFnLangItem;
-use rustc::infer::InferCtxt;
 use rustc::ty::subst::{Substs};
 use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt};
@@ -117,16 +116,15 @@ pub fn get_drop_glue_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     match t.sty {
         ty::TyBox(typ) if !type_needs_drop(tcx, typ)
                          && type_is_sized(tcx, typ) => {
-            let infcx = InferCtxt::normalizing(tcx,
-                                               &tcx.tables,
-                                               traits::ProjectionMode::Any);
-            let layout = t.layout(&infcx).unwrap();
-            if layout.size(&tcx.data_layout).bytes() == 0 {
-                // `Box<ZeroSizeType>` does not allocate.
-                tcx.types.i8
-            } else {
-                tcx.erase_regions(&t)
-            }
+            tcx.normalizing_infer_ctxt(traits::ProjectionMode::Any).enter(|infcx| {
+                let layout = t.layout(&infcx).unwrap();
+                if layout.size(&tcx.data_layout).bytes() == 0 {
+                    // `Box<ZeroSizeType>` does not allocate.
+                    tcx.types.i8
+                } else {
+                    tcx.erase_regions(&t)
+                }
+            })
         }
         _ => tcx.erase_regions(&t)
     }
diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs
index 1c559749a87..9b279a397f8 100644
--- a/src/librustc_trans/meth.rs
+++ b/src/librustc_trans/meth.rs
@@ -14,7 +14,6 @@ use arena::TypedArena;
 use back::symbol_names;
 use llvm::{ValueRef, get_params};
 use rustc::hir::def_id::DefId;
-use rustc::infer::InferCtxt;
 use rustc::ty::subst::{FnSpace, Subst, Substs};
 use rustc::ty::subst;
 use rustc::traits::{self, ProjectionMode};
@@ -317,8 +316,14 @@ pub fn get_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     match trait_def.ancestors(impl_def_id).fn_defs(tcx, name).next() {
         Some(node_item) => {
-            let substs = InferCtxt::enter_normalizing(tcx, ProjectionMode::Any, |infcx| {
-                traits::translate_substs(&infcx, impl_def_id, substs, node_item.node)
+            let substs = tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
+                let substs = traits::translate_substs(&infcx, impl_def_id,
+                                                      substs, node_item.node);
+                tcx.lift(&substs).unwrap_or_else(|| {
+                    bug!("trans::meth::get_impl_method: translate_substs \
+                          returned {:?} which contains inference types/regions",
+                         substs);
+                })
             });
             ImplMethod {
                 method: node_item.item,
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index c1be6daefd3..039304ece60 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -13,6 +13,7 @@ use rustc::middle::const_val::ConstVal;
 use rustc_const_eval::ErrKind;
 use rustc_const_math::ConstInt::*;
 use rustc::hir::def_id::DefId;
+use rustc::infer::TransNormalize;
 use rustc::mir::repr as mir;
 use rustc::mir::tcx::LvalueTy;
 use rustc::traits;
@@ -252,7 +253,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
     }
 
     fn monomorphize<T>(&self, value: &T) -> T
-        where T : TypeFoldable<'tcx>
+        where T: TransNormalize<'tcx>
     {
         monomorphize::apply_param_substs(self.ccx.tcx(),
                                          self.substs,
diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs
index 7c3feba5de7..8b1809e4023 100644
--- a/src/librustc_trans/monomorphize.rs
+++ b/src/librustc_trans/monomorphize.rs
@@ -12,6 +12,7 @@ use back::symbol_names;
 use llvm::ValueRef;
 use llvm;
 use rustc::hir::def_id::DefId;
+use rustc::infer::TransNormalize;
 use rustc::ty::subst;
 use rustc::ty::subst::{Subst, Substs};
 use rustc::ty::{self, Ty, TypeFoldable, TyCtxt};
@@ -193,7 +194,7 @@ pub fn apply_param_substs<'a, 'tcx, T>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                        param_substs: &Substs<'tcx>,
                                        value: &T)
                                        -> T
-    where T : TypeFoldable<'tcx>
+    where T: TransNormalize<'tcx>
 {
     let substituted = value.subst(tcx, param_substs);
     tcx.normalize_associated_type(&substituted)
diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs
index 9db7503b3ab..98ec87ebbcf 100644
--- a/src/librustc_trans/type_of.rs
+++ b/src/librustc_trans/type_of.rs
@@ -11,7 +11,6 @@
 #![allow(non_camel_case_types)]
 
 use rustc::hir::def_id::DefId;
-use rustc::infer::InferCtxt;
 use rustc::ty::subst;
 use abi::FnType;
 use adt;
@@ -124,7 +123,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
     cx.llsizingtypes().borrow_mut().insert(t, llsizingty);
 
     // FIXME(eddyb) Temporary sanity check for ty::layout.
-    let layout = InferCtxt::enter_normalizing(cx.tcx(), ProjectionMode::Any, |infcx| {
+    let layout = cx.tcx().normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
         t.layout(&infcx)
     });
     match layout {
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index fc02506b1cd..a1a6a83d34f 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use middle::free_region::FreeRegionMap;
-use rustc::infer::{self, InferCtxt, InferOk, TypeOrigin};
+use rustc::infer::{self, InferOk, TypeOrigin};
 use rustc::ty;
 use rustc::traits::{self, ProjectionMode};
 use rustc::ty::subst::{self, Subst, Substs, VecPerParamSpace};
@@ -196,27 +196,22 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         return;
     }
 
-    // Create obligations for each predicate declared by the impl
-    // definition in the context of the trait's parameter
-    // environment. We can't just use `impl_env.caller_bounds`,
-    // however, because we want to replace all late-bound regions with
-    // region variables.
-    let impl_bounds =
-        impl_m.predicates.instantiate(tcx, impl_to_skol_substs);
-
-    InferCtxt::enter(tcx, None, None, ProjectionMode::AnyFinal, |mut infcx| {
+    tcx.infer_ctxt(None, None, ProjectionMode::AnyFinal).enter(|mut infcx| {
         let mut fulfillment_cx = traits::FulfillmentContext::new();
-        let (impl_bounds, _) =
-            infcx.replace_late_bound_regions_with_fresh_var(
-                impl_m_span,
-                infer::HigherRankedType,
-                &ty::Binder(impl_bounds));
-        debug!("compare_impl_method: impl_bounds={:?}",
-               impl_bounds);
 
         // Normalize the associated types in the trait_bounds.
         let trait_bounds = trait_m.predicates.instantiate(tcx, &trait_to_skol_substs);
 
+        // Create obligations for each predicate declared by the impl
+        // definition in the context of the trait's parameter
+        // environment. We can't just use `impl_env.caller_bounds`,
+        // however, because we want to replace all late-bound regions with
+        // region variables.
+        let impl_bounds =
+            impl_m.predicates.instantiate(tcx, impl_to_skol_substs);
+
+        debug!("compare_impl_method: impl_bounds={:?}", impl_bounds);
+
         // Obtain the predicate split predicate sets for each.
         let trait_pred = trait_bounds.predicates.split();
         let impl_pred = impl_bounds.predicates.split();
@@ -250,7 +245,12 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
         let mut selcx = traits::SelectionContext::new(&infcx);
 
-        for predicate in impl_pred.fns {
+        let (impl_pred_fns, _) =
+            infcx.replace_late_bound_regions_with_fresh_var(
+                impl_m_span,
+                infer::HigherRankedType,
+                &ty::Binder(impl_pred.fns));
+        for predicate in impl_pred_fns {
             let traits::Normalized { value: predicate, .. } =
                 traits::normalize(&mut selcx, normalize_cause.clone(), &predicate);
 
@@ -285,6 +285,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs);
 
         let err = infcx.commit_if_ok(|snapshot| {
+            let tcx = infcx.tcx;
             let origin = TypeOrigin::MethodCompatCheck(impl_m_span);
 
             let (impl_sig, _) =
@@ -421,7 +422,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
            impl_trait_ref);
 
     let tcx = ccx.tcx;
-    InferCtxt::enter(tcx, None, None, ProjectionMode::AnyFinal, |infcx| {
+    tcx.infer_ctxt(None, None, ProjectionMode::AnyFinal).enter(|infcx| {
         let mut fulfillment_cx = traits::FulfillmentContext::new();
 
         // The below is for the most part highly similar to the procedure
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index 862dae4bb33..ae614d7b021 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -13,7 +13,7 @@ use check::regionck::RegionCtxt;
 
 use hir::def_id::DefId;
 use middle::free_region::FreeRegionMap;
-use rustc::infer::{self, InferCtxt};
+use rustc::infer;
 use middle::region;
 use rustc::ty::subst::{self, Subst};
 use rustc::ty::{self, Ty, TyCtxt};
@@ -84,7 +84,8 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
     // check that the impl type can be made to match the trait type.
 
     let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_node_id);
-    InferCtxt::enter(tcx, None, Some(impl_param_env), ProjectionMode::AnyFinal, |infcx| {
+    tcx.infer_ctxt(None, Some(impl_param_env), ProjectionMode::AnyFinal).enter(|infcx| {
+        let tcx = infcx.tcx;
         let mut fulfillment_cx = traits::FulfillmentContext::new();
 
         let named_type = tcx.lookup_item_type(self_type_did).ty;
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 9e771d95bbd..ad0ccdcf389 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -372,17 +372,32 @@ impl<'a, 'gcx, 'tcx> Deref for FnCtxt<'a, 'gcx, 'tcx> {
     }
 }
 
-impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
-    fn enter<F, R>(ccx: &'a CrateCtxt<'a, 'tcx>,
-                   param_env: ty::ParameterEnvironment<'tcx>,
-                   f: F) -> R
-        where F: for<'b> FnOnce(Inherited<'b, 'tcx, 'tcx>) -> R
+/// Helper type of a temporary returned by ccx.inherited(...).
+/// Necessary because we can't write the following bound:
+/// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(Inherited<'b, 'gcx, 'tcx>).
+pub struct InheritedBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+    ccx: &'a CrateCtxt<'a, 'gcx>,
+    infcx: infer::InferCtxtBuilder<'a, 'gcx, 'tcx>
+}
+
+impl<'a, 'gcx, 'tcx> CrateCtxt<'a, 'gcx> {
+    pub fn inherited(&'a self, param_env: Option<ty::ParameterEnvironment<'gcx>>)
+                     -> InheritedBuilder<'a, 'gcx, 'tcx> {
+        InheritedBuilder {
+            ccx: self,
+            infcx: self.tcx.infer_ctxt(Some(ty::Tables::empty()),
+                                       param_env,
+                                       ProjectionMode::AnyFinal)
+        }
+    }
+}
+
+impl<'a, 'gcx, 'tcx> InheritedBuilder<'a, 'gcx, 'tcx> {
+    fn enter<F, R>(&'tcx mut self, f: F) -> R
+        where F: for<'b> FnOnce(Inherited<'b, 'gcx, 'tcx>) -> R
     {
-        InferCtxt::enter(ccx.tcx,
-                         Some(ty::Tables::empty()),
-                         Some(param_env),
-                         ProjectionMode::AnyFinal,
-                         |infcx| {
+        let ccx = self.ccx;
+        self.infcx.enter(|infcx| {
             f(Inherited {
                 ccx: ccx,
                 infcx: infcx,
@@ -393,7 +408,9 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
             })
         })
     }
+}
 
+impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
     fn normalize_associated_types_in<T>(&self,
                                         span: Span,
                                         body_id: ast::NodeId,
@@ -491,7 +508,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         _ => span_bug!(body.span, "check_bare_fn: function type expected")
     };
 
-    Inherited::enter(ccx, param_env, |inh| {
+    ccx.inherited(Some(param_env)).enter(|inh| {
         // Compute the fty from point of view of inside fn.
         let fn_scope = inh.tcx.region_maps.call_site_extent(fn_id, body.id);
         let fn_sig =
@@ -1124,7 +1141,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 fn check_const_in_type<'a,'tcx>(ccx: &'a CrateCtxt<'a,'tcx>,
                                 expr: &'tcx hir::Expr,
                                 expected_type: Ty<'tcx>) {
-    Inherited::enter(ccx, ccx.tcx.empty_parameter_environment(), |inh| {
+    ccx.inherited(None).enter(|inh| {
         let fcx = FnCtxt::new(&inh, ty::FnConverging(expected_type), expr.id);
         fcx.check_const_with_ty(expr.span, expr, expected_type);
     });
@@ -1134,7 +1151,7 @@ fn check_const<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                         sp: Span,
                         e: &'tcx hir::Expr,
                         id: ast::NodeId) {
-    Inherited::enter(ccx, ccx.tcx.empty_parameter_environment(), |inh| {
+    ccx.inherited(None).enter(|inh| {
         let rty = ccx.tcx.node_id_to_type(id);
         let fcx = FnCtxt::new(&inh, ty::FnConverging(rty), e.id);
         let declty = fcx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(id)).ty;
@@ -1208,7 +1225,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
             "unsupported representation for zero-variant enum");
     }
 
-    Inherited::enter(ccx, ccx.tcx.empty_parameter_environment(), |inh| {
+    ccx.inherited(None).enter(|inh| {
         let rty = ccx.tcx.node_id_to_type(id);
         let fcx = FnCtxt::new(&inh, ty::FnConverging(rty), id);
 
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 7739bb6bb8f..bb63cf11d9a 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use check::{FnCtxt, Inherited};
+use check::FnCtxt;
 use constrained_type_params::{identify_constrained_type_params, Parameter};
 use CrateCtxt;
 use hir::def_id::DefId;
@@ -30,16 +30,46 @@ pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> {
     code: traits::ObligationCauseCode<'tcx>,
 }
 
-impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
-    pub fn new(ccx: &'ccx CrateCtxt<'ccx, 'tcx>)
-               -> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
+/// Helper type of a temporary returned by .for_item(...).
+/// Necessary because we can't write the following bound:
+/// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(FnCtxt<'b, 'gcx, 'tcx>).
+struct CheckWfFcxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+    inherited: super::InheritedBuilder<'a, 'gcx, 'tcx>,
+    code: traits::ObligationCauseCode<'gcx>,
+    id: ast::NodeId,
+    span: Span
+}
+
+impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
+    fn with_fcx<F>(&'tcx mut self, f: F) where
+        F: for<'b> FnOnce(&FnCtxt<'b, 'gcx, 'tcx>,
+                          &mut CheckTypeWellFormedVisitor<'b, 'gcx>) -> Vec<Ty<'tcx>>
+    {
+        let code = self.code.clone();
+        let id = self.id;
+        let span = self.span;
+        self.inherited.enter(|inh| {
+            let fcx = FnCtxt::new(&inh, ty::FnDiverging, id);
+            let wf_tys = f(&fcx, &mut CheckTypeWellFormedVisitor {
+                ccx: fcx.ccx,
+                code: code
+            });
+            fcx.select_all_obligations_or_error();
+            fcx.regionck_item(id, span, &wf_tys);
+        });
+    }
+}
+
+impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
+    pub fn new(ccx: &'ccx CrateCtxt<'ccx, 'gcx>)
+               -> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
         CheckTypeWellFormedVisitor {
             ccx: ccx,
             code: traits::ObligationCauseCode::MiscObligation
         }
     }
 
-    fn tcx(&self) -> TyCtxt<'ccx, 'tcx, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'ccx, 'gcx, 'gcx> {
         self.ccx.tcx
     }
 
@@ -128,7 +158,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
 
     fn check_trait_or_impl_item(&mut self, item_id: ast::NodeId, span: Span) {
         let code = self.code.clone();
-        self.with_fcx(item_id, span, |fcx, this| {
+        self.for_id(item_id, span).with_fcx(|fcx, this| {
             let free_substs = &fcx.parameter_environment.free_substs;
             let free_id_outlive = fcx.parameter_environment.free_id_outlive;
 
@@ -166,32 +196,28 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
         })
     }
 
-    fn with_item_fcx<F>(&mut self, item: &hir::Item, f: F) where
-        F: for<'fcx> FnMut(&FnCtxt<'fcx, 'tcx, 'tcx>,
-                           &mut CheckTypeWellFormedVisitor<'ccx,'tcx>) -> Vec<Ty<'tcx>>,
-    {
-        self.with_fcx(item.id, item.span, f)
+    fn for_item<'tcx>(&self, item: &hir::Item)
+                      -> CheckWfFcxBuilder<'ccx, 'gcx, 'tcx> {
+        self.for_id(item.id, item.span)
     }
 
-    fn with_fcx<F>(&mut self, id: ast::NodeId, span: Span, mut f: F) where
-        F: for<'fcx> FnMut(&FnCtxt<'fcx, 'tcx, 'tcx>,
-                           &mut CheckTypeWellFormedVisitor<'ccx,'tcx>) -> Vec<Ty<'tcx>>,
-    {
-        let ccx = self.ccx;
-        let param_env = ty::ParameterEnvironment::for_item(ccx.tcx, id);
-        Inherited::enter(ccx, param_env, |inh| {
-            let fcx = FnCtxt::new(&inh, ty::FnDiverging, id);
-            let wf_tys = f(&fcx, self);
-            fcx.select_all_obligations_or_error();
-            fcx.regionck_item(id, span, &wf_tys);
-        });
+    fn for_id<'tcx>(&self, id: ast::NodeId, span: Span)
+                    -> CheckWfFcxBuilder<'ccx, 'gcx, 'tcx> {
+        let param_env = ty::ParameterEnvironment::for_item(self.ccx.tcx, id);
+        CheckWfFcxBuilder {
+            inherited: self.ccx.inherited(Some(param_env)),
+            code: self.code.clone(),
+            id: id,
+            span: span
+        }
     }
 
     /// In a type definition, we check that to ensure that the types of the fields are well-formed.
     fn check_type_defn<F>(&mut self, item: &hir::Item, mut lookup_fields: F) where
-        F: for<'fcx> FnMut(&FnCtxt<'fcx, 'tcx, 'tcx>) -> Vec<AdtVariant<'tcx>>,
+        F: for<'fcx, 'tcx> FnMut(&FnCtxt<'fcx, 'gcx, 'tcx>)
+                                 -> Vec<AdtVariant<'tcx>>
     {
-        self.with_item_fcx(item, |fcx, this| {
+        self.for_item(item).with_fcx(|fcx, this| {
             let variants = lookup_fields(fcx);
 
             for variant in &variants {
@@ -234,7 +260,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
             }
         }
 
-        self.with_item_fcx(item, |fcx, this| {
+        self.for_item(item).with_fcx(|fcx, this| {
             let free_substs = &fcx.parameter_environment.free_substs;
             let predicates = fcx.tcx.lookup_predicates(trait_def_id);
             let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates);
@@ -247,7 +273,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
                      item: &hir::Item,
                      body: &hir::Block)
     {
-        self.with_item_fcx(item, |fcx, this| {
+        self.for_item(item).with_fcx(|fcx, this| {
             let free_substs = &fcx.parameter_environment.free_substs;
             let type_scheme = fcx.tcx.lookup_item_type(fcx.tcx.map.local_def_id(item.id));
             let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &type_scheme.ty);
@@ -274,7 +300,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
     {
         debug!("check_item_type: {:?}", item);
 
-        self.with_item_fcx(item, |fcx, this| {
+        self.for_item(item).with_fcx(|fcx, this| {
             let type_scheme = fcx.tcx.lookup_item_type(fcx.tcx.map.local_def_id(item.id));
             let item_ty = fcx.instantiate_type_scheme(item.span,
                                                       &fcx.parameter_environment
@@ -294,7 +320,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
     {
         debug!("check_impl: {:?}", item);
 
-        self.with_item_fcx(item, |fcx, this| {
+        self.for_item(item).with_fcx(|fcx, this| {
             let free_substs = &fcx.parameter_environment.free_substs;
             let item_def_id = fcx.tcx.map.local_def_id(item.id);
 
@@ -328,10 +354,10 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
         });
     }
 
-    fn check_where_clauses<'fcx>(&mut self,
-                                 fcx: &FnCtxt<'fcx,'tcx, 'tcx>,
-                                 span: Span,
-                                 predicates: &ty::InstantiatedPredicates<'tcx>)
+    fn check_where_clauses<'fcx, 'tcx>(&mut self,
+                                       fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
+                                       span: Span,
+                                       predicates: &ty::InstantiatedPredicates<'tcx>)
     {
         let obligations =
             predicates.predicates
@@ -346,13 +372,13 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
         }
     }
 
-    fn check_fn_or_method<'fcx>(&mut self,
-                                fcx: &FnCtxt<'fcx,'tcx, 'tcx>,
-                                span: Span,
-                                fty: &'tcx ty::BareFnTy<'tcx>,
-                                predicates: &ty::InstantiatedPredicates<'tcx>,
-                                free_id_outlive: CodeExtent,
-                                implied_bounds: &mut Vec<Ty<'tcx>>)
+    fn check_fn_or_method<'fcx, 'tcx>(&mut self,
+                                      fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
+                                      span: Span,
+                                      fty: &'tcx ty::BareFnTy<'tcx>,
+                                      predicates: &ty::InstantiatedPredicates<'tcx>,
+                                      free_id_outlive: CodeExtent,
+                                      implied_bounds: &mut Vec<Ty<'tcx>>)
     {
         let free_substs = &fcx.parameter_environment.free_substs;
         let fty = fcx.instantiate_type_scheme(span, free_substs, &fty);
@@ -376,12 +402,12 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
         self.check_where_clauses(fcx, span, predicates);
     }
 
-    fn check_method_receiver<'fcx>(&mut self,
-                                   fcx: &FnCtxt<'fcx,'tcx, 'tcx>,
-                                   span: Span,
-                                   method: &ty::Method<'tcx>,
-                                   free_id_outlive: CodeExtent,
-                                   self_ty: ty::Ty<'tcx>)
+    fn check_method_receiver<'fcx, 'tcx>(&mut self,
+                                         fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
+                                         span: Span,
+                                         method: &ty::Method<'tcx>,
+                                         free_id_outlive: CodeExtent,
+                                         self_ty: ty::Ty<'tcx>)
     {
         // check that the type of the method's receiver matches the
         // method's first parameter.
@@ -549,7 +575,7 @@ struct AdtField<'tcx> {
     span: Span,
 }
 
-impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 fn struct_variant(&self, struct_def: &hir::VariantData) -> AdtVariant<'tcx> {
     let fields =
         struct_def.fields().iter()
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 8c0e11780b2..33238f6cda7 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -56,7 +56,7 @@ struct CoherenceCheckVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     cc: &'a CoherenceChecker<'a, 'gcx, 'tcx>
 }
 
-impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for CoherenceCheckVisitor<'a, 'tcx, 'tcx> {
+impl<'a, 'gcx, 'tcx, 'v> intravisit::Visitor<'v> for CoherenceCheckVisitor<'a, 'gcx, 'tcx> {
     fn visit_item(&mut self, item: &Item) {
         if let ItemImpl(..) = item.node {
             self.cc.check_implementation(item)
@@ -64,7 +64,7 @@ impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for CoherenceCheckVisitor<'a, 'tcx, '
     }
 }
 
-impl<'a, 'tcx> CoherenceChecker<'a, 'tcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
 
 // Returns the def ID of the base type, if there is one.
 fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option<DefId> {
@@ -187,7 +187,7 @@ fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option<DefId> {
             Rc::new(RefCell::new(vec!(impl_def_id))));
     }
 
-    fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'tcx>, impl_def_id: DefId) {
+    fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'gcx>, impl_def_id: DefId) {
         debug!("add_trait_impl: impl_trait_ref={:?} impl_def_id={:?}",
                impl_trait_ref, impl_def_id);
         let trait_def = self.crate_context.tcx.lookup_trait_def(impl_trait_ref.def_id);
@@ -376,10 +376,10 @@ fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option<DefId> {
             debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (free)",
                    source, target);
 
-            InferCtxt::enter(tcx, None, Some(param_env), ProjectionMode::Topmost, |infcx| {
+            tcx.infer_ctxt(None, Some(param_env), ProjectionMode::Topmost).enter(|infcx| {
                 let origin = TypeOrigin::Misc(span);
-                let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, mt_b: ty::TypeAndMut<'tcx>,
-                                   mk_ptr: &Fn(Ty<'tcx>) -> Ty<'tcx>| {
+                let check_mutbl = |mt_a: ty::TypeAndMut<'gcx>, mt_b: ty::TypeAndMut<'gcx>,
+                                   mk_ptr: &Fn(Ty<'gcx>) -> Ty<'gcx>| {
                     if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) {
                         infcx.report_mismatched_types(origin, mk_ptr(mt_b.ty),
                                                       target, ty::error::TypeError::Mutability);
@@ -513,7 +513,7 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: Def
 
 pub fn check_coherence(ccx: &CrateCtxt) {
     let _task = ccx.tcx.dep_graph.in_task(DepNode::Coherence);
-    InferCtxt::enter(ccx.tcx, None, None, ProjectionMode::Topmost, |infcx| {
+    ccx.tcx.infer_ctxt(None, None, ProjectionMode::Topmost).enter(|infcx| {
         CoherenceChecker {
             crate_context: ccx,
             inference_context: infcx,
diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs
index 0f0a5b5241e..dcaa5cfb20a 100644
--- a/src/librustc_typeck/coherence/overlap.rs
+++ b/src/librustc_typeck/coherence/overlap.rs
@@ -14,7 +14,6 @@
 
 use hir::def_id::DefId;
 use rustc::traits::{self, ProjectionMode};
-use rustc::infer::InferCtxt;
 use rustc::ty::{self, TyCtxt};
 use syntax::ast;
 use rustc::dep_graph::DepNode;
@@ -85,7 +84,7 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
 
         for (i, &impl1_def_id) in impls.iter().enumerate() {
             for &impl2_def_id in &impls[(i+1)..] {
-                InferCtxt::enter(self.tcx, None, None, ProjectionMode::Topmost, |infcx| {
+                self.tcx.infer_ctxt(None, None, ProjectionMode::Topmost).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 3c46d962198..b88b3c9802d 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -104,7 +104,7 @@ pub use rustc::util;
 use dep_graph::DepNode;
 use hir::map as hir_map;
 use hir::def::Def;
-use rustc::infer::{InferCtxt, TypeOrigin};
+use rustc::infer::TypeOrigin;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::traits::ProjectionMode;
@@ -211,7 +211,7 @@ fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                 t2: Ty<'tcx>,
                                 msg: &str)
                                 -> bool {
-    InferCtxt::enter(ccx.tcx, None, None, ProjectionMode::AnyFinal, |infcx| {
+    ccx.tcx.infer_ctxt(None, None, ProjectionMode::AnyFinal).enter(|infcx| {
         if let Err(err) = infcx.eq_types(false, TypeOrigin::Misc(span), t1, t2) {
             emit_type_err(infcx.tcx, span, t1, t2, &err, msg);
             false