about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEduard Burtescu <edy.burt@gmail.com>2016-03-24 18:49:04 +0200
committerEduard Burtescu <edy.burt@gmail.com>2016-05-11 04:14:58 +0300
commit0053b442f8cd5bf5e310a2664fc3a47a8f33da71 (patch)
tree086be6236e61e4663b9bd57ff0a61059779bb480 /src
parent76affa5d6f5d1b8c3afcd4e0c6bbaee1fb0daeb4 (diff)
downloadrust-0053b442f8cd5bf5e310a2664fc3a47a8f33da71.tar.gz
rust-0053b442f8cd5bf5e310a2664fc3a47a8f33da71.zip
rustc_typeck: Use Deref for FnCtxt, Inherited and InferCtxt fields and methods.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_typeck/check/_match.rs63
-rw-r--r--src/librustc_typeck/check/callee.rs36
-rw-r--r--src/librustc_typeck/check/cast.rs65
-rw-r--r--src/librustc_typeck/check/closure.rs40
-rw-r--r--src/librustc_typeck/check/coercion.rs115
-rw-r--r--src/librustc_typeck/check/demand.rs14
-rw-r--r--src/librustc_typeck/check/dropck.rs12
-rw-r--r--src/librustc_typeck/check/method/confirm.rs150
-rw-r--r--src/librustc_typeck/check/method/mod.rs32
-rw-r--r--src/librustc_typeck/check/method/probe.rs171
-rw-r--r--src/librustc_typeck/check/method/suggest.rs35
-rw-r--r--src/librustc_typeck/check/mod.rs544
-rw-r--r--src/librustc_typeck/check/op.rs30
-rw-r--r--src/librustc_typeck/check/regionck.rs179
-rw-r--r--src/librustc_typeck/check/upvar.rs46
-rw-r--r--src/librustc_typeck/check/wfcheck.rs83
-rw-r--r--src/librustc_typeck/check/writeback.rs44
17 files changed, 804 insertions, 855 deletions
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 537f1e33c36..1dab0c97b8a 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -58,7 +58,7 @@ fn bad_struct_kind_err(sess: &Session, pat: &hir::Pat, path: &hir::Path, lint: b
 
 impl<'a, 'tcx> PatCtxt<'a, 'tcx, 'tcx> {
 pub fn check_pat(&self, pat: &'tcx hir::Pat, expected: Ty<'tcx>) {
-    let tcx = self.tcx();
+    let tcx = self.tcx;
 
     debug!("check_pat(pat={:?},expected={:?})", pat, expected);
 
@@ -126,15 +126,15 @@ pub fn check_pat(&self, pat: &'tcx hir::Pat, expected: Ty<'tcx>) {
                 span_err!(tcx.sess, span, E0029,
                           "only char and numeric types are allowed in range patterns\n \
                            start type: {}\n end type: {}",
-                          self.infcx().ty_to_string(lhs_ty),
-                          self.infcx().ty_to_string(rhs_ty)
+                          self.ty_to_string(lhs_ty),
+                          self.ty_to_string(rhs_ty)
                 );
                 return;
             }
 
             // Check that the types of the end-points can be unified.
             let types_unify = require_same_types(
-                self.ccx, Some(self.infcx()), pat.span, rhs_ty, lhs_ty,
+                self.ccx, Some(self), pat.span, rhs_ty, lhs_ty,
                 "mismatched types in range",
             );
 
@@ -145,7 +145,7 @@ pub fn check_pat(&self, pat: &'tcx hir::Pat, expected: Ty<'tcx>) {
 
             // Now that we know the types can be unified we find the unified type and use
             // it to type the entire expression.
-            let common_type = self.infcx().resolve_type_vars_if_possible(&lhs_ty);
+            let common_type = self.resolve_type_vars_if_possible(&lhs_ty);
 
             self.write_ty(pat.id, common_type);
 
@@ -181,7 +181,7 @@ pub fn check_pat(&self, pat: &'tcx hir::Pat, expected: Ty<'tcx>) {
                     //    ref x | ref const x | ref mut x
                     // then `x` is assigned a value of type `&M T` where M is the mutability
                     // and T is the expected type.
-                    let region_var = self.infcx().next_region_var(infer::PatternRegion(pat.span));
+                    let region_var = self.next_region_var(infer::PatternRegion(pat.span));
                     let mt = ty::TypeAndMut { ty: expected, mutbl: mutbl };
                     let region_ty = tcx.mk_ref(tcx.mk_region(region_var), mt);
 
@@ -227,14 +227,14 @@ pub fn check_pat(&self, pat: &'tcx hir::Pat, expected: Ty<'tcx>) {
             let self_ty = self.to_ty(&qself.ty);
             let path_res = if let Some(&d) = tcx.def_map.borrow().get(&pat.id) {
                 if d.base_def == Def::Err {
-                    self.infcx().set_tainted_by_errors();
+                    self.set_tainted_by_errors();
                     self.write_error(pat.id);
                     return;
                 }
                 d
             } else if qself.position == 0 {
                 // This is just a sentinel for finish_resolving_def_to_ty.
-                let sentinel = self.tcx().map.local_def_id(ast::CRATE_NODE_ID);
+                let sentinel = self.tcx.map.local_def_id(ast::CRATE_NODE_ID);
                 def::PathResolution {
                     base_def: Def::Mod(sentinel),
                     depth: path.segments.len()
@@ -264,8 +264,7 @@ pub fn check_pat(&self, pat: &'tcx hir::Pat, expected: Ty<'tcx>) {
         }
         PatKind::Tup(ref elements) => {
             let element_tys: Vec<_> =
-                (0..elements.len()).map(|_| self.infcx().next_ty_var())
-                                        .collect();
+                (0..elements.len()).map(|_| self.next_ty_var()).collect();
             let pat_ty = tcx.mk_tup(element_tys.clone());
             self.write_ty(pat.id, pat_ty);
             self.demand_eqtype(pat.span, expected, pat_ty);
@@ -274,7 +273,7 @@ pub fn check_pat(&self, pat: &'tcx hir::Pat, expected: Ty<'tcx>) {
             }
         }
         PatKind::Box(ref inner) => {
-            let inner_ty = self.infcx().next_ty_var();
+            let inner_ty = self.next_ty_var();
             let uniq_ty = tcx.mk_box(inner_ty);
 
             if self.check_dereferencable(pat.span, expected, &inner) {
@@ -290,7 +289,7 @@ pub fn check_pat(&self, pat: &'tcx hir::Pat, expected: Ty<'tcx>) {
             }
         }
         PatKind::Ref(ref inner, mutbl) => {
-            let expected = self.infcx().shallow_resolve(expected);
+            let expected = self.shallow_resolve(expected);
             if self.check_dereferencable(pat.span, expected, &inner) {
                 // `demand::subtype` would be good enough, but using
                 // `eqtype` turns out to be equally general. See (*)
@@ -305,9 +304,9 @@ pub fn check_pat(&self, pat: &'tcx hir::Pat, expected: Ty<'tcx>) {
                         (expected, mt.ty)
                     }
                     _ => {
-                        let inner_ty = self.infcx().next_ty_var();
+                        let inner_ty = self.next_ty_var();
                         let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl };
-                        let region = self.infcx().next_region_var(infer::PatternRegion(pat.span));
+                        let region = self.next_region_var(infer::PatternRegion(pat.span));
                         let rptr_ty = tcx.mk_ref(tcx.mk_region(region), mt);
                         self.demand_eqtype(pat.span, expected, rptr_ty);
                         (rptr_ty, inner_ty)
@@ -323,7 +322,7 @@ pub fn check_pat(&self, pat: &'tcx hir::Pat, expected: Ty<'tcx>) {
         }
         PatKind::Vec(ref before, ref slice, ref after) => {
             let expected_ty = self.structurally_resolved_type(pat.span, expected);
-            let inner_ty = self.infcx().next_ty_var();
+            let inner_ty = self.next_ty_var();
             let pat_ty = match expected_ty.sty {
                 ty::TyArray(_, size) => tcx.mk_array(inner_ty, {
                     let min_len = before.len() + after.len();
@@ -333,7 +332,7 @@ pub fn check_pat(&self, pat: &'tcx hir::Pat, expected: Ty<'tcx>) {
                     }
                 }),
                 _ => {
-                    let region = self.infcx().next_region_var(infer::PatternRegion(pat.span));
+                    let region = self.next_region_var(infer::PatternRegion(pat.span));
                     tcx.mk_ref(tcx.mk_region(region), ty::TypeAndMut {
                         ty: tcx.mk_slice(inner_ty),
                         mutbl: expected_ty.builtin_deref(true, ty::NoPreference).map(|mt| mt.mutbl)
@@ -353,7 +352,7 @@ pub fn check_pat(&self, pat: &'tcx hir::Pat, expected: Ty<'tcx>) {
                 self.check_pat(&elt, inner_ty);
             }
             if let Some(ref slice) = *slice {
-                let region = self.infcx().next_region_var(infer::PatternRegion(pat.span));
+                let region = self.next_region_var(infer::PatternRegion(pat.span));
                 let mutbl = expected_ty.builtin_deref(true, ty::NoPreference)
                     .map_or(hir::MutImmutable, |mt| mt.mutbl);
 
@@ -425,7 +424,7 @@ fn check_assoc_item_is_const(&self, def: Def, span: Span) -> bool {
     match def {
         Def::AssociatedConst(..) => true,
         Def::Method(..) => {
-            span_err!(self.tcx().sess, span, E0327,
+            span_err!(self.tcx.sess, span, E0327,
                       "associated items in match patterns must be constants");
             false
         }
@@ -436,16 +435,16 @@ fn check_assoc_item_is_const(&self, def: Def, span: Span) -> bool {
 }
 
 pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool {
-    let tcx = self.tcx();
+    let tcx = self.tcx;
     if pat_is_binding(&tcx.def_map.borrow(), inner) {
-        let expected = self.infcx().shallow_resolve(expected);
+        let expected = self.shallow_resolve(expected);
         expected.builtin_deref(true, ty::NoPreference).map_or(true, |mt| match mt.ty.sty {
             ty::TyTrait(_) => {
                 // This is "x = SomeTrait" being reduced from
                 // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
                 span_err!(tcx.sess, span, E0033,
                           "type `{}` cannot be dereferenced",
-                          self.infcx().ty_to_string(expected));
+                          self.ty_to_string(expected));
                 false
             }
             _ => true
@@ -463,7 +462,7 @@ pub fn check_match(&self,
                    arms: &'tcx [hir::Arm],
                    expected: Expectation<'tcx>,
                    match_src: hir::MatchSource) {
-    let tcx = self.tcx();
+    let tcx = self.tcx;
 
     // Not entirely obvious: if matches may create ref bindings, we
     // want to use the *precise* type of the discriminant, *not* some
@@ -482,7 +481,7 @@ pub fn check_match(&self,
         // ...but otherwise we want to use any supertype of the
         // discriminant. This is sort of a workaround, see note (*) in
         // `check_pat` for some details.
-        discrim_ty = self.infcx().next_ty_var();
+        discrim_ty = self.next_ty_var();
         self.check_expr_has_type(discrim, discrim_ty);
     };
 
@@ -508,14 +507,14 @@ pub fn check_match(&self,
     // of execution reach it, we will panic, so bottom is an appropriate
     // type in that case)
     let expected = expected.adjust_for_branches(self);
-    let mut result_ty = self.infcx().next_diverging_ty_var();
+    let mut result_ty = self.next_diverging_ty_var();
     let coerce_first = match expected {
         // We don't coerce to `()` so that if the match expression is a
         // statement it's branches can have any consistent type. That allows
         // us to give better error messages (pointing to a usually better
         // arm for inconsistent arms or to the whole match when a `()` type
         // is required).
-        Expectation::ExpectHasType(ety) if ety != self.tcx().mk_nil() => {
+        Expectation::ExpectHasType(ety) if ety != self.tcx.mk_nil() => {
             ety
         }
         _ => result_ty
@@ -547,7 +546,7 @@ pub fn check_match(&self,
         };
 
         let result = if is_if_let_fallback {
-            self.infcx().eq_types(true, origin, arm_ty, result_ty)
+            self.eq_types(true, origin, arm_ty, result_ty)
                 .map(|InferOk { obligations, .. }| {
                     // FIXME(#32730) propagate obligations
                     assert!(obligations.is_empty());
@@ -569,8 +568,8 @@ pub fn check_match(&self,
                 } else {
                     (result_ty, arm_ty)
                 };
-                self.infcx().report_mismatched_types(origin, expected, found, e);
-                self.tcx().types.err
+                self.report_mismatched_types(origin, expected, found, e);
+                self.tcx.types.err
             }
         };
     }
@@ -583,7 +582,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx, 'tcx> {
 pub fn check_pat_struct(&self, pat: &'tcx hir::Pat,
                         path: &hir::Path, fields: &'tcx [Spanned<hir::FieldPat>],
                         etc: bool, expected: Ty<'tcx>) {
-    let tcx = self.tcx();
+    let tcx = self.tcx;
 
     let def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
     let variant = match self.def_struct_variant(def, path.span) {
@@ -621,12 +620,12 @@ fn check_pat_enum(&self,
                   is_tuple_struct_pat: bool)
 {
     // Typecheck the path.
-    let tcx = self.tcx();
+    let tcx = self.tcx;
 
     let path_res = match tcx.def_map.borrow().get(&pat.id) {
         Some(&path_res) if path_res.base_def != Def::Err => path_res,
         _ => {
-            self.infcx().set_tainted_by_errors();
+            self.set_tainted_by_errors();
             self.write_error(pat.id);
 
             if let Some(subpats) = subpats {
@@ -767,7 +766,7 @@ pub fn check_struct_pat_fields(&self,
                                variant: ty::VariantDef<'tcx>,
                                substs: &Substs<'tcx>,
                                etc: bool) {
-    let tcx = self.tcx();
+    let tcx = self.tcx;
 
     // Index the struct fields' types.
     let field_map = variant.fields
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index f46e6204ea4..e1d64c2253d 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -128,13 +128,13 @@ fn try_overloaded_call_step(&self,
             // Check whether this is a call to a closure where we
             // haven't yet decided on whether the closure is fn vs
             // fnmut vs fnonce. If so, we have to defer further processing.
-            if self.infcx().closure_kind(def_id).is_none() {
+            if self.closure_kind(def_id).is_none() {
                 let closure_ty =
-                    self.infcx().closure_type(def_id, substs);
+                    self.closure_type(def_id, substs);
                 let fn_sig =
-                    self.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
-                                                                           infer::FnCall,
-                                                                           &closure_ty.sig).0;
+                    self.replace_late_bound_regions_with_fresh_var(call_expr.span,
+                                                                   infer::FnCall,
+                                                                   &closure_ty.sig).0;
                 self.record_deferred_call_resolution(def_id, Box::new(CallResolution {
                     call_expr: call_expr,
                     callee_expr: callee_expr,
@@ -175,9 +175,9 @@ fn try_overloaded_call_traits(&self,
 {
     // Try the options that are least restrictive on the caller first.
     for &(opt_trait_def_id, method_name) in &[
-        (self.tcx().lang_items.fn_trait(), token::intern("call")),
-        (self.tcx().lang_items.fn_mut_trait(), token::intern("call_mut")),
-        (self.tcx().lang_items.fn_once_trait(), token::intern("call_once")),
+        (self.tcx.lang_items.fn_trait(), token::intern("call")),
+        (self.tcx.lang_items.fn_mut_trait(), token::intern("call_mut")),
+        (self.tcx.lang_items.fn_once_trait(), token::intern("call_once")),
     ] {
         let trait_def_id = match opt_trait_def_id {
             Some(def_id) => def_id,
@@ -221,7 +221,7 @@ fn confirm_builtin_call(&self,
             }, callee_ty, None);
 
             if let hir::ExprCall(ref expr, _) = call_expr.node {
-                let tcx = self.tcx();
+                let tcx = self.tcx;
                 if let Some(pr) = tcx.def_map.borrow().get(&expr.id) {
                     if pr.depth == 0 && pr.base_def != Def::Err {
                         if let Some(span) = tcx.map.span_if_local(pr.def_id()) {
@@ -238,7 +238,7 @@ fn confirm_builtin_call(&self,
             // set up all the node type bindings.
             error_fn_sig = ty::Binder(ty::FnSig {
                 inputs: self.err_args(arg_exprs.len()),
-                output: ty::FnConverging(self.tcx().types.err),
+                output: ty::FnConverging(self.tcx.types.err),
                 variadic: false
             });
 
@@ -252,9 +252,9 @@ fn confirm_builtin_call(&self,
     // previously appeared within a `Binder<>` and hence would not
     // have been normalized before.
     let fn_sig =
-        self.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
-                                                               infer::FnCall,
-                                                               fn_sig).0;
+        self.replace_late_bound_regions_with_fresh_var(call_expr.span,
+                                                       infer::FnCall,
+                                                       fn_sig).0;
     let fn_sig =
         self.normalize_associated_types_in(call_expr.span, &fn_sig);
 
@@ -323,7 +323,7 @@ fn write_overloaded_call_method_map(&self,
                                     call_expr: &hir::Expr,
                                     method_callee: ty::MethodCallee<'tcx>) {
     let method_call = ty::MethodCall::expr(call_expr.id);
-    self.inh.tables.borrow_mut().method_map.insert(method_call, method_callee);
+    self.tables.borrow_mut().method_map.insert(method_call, method_callee);
 }
 }
 
@@ -344,7 +344,7 @@ impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> {
 
         // we should not be invoked until the closure kind has been
         // determined by upvar inference
-        assert!(fcx.infcx().closure_kind(self.closure_def_id).is_some());
+        assert!(fcx.closure_kind(self.closure_def_id).is_some());
 
         // We may now know enough to figure out fn vs fnmut etc.
         match fcx.try_overloaded_call_traits(self.call_expr, self.callee_expr,
@@ -358,8 +358,8 @@ impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> {
                 // can't because of the annoying need for a TypeTrace.
                 // (This always bites me, should find a way to
                 // refactor it.)
-                let method_sig = fcx.tcx().no_late_bound_regions(method_callee.ty.fn_sig())
-                                          .unwrap();
+                let method_sig = fcx.tcx.no_late_bound_regions(method_callee.ty.fn_sig())
+                                        .unwrap();
 
                 debug!("attempt_resolution: method_callee={:?}",
                        method_callee);
@@ -370,7 +370,7 @@ impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> {
                     fcx.demand_eqtype(self.call_expr.span, self_arg_ty, method_arg_ty);
                 }
 
-                let nilty = fcx.tcx().mk_nil();
+                let nilty = fcx.tcx.mk_nil();
                 fcx.demand_eqtype(self.call_expr.span,
                                   method_sig.output.unwrap_or(nilty),
                                   self.fn_sig.output.unwrap_or(nilty));
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index e4cd9540e96..158867eebf6 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -83,7 +83,7 @@ fn unsize_kind(&self, t: Ty<'tcx>) -> Option<UnsizeKind<'tcx>> {
             // FIXME(arielb1): do some kind of normalization
             match def.struct_variant().fields.last() {
                 None => None,
-                Some(f) => self.unsize_kind(f.ty(self.tcx(), substs))
+                Some(f) => self.unsize_kind(f.ty(self.tcx, substs))
             }
         }
         // We should really try to normalize here.
@@ -148,7 +148,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 fcx.type_error_struct(self.span, |actual| {
                     format!("casting `{}` as `{}` is invalid",
                             actual,
-                            fcx.infcx().ty_to_string(self.cast_ty))
+                            fcx.ty_to_string(self.cast_ty))
                 }, self.expr_ty, None)
                     .help(&format!("cast through {} first", match e {
                             CastError::NeedViaPtr => "a raw pointer",
@@ -160,7 +160,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                     .emit();
             }
             CastError::CastToBool => {
-                struct_span_err!(fcx.tcx().sess, self.span, E0054, "cannot cast as `bool`")
+                struct_span_err!(fcx.tcx.sess, self.span, E0054, "cannot cast as `bool`")
                     .help("compare with zero instead")
                     .emit();
             }
@@ -173,28 +173,28 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 fcx.type_error_message(self.span, |actual| {
                     format!("non-scalar cast: `{}` as `{}`",
                             actual,
-                            fcx.infcx().ty_to_string(self.cast_ty))
+                            fcx.ty_to_string(self.cast_ty))
                 }, self.expr_ty, None);
             }
             CastError::IllegalCast => {
                 fcx.type_error_message(self.span, |actual| {
                     format!("casting `{}` as `{}` is invalid",
                             actual,
-                            fcx.infcx().ty_to_string(self.cast_ty))
+                            fcx.ty_to_string(self.cast_ty))
                 }, self.expr_ty, None);
             }
             CastError::SizedUnsizedCast => {
                 fcx.type_error_message(self.span, |actual| {
                     format!("cannot cast thin pointer `{}` to fat pointer `{}`",
                             actual,
-                            fcx.infcx().ty_to_string(self.cast_ty))
+                            fcx.ty_to_string(self.cast_ty))
                 }, self.expr_ty, None)
             }
             CastError::DifferingKinds => {
                 fcx.type_error_struct(self.span, |actual| {
                     format!("casting `{}` as `{}` is invalid",
                             actual,
-                            fcx.infcx().ty_to_string(self.cast_ty))
+                            fcx.ty_to_string(self.cast_ty))
                 }, self.expr_ty, None)
                     .note("vtable kinds may not match")
                     .emit();
@@ -210,7 +210,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             return;
         }
 
-        let tstr = fcx.infcx().ty_to_string(self.cast_ty);
+        let tstr = fcx.ty_to_string(self.cast_ty);
         let mut err = fcx.type_error_struct(self.span, |actual| {
             format!("cast to unsized type: `{}` as `{}`", actual, tstr)
         }, self.expr_ty, None);
@@ -221,7 +221,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                     hir::MutImmutable => ""
                 };
                 if self.cast_ty.is_trait() {
-                    match fcx.tcx().sess.codemap().span_to_snippet(self.cast_span) {
+                    match fcx.tcx.sess.codemap().span_to_snippet(self.cast_span) {
                         Ok(s) => {
                             err.span_suggestion(self.cast_span,
                                                 "try casting to a reference instead:",
@@ -238,7 +238,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 }
             }
             ty::TyBox(..) => {
-                match fcx.tcx().sess.codemap().span_to_snippet(self.cast_span) {
+                match fcx.tcx.sess.codemap().span_to_snippet(self.cast_span) {
                     Ok(s) => {
                         err.span_suggestion(self.cast_span,
                                             "try casting to a `Box` instead:",
@@ -260,23 +260,23 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         let t_cast = self.cast_ty;
         let t_expr = self.expr_ty;
         if t_cast.is_numeric() && t_expr.is_numeric() {
-            fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS,
-                                    self.expr.id,
-                                    self.span,
-                                    format!("trivial numeric cast: `{}` as `{}`. Cast can be \
-                                             replaced by coercion, this might require type \
-                                             ascription or a temporary variable",
-                                            fcx.infcx().ty_to_string(t_expr),
-                                            fcx.infcx().ty_to_string(t_cast)));
+            fcx.tcx.sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS,
+                                  self.expr.id,
+                                  self.span,
+                                  format!("trivial numeric cast: `{}` as `{}`. Cast can be \
+                                           replaced by coercion, this might require type \
+                                           ascription or a temporary variable",
+                                          fcx.ty_to_string(t_expr),
+                                          fcx.ty_to_string(t_cast)));
         } else {
-            fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_CASTS,
-                                    self.expr.id,
-                                    self.span,
-                                    format!("trivial cast: `{}` as `{}`. Cast can be \
-                                             replaced by coercion, this might require type \
-                                             ascription or a temporary variable",
-                                            fcx.infcx().ty_to_string(t_expr),
-                                            fcx.infcx().ty_to_string(t_cast)));
+            fcx.tcx.sess.add_lint(lint::builtin::TRIVIAL_CASTS,
+                                  self.expr.id,
+                                  self.span,
+                                  format!("trivial cast: `{}` as `{}`. Cast can be \
+                                           replaced by coercion, this might require type \
+                                           ascription or a temporary variable",
+                                          fcx.ty_to_string(t_expr),
+                                          fcx.ty_to_string(t_cast)));
         }
 
     }
@@ -295,12 +295,12 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         } else if self.try_coercion_cast(fcx) {
             self.trivial_cast_lint(fcx);
             debug!(" -> CoercionCast");
-            fcx.tcx().cast_kinds.borrow_mut().insert(self.expr.id,
-                                                     CastKind::CoercionCast);
+            fcx.tcx.cast_kinds.borrow_mut().insert(self.expr.id,
+                                                   CastKind::CoercionCast);
         } else { match self.do_check(fcx) {
             Ok(k) => {
                 debug!(" -> {:?}", k);
-                fcx.tcx().cast_kinds.borrow_mut().insert(self.expr.id, k);
+                fcx.tcx.cast_kinds.borrow_mut().insert(self.expr.id, k);
             }
             Err(e) => self.report_cast_error(fcx, e)
         };}
@@ -321,7 +321,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 if let ty::TyFnDef(_, _, f) = self.expr_ty.sty {
                     // Attempt a coercion to a fn pointer type.
                     let res = fcx.try_coerce(self.expr,
-                                             fcx.tcx().mk_ty(ty::TyFnPtr(f)));
+                                             fcx.tcx.mk_ty(ty::TyFnPtr(f)));
                     if !res.is_ok() {
                         return Err(CastError::NonScalar);
                     }
@@ -482,10 +482,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
                                  span: Span)
                                  -> bool
     {
-        traits::type_known_to_meet_builtin_bound(self.infcx(),
-                                                 ty,
-                                                 ty::BoundSized,
-                                                 span)
+        traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundSized, span)
     }
 }
 
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index e6ec47f1364..7e0376c1683 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -46,7 +46,7 @@ fn check_closure(&self,
                  decl: &'tcx hir::FnDecl,
                  body: &'tcx hir::Block,
                  expected_sig: Option<ty::FnSig<'tcx>>) {
-    let expr_def_id = self.tcx().map.local_def_id(expr.id);
+    let expr_def_id = self.tcx.map.local_def_id(expr.id);
 
     debug!("check_closure opt_kind={:?} expected_sig={:?}",
            opt_kind,
@@ -61,20 +61,20 @@ fn check_closure(&self,
     // Create type variables (for now) to represent the transformed
     // types of upvars. These will be unified during the upvar
     // inference phase (`upvar.rs`).
-    let num_upvars = self.tcx().with_freevars(expr.id, |fv| fv.len());
-    let upvar_tys = self.infcx().next_ty_vars(num_upvars);
+    let num_upvars = self.tcx.with_freevars(expr.id, |fv| fv.len());
+    let upvar_tys = self.next_ty_vars(num_upvars);
 
     debug!("check_closure: expr.id={:?} upvar_tys={:?}",
            expr.id, upvar_tys);
 
-    let closure_type = self.tcx().mk_closure(expr_def_id,
-        self.tcx().mk_substs(self.inh.infcx.parameter_environment.free_substs.clone()),
+    let closure_type = self.tcx.mk_closure(expr_def_id,
+        self.tcx.mk_substs(self.parameter_environment.free_substs.clone()),
         upvar_tys);
 
     self.write_ty(expr.id, closure_type);
 
-    let fn_sig = self.tcx().liberate_late_bound_regions(
-        self.tcx().region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig);
+    let fn_sig = self.tcx.liberate_late_bound_regions(
+        self.tcx.region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig);
 
     check_fn(self.ccx,
              hir::Unsafety::Normal,
@@ -83,20 +83,20 @@ fn check_closure(&self,
              decl,
              expr.id,
              &body,
-             self.inh);
+             self);
 
     // Tuple up the arguments and insert the resulting function type into
     // the `closures` table.
-    fn_ty.sig.0.inputs = vec![self.tcx().mk_tup(fn_ty.sig.0.inputs)];
+    fn_ty.sig.0.inputs = vec![self.tcx.mk_tup(fn_ty.sig.0.inputs)];
 
     debug!("closure for {:?} --> sig={:?} opt_kind={:?}",
            expr_def_id,
            fn_ty.sig,
            opt_kind);
 
-    self.inh.tables.borrow_mut().closure_tys.insert(expr_def_id, fn_ty);
+    self.tables.borrow_mut().closure_tys.insert(expr_def_id, fn_ty);
     match opt_kind {
-        Some(kind) => { self.inh.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); }
+        Some(kind) => { self.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); }
         None => { }
     }
 }
@@ -109,12 +109,12 @@ fn deduce_expectations_from_expected_type(&self, expected_ty: Ty<'tcx>)
 
     match expected_ty.sty {
         ty::TyTrait(ref object_type) => {
-            let proj_bounds = object_type.projection_bounds_with_self_ty(self.tcx(),
-                                                                         self.tcx().types.err);
+            let proj_bounds = object_type.projection_bounds_with_self_ty(self.tcx,
+                                                                         self.tcx.types.err);
             let sig = proj_bounds.iter()
                                  .filter_map(|pb| self.deduce_sig_from_projection(pb))
                                  .next();
-            let kind = self.tcx().lang_items.fn_trait_kind(object_type.principal_def_id());
+            let kind = self.tcx.lang_items.fn_trait_kind(object_type.principal_def_id());
             (sig, kind)
         }
         ty::TyInfer(ty::TyVar(vid)) => {
@@ -129,7 +129,7 @@ fn deduce_expectations_from_expected_type(&self, expected_ty: Ty<'tcx>)
 fn deduce_expectations_from_obligations(&self, expected_vid: ty::TyVid)
     -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>)
 {
-    let fulfillment_cx = self.inh.fulfillment_cx.borrow();
+    let fulfillment_cx = self.fulfillment_cx.borrow();
     // Here `expected_ty` is known to be a type inference variable.
 
     let expected_sig =
@@ -188,7 +188,7 @@ fn deduce_expectations_from_obligations(&self, expected_vid: ty::TyVid)
             };
             opt_trait_ref
                 .and_then(|trait_ref| self.self_type_matches_expected_vid(trait_ref, expected_vid))
-                .and_then(|trait_ref| self.tcx().lang_items.fn_trait_kind(trait_ref.def_id()))
+                .and_then(|trait_ref| self.tcx.lang_items.fn_trait_kind(trait_ref.def_id()))
         })
         .fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));
 
@@ -201,7 +201,7 @@ fn deduce_sig_from_projection(&self,
     projection: &ty::PolyProjectionPredicate<'tcx>)
     -> Option<ty::FnSig<'tcx>>
 {
-    let tcx = self.tcx();
+    let tcx = self.tcx;
 
     debug!("deduce_sig_from_projection({:?})",
            projection);
@@ -213,7 +213,7 @@ fn deduce_sig_from_projection(&self,
     }
 
     let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0);
-    let arg_param_ty = self.infcx().resolve_type_vars_if_possible(&arg_param_ty);
+    let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty);
     debug!("deduce_sig_from_projection: arg_param_ty {:?}", arg_param_ty);
 
     let input_tys = match arg_param_ty.sty {
@@ -223,7 +223,7 @@ fn deduce_sig_from_projection(&self,
     debug!("deduce_sig_from_projection: input_tys {:?}", input_tys);
 
     let ret_param_ty = projection.0.ty;
-    let ret_param_ty = self.infcx().resolve_type_vars_if_possible(&ret_param_ty);
+    let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty);
     debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty);
 
     let fn_sig = ty::FnSig {
@@ -241,7 +241,7 @@ fn self_type_matches_expected_vid(&self,
     expected_vid: ty::TyVid)
     -> Option<ty::PolyTraitRef<'tcx>>
 {
-    let self_ty = self.infcx().shallow_resolve(trait_ref.self_ty());
+    let self_ty = self.shallow_resolve(trait_ref.self_ty());
     debug!("self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})",
            trait_ref,
            self_ty);
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 6e24df481bd..d471ab3c99c 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -62,12 +62,13 @@
 
 use check::{FnCtxt, UnresolvedTypeAction};
 
+use rustc::hir;
 use rustc::infer::{Coercion, InferOk, TypeOrigin, TypeTrace};
 use rustc::traits::{self, ObligationCause};
 use rustc::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef};
 use rustc::ty::adjustment::{AutoPtr, AutoUnsafe, AdjustReifyFnPointer};
 use rustc::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer};
-use rustc::ty::{self, LvaluePreference, TypeAndMut, Ty, TyCtxt};
+use rustc::ty::{self, LvaluePreference, TypeAndMut, Ty};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::error::TypeError;
 use rustc::ty::relate::RelateResult;
@@ -75,7 +76,7 @@ use util::common::indent;
 
 use std::cell::RefCell;
 use std::collections::VecDeque;
-use rustc::hir;
+use std::ops::Deref;
 
 struct Coerce<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
@@ -84,6 +85,13 @@ struct Coerce<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     unsizing_obligations: RefCell<Vec<traits::PredicateObligation<'tcx>>>,
 }
 
+impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> {
+    type Target = FnCtxt<'a, 'gcx, 'tcx>;
+    fn deref(&self) -> &Self::Target {
+        &self.fcx
+    }
+}
+
 type CoerceResult<'tcx> = RelateResult<'tcx, (Ty<'tcx>, AutoAdjustment<'tcx>)>;
 
 fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
@@ -107,23 +115,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx, 'tcx> {
         }
     }
 
-    fn tcx(&self) -> TyCtxt<'f, 'tcx, 'tcx> {
-        self.fcx.tcx()
-    }
-
     fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-        let infcx = self.fcx.infcx();
-        infcx.commit_if_ok(|_| {
+        self.commit_if_ok(|_| {
             let trace = TypeTrace::types(self.origin, false, a, b);
             if self.use_lub {
-                infcx.lub(false, trace, &a, &b)
+                self.lub(false, trace, &a, &b)
                     .map(|InferOk { value, obligations }| {
                         // FIXME(#32730) propagate obligations
                         assert!(obligations.is_empty());
                         value
                     })
             } else {
-                infcx.sub(false, trace, &a, &b)
+                self.sub(false, trace, &a, &b)
                     .map(|InferOk { value, obligations }| {
                         // FIXME(#32730) propagate obligations
                         assert!(obligations.is_empty());
@@ -156,7 +159,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx, 'tcx> {
         where E: Fn() -> I,
               I: IntoIterator<Item=&'a hir::Expr> {
 
-        let a = self.fcx.infcx().shallow_resolve(a);
+        let a = self.shallow_resolve(a);
         debug!("Coerce.tys({:?} => {:?})", a, b);
 
         // Just ignore error types.
@@ -240,10 +243,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx, 'tcx> {
         let lvalue_pref = LvaluePreference::from_mutbl(mt_b.mutbl);
         let mut first_error = None;
         let mut r_borrow_var = None;
-        let (_, autoderefs, success) = self.fcx.autoderef(span, a, exprs,
-                                                          UnresolvedTypeAction::Ignore,
-                                                          lvalue_pref,
-                                                          |referent_ty, autoderef|
+        let (_, autoderefs, success) = self.autoderef(span, a, exprs,
+                                                      UnresolvedTypeAction::Ignore,
+                                                      lvalue_pref,
+                                                      |referent_ty, autoderef|
         {
             if autoderef == 0 {
                 // Don't let this pass, otherwise it would cause
@@ -328,12 +331,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx, 'tcx> {
             } else {
                 if r_borrow_var.is_none() { // create var lazilly, at most once
                     let coercion = Coercion(span);
-                    let r = self.fcx.infcx().next_region_var(coercion);
-                    r_borrow_var = Some(self.tcx().mk_region(r)); // [4] above
+                    let r = self.next_region_var(coercion);
+                    r_borrow_var = Some(self.tcx.mk_region(r)); // [4] above
                 }
                 r_borrow_var.unwrap()
             };
-            let derefd_ty_a = self.tcx().mk_ref(r, TypeAndMut {
+            let derefd_ty_a = self.tcx.mk_ref(r, TypeAndMut {
                 ty: referent_ty,
                 mutbl: mt_b.mutbl // [1] above
             });
@@ -405,8 +408,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx, 'tcx> {
                source,
                target);
 
-        let traits = (self.tcx().lang_items.unsize_trait(),
-                      self.tcx().lang_items.coerce_unsized_trait());
+        let traits = (self.tcx.lang_items.unsize_trait(),
+                      self.tcx.lang_items.coerce_unsized_trait());
         let (unsize_did, coerce_unsized_did) = if let (Some(u), Some(cu)) = traits {
             (u, cu)
         } else {
@@ -425,8 +428,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx, 'tcx> {
                 coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
 
                 let coercion = Coercion(self.origin.span());
-                let r_borrow = self.fcx.infcx().next_region_var(coercion);
-                let region = self.tcx().mk_region(r_borrow);
+                let r_borrow = self.next_region_var(coercion);
+                let region = self.tcx.mk_region(r_borrow);
                 (mt_a.ty, Some(AutoPtr(region, mt_b.mutbl)))
             }
             (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) => {
@@ -435,21 +438,21 @@ impl<'f, 'tcx> Coerce<'f, 'tcx, 'tcx> {
             }
             _ => (source, None)
         };
-        let source = source.adjust_for_autoref(self.tcx(), reborrow);
+        let source = source.adjust_for_autoref(self.tcx, reborrow);
 
-        let mut selcx = traits::SelectionContext::new(self.fcx.infcx());
+        let mut selcx = traits::SelectionContext::new(self);
 
         // Use a FIFO queue for this custom fulfillment procedure.
         let mut queue = VecDeque::new();
         let mut leftover_predicates = vec![];
 
         // Create an obligation for `Source: CoerceUnsized<Target>`.
-        let cause = ObligationCause::misc(self.origin.span(), self.fcx.body_id);
-        queue.push_back(self.tcx().predicate_for_trait_def(cause,
-                                                           coerce_unsized_did,
-                                                           0,
-                                                           source,
-                                                           vec![target]));
+        let cause = ObligationCause::misc(self.origin.span(), self.body_id);
+        queue.push_back(self.tcx.predicate_for_trait_def(cause,
+                                                         coerce_unsized_did,
+                                                         0,
+                                                         source,
+                                                         vec![target]));
 
         // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
         // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
@@ -475,7 +478,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx, 'tcx> {
 
                 // Object safety violations or miscellaneous.
                 Err(err) => {
-                    self.fcx.infcx().report_selection_error(&obligation, &err, None);
+                    self.report_selection_error(&obligation, &err, None);
                     // Treat this like an obligation and follow through
                     // with the unsizing - the lack of a coercion should
                     // be silent, as it causes a type mismatch later.
@@ -511,13 +514,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx, 'tcx> {
          * into a closure or a `proc`.
          */
 
-        let b = self.fcx.infcx().shallow_resolve(b);
+        let b = self.shallow_resolve(b);
         debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b);
 
         if let ty::TyFnPtr(fn_ty_b) = b.sty {
             match (fn_ty_a.unsafety, fn_ty_b.unsafety) {
                 (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => {
-                    let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a);
+                    let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
                     return self.unify_and_identity(unsafe_a, b).map(|(ty, _)| {
                         (ty, AdjustUnsafeFnPointer)
                     });
@@ -538,12 +541,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx, 'tcx> {
          * into a closure or a `proc`.
          */
 
-        let b = self.fcx.infcx().shallow_resolve(b);
+        let b = self.shallow_resolve(b);
         debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b);
 
         match b.sty {
             ty::TyFnPtr(_) => {
-                let a_fn_pointer = self.tcx().mk_ty(ty::TyFnPtr(fn_ty_a));
+                let a_fn_pointer = self.tcx.mk_ty(ty::TyFnPtr(fn_ty_a));
                 self.unify_and_identity(a_fn_pointer, b).map(|(ty, _)| {
                     (ty, AdjustReifyFnPointer)
                 })
@@ -570,7 +573,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx, 'tcx> {
         };
 
         // Check that the types which they point at are compatible.
-        let a_unsafe = self.tcx().mk_ptr(ty::TypeAndMut{ mutbl: mutbl_b, ty: mt_a.ty });
+        let a_unsafe = self.tcx.mk_ptr(ty::TypeAndMut{ mutbl: mutbl_b, ty: mt_a.ty });
         let (ty, noop) = self.unify_and_identity(a_unsafe, b)?;
         coerce_mutbls(mt_a.mutbl, mutbl_b)?;
 
@@ -623,16 +626,16 @@ pub fn try_coerce(&self,
                   expr: &hir::Expr,
                   target: Ty<'tcx>)
                   -> RelateResult<'tcx, Ty<'tcx>> {
-    let source = self.resolve_type_vars_if_possible(self.expr_ty(expr));
+    let source = self.resolve_type_vars_with_obligations(self.expr_ty(expr));
     debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
 
     let mut coerce = Coerce::new(self, TypeOrigin::ExprAssignable(expr.span));
-    self.infcx().commit_if_ok(|_| {
+    self.commit_if_ok(|_| {
         let (ty, adjustment) =
             apply(&mut coerce, &|| Some(expr), source, target)?;
         if !adjustment.is_identity() {
             debug!("Success, coerced with {:?}", adjustment);
-            assert!(!self.inh.tables.borrow().adjustments.contains_key(&expr.id));
+            assert!(!self.tables.borrow().adjustments.contains_key(&expr.id));
             self.write_adjustment(expr.id, adjustment);
         }
         Ok(ty)
@@ -652,8 +655,8 @@ pub fn try_find_coercion_lub<'b, E, I>(&self,
     where E: Fn() -> I,
           I: IntoIterator<Item=&'b hir::Expr> {
 
-    let prev_ty = self.resolve_type_vars_if_possible(prev_ty);
-    let new_ty = self.resolve_type_vars_if_possible(self.expr_ty(new));
+    let prev_ty = self.resolve_type_vars_with_obligations(prev_ty);
+    let new_ty = self.resolve_type_vars_with_obligations(self.expr_ty(new));
     debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty);
 
     let trace = TypeTrace::types(origin, true, prev_ty, new_ty);
@@ -664,7 +667,7 @@ pub fn try_find_coercion_lub<'b, E, I>(&self,
         (&ty::TyFnDef(a_def_id, a_substs, a_fty),
          &ty::TyFnDef(b_def_id, b_substs, b_fty)) => {
             // The signature must always match.
-            let fty = self.infcx().lub(true, trace.clone(), a_fty, b_fty)
+            let fty = self.lub(true, trace.clone(), a_fty, b_fty)
                 .map(|InferOk { value, obligations }| {
                     // FIXME(#32730) propagate obligations
                     assert!(obligations.is_empty());
@@ -673,28 +676,28 @@ pub fn try_find_coercion_lub<'b, E, I>(&self,
 
             if a_def_id == b_def_id {
                 // Same function, maybe the parameters match.
-                let substs = self.infcx().commit_if_ok(|_| {
-                    self.infcx().lub(true, trace.clone(), a_substs, b_substs)
+                let substs = self.commit_if_ok(|_| {
+                    self.lub(true, trace.clone(), a_substs, b_substs)
                         .map(|InferOk { value, obligations }| {
                             // FIXME(#32730) propagate obligations
                             assert!(obligations.is_empty());
                             value
                         })
-                }).map(|s| self.tcx().mk_substs(s));
+                }).map(|s| self.tcx.mk_substs(s));
 
                 if let Ok(substs) = substs {
                     // We have a LUB of prev_ty and new_ty, just return it.
-                    return Ok(self.tcx().mk_fn_def(a_def_id, substs, fty));
+                    return Ok(self.tcx.mk_fn_def(a_def_id, substs, fty));
                 }
             }
 
             // Reify both sides and return the reified fn pointer type.
             for expr in exprs().into_iter().chain(Some(new)) {
                 // No adjustments can produce a fn item, so this should never trip.
-                assert!(!self.inh.tables.borrow().adjustments.contains_key(&expr.id));
+                assert!(!self.tables.borrow().adjustments.contains_key(&expr.id));
                 self.write_adjustment(expr.id, AdjustReifyFnPointer);
             }
-            return Ok(self.tcx().mk_fn_ptr(fty));
+            return Ok(self.tcx.mk_fn_ptr(fty));
         }
         _ => {}
     }
@@ -705,8 +708,8 @@ pub fn try_find_coercion_lub<'b, E, I>(&self,
     // First try to coerce the new expression to the type of the previous ones,
     // but only if the new expression has no coercion already applied to it.
     let mut first_error = None;
-    if !self.inh.tables.borrow().adjustments.contains_key(&new.id) {
-        let result = self.infcx().commit_if_ok(|_| {
+    if !self.tables.borrow().adjustments.contains_key(&new.id) {
+        let result = self.commit_if_ok(|_| {
             apply(&mut coerce, &|| Some(new), new_ty, prev_ty)
         });
         match result {
@@ -724,7 +727,7 @@ pub fn try_find_coercion_lub<'b, E, I>(&self,
     // This requires ensuring there are no coercions applied to *any* of the
     // previous expressions, other than noop reborrows (ignoring lifetimes).
     for expr in exprs() {
-        let noop = match self.inh.tables.borrow().adjustments.get(&expr.id) {
+        let noop = match self.tables.borrow().adjustments.get(&expr.id) {
             Some(&AdjustDerefRef(AutoDerefRef {
                 autoderefs: 1,
                 autoref: Some(AutoPtr(_, mutbl_adj)),
@@ -741,8 +744,8 @@ pub fn try_find_coercion_lub<'b, E, I>(&self,
         };
 
         if !noop {
-            return self.infcx().commit_if_ok(|_| {
-                self.infcx().lub(true, trace.clone(), &prev_ty, &new_ty)
+            return self.commit_if_ok(|_| {
+                self.lub(true, trace.clone(), &prev_ty, &new_ty)
                     .map(|InferOk { value, obligations }| {
                         // FIXME(#32730) propagate obligations
                         assert!(obligations.is_empty());
@@ -752,14 +755,14 @@ pub fn try_find_coercion_lub<'b, E, I>(&self,
         }
     }
 
-    match self.infcx().commit_if_ok(|_| apply(&mut coerce, &exprs, prev_ty, new_ty)) {
+    match self.commit_if_ok(|_| apply(&mut coerce, &exprs, prev_ty, new_ty)) {
         Err(_) => {
             // Avoid giving strange errors on failed attempts.
             if let Some(e) = first_error {
                 Err(e)
             } else {
-                self.infcx().commit_if_ok(|_| {
-                    self.infcx().lub(true, trace, &prev_ty, &new_ty)
+                self.commit_if_ok(|_| {
+                    self.lub(true, trace, &prev_ty, &new_ty)
                         .map(|InferOk { value, obligations }| {
                             // FIXME(#32730) propagate obligations
                             assert!(obligations.is_empty());
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index f80e715721c..4f4b7fa9ef7 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -21,37 +21,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
 // they don't.
 pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
     let origin = TypeOrigin::Misc(sp);
-    match self.infcx().sub_types(false, origin, actual, expected) {
+    match self.sub_types(false, origin, actual, expected) {
         Ok(InferOk { obligations, .. }) => {
             // FIXME(#32730) propagate obligations
             assert!(obligations.is_empty());
         },
         Err(e) => {
-            self.infcx().report_mismatched_types(origin, expected, actual, e);
+            self.report_mismatched_types(origin, expected, actual, e);
         }
     }
 }
 
 pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
     let origin = TypeOrigin::Misc(sp);
-    match self.infcx().eq_types(false, origin, actual, expected) {
+    match self.eq_types(false, origin, actual, expected) {
         Ok(InferOk { obligations, .. }) => {
             // FIXME(#32730) propagate obligations
             assert!(obligations.is_empty());
         },
         Err(e) => {
-            self.infcx().report_mismatched_types(origin, expected, actual, e);
+            self.report_mismatched_types(origin, expected, actual, e);
         }
     }
 }
 
 // Checks that the type of `expr` can be coerced to `expected`.
 pub fn demand_coerce(&self, expr: &hir::Expr, expected: Ty<'tcx>) {
-    let expected = self.resolve_type_vars_if_possible(expected);
+    let expected = self.resolve_type_vars_with_obligations(expected);
     if let Err(e) = self.try_coerce(expr, expected) {
         let origin = TypeOrigin::Misc(expr.span);
-        let expr_ty = self.resolve_type_vars_if_possible(self.expr_ty(expr));
-        self.infcx().report_mismatched_types(origin, expected, expr_ty, e);
+        let expr_ty = self.resolve_type_vars_with_obligations(self.expr_ty(expr));
+        self.report_mismatched_types(origin, expected, expr_ty, e);
     }
 }
 }
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index e5f14478025..b705dee4ae8 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -281,7 +281,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut RegionCtxt<'a
     debug!("check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}",
            typ, scope);
 
-    let parent_scope = rcx.tcx().region_maps.opt_encl_scope(scope).unwrap_or_else(|| {
+    let parent_scope = rcx.tcx.region_maps.opt_encl_scope(scope).unwrap_or_else(|| {
         span_bug!(span, "no enclosing scope found for scope: {:?}", scope)
     });
 
@@ -298,7 +298,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut RegionCtxt<'a
     match result {
         Ok(()) => {}
         Err(Error::Overflow(ref ctxt, ref detected_on_typ)) => {
-            let tcx = rcx.tcx();
+            let tcx = rcx.tcx;
             let mut err = struct_span_err!(tcx.sess, span, E0320,
                                            "overflow while adding drop-check rules for {}", typ);
             match *ctxt {
@@ -360,7 +360,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>(
     ty: Ty<'tcx>,
     depth: usize) -> Result<(), Error<'tcx>>
 {
-    let tcx = cx.rcx.tcx();
+    let tcx = cx.rcx.tcx;
     // Issue #22443: Watch out for overflow. While we are careful to
     // handle regular types properly, non-regular ones cause problems.
     let recursion_limit = tcx.sess.recursion_limit.get();
@@ -373,7 +373,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>(
 
     // canoncialize the regions in `ty` before inserting - infinitely many
     // region variables can refer to the same region.
-    let ty = cx.rcx.infcx().resolve_type_and_region_vars_if_possible(&ty);
+    let ty = cx.rcx.resolve_type_and_region_vars_if_possible(&ty);
 
     if !cx.breadcrumbs.insert(ty) {
         debug!("iterate_over_potentially_unsafe_regions_in_type \
@@ -453,7 +453,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>(
             for variant in &def.variants {
                 for field in variant.fields.iter() {
                     let fty = field.ty(tcx, substs);
-                    let fty = cx.rcx.fcx.resolve_type_vars_if_possible(
+                    let fty = cx.rcx.fcx.resolve_type_vars_with_obligations(
                         cx.rcx.fcx.normalize_associated_types_in(cx.span, &fty));
                     iterate_over_potentially_unsafe_regions_in_type(
                         cx,
@@ -504,7 +504,7 @@ fn has_dtor_of_interest<'a, 'b, 'tcx>(cx: &DropckContext<'a, 'b, 'tcx, 'tcx>,
                                       ty: ty::Ty<'tcx>) -> bool {
     match ty.sty {
         ty::TyEnum(def, _) | ty::TyStruct(def, _) => {
-            def.is_dtorck(cx.rcx.tcx())
+            def.is_dtorck(cx.rcx.tcx)
         }
         ty::TyTrait(..) | ty::TyProjection(..) => {
             debug!("ty: {:?} isn't known, and therefore is a dropck type", ty);
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index a2570ef8eef..ca17f4bd3a8 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -15,14 +15,15 @@ use check::UnresolvedTypeAction;
 use hir::def_id::DefId;
 use rustc::ty::subst::{self};
 use rustc::traits;
-use rustc::ty::{self, NoPreference, PreferMutLvalue, Ty, TyCtxt};
+use rustc::ty::{self, NoPreference, PreferMutLvalue, Ty};
 use rustc::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr};
 use rustc::ty::fold::TypeFoldable;
-use rustc::infer;
-use rustc::infer::{InferCtxt, InferOk, TypeOrigin};
+use rustc::infer::{self, InferOk, TypeOrigin};
 use syntax::codemap::Span;
 use rustc::hir;
 
+use std::ops::Deref;
+
 struct ConfirmContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a>{
     fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
     span: Span,
@@ -30,6 +31,13 @@ struct ConfirmContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a>{
     call_expr: &'gcx hir::Expr,
 }
 
+impl<'a, 'gcx, 'tcx> Deref for ConfirmContext<'a, 'gcx, 'tcx> {
+    type Target = FnCtxt<'a, 'gcx, 'tcx>;
+    fn deref(&self) -> &Self::Target {
+        &self.fcx
+    }
+}
+
 struct InstantiatedMethodSig<'tcx> {
     /// Function signature of the method being invoked. The 0th
     /// argument is the receiver.
@@ -100,7 +108,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx, 'tcx> {
         let InstantiatedMethodSig {
             method_sig, all_substs, method_predicates
         } = self.instantiate_method_sig(&pick, all_substs);
-        let all_substs = self.tcx().mk_substs(all_substs);
+        let all_substs = self.tcx.mk_substs(all_substs);
         let method_self_ty = method_sig.inputs[0];
 
         // Unify the (adjusted) self type with what the method expects.
@@ -109,7 +117,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx, 'tcx> {
         // Create the method type
         let def_id = pick.item.def_id();
         let method_ty = pick.item.as_opt_method().unwrap();
-        let fty = self.tcx().mk_fn_def(def_id, all_substs, ty::BareFnTy {
+        let fty = self.tcx.mk_fn_def(def_id, all_substs, ty::BareFnTy {
             sig: ty::Binder(method_sig),
             unsafety: method_ty.fty.unsafety,
             abi: method_ty.fty.abi.clone(),
@@ -141,10 +149,10 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx, 'tcx> {
                       -> Ty<'tcx>
     {
         let (autoref, unsize) = if let Some(mutbl) = pick.autoref {
-            let region = self.infcx().next_region_var(infer::Autoref(self.span));
-            let autoref = AutoPtr(self.tcx().mk_region(region), mutbl);
+            let region = self.next_region_var(infer::Autoref(self.span));
+            let autoref = AutoPtr(self.tcx.mk_region(region), mutbl);
             (Some(autoref), pick.unsize.map(|target| {
-                target.adjust_for_autoref(self.tcx(), Some(autoref))
+                target.adjust_for_autoref(self.tcx, Some(autoref))
             }))
         } else {
             // No unsizing should be performed without autoref (at
@@ -157,12 +165,12 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx, 'tcx> {
 
         // Commit the autoderefs by calling `autoderef again, but this
         // time writing the results into the various tables.
-        let (autoderefd_ty, n, result) = self.fcx.autoderef(self.span,
-                                                            unadjusted_self_ty,
-                                                            || Some(self.self_expr),
-                                                            UnresolvedTypeAction::Error,
-                                                            NoPreference,
-                                                            |_, n| {
+        let (autoderefd_ty, n, result) = self.autoderef(self.span,
+                                                        unadjusted_self_ty,
+                                                        || Some(self.self_expr),
+                                                        UnresolvedTypeAction::Error,
+                                                        NoPreference,
+                                                        |_, n| {
             if n == pick.autoderefs {
                 Some(())
             } else {
@@ -173,8 +181,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx, 'tcx> {
         assert_eq!(result, Some(()));
 
         // Write out the final adjustment.
-        self.fcx.write_adjustment(self.self_expr.id,
-                                  AdjustDerefRef(AutoDerefRef {
+        self.write_adjustment(self.self_expr.id, AdjustDerefRef(AutoDerefRef {
             autoderefs: pick.autoderefs,
             autoref: autoref,
             unsize: unsize
@@ -183,7 +190,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx, 'tcx> {
         if let Some(target) = unsize {
             target
         } else {
-            autoderefd_ty.adjust_for_autoref(self.tcx(), autoref)
+            autoderefd_ty.adjust_for_autoref(self.tcx, autoref)
         }
     }
 
@@ -204,9 +211,9 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx, 'tcx> {
         match pick.kind {
             probe::InherentImplPick => {
                 let impl_def_id = pick.item.container().id();
-                assert!(self.tcx().impl_trait_ref(impl_def_id).is_none(),
+                assert!(self.tcx.impl_trait_ref(impl_def_id).is_none(),
                         "impl {:?} is not an inherent impl", impl_def_id);
-                self.fcx.impl_self_ty(self.span, impl_def_id).substs
+                self.impl_self_ty(self.span, impl_def_id).substs
             }
 
             probe::ObjectPick => {
@@ -223,7 +230,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx, 'tcx> {
                     // been ruled out when we deemed the trait to be
                     // "object safe".
                     let original_poly_trait_ref =
-                        data.principal_trait_ref_with_self_ty(this.tcx(), object_ty);
+                        data.principal_trait_ref_with_self_ty(this.tcx, object_ty);
                     let upcast_poly_trait_ref =
                         this.upcast(original_poly_trait_ref.clone(), trait_def_id);
                     let upcast_trait_ref =
@@ -246,27 +253,27 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx, 'tcx> {
                 // respectively, then we want to return the type
                 // parameters from the trait ([$A,$B]), not those from
                 // the impl ([$A,$B,$C]) not the receiver type ([$C]).
-                let impl_polytype = self.fcx.impl_self_ty(self.span, impl_def_id);
+                let impl_polytype = self.impl_self_ty(self.span, impl_def_id);
                 let impl_trait_ref =
-                    self.fcx.instantiate_type_scheme(
+                    self.instantiate_type_scheme(
                         self.span,
                         &impl_polytype.substs,
-                        &self.tcx().impl_trait_ref(impl_def_id).unwrap());
+                        &self.tcx.impl_trait_ref(impl_def_id).unwrap());
                 impl_trait_ref.substs.clone()
             }
 
             probe::TraitPick => {
                 let trait_def_id = pick.item.container().id();
-                let trait_def = self.tcx().lookup_trait_def(trait_def_id);
+                let trait_def = self.tcx.lookup_trait_def(trait_def_id);
 
                 // Make a trait reference `$0 : Trait<$1...$n>`
                 // consisting entirely of type variables. Later on in
                 // the process we will unify the transformed-self-type
                 // of the method with the actual type in order to
                 // unify some of these variables.
-                self.infcx().fresh_substs_for_trait(self.span,
-                                                    &trait_def.generics,
-                                                    self.infcx().next_ty_var())
+                self.fresh_substs_for_trait(self.span,
+                                            &trait_def.generics,
+                                            self.next_ty_var())
             }
 
             probe::WhereClausePick(ref poly_trait_ref) => {
@@ -328,7 +335,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx, 'tcx> {
         //
         // FIXME -- permit users to manually specify lifetimes
         let method_regions =
-            self.fcx.infcx().region_vars_for_defs(
+            self.region_vars_for_defs(
                 self.span,
                 pick.item.as_opt_method().unwrap()
                     .generics.regions.get_slice(subst::FnSpace));
@@ -338,26 +345,26 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx, 'tcx> {
         let mut final_substs = subst::Substs { types: types, regions: regions };
 
         if num_supplied_types == 0 {
-            self.fcx.infcx().type_vars_for_defs(
+            self.type_vars_for_defs(
                 self.span,
                 subst::FnSpace,
                 &mut final_substs,
                 method_types);
         } else if num_method_types == 0 {
-            span_err!(self.tcx().sess, self.span, E0035,
+            span_err!(self.tcx.sess, self.span, E0035,
                 "does not take type parameters");
-            self.fcx.infcx().type_vars_for_defs(
+            self.type_vars_for_defs(
                 self.span,
                 subst::FnSpace,
                 &mut final_substs,
                 method_types);
         } else if num_supplied_types != num_method_types {
-            span_err!(self.tcx().sess, self.span, E0036,
+            span_err!(self.tcx.sess, self.span, E0036,
                 "incorrect number of type parameters given for this method: expected {}, found {}",
                 num_method_types, num_supplied_types);
             final_substs.types.replace(
                 subst::FnSpace,
-                vec![self.tcx().types.err; num_method_types]);
+                vec![self.tcx.types.err; num_method_types]);
         } else {
             final_substs.types.replace(subst::FnSpace, supplied_method_types);
         }
@@ -369,8 +376,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx, 'tcx> {
                        self_ty: Ty<'tcx>,
                        method_self_ty: Ty<'tcx>)
     {
-        match self.fcx.infcx().sub_types(false, TypeOrigin::Misc(self.span),
-                                         self_ty, method_self_ty) {
+        match self.sub_types(false, TypeOrigin::Misc(self.span),
+                             self_ty, method_self_ty) {
             Ok(InferOk { obligations, .. }) => {
                 // FIXME(#32730) propagate obligations
                 assert!(obligations.is_empty());
@@ -400,9 +407,9 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx, 'tcx> {
         // type/early-bound-regions substitutions performed. There can
         // be no late-bound regions appearing here.
         let method_predicates = pick.item.as_opt_method().unwrap()
-                                    .predicates.instantiate(self.tcx(), &all_substs);
-        let method_predicates = self.fcx.normalize_associated_types_in(self.span,
-                                                                       &method_predicates);
+                                    .predicates.instantiate(self.tcx, &all_substs);
+        let method_predicates = self.normalize_associated_types_in(self.span,
+                                                                   &method_predicates);
 
         debug!("method_predicates after subst = {:?}",
                method_predicates);
@@ -418,7 +425,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx, 'tcx> {
         debug!("late-bound lifetimes from method instantiated, method_sig={:?}",
                method_sig);
 
-        let method_sig = self.fcx.instantiate_type_scheme(self.span, &all_substs, &method_sig);
+        let method_sig = self.instantiate_type_scheme(self.span, &all_substs, &method_sig);
         debug!("type scheme substituted, method_sig={:?}",
                method_sig);
 
@@ -438,20 +445,18 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx, 'tcx> {
                all_substs,
                method_predicates);
 
-        self.fcx.add_obligations_for_parameters(
-            traits::ObligationCause::misc(self.span, self.fcx.body_id),
+        self.add_obligations_for_parameters(
+            traits::ObligationCause::misc(self.span, self.body_id),
             method_predicates);
 
         // this is a projection from a trait reference, so we have to
         // make sure that the trait reference inputs are well-formed.
-        self.fcx.add_wf_bounds(
-            all_substs,
-            self.call_expr);
+        self.add_wf_bounds(all_substs, self.call_expr);
 
         // the function type must also be well-formed (this is not
         // implied by the substs being well-formed because of inherent
         // impls and late-bound regions - see issue #28609).
-        self.fcx.register_wf_obligation(fty, self.span, traits::MiscObligation);
+        self.register_wf_obligation(fty, self.span, traits::MiscObligation);
     }
 
     ///////////////////////////////////////////////////////////////////////////
@@ -495,9 +500,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx, 'tcx> {
         // Fix up autoderefs and derefs.
         for (i, &expr) in exprs.iter().rev().enumerate() {
             // Count autoderefs.
-            let autoderef_count = match self.fcx
-                                            .inh
-                                            .tables
+            let autoderef_count = match self.tables
                                             .borrow()
                                             .adjustments
                                             .get(&expr.id) {
@@ -510,12 +513,12 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx, 'tcx> {
                    i, expr, autoderef_count);
 
             if autoderef_count > 0 {
-                self.fcx.autoderef(expr.span,
-                                   self.fcx.expr_ty(expr),
-                                   || Some(expr),
-                                   UnresolvedTypeAction::Error,
-                                   PreferMutLvalue,
-                                   |_, autoderefs| {
+                self.autoderef(expr.span,
+                               self.expr_ty(expr),
+                               || Some(expr),
+                               UnresolvedTypeAction::Error,
+                               PreferMutLvalue,
+                               |_, autoderefs| {
                     if autoderefs == autoderef_count + 1 {
                         Some(())
                     } else {
@@ -538,8 +541,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx, 'tcx> {
                     // expects. This is annoying and horrible. We
                     // ought to recode this routine so it doesn't
                     // (ab)use the normal type checking paths.
-                    let adj = self.fcx.inh.tables.borrow().adjustments.get(&base_expr.id)
-                                                                        .cloned();
+                    let adj = self.tables.borrow().adjustments.get(&base_expr.id).cloned();
                     let (autoderefs, unsize) = match adj {
                         Some(AdjustDerefRef(adr)) => match adr.autoref {
                             None => {
@@ -570,16 +572,16 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx, 'tcx> {
                     let (adjusted_base_ty, unsize) = if let Some(target) = unsize {
                         (target, true)
                     } else {
-                        (self.fcx.adjust_expr_ty(base_expr,
+                        (self.adjust_expr_ty(base_expr,
                             Some(&AdjustDerefRef(AutoDerefRef {
                                 autoderefs: autoderefs,
                                 autoref: None,
                                 unsize: None
                             }))), false)
                     };
-                    let index_expr_ty = self.fcx.expr_ty(&index_expr);
+                    let index_expr_ty = self.expr_ty(&index_expr);
 
-                    let result = self.fcx.try_index_step(
+                    let result = self.try_index_step(
                         ty::MethodCall::expr(expr.id),
                         expr,
                         &base_expr,
@@ -590,23 +592,23 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx, 'tcx> {
                         index_expr_ty);
 
                     if let Some((input_ty, return_ty)) = result {
-                        self.fcx.demand_suptype(index_expr.span, input_ty, index_expr_ty);
+                        self.demand_suptype(index_expr.span, input_ty, index_expr_ty);
 
-                        let expr_ty = self.fcx.expr_ty(&expr);
-                        self.fcx.demand_suptype(expr.span, expr_ty, return_ty);
+                        let expr_ty = self.expr_ty(&expr);
+                        self.demand_suptype(expr.span, expr_ty, return_ty);
                     }
                 }
                 hir::ExprUnary(hir::UnDeref, ref base_expr) => {
                     // if this is an overloaded deref, then re-evaluate with
                     // a preference for mut
                     let method_call = ty::MethodCall::expr(expr.id);
-                    if self.fcx.inh.tables.borrow().method_map.contains_key(&method_call) {
-                        let method = self.fcx.try_overloaded_deref(expr.span,
+                    if self.tables.borrow().method_map.contains_key(&method_call) {
+                        let method = self.try_overloaded_deref(expr.span,
                             Some(&base_expr),
-                            self.fcx.expr_ty(&base_expr),
+                            self.expr_ty(&base_expr),
                             PreferMutLvalue);
                         let method = method.expect("re-trying deref failed");
-                        self.fcx.inh.tables.borrow_mut().method_map.insert(method_call, method);
+                        self.tables.borrow_mut().method_map.insert(method_call, method);
                     }
                 }
                 _ => {}
@@ -617,19 +619,11 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx, 'tcx> {
     ///////////////////////////////////////////////////////////////////////////
     // MISCELLANY
 
-    fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
-        self.fcx.tcx()
-    }
-
-    fn infcx(&self) -> &'a InferCtxt<'a, 'tcx, 'tcx> {
-        self.fcx.infcx()
-    }
-
     fn enforce_illegal_method_limitations(&self, pick: &probe::Pick) {
         // Disallow calls to the method `drop` defined in the `Drop` trait.
         match pick.item.container() {
             ty::TraitContainer(trait_def_id) => {
-                callee::check_legal_trait_for_method_call(self.fcx.ccx, self.span, trait_def_id)
+                callee::check_legal_trait_for_method_call(self.ccx, self.span, trait_def_id)
             }
             ty::ImplContainer(..) => {}
         }
@@ -640,8 +634,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx, 'tcx> {
               target_trait_def_id: DefId)
               -> ty::PolyTraitRef<'tcx>
     {
-        let upcast_trait_refs = self.tcx().upcast_choices(source_trait_ref.clone(),
-                                                          target_trait_def_id);
+        let upcast_trait_refs = self.tcx.upcast_choices(source_trait_ref.clone(),
+                                                        target_trait_def_id);
 
         // must be exactly one trait ref or we'd get an ambig error etc
         if upcast_trait_refs.len() != 1 {
@@ -659,7 +653,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx, 'tcx> {
     fn replace_late_bound_regions_with_fresh_var<T>(&self, value: &ty::Binder<T>) -> T
         where T : TypeFoldable<'tcx>
     {
-        self.infcx().replace_late_bound_regions_with_fresh_var(
+        self.fcx.replace_late_bound_regions_with_fresh_var(
             self.span, infer::FnCall, value).0
     }
 }
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index ae3446bbde8..f63f9870977 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -127,11 +127,11 @@ pub fn lookup_method(&self,
            self_expr);
 
     let mode = probe::Mode::MethodCall;
-    let self_ty = self.infcx().resolve_type_vars_if_possible(&self_ty);
+    let self_ty = self.resolve_type_vars_if_possible(&self_ty);
     let pick = self.probe_method(span, mode, method_name, self_ty, call_expr.id)?;
 
     if let Some(import_id) = pick.import_id {
-        self.tcx().used_trait_imports.borrow_mut().insert(import_id);
+        self.tcx.used_trait_imports.borrow_mut().insert(import_id);
     }
 
     Ok(self.confirm_method(span, self_expr, call_expr, self_ty, pick, supplied_method_types))
@@ -176,7 +176,7 @@ pub fn lookup_method_in_trait_adjusted(&self,
            m_name,
            trait_def_id);
 
-    let trait_def = self.tcx().lookup_trait_def(trait_def_id);
+    let trait_def = self.tcx.lookup_trait_def(trait_def_id);
 
     let type_parameter_defs = trait_def.generics.types.get_slice(subst::TypeSpace);
     let expected_number_of_input_types = type_parameter_defs.len();
@@ -194,7 +194,7 @@ pub fn lookup_method_in_trait_adjusted(&self,
         }
 
         None => {
-            self.inh.infcx.type_vars_for_defs(
+            self.type_vars_for_defs(
                 span,
                 subst::ParamSpace::TypeSpace,
                 &mut substs,
@@ -202,7 +202,7 @@ pub fn lookup_method_in_trait_adjusted(&self,
         }
     }
 
-    let trait_ref = ty::TraitRef::new(trait_def_id, self.tcx().mk_substs(substs));
+    let trait_ref = ty::TraitRef::new(trait_def_id, self.tcx.mk_substs(substs));
 
     // Construct an obligation
     let poly_trait_ref = trait_ref.to_poly_trait_ref();
@@ -211,7 +211,7 @@ pub fn lookup_method_in_trait_adjusted(&self,
                                               poly_trait_ref.to_predicate());
 
     // Now we want to know if this can be matched
-    let mut selcx = traits::SelectionContext::new(self.infcx());
+    let mut selcx = traits::SelectionContext::new(self);
     if !selcx.evaluate_obligation(&obligation) {
         debug!("--> Cannot match obligation");
         return None; // Cannot be matched, no such method resolution is possible.
@@ -219,7 +219,7 @@ pub fn lookup_method_in_trait_adjusted(&self,
 
     // Trait must have a method named `m_name` and it should not have
     // type parameters or early-bound regions.
-    let tcx = self.tcx();
+    let tcx = self.tcx;
     let method_item = self.trait_item(trait_def_id, m_name).unwrap();
     let method_ty = method_item.as_opt_method().unwrap();
     assert_eq!(method_ty.generics.types.len(subst::FnSpace), 0);
@@ -234,9 +234,9 @@ pub fn lookup_method_in_trait_adjusted(&self,
     // NB: Instantiate late-bound regions first so that
     // `instantiate_type_scheme` can normalize associated types that
     // may reference those regions.
-    let fn_sig = self.infcx().replace_late_bound_regions_with_fresh_var(span,
-                                                                        infer::FnCall,
-                                                                        &method_ty.fty.sig).0;
+    let fn_sig = self.replace_late_bound_regions_with_fresh_var(span,
+                                                                infer::FnCall,
+                                                                &method_ty.fty.sig).0;
     let fn_sig = self.instantiate_type_scheme(span, trait_ref.substs, &fn_sig);
     let transformed_self_ty = fn_sig.inputs[0];
     let def_id = method_item.def_id();
@@ -347,14 +347,14 @@ pub fn resolve_ufcs(&self,
     let pick = self.probe_method(span, mode, method_name, self_ty, expr_id)?;
 
     if let Some(import_id) = pick.import_id {
-        self.tcx().used_trait_imports.borrow_mut().insert(import_id);
+        self.tcx.used_trait_imports.borrow_mut().insert(import_id);
     }
 
     let def = pick.item.def();
     if let probe::InherentImplPick = pick.kind {
-        if !pick.item.vis().is_accessible_from(self.body_id, &self.tcx().map) {
+        if !pick.item.vis().is_accessible_from(self.body_id, &self.tcx.map) {
             let msg = format!("{} `{}` is private", def.kind_name(), &method_name.as_str());
-            self.tcx().sess.span_err(span, &msg);
+            self.tcx.sess.span_err(span, &msg);
         }
     }
     Ok(def)
@@ -367,7 +367,7 @@ pub fn trait_item(&self,
                   item_name: ast::Name)
                   -> Option<ty::ImplOrTraitItem<'tcx>>
 {
-    let trait_items = self.tcx().trait_items(trait_def_id);
+    let trait_items = self.tcx.trait_items(trait_def_id);
     trait_items.iter()
                .find(|item| item.name() == item_name)
                .cloned()
@@ -378,11 +378,11 @@ pub fn impl_item(&self,
                  item_name: ast::Name)
                  -> Option<ty::ImplOrTraitItem<'tcx>>
 {
-    let impl_items = self.tcx().impl_items.borrow();
+    let impl_items = self.tcx.impl_items.borrow();
     let impl_items = impl_items.get(&impl_def_id).unwrap();
     impl_items
         .iter()
-        .map(|&did| self.tcx().impl_or_trait_item(did.def_id()))
+        .map(|&did| self.tcx.impl_or_trait_item(did.def_id()))
         .find(|m| m.name() == item_name)
 }
 }
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 00c90dcbee4..6ee309516a0 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -19,13 +19,14 @@ use hir::def::Def;
 use rustc::ty::subst;
 use rustc::ty::subst::Subst;
 use rustc::traits;
-use rustc::ty::{self, NoPreference, Ty, TyCtxt, ToPolyTraitRef, TraitRef, TypeFoldable};
-use rustc::infer::{self, InferCtxt, InferOk, TypeOrigin};
+use rustc::ty::{self, NoPreference, Ty, ToPolyTraitRef, TraitRef, TypeFoldable};
+use rustc::infer::{InferOk, TypeOrigin};
 use syntax::ast;
 use syntax::codemap::{Span, DUMMY_SP};
 use rustc::hir;
 use std::collections::HashSet;
 use std::mem;
+use std::ops::Deref;
 use std::rc::Rc;
 
 use self::CandidateKind::*;
@@ -55,6 +56,13 @@ struct ProbeContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     unsatisfied_predicates: Vec<TraitRef<'tcx>>
 }
 
+impl<'a, 'gcx, 'tcx> Deref for ProbeContext<'a, 'gcx, 'tcx> {
+    type Target = FnCtxt<'a, 'gcx, 'tcx>;
+    fn deref(&self) -> &Self::Target {
+        &self.fcx
+    }
+}
+
 #[derive(Debug)]
 struct CandidateStep<'tcx> {
     self_ty: Ty<'tcx>,
@@ -148,7 +156,7 @@ pub fn probe_method(&self,
     // side-effects. This is a bit of a pain to refactor. So just let
     // it ride, although it's really not great, and in fact could I
     // think cause spurious errors. Really though this part should
-    // take place in the `self.infcx().probe` below.
+    // take place in the `self.probe` below.
     let steps = if mode == Mode::MethodCall {
         match self.create_steps(span, self_ty) {
             Some(steps) => steps,
@@ -166,7 +174,7 @@ pub fn probe_method(&self,
     // Create a list of simplified self types, if we can.
     let mut simplified_steps = Vec::new();
     for step in &steps {
-        match ty::fast_reject::simplify_type(self.tcx(), step.self_ty, true) {
+        match ty::fast_reject::simplify_type(self.tcx, step.self_ty, true) {
             None => { break; }
             Some(simplified_type) => { simplified_steps.push(simplified_type); }
         }
@@ -184,7 +192,7 @@ pub fn probe_method(&self,
 
     // this creates one big transaction so that all type variables etc
     // that we create during the probe process are removed later
-    self.infcx().probe(|_| {
+    self.probe(|_| {
         let mut probe_cx = ProbeContext::new(self,
                                              span,
                                              mode,
@@ -220,7 +228,7 @@ fn create_steps(&self,
     match final_ty.sty {
         ty::TyArray(elem_ty, _) => {
             steps.push(CandidateStep {
-                self_ty: self.tcx().mk_slice(elem_ty),
+                self_ty: self.tcx.mk_slice(elem_ty),
                 autoderefs: dereferences,
                 unsize: true
             });
@@ -267,14 +275,6 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
         self.private_candidate = None;
     }
 
-    fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
-        self.fcx.tcx()
-    }
-
-    fn infcx(&self) -> &'a InferCtxt<'a, 'tcx, 'tcx> {
-        self.fcx.infcx()
-    }
-
     ///////////////////////////////////////////////////////////////////////////
     // CANDIDATE ASSEMBLY
 
@@ -299,7 +299,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
                 self.assemble_inherent_impl_candidates_for_type(def.did);
             }
             ty::TyBox(_) => {
-                if let Some(box_did) = self.tcx().lang_items.owned_box() {
+                if let Some(box_did) = self.tcx.lang_items.owned_box() {
                     self.assemble_inherent_impl_candidates_for_type(box_did);
                 }
             }
@@ -307,71 +307,71 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
                 self.assemble_inherent_candidates_from_param(self_ty, p);
             }
             ty::TyChar => {
-                let lang_def_id = self.tcx().lang_items.char_impl();
+                let lang_def_id = self.tcx.lang_items.char_impl();
                 self.assemble_inherent_impl_for_primitive(lang_def_id);
             }
             ty::TyStr => {
-                let lang_def_id = self.tcx().lang_items.str_impl();
+                let lang_def_id = self.tcx.lang_items.str_impl();
                 self.assemble_inherent_impl_for_primitive(lang_def_id);
             }
             ty::TySlice(_) => {
-                let lang_def_id = self.tcx().lang_items.slice_impl();
+                let lang_def_id = self.tcx.lang_items.slice_impl();
                 self.assemble_inherent_impl_for_primitive(lang_def_id);
             }
             ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
-                let lang_def_id = self.tcx().lang_items.const_ptr_impl();
+                let lang_def_id = self.tcx.lang_items.const_ptr_impl();
                 self.assemble_inherent_impl_for_primitive(lang_def_id);
             }
             ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
-                let lang_def_id = self.tcx().lang_items.mut_ptr_impl();
+                let lang_def_id = self.tcx.lang_items.mut_ptr_impl();
                 self.assemble_inherent_impl_for_primitive(lang_def_id);
             }
             ty::TyInt(ast::IntTy::I8) => {
-                let lang_def_id = self.tcx().lang_items.i8_impl();
+                let lang_def_id = self.tcx.lang_items.i8_impl();
                 self.assemble_inherent_impl_for_primitive(lang_def_id);
             }
             ty::TyInt(ast::IntTy::I16) => {
-                let lang_def_id = self.tcx().lang_items.i16_impl();
+                let lang_def_id = self.tcx.lang_items.i16_impl();
                 self.assemble_inherent_impl_for_primitive(lang_def_id);
             }
             ty::TyInt(ast::IntTy::I32) => {
-                let lang_def_id = self.tcx().lang_items.i32_impl();
+                let lang_def_id = self.tcx.lang_items.i32_impl();
                 self.assemble_inherent_impl_for_primitive(lang_def_id);
             }
             ty::TyInt(ast::IntTy::I64) => {
-                let lang_def_id = self.tcx().lang_items.i64_impl();
+                let lang_def_id = self.tcx.lang_items.i64_impl();
                 self.assemble_inherent_impl_for_primitive(lang_def_id);
             }
             ty::TyInt(ast::IntTy::Is) => {
-                let lang_def_id = self.tcx().lang_items.isize_impl();
+                let lang_def_id = self.tcx.lang_items.isize_impl();
                 self.assemble_inherent_impl_for_primitive(lang_def_id);
             }
             ty::TyUint(ast::UintTy::U8) => {
-                let lang_def_id = self.tcx().lang_items.u8_impl();
+                let lang_def_id = self.tcx.lang_items.u8_impl();
                 self.assemble_inherent_impl_for_primitive(lang_def_id);
             }
             ty::TyUint(ast::UintTy::U16) => {
-                let lang_def_id = self.tcx().lang_items.u16_impl();
+                let lang_def_id = self.tcx.lang_items.u16_impl();
                 self.assemble_inherent_impl_for_primitive(lang_def_id);
             }
             ty::TyUint(ast::UintTy::U32) => {
-                let lang_def_id = self.tcx().lang_items.u32_impl();
+                let lang_def_id = self.tcx.lang_items.u32_impl();
                 self.assemble_inherent_impl_for_primitive(lang_def_id);
             }
             ty::TyUint(ast::UintTy::U64) => {
-                let lang_def_id = self.tcx().lang_items.u64_impl();
+                let lang_def_id = self.tcx.lang_items.u64_impl();
                 self.assemble_inherent_impl_for_primitive(lang_def_id);
             }
             ty::TyUint(ast::UintTy::Us) => {
-                let lang_def_id = self.tcx().lang_items.usize_impl();
+                let lang_def_id = self.tcx.lang_items.usize_impl();
                 self.assemble_inherent_impl_for_primitive(lang_def_id);
             }
             ty::TyFloat(ast::FloatTy::F32) => {
-                let lang_def_id = self.tcx().lang_items.f32_impl();
+                let lang_def_id = self.tcx.lang_items.f32_impl();
                 self.assemble_inherent_impl_for_primitive(lang_def_id);
             }
             ty::TyFloat(ast::FloatTy::F64) => {
-                let lang_def_id = self.tcx().lang_items.f64_impl();
+                let lang_def_id = self.tcx.lang_items.f64_impl();
                 self.assemble_inherent_impl_for_primitive(lang_def_id);
             }
             _ => {
@@ -381,7 +381,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
 
     fn assemble_inherent_impl_for_primitive(&mut self, lang_def_id: Option<DefId>) {
         if let Some(impl_def_id) = lang_def_id {
-            self.tcx().populate_implementations_for_primitive_if_necessary(impl_def_id);
+            self.tcx.populate_implementations_for_primitive_if_necessary(impl_def_id);
 
             self.assemble_inherent_impl_probe(impl_def_id);
         }
@@ -390,9 +390,9 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
     fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId) {
         // Read the inherent implementation candidates for this type from the
         // metadata if necessary.
-        self.tcx().populate_inherent_implementations_for_type_if_necessary(def_id);
+        self.tcx.populate_inherent_implementations_for_type_if_necessary(def_id);
 
-        if let Some(impl_infos) = self.tcx().inherent_impls.borrow().get(&def_id) {
+        if let Some(impl_infos) = self.tcx.inherent_impls.borrow().get(&def_id) {
             for &impl_def_id in impl_infos.iter() {
                 self.assemble_inherent_impl_probe(impl_def_id);
             }
@@ -416,21 +416,21 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
             return self.record_static_candidate(ImplSource(impl_def_id));
         }
 
-        if !item.vis().is_accessible_from(self.fcx.body_id, &self.tcx().map) {
+        if !item.vis().is_accessible_from(self.body_id, &self.tcx.map) {
             self.private_candidate = Some(item.def());
             return
         }
 
         let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id);
-        let impl_ty = impl_ty.subst(self.tcx(), &impl_substs);
+        let impl_ty = impl_ty.subst(self.tcx, &impl_substs);
 
         // Determine the receiver type that the method itself expects.
         let xform_self_ty = self.xform_self_ty(&item, impl_ty, &impl_substs);
 
         // We can't use normalize_associated_types_in as it will pollute the
         // fcx's fulfillment context after this probe is over.
-        let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
-        let mut selcx = &mut traits::SelectionContext::new(self.fcx.infcx());
+        let cause = traits::ObligationCause::misc(self.span, self.body_id);
+        let mut selcx = &mut traits::SelectionContext::new(self.fcx);
         let traits::Normalized { value: xform_self_ty, obligations } =
             traits::normalize(selcx, cause, &xform_self_ty);
         debug!("assemble_inherent_impl_probe: xform_self_ty = {:?}",
@@ -457,7 +457,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
         // a substitution that replaces `Self` with the object type
         // itself. Hence, a `&self` method will wind up with an
         // argument type like `&Trait`.
-        let trait_ref = data.principal_trait_ref_with_self_ty(self.tcx(), self_ty);
+        let trait_ref = data.principal_trait_ref_with_self_ty(self.tcx, self_ty);
         self.elaborate_bounds(&[trait_ref], |this, new_trait_ref, item| {
             let new_trait_ref = this.erase_late_bound_regions(&new_trait_ref);
 
@@ -480,7 +480,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
         // FIXME -- Do we want to commit to this behavior for param bounds?
 
         let bounds: Vec<_> =
-            self.fcx.inh.infcx.parameter_environment.caller_bounds
+            self.parameter_environment.caller_bounds
             .iter()
             .filter_map(|predicate| {
                 match *predicate {
@@ -561,7 +561,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
     {
         debug!("elaborate_bounds(bounds={:?})", bounds);
 
-        let tcx = self.tcx();
+        let tcx = self.tcx;
         for bound_trait_ref in traits::transitive_bounds(tcx, bounds) {
             let item = match self.trait_item(bound_trait_ref.def_id()) {
                 Some(v) => v,
@@ -581,7 +581,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
                                                          -> Result<(), MethodError<'tcx>>
     {
         let mut duplicates = HashSet::new();
-        let opt_applicable_traits = self.fcx.ccx.trait_map.get(&expr_id);
+        let opt_applicable_traits = self.ccx.trait_map.get(&expr_id);
         if let Some(applicable_traits) = opt_applicable_traits {
             for trait_candidate in applicable_traits {
                 let trait_did = trait_candidate.def_id;
@@ -598,7 +598,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
 
     fn assemble_extension_candidates_for_all_traits(&mut self) -> Result<(), MethodError<'tcx>> {
         let mut duplicates = HashSet::new();
-        for trait_info in suggest::all_traits(self.fcx.ccx) {
+        for trait_info in suggest::all_traits(self.ccx) {
             if duplicates.insert(trait_info.def_id) {
                 self.assemble_extension_candidates_for_trait(trait_info.def_id)?;
             }
@@ -615,7 +615,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
 
         // Check whether `trait_def_id` defines a method with suitable name:
         let trait_items =
-            self.tcx().trait_items(trait_def_id);
+            self.tcx.trait_items(trait_def_id);
         let maybe_item =
             trait_items.iter()
                        .find(|item| item.name() == self.item_name);
@@ -646,10 +646,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
                                                      trait_def_id: DefId,
                                                      item: ty::ImplOrTraitItem<'tcx>)
     {
-        let trait_def = self.tcx().lookup_trait_def(trait_def_id);
+        let trait_def = self.tcx.lookup_trait_def(trait_def_id);
 
         // FIXME(arielb1): can we use for_each_relevant_impl here?
-        trait_def.for_each_impl(self.tcx(), |impl_def_id| {
+        trait_def.for_each_impl(self.tcx, |impl_def_id| {
             debug!("assemble_extension_candidates_for_trait_impl: trait_def_id={:?} \
                                                                   impl_def_id={:?}",
                    trait_def_id,
@@ -664,9 +664,9 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
             debug!("impl_substs={:?}", impl_substs);
 
             let impl_trait_ref =
-                self.tcx().impl_trait_ref(impl_def_id)
+                self.tcx.impl_trait_ref(impl_def_id)
                 .unwrap() // we know this is a trait impl
-                .subst(self.tcx(), &impl_substs);
+                .subst(self.tcx, &impl_substs);
 
             debug!("impl_trait_ref={:?}", impl_trait_ref);
 
@@ -679,8 +679,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
             // Normalize the receiver. We can't use normalize_associated_types_in
             // as it will pollute the fcx's fulfillment context after this probe
             // is over.
-            let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
-            let mut selcx = &mut traits::SelectionContext::new(self.fcx.infcx());
+            let cause = traits::ObligationCause::misc(self.span, self.body_id);
+            let mut selcx = &mut traits::SelectionContext::new(self.fcx);
             let traits::Normalized { value: xform_self_ty, obligations } =
                 traits::normalize(selcx, cause, &xform_self_ty);
 
@@ -701,9 +701,9 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
             None => { return true; }
         };
 
-        let impl_type = self.tcx().lookup_item_type(impl_def_id);
+        let impl_type = self.tcx.lookup_item_type(impl_def_id);
         let impl_simplified_type =
-            match ty::fast_reject::simplify_type(self.tcx(), impl_type.ty, false) {
+            match ty::fast_reject::simplify_type(self.tcx, impl_type.ty, false) {
                 Some(simplified_type) => simplified_type,
                 None => { return true; }
             };
@@ -717,7 +717,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
                                    -> Result<(), MethodError<'tcx>>
     {
         // Check if this is one of the Fn,FnMut,FnOnce traits.
-        let tcx = self.tcx();
+        let tcx = self.tcx;
         let kind = if Some(trait_def_id) == tcx.lang_items.fn_trait() {
             ty::ClosureKind::Fn
         } else if Some(trait_def_id) == tcx.lang_items.fn_mut_trait() {
@@ -737,7 +737,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
                 _ => continue,
             };
 
-            let closure_kinds = &self.fcx.inh.tables.borrow().closure_kinds;
+            let closure_kinds = &self.tables.borrow().closure_kinds;
             let closure_kind = match closure_kinds.get(&closure_def_id) {
                 Some(&k) => k,
                 None => {
@@ -754,10 +754,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
             // for the purposes of our method lookup, we only take
             // receiver type into account, so we can just substitute
             // fresh types here to use during substitution and subtyping.
-            let trait_def = self.tcx().lookup_trait_def(trait_def_id);
-            let substs = self.infcx().fresh_substs_for_trait(self.span,
-                                                             &trait_def.generics,
-                                                             step.self_ty);
+            let trait_def = self.tcx.lookup_trait_def(trait_def_id);
+            let substs = self.fresh_substs_for_trait(self.span,
+                                                     &trait_def.generics,
+                                                     step.self_ty);
 
             let xform_self_ty = self.xform_self_ty(&item,
                                                    step.self_ty,
@@ -795,13 +795,13 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
             debug!("assemble_projection_candidates: projection_trait_ref={:?}",
                    projection_trait_ref);
 
-            let trait_predicates = self.tcx().lookup_predicates(projection_trait_ref.def_id);
-            let bounds = trait_predicates.instantiate(self.tcx(), projection_trait_ref.substs);
+            let trait_predicates = self.tcx.lookup_predicates(projection_trait_ref.def_id);
+            let bounds = trait_predicates.instantiate(self.tcx, projection_trait_ref.substs);
             let predicates = bounds.predicates.into_vec();
             debug!("assemble_projection_candidates: predicates={:?}",
                    predicates);
             for poly_bound in
-                traits::elaborate_predicates(self.tcx(), predicates)
+                traits::elaborate_predicates(self.tcx, predicates)
                 .filter_map(|p| p.to_opt_poly_trait_ref())
                 .filter(|b| b.def_id() == trait_def_id)
             {
@@ -811,7 +811,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
                        projection_trait_ref,
                        bound);
 
-                if self.infcx().can_equate(&step.self_ty, &bound.self_ty()).is_ok() {
+                if self.can_equate(&step.self_ty, &bound.self_ty()).is_ok() {
                     let xform_self_ty = self.xform_self_ty(&item,
                                                            bound.self_ty(),
                                                            bound.substs);
@@ -838,8 +838,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
         debug!("assemble_where_clause_candidates(trait_def_id={:?})",
                trait_def_id);
 
-        let caller_predicates = self.fcx.inh.infcx.parameter_environment.caller_bounds.clone();
-        for poly_bound in traits::elaborate_predicates(self.tcx(), caller_predicates)
+        let caller_predicates = self.parameter_environment.caller_bounds.clone();
+        for poly_bound in traits::elaborate_predicates(self.tcx, caller_predicates)
                           .filter_map(|p| p.to_opt_poly_trait_ref())
                           .filter(|b| b.def_id() == trait_def_id)
         {
@@ -878,7 +878,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
         self.reset();
 
         let span = self.span;
-        let tcx = self.tcx();
+        let tcx = self.tcx;
 
         self.assemble_extension_candidates_for_all_traits()?;
 
@@ -973,7 +973,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
                             step: &CandidateStep<'tcx>)
                             -> Option<PickResult<'tcx>>
     {
-        let tcx = self.tcx();
+        let tcx = self.tcx;
 
         // In general, during probing we erase regions. See
         // `impl_self_ty()` for an explanation.
@@ -999,7 +999,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
     }
 
     fn pick_method(&mut self, self_ty: Ty<'tcx>) -> Option<PickResult<'tcx>> {
-        debug!("pick_method(self_ty={})", self.infcx().ty_to_string(self_ty));
+        debug!("pick_method(self_ty={})", self.ty_to_string(self_ty));
 
         let mut possibly_unsatisfied_predicates = Vec::new();
 
@@ -1057,10 +1057,14 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
                self_ty,
                probe);
 
-        self.infcx().probe(|_| {
+        self.probe(|_| {
             // First check that the self type can be related.
-            match self.make_sub_ty(self_ty, probe.xform_self_ty) {
-                Ok(()) => { }
+            match self.sub_types(false, TypeOrigin::Misc(DUMMY_SP),
+                                 self_ty, probe.xform_self_ty) {
+                Ok(InferOk { obligations, .. }) => {
+                    // FIXME(#32730) propagate obligations
+                    assert!(obligations.is_empty())
+                }
                 Err(_) => {
                     debug!("--> cannot relate self-types");
                     return false;
@@ -1088,12 +1092,12 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
                 }
             };
 
-            let selcx = &mut traits::SelectionContext::new(self.infcx());
-            let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
+            let selcx = &mut traits::SelectionContext::new(self);
+            let cause = traits::ObligationCause::misc(self.span, self.body_id);
 
             // Check whether the impl imposes obligations we have to worry about.
-            let impl_bounds = self.tcx().lookup_predicates(impl_def_id);
-            let impl_bounds = impl_bounds.instantiate(self.tcx(), substs);
+            let impl_bounds = self.tcx.lookup_predicates(impl_def_id);
+            let impl_bounds = impl_bounds.instantiate(self.tcx, substs);
             let traits::Normalized { value: impl_bounds,
                                         obligations: norm_obligations } =
                 traits::normalize(selcx, cause.clone(), &impl_bounds);
@@ -1163,13 +1167,6 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
 
     ///////////////////////////////////////////////////////////////////////////
     // MISCELLANY
-
-    fn make_sub_ty(&self, sub: Ty<'tcx>, sup: Ty<'tcx>) -> infer::UnitResult<'tcx> {
-        self.infcx().sub_types(false, TypeOrigin::Misc(DUMMY_SP), sub, sup)
-            // FIXME(#32730) propagate obligations
-            .map(|InferOk { obligations, .. }| assert!(obligations.is_empty()))
-    }
-
     fn has_applicable_self(&self, item: &ty::ImplOrTraitItem) -> bool {
         // "fast track" -- check for usage of sugar
         match *item {
@@ -1249,7 +1246,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
 
             placeholder = (*substs).clone().with_method(Vec::new(), method_regions);
 
-            self.infcx().type_vars_for_defs(
+            self.type_vars_for_defs(
                 self.span,
                 subst::FnSpace,
                 &mut placeholder,
@@ -1262,7 +1259,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
         // in the values from the substitution.
         let xform_self_ty = method.fty.sig.input(0);
         let xform_self_ty = self.erase_late_bound_regions(&xform_self_ty);
-        let xform_self_ty = xform_self_ty.subst(self.tcx(), substs);
+        let xform_self_ty = xform_self_ty.subst(self.tcx, substs);
 
         xform_self_ty
     }
@@ -1272,11 +1269,11 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
                           impl_def_id: DefId)
                           -> (Ty<'tcx>, subst::Substs<'tcx>)
     {
-        let impl_pty = self.tcx().lookup_item_type(impl_def_id);
+        let impl_pty = self.tcx.lookup_item_type(impl_def_id);
 
         let type_vars =
             impl_pty.generics.types.map(
-                |_| self.infcx().next_ty_var());
+                |_| self.next_ty_var());
 
         let region_placeholders =
             impl_pty.generics.regions.map(
@@ -1307,7 +1304,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx, 'tcx> {
     fn erase_late_bound_regions<T>(&self, value: &ty::Binder<T>) -> T
         where T : TypeFoldable<'tcx>
     {
-        self.tcx().erase_late_bound_regions(value)
+        self.tcx.erase_late_bound_regions(value)
     }
 
     fn impl_item(&self, impl_def_id: DefId)
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index ab3c6b4513d..897a588bb62 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -41,7 +41,7 @@ use super::probe::Mode;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
 fn is_fn_ty(&self, ty: &Ty<'tcx>, span: Span) -> bool {
-    let tcx = self.tcx();
+    let tcx = self.tcx;
     match ty.sty {
         // Not all of these (e.g. unsafe fns) implement FnOnce
         // so we look for these beforehand
@@ -50,16 +50,15 @@ fn is_fn_ty(&self, ty: &Ty<'tcx>, span: Span) -> bool {
         _ => {
             if let Ok(fn_once_trait_did) =
                     tcx.lang_items.require(FnOnceTraitLangItem) {
-                let infcx = self.infcx();
                 let (_, _, opt_is_fn) = self.autoderef(span,
                                                        ty,
                                                        || None,
                                                        UnresolvedTypeAction::Ignore,
                                                        LvaluePreference::NoPreference,
                                                        |ty, _| {
-                    infcx.probe(|_| {
+                    self.probe(|_| {
                         let fn_once_substs =
-                            Substs::new_trait(vec![infcx.next_ty_var()], vec![], ty);
+                            Substs::new_trait(vec![self.next_ty_var()], vec![], ty);
                         let trait_ref =
                             ty::TraitRef::new(fn_once_trait_did,
                                               tcx.mk_substs(fn_once_substs));
@@ -68,7 +67,7 @@ fn is_fn_ty(&self, ty: &Ty<'tcx>, span: Span) -> bool {
                                                           self.body_id,
                                                           poly_trait_ref
                                                              .to_predicate());
-                        let mut selcx = SelectionContext::new(infcx);
+                        let mut selcx = SelectionContext::new(self);
 
                         if selcx.evaluate_obligation(&obligation) {
                             Some(())
@@ -111,22 +110,22 @@ pub fn report_method_error(&self,
                     let item = self.impl_item(impl_did, item_name)
                         .or_else(|| {
                             self.trait_item(
-                                self.tcx().impl_trait_ref(impl_did).unwrap().def_id,
+                                self.tcx.impl_trait_ref(impl_did).unwrap().def_id,
 
                                 item_name
                             )
                         }).unwrap();
-                    let note_span = self.tcx().map.span_if_local(item.def_id()).or_else(|| {
-                        self.tcx().map.span_if_local(impl_did)
+                    let note_span = self.tcx.map.span_if_local(item.def_id()).or_else(|| {
+                        self.tcx.map.span_if_local(impl_did)
                     });
 
                     let impl_ty = self.impl_self_ty(span, impl_did).ty;
 
-                    let insertion = match self.tcx().impl_trait_ref(impl_did) {
+                    let insertion = match self.tcx.impl_trait_ref(impl_did) {
                         None => format!(""),
                         Some(trait_ref) => {
                             format!(" of the trait `{}`",
-                                    self.tcx().item_path_str(trait_ref.def_id))
+                                    self.tcx.item_path_str(trait_ref.def_id))
                         }
                     };
 
@@ -144,11 +143,11 @@ pub fn report_method_error(&self,
                 }
                 CandidateSource::TraitSource(trait_did) => {
                     let item = self.trait_item(trait_did, item_name).unwrap();
-                    let item_span = self.tcx().map.def_id_span(item.def_id(), span);
+                    let item_span = self.tcx.map.def_id_span(item.def_id(), span);
                     span_note!(err, item_span,
                                "candidate #{} is defined in the trait `{}`",
                                idx + 1,
-                               self.tcx().item_path_str(trait_did));
+                               self.tcx.item_path_str(trait_did));
                 }
             }
         }
@@ -159,7 +158,7 @@ pub fn report_method_error(&self,
                                            unsatisfied_predicates,
                                            out_of_scope_traits,
                                            mode, .. }) => {
-            let tcx = self.tcx();
+            let tcx = self.tcx;
 
             let mut err = self.type_error_struct(
                 span,
@@ -258,7 +257,7 @@ pub fn report_method_error(&self,
                                invoked on this closure as we have not yet inferred what \
                                kind of closure it is",
                                item_name,
-                               self.tcx().item_path_str(trait_def_id));
+                               self.tcx.item_path_str(trait_def_id));
             let msg = if let Some(callee) = rcvr_expr {
                 format!("{}; use overloaded call notation instead (e.g., `{}()`)",
                         msg, pprust::expr_to_string(callee))
@@ -270,7 +269,7 @@ pub fn report_method_error(&self,
 
         MethodError::PrivateMatch(def) => {
             let msg = format!("{} `{}` is private", def.kind_name(), item_name);
-            self.tcx().sess.span_err(span, &msg);
+            self.tcx.sess.span_err(span, &msg);
         }
     }
 }
@@ -299,7 +298,7 @@ fn suggest_traits_to_import(&self,
         for (i, trait_did) in candidates.iter().enumerate() {
             err.help(&format!("candidate #{}: `use {}`",
                               i + 1,
-                              self.tcx().item_path_str(*trait_did)));
+                              self.tcx.item_path_str(*trait_did)));
         }
         return
     }
@@ -343,7 +342,7 @@ fn suggest_traits_to_import(&self,
         for (i, trait_info) in candidates.iter().enumerate() {
             err.help(&format!("candidate #{}: `{}`",
                               i + 1,
-                              self.tcx().item_path_str(trait_info.def_id)));
+                              self.tcx.item_path_str(trait_info.def_id)));
         }
     }
 }
@@ -373,7 +372,7 @@ fn type_derefs_to_local(&self,
     // This occurs for UFCS desugaring of `T::method`, where there is no
     // receiver expression for the method call, and thus no autoderef.
     if rcvr_expr.is_none() {
-        return is_local(self.resolve_type_vars_if_possible(rcvr_ty));
+        return is_local(self.resolve_type_vars_with_obligations(rcvr_ty));
     }
 
     self.autoderef(span, rcvr_ty, || None,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 486b353488e..0379fe13b18 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -97,7 +97,6 @@ use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
 use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, Visibility};
 use rustc::ty::{MethodCall, MethodCallee};
 use rustc::ty::adjustment;
-use rustc::ty::error::TypeError;
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::util::{Representability, IntTypeExt};
 use require_c_abi_if_variadic;
@@ -112,6 +111,7 @@ use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
 use std::cell::{Cell, Ref, RefCell};
 use std::collections::{HashSet};
 use std::mem::replace;
+use std::ops::Deref;
 use syntax::abi::Abi;
 use syntax::ast;
 use syntax::attr;
@@ -155,13 +155,12 @@ mod op;
 /// `bar()` will each have their own `FnCtxt`, but they will
 /// share the inherited fields.
 pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+    ccx: &'a CrateCtxt<'a, 'gcx>,
     infcx: InferCtxt<'a, 'gcx, 'tcx>,
     locals: RefCell<NodeMap<Ty<'tcx>>>,
 
     fulfillment_cx: RefCell<traits::FulfillmentContext<'tcx>>,
 
-    tables: &'a RefCell<ty::Tables<'tcx>>,
-
     // When we process a call like `c()` where `c` is a closure type,
     // we may not have decided yet whether `c` is a `Fn`, `FnMut`, or
     // `FnOnce` closure. In that case, we defer full resolution of the
@@ -174,6 +173,13 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     deferred_cast_checks: RefCell<Vec<cast::CastCheck<'tcx>>>,
 }
 
+impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> {
+    type Target = InferCtxt<'a, 'gcx, 'tcx>;
+    fn deref(&self) -> &Self::Target {
+        &self.infcx
+    }
+}
+
 trait DeferredCallResolution<'tcx> {
     fn resolve<'a>(&mut self, fcx: &FnCtxt<'a,'tcx, 'tcx>);
 }
@@ -218,7 +224,7 @@ impl<'a, 'tcx> Expectation<'tcx> {
     fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx, 'tcx>) -> Expectation<'tcx> {
         match *self {
             ExpectHasType(ety) => {
-                let ety = fcx.infcx().shallow_resolve(ety);
+                let ety = fcx.shallow_resolve(ety);
                 if !ety.is_ty_var() {
                     ExpectHasType(ety)
                 } else {
@@ -252,7 +258,7 @@ impl<'a, 'tcx> Expectation<'tcx> {
     /// See the test case `test/run-pass/coerce-expect-unsized.rs` and #20169
     /// for examples of where this comes up,.
     fn rvalue_hint(fcx: &FnCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> {
-        match fcx.tcx().struct_tail(ty).sty {
+        match fcx.tcx.struct_tail(ty).sty {
             ty::TySlice(_) | ty::TyStr | ty::TyTrait(..) => {
                 ExpectRvalueLikeUnsized(ty)
             }
@@ -269,16 +275,13 @@ impl<'a, 'tcx> Expectation<'tcx> {
                 NoExpectation
             }
             ExpectCastableToType(t) => {
-                ExpectCastableToType(
-                    fcx.infcx().resolve_type_vars_if_possible(&t))
+                ExpectCastableToType(fcx.resolve_type_vars_if_possible(&t))
             }
             ExpectHasType(t) => {
-                ExpectHasType(
-                    fcx.infcx().resolve_type_vars_if_possible(&t))
+                ExpectHasType(fcx.resolve_type_vars_if_possible(&t))
             }
             ExpectRvalueLikeUnsized(t) => {
-                ExpectRvalueLikeUnsized(
-                    fcx.infcx().resolve_type_vars_if_possible(&t))
+                ExpectRvalueLikeUnsized(fcx.resolve_type_vars_if_possible(&t))
             }
         }
     }
@@ -360,21 +363,29 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     ps: RefCell<UnsafetyState>,
 
     inh: &'a Inherited<'a, 'gcx, 'tcx>,
+}
 
-    ccx: &'a CrateCtxt<'a, 'gcx>,
+impl<'a, 'gcx, 'tcx> Deref for FnCtxt<'a, 'gcx, 'tcx> {
+    type Target = Inherited<'a, 'gcx, 'tcx>;
+    fn deref(&self) -> &Self::Target {
+        &self.inh
+    }
 }
 
 impl<'a, 'tcx> Inherited<'a, 'tcx, 'tcx> {
-    fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    fn new(ccx: &'a CrateCtxt<'a, 'tcx>,
            tables: &'a RefCell<ty::Tables<'tcx>>,
            param_env: ty::ParameterEnvironment<'a, 'tcx>)
            -> Inherited<'a, 'tcx, 'tcx> {
 
         Inherited {
-            infcx: InferCtxt::new(tcx, tables, Some(param_env), ProjectionMode::AnyFinal),
+            ccx: ccx,
+            infcx: InferCtxt::new(ccx.tcx,
+                                  tables,
+                                  Some(param_env),
+                                  ProjectionMode::AnyFinal),
             fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
             locals: RefCell::new(NodeMap()),
-            tables: tables,
             deferred_call_resolutions: RefCell::new(DefIdMap()),
             deferred_cast_checks: RefCell::new(Vec::new()),
         }
@@ -387,7 +398,7 @@ impl<'a, 'tcx> Inherited<'a, 'tcx, 'tcx> {
                                         -> T
         where T : TypeFoldable<'tcx>
     {
-        assoc::normalize_associated_types_in(&self.infcx,
+        assoc::normalize_associated_types_in(self,
                                              &mut self.fulfillment_cx.borrow_mut(),
                                              span,
                                              body_id,
@@ -402,7 +413,7 @@ fn static_inherited_fields<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
     // It's kind of a kludge to manufacture a fake function context
     // and statement context, but we might as well do write the code only once
     let param_env = ccx.tcx.empty_parameter_environment();
-    Inherited::new(ccx.tcx, &tables, param_env)
+    Inherited::new(ccx, &tables, param_env)
 }
 
 struct CheckItemTypesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> }
@@ -484,12 +495,12 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     match raw_fty.sty {
         ty::TyFnDef(_, _, ref fn_ty) => {
             let tables = RefCell::new(ty::Tables::empty());
-            let inh = Inherited::new(ccx.tcx, &tables, param_env);
+            let inh = Inherited::new(ccx, &tables, param_env);
 
             // Compute the fty from point of view of inside fn.
             let fn_scope = ccx.tcx.region_maps.call_site_extent(fn_id, body.id);
             let fn_sig =
-                fn_ty.sig.subst(ccx.tcx, &inh.infcx.parameter_environment.free_substs);
+                fn_ty.sig.subst(ccx.tcx, &inh.parameter_environment.free_substs);
             let fn_sig =
                 ccx.tcx.liberate_late_bound_regions(fn_scope, &fn_sig);
             let fn_sig =
@@ -522,13 +533,13 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx, 'tcx> {
         match ty_opt {
             None => {
                 // infer the variable's type
-                let var_ty = self.fcx.infcx().next_ty_var();
-                self.fcx.inh.locals.borrow_mut().insert(nid, var_ty);
+                let var_ty = self.fcx.next_ty_var();
+                self.fcx.locals.borrow_mut().insert(nid, var_ty);
                 var_ty
             }
             Some(typ) => {
                 // take type that the user specified
-                self.fcx.inh.locals.borrow_mut().insert(nid, typ);
+                self.fcx.locals.borrow_mut().insert(nid, typ);
                 typ
             }
         }
@@ -545,15 +556,15 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx, 'tcx> {
         self.assign(local.span, local.id, o_ty);
         debug!("Local variable {:?} is assigned type {}",
                local.pat,
-               self.fcx.infcx().ty_to_string(
-                   self.fcx.inh.locals.borrow().get(&local.id).unwrap().clone()));
+               self.fcx.ty_to_string(
+                   self.fcx.locals.borrow().get(&local.id).unwrap().clone()));
         intravisit::walk_local(self, local);
     }
 
     // Add pattern bindings.
     fn visit_pat(&mut self, p: &'tcx hir::Pat) {
         if let PatKind::Ident(_, ref path1, _) = p.node {
-            if pat_util::pat_is_binding(&self.fcx.tcx().def_map.borrow(), p) {
+            if pat_util::pat_is_binding(&self.fcx.tcx.def_map.borrow(), p) {
                 let var_ty = self.assign(p.span, p.id, None);
 
                 self.fcx.require_type_is_sized(var_ty, p.span,
@@ -561,8 +572,8 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx, 'tcx> {
 
                 debug!("Pattern binding {} is assigned to {} with type {:?}",
                        path1.node,
-                       self.fcx.infcx().ty_to_string(
-                           self.fcx.inh.locals.borrow().get(&p.id).unwrap().clone()),
+                       self.fcx.ty_to_string(
+                           self.fcx.locals.borrow().get(&p.id).unwrap().clone()),
                        var_ty);
             }
         }
@@ -582,7 +593,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx, 'tcx> {
         match t.node {
             hir::TyFixedLengthVec(ref ty, ref count_expr) => {
                 self.visit_ty(&ty);
-                self.fcx.check_expr_with_hint(&count_expr, self.fcx.tcx().types.usize);
+                self.fcx.check_expr_with_hint(&count_expr, self.fcx.tcx.types.usize);
             }
             hir::TyBareFn(ref function_declaration) => {
                 intravisit::walk_fn_decl_nopat(self, &function_declaration.decl);
@@ -625,7 +636,7 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
 
     // Create the function context.  This is either derived from scratch or,
     // in the case of function expressions, based on the outer context.
-    let fcx = FnCtxt::new(ccx, inherited, ret_ty, body.id);
+    let fcx = FnCtxt::new(inherited, ret_ty, body.id);
     *fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id);
 
     if let ty::FnConverging(ret_ty) = ret_ty {
@@ -1126,7 +1137,7 @@ fn check_const_in_type<'a,'tcx>(ccx: &'a CrateCtxt<'a,'tcx>,
                                 expected_type: Ty<'tcx>) {
     let tables = RefCell::new(ty::Tables::empty());
     let inh = static_inherited_fields(ccx, &tables);
-    let fcx = FnCtxt::new(ccx, &inh, ty::FnConverging(expected_type), expr.id);
+    let fcx = FnCtxt::new(&inh, ty::FnConverging(expected_type), expr.id);
     fcx.check_const_with_ty(expr.span, expr, expected_type);
 }
 
@@ -1137,8 +1148,8 @@ fn check_const<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
     let tables = RefCell::new(ty::Tables::empty());
     let inh = static_inherited_fields(ccx, &tables);
     let rty = ccx.tcx.node_id_to_type(id);
-    let fcx = FnCtxt::new(ccx, &inh, ty::FnConverging(rty), e.id);
-    let declty = fcx.tcx().lookup_item_type(ccx.tcx.map.local_def_id(id)).ty;
+    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;
     fcx.check_const_with_ty(sp, e, declty);
 }
 
@@ -1210,7 +1221,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
 
         let tables = RefCell::new(ty::Tables::empty());
         let inh = static_inherited_fields(ccx, &tables);
-        let fcx = FnCtxt::new(ccx, &inh, ty::FnConverging(rty), id);
+        let fcx = FnCtxt::new(&inh, ty::FnConverging(rty), id);
 
         let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(ccx.tcx);
         for v in vs {
@@ -1255,7 +1266,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
 }
 
 impl<'a, 'tcx> AstConv<'tcx, 'tcx> for FnCtxt<'a, 'tcx, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { self.infcx().tcx }
+    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { self.tcx }
 
     fn get_item_type_scheme(&self, _: Span, id: DefId)
                             -> Result<ty::TypeScheme<'tcx>, ErrorReported>
@@ -1275,7 +1286,7 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for FnCtxt<'a, 'tcx, 'tcx> {
     }
 
     fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
-        Some(&self.inh.infcx.parameter_environment.free_substs)
+        Some(&self.parameter_environment.free_substs)
     }
 
     fn get_type_parameter_bounds(&self,
@@ -1283,8 +1294,8 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for FnCtxt<'a, 'tcx, 'tcx> {
                                  node_id: ast::NodeId)
                                  -> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>
     {
-        let def = self.tcx().type_parameter_def(node_id);
-        let r = self.inh.infcx.parameter_environment
+        let def = self.tcx.type_parameter_def(node_id);
+        let r = self.parameter_environment
                                   .caller_bounds
                                   .iter()
                                   .filter_map(|predicate| {
@@ -1328,7 +1339,7 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for FnCtxt<'a, 'tcx, 'tcx> {
             })
         });
 
-        let ty_var = self.infcx().next_ty_var_with_default(default);
+        let ty_var = self.next_ty_var_with_default(default);
 
         // Finally we add the type variable to the substs
         match substs {
@@ -1344,7 +1355,7 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for FnCtxt<'a, 'tcx, 'tcx> {
                                         -> Ty<'tcx>
     {
         let (trait_ref, _) =
-            self.infcx().replace_late_bound_regions_with_fresh_var(
+            self.replace_late_bound_regions_with_fresh_var(
                 span,
                 infer::LateBoundRegionConversionTime::AssocTypeProjection(item_name),
                 &poly_trait_ref);
@@ -1362,7 +1373,7 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for FnCtxt<'a, 'tcx, 'tcx> {
     }
 
     fn set_tainted_by_errors(&self) {
-        self.infcx().set_tainted_by_errors()
+        self.infcx.set_tainted_by_errors()
     }
 }
 
@@ -1379,13 +1390,13 @@ impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx, 'tcx> {
         // (and anyway, within a fn body the right region may not even
         // be something the user can write explicitly, since it might
         // be some expression).
-        self.infcx().next_region_var(infer::MiscVariable(span))
+        self.next_region_var(infer::MiscVariable(span))
     }
 
     fn anon_regions(&self, span: Span, count: usize)
                     -> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>> {
         Ok((0..count).map(|_| {
-            self.infcx().next_region_var(infer::MiscVariable(span))
+            self.next_region_var(infer::MiscVariable(span))
         }).collect())
     }
 }
@@ -1424,56 +1435,49 @@ enum TupleArgumentsFlag {
 }
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
-    pub fn new(ccx: &'a CrateCtxt<'a, 'tcx>,
-               inh: &'a Inherited<'a, 'tcx, 'tcx>,
+    pub fn new(inh: &'a Inherited<'a, 'tcx, 'tcx>,
                rty: ty::FnOutput<'tcx>,
                body_id: ast::NodeId)
                -> FnCtxt<'a, 'tcx, 'tcx> {
         FnCtxt {
             body_id: body_id,
             writeback_errors: Cell::new(false),
-            err_count_on_creation: ccx.tcx.sess.err_count(),
+            err_count_on_creation: inh.tcx.sess.err_count(),
             ret_ty: rty,
             ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, 0)),
             inh: inh,
-            ccx: ccx
         }
     }
 
-    pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.infcx().tcx }
-
-    pub fn infcx(&self) -> &InferCtxt<'a,'tcx, 'tcx> {
-        &self.inh.infcx
-    }
-
     pub fn param_env(&self) -> &ty::ParameterEnvironment<'a,'tcx> {
-        &self.inh.infcx.parameter_environment
+        &self.parameter_environment
     }
 
     pub fn sess(&self) -> &Session {
-        &self.tcx().sess
+        &self.tcx.sess
     }
 
     pub fn err_count_since_creation(&self) -> usize {
-        self.tcx().sess.err_count() - self.err_count_on_creation
+        self.tcx.sess.err_count() - self.err_count_on_creation
     }
 
     /// Resolves type variables in `ty` if possible. Unlike the infcx
-    /// version, this version will also select obligations if it seems
-    /// useful, in an effort to get more type information.
-    fn resolve_type_vars_if_possible(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
-        debug!("resolve_type_vars_if_possible(ty={:?})", ty);
+    /// version (resolve_type_vars_if_possible), this version will
+    /// also select obligations if it seems useful, in an effort
+    /// to get more type information.
+    fn resolve_type_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
+        debug!("resolve_type_vars_with_obligations(ty={:?})", ty);
 
         // No TyInfer()? Nothing needs doing.
         if !ty.has_infer_types() {
-            debug!("resolve_type_vars_if_possible: ty={:?}", ty);
+            debug!("resolve_type_vars_with_obligations: ty={:?}", ty);
             return ty;
         }
 
         // If `ty` is a type variable, see whether we already know what it is.
-        ty = self.infcx().resolve_type_vars_if_possible(&ty);
+        ty = self.resolve_type_vars_if_possible(&ty);
         if !ty.has_infer_types() {
-            debug!("resolve_type_vars_if_possible: ty={:?}", ty);
+            debug!("resolve_type_vars_with_obligations: ty={:?}", ty);
             return ty;
         }
 
@@ -1482,16 +1486,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
         // indirect dependencies that don't seem worth tracking
         // precisely.
         self.select_obligations_where_possible();
-        ty = self.infcx().resolve_type_vars_if_possible(&ty);
+        ty = self.resolve_type_vars_if_possible(&ty);
 
-        debug!("resolve_type_vars_if_possible: ty={:?}", ty);
+        debug!("resolve_type_vars_with_obligations: ty={:?}", ty);
         ty
     }
 
     fn record_deferred_call_resolution(&self,
                                        closure_def_id: DefId,
                                        r: DeferredCallResolutionHandler<'tcx>) {
-        let mut deferred_call_resolutions = self.inh.deferred_call_resolutions.borrow_mut();
+        let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut();
         deferred_call_resolutions.entry(closure_def_id).or_insert(vec![]).push(r);
     }
 
@@ -1499,7 +1503,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
                                         closure_def_id: DefId)
                                         -> Vec<DeferredCallResolutionHandler<'tcx>>
     {
-        let mut deferred_call_resolutions = self.inh.deferred_call_resolutions.borrow_mut();
+        let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut();
         deferred_call_resolutions.remove(&closure_def_id).unwrap_or(Vec::new())
     }
 
@@ -1509,13 +1513,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
     }
 
     pub fn local_ty(&self, span: Span, nid: ast::NodeId) -> Ty<'tcx> {
-        match self.inh.locals.borrow().get(&nid) {
+        match self.locals.borrow().get(&nid) {
             Some(&t) => t,
             None => {
-                span_err!(self.tcx().sess, span, E0513,
+                span_err!(self.tcx.sess, span, E0513,
                           "no type for local variable {}",
                           nid);
-                self.tcx().types.err
+                self.tcx.types.err
             }
         }
     }
@@ -1524,7 +1528,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
     pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) {
         debug!("write_ty({}, {:?}) in fcx {}",
                node_id, ty, self.tag());
-        self.inh.tables.borrow_mut().node_types.insert(node_id, ty);
+        self.tables.borrow_mut().node_types.insert(node_id, ty);
     }
 
     pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) {
@@ -1534,7 +1538,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
                    substs,
                    self.tag());
 
-            self.inh.tables.borrow_mut().item_substs.insert(node_id, substs);
+            self.tables.borrow_mut().item_substs.insert(node_id, substs);
         }
     }
 
@@ -1560,7 +1564,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
             return;
         }
 
-        self.inh.tables.borrow_mut().adjustments.insert(node_id, adj);
+        self.tables.borrow_mut().adjustments.insert(node_id, adj);
     }
 
     /// Basically whenever we are converting from a type scheme into
@@ -1573,7 +1577,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
                                   -> T
         where T : TypeFoldable<'tcx>
     {
-        let value = value.subst(self.tcx(), substs);
+        let value = value.subst(self.tcx, substs);
         let result = self.normalize_associated_types_in(span, &value);
         debug!("instantiate_type_scheme(value={:?}, substs={:?}) = {:?}",
                value,
@@ -1611,10 +1615,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
         let cause = traits::ObligationCause::new(span,
                                                  self.body_id,
                                                  traits::ObligationCauseCode::MiscObligation);
-        self.inh
-            .fulfillment_cx
+        self.fulfillment_cx
             .borrow_mut()
-            .normalize_projection_type(self.infcx(),
+            .normalize_projection_type(self,
                                        ty::ProjectionTy {
                                            trait_ref: trait_ref,
                                            item_name: item_name,
@@ -1634,9 +1637,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
     {
         debug!("instantiate_type(did={:?}, path={:?})", did, path);
         let type_scheme =
-            self.tcx().lookup_item_type(did);
+            self.tcx.lookup_item_type(did);
         let type_predicates =
-            self.tcx().lookup_predicates(did);
+            self.tcx.lookup_predicates(did);
         let substs = astconv::ast_path_substs_for_ty(self, self,
                                                      path.span,
                                                      PathParamMode::Optional,
@@ -1663,11 +1666,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
     {
         let (adt, variant) = match def {
             Def::Variant(enum_id, variant_id) => {
-                let adt = self.tcx().lookup_adt_def(enum_id);
+                let adt = self.tcx.lookup_adt_def(enum_id);
                 (adt, adt.variant_with_id(variant_id))
             }
             Def::Struct(did) | Def::TyAlias(did) => {
-                let typ = self.tcx().lookup_item_type(did);
+                let typ = self.tcx.lookup_item_type(did);
                 if let ty::TyStruct(adt, _) = typ.ty.sty {
                     (adt, adt.struct_variant())
                 } else {
@@ -1688,10 +1691,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
     }
 
     pub fn write_nil(&self, node_id: ast::NodeId) {
-        self.write_ty(node_id, self.tcx().mk_nil());
+        self.write_ty(node_id, self.tcx.mk_nil());
     }
     pub fn write_error(&self, node_id: ast::NodeId) {
-        self.write_ty(node_id, self.tcx().types.err);
+        self.write_ty(node_id, self.tcx.types.err);
     }
 
     pub fn require_type_meets(&self,
@@ -1726,8 +1729,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
                                   builtin_bound: ty::BuiltinBound,
                                   cause: traits::ObligationCause<'tcx>)
     {
-        self.inh.fulfillment_cx.borrow_mut()
-            .register_builtin_bound(self.infcx(), ty, builtin_bound, cause);
+        self.fulfillment_cx.borrow_mut()
+            .register_builtin_bound(self, ty, builtin_bound, cause);
     }
 
     pub fn register_predicate(&self,
@@ -1735,9 +1738,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
     {
         debug!("register_predicate({:?})",
                obligation);
-        self.inh.fulfillment_cx
+        self.fulfillment_cx
             .borrow_mut()
-            .register_predicate_obligation(self.infcx(), obligation);
+            .register_predicate_obligation(self, obligation);
     }
 
     pub fn to_ty(&self, ast_t: &hir::Ty) -> Ty<'tcx> {
@@ -1747,7 +1750,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
     }
 
     pub fn expr_ty(&self, ex: &hir::Expr) -> Ty<'tcx> {
-        match self.inh.tables.borrow().node_types.get(&ex.id) {
+        match self.tables.borrow().node_types.get(&ex.id) {
             Some(&t) => t,
             None => {
                 bug!("no type for expr in fcx {}", self.tag());
@@ -1762,21 +1765,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
                           -> Ty<'tcx>
     {
         let raw_ty = self.expr_ty(expr);
-        let raw_ty = self.infcx().shallow_resolve(raw_ty);
-        let resolve_ty = |ty: Ty<'tcx>| self.infcx().resolve_type_vars_if_possible(&ty);
-        raw_ty.adjust(self.tcx(), expr.span, expr.id, adjustment, |method_call| {
-            self.inh.tables.borrow().method_map.get(&method_call)
+        let raw_ty = self.shallow_resolve(raw_ty);
+        let resolve_ty = |ty: Ty<'tcx>| self.resolve_type_vars_if_possible(&ty);
+        raw_ty.adjust(self.tcx, expr.span, expr.id, adjustment, |method_call| {
+            self.tables.borrow().method_map.get(&method_call)
                                         .map(|method| resolve_ty(method.ty))
         })
     }
 
     pub fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx> {
-        match self.inh.tables.borrow().node_types.get(&id) {
+        match self.tables.borrow().node_types.get(&id) {
             Some(&t) => t,
-            None if self.err_count_since_creation() != 0 => self.tcx().types.err,
+            None if self.err_count_since_creation() != 0 => self.tcx.types.err,
             None => {
                 bug!("no type for node {}: {} in fcx {}",
-                     id, self.tcx().map.node_to_string(id),
+                     id, self.tcx.map.node_to_string(id),
                      self.tag());
             }
         }
@@ -1790,7 +1793,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
             &tables.item_substs
         }
 
-        Ref::map(self.inh.tables.borrow(), project_item_susbts)
+        Ref::map(self.tables.borrow(), project_item_susbts)
     }
 
     pub fn opt_node_ty_substs<F>(&self,
@@ -1798,33 +1801,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
                                  f: F) where
         F: FnOnce(&ty::ItemSubsts<'tcx>),
     {
-        match self.inh.tables.borrow().item_substs.get(&id) {
+        match self.tables.borrow().item_substs.get(&id) {
             Some(s) => { f(s) }
             None => { }
         }
     }
 
-    pub fn type_error_message<M>(&self,
-                                 sp: Span,
-                                 mk_msg: M,
-                                 actual_ty: Ty<'tcx>,
-                                 err: Option<&TypeError<'tcx>>)
-        where M: FnOnce(String) -> String,
-    {
-        self.infcx().type_error_message(sp, mk_msg, actual_ty, err);
-    }
-
-    pub fn type_error_struct<M>(&self,
-                                sp: Span,
-                                mk_msg: M,
-                                actual_ty: Ty<'tcx>,
-                                err: Option<&TypeError<'tcx>>)
-                                -> DiagnosticBuilder<'tcx>
-        where M: FnOnce(String) -> String,
-    {
-        self.infcx().type_error_struct(sp, mk_msg, actual_ty, err)
-    }
-
     /// Registers an obligation for checking later, during regionck, that the type `ty` must
     /// outlive the region `r`.
     pub fn register_region_obligation(&self,
@@ -1832,7 +1814,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
                                       region: ty::Region,
                                       cause: traits::ObligationCause<'tcx>)
     {
-        let mut fulfillment_cx = self.inh.fulfillment_cx.borrow_mut();
+        let mut fulfillment_cx = self.fulfillment_cx.borrow_mut();
         fulfillment_cx.register_region_obligation(ty, region, cause);
     }
 
@@ -1913,11 +1895,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
                     -> Ty<'tcx>
     {
         self.normalize_associated_types_in(span,
-                                           &field.ty(self.tcx(), substs))
+                                           &field.ty(self.tcx, substs))
     }
 
     fn check_casts(&self) {
-        let mut deferred_cast_checks = self.inh.deferred_cast_checks.borrow_mut();
+        let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
         for cast in deferred_cast_checks.drain(..) {
             cast.check(self);
         }
@@ -1933,9 +1915,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
         // encountered type-checking errors. Therefore, if we think we saw
         // some errors in this function, just resolve all uninstanted type
         // varibles to TyError.
-        if self.infcx().is_tainted_by_errors() {
-            for ty in &self.infcx().unsolved_variables() {
-                if let ty::TyInfer(_) = self.infcx().shallow_resolve(ty).sty {
+        if self.is_tainted_by_errors() {
+            for ty in &self.unsolved_variables() {
+                if let ty::TyInfer(_) = self.shallow_resolve(ty).sty {
                     debug!("default_type_parameters: defaulting `{:?}` to error", ty);
                     self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.err);
                 }
@@ -1943,23 +1925,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
             return;
         }
 
-        for ty in &self.infcx().unsolved_variables() {
-            let resolved = self.infcx().resolve_type_vars_if_possible(ty);
-            if self.infcx().type_var_diverges(resolved) {
+        for ty in &self.unsolved_variables() {
+            let resolved = self.resolve_type_vars_if_possible(ty);
+            if self.type_var_diverges(resolved) {
                 debug!("default_type_parameters: defaulting `{:?}` to `()` because it diverges",
                        resolved);
-                self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().mk_nil());
+                self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx.mk_nil());
             } else {
-                match self.infcx().type_is_unconstrained_numeric(resolved) {
+                match self.type_is_unconstrained_numeric(resolved) {
                     UnconstrainedInt => {
                         debug!("default_type_parameters: defaulting `{:?}` to `i32`",
                                resolved);
-                        self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.i32)
+                        self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx.types.i32)
                     },
                     UnconstrainedFloat => {
                         debug!("default_type_parameters: defaulting `{:?}` to `f32`",
                                resolved);
-                        self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.f64)
+                        self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx.types.f64)
                     }
                     Neither => { }
                 }
@@ -1968,7 +1950,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
     }
 
     fn select_all_obligations_and_apply_defaults(&self) {
-        if self.tcx().sess.features.borrow().default_type_parameter_fallback {
+        if self.tcx.sess.features.borrow().default_type_parameter_fallback {
             self.new_select_all_obligations_and_apply_defaults();
         } else {
             self.old_select_all_obligations_and_apply_defaults();
@@ -1988,11 +1970,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
 
         // For the time being this errs on the side of being memory wasteful but provides better
         // error reporting.
-        // let type_variables = self.infcx().type_variables.clone();
+        // let type_variables = self.type_variables.clone();
 
         // There is a possibility that this algorithm will have to run an arbitrary number of times
         // to terminate so we bound it by the compiler's recursion limit.
-        for _ in 0..self.tcx().sess.recursion_limit.get() {
+        for _ in 0..self.tcx.sess.recursion_limit.get() {
             // First we try to solve all obligations, it is possible that the last iteration
             // has made it possible to make more progress.
             self.select_obligations_where_possible();
@@ -2000,7 +1982,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
             let mut conflicts = Vec::new();
 
             // Collect all unsolved type, integral and floating point variables.
-            let unsolved_variables = self.inh.infcx.unsolved_variables();
+            let unsolved_variables = self.unsolved_variables();
 
             // We must collect the defaults *before* we do any unification. Because we have
             // directly attached defaults to the type variables any unification that occurs
@@ -2008,7 +1990,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
             let default_map: FnvHashMap<_, _> =
                 unsolved_variables
                     .iter()
-                    .filter_map(|t| self.infcx().default(t).map(|d| (t, d)))
+                    .filter_map(|t| self.default(t).map(|d| (t, d)))
                     .collect();
 
             let mut unbound_tyvars = HashSet::new();
@@ -2020,11 +2002,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
             // variables. We do this so we only apply literal fallback to type
             // variables without defaults.
             for ty in &unsolved_variables {
-                let resolved = self.infcx().resolve_type_vars_if_possible(ty);
-                if self.infcx().type_var_diverges(resolved) {
-                    self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().mk_nil());
+                let resolved = self.resolve_type_vars_if_possible(ty);
+                if self.type_var_diverges(resolved) {
+                    self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx.mk_nil());
                 } else {
-                    match self.infcx().type_is_unconstrained_numeric(resolved) {
+                    match self.type_is_unconstrained_numeric(resolved) {
                         UnconstrainedInt | UnconstrainedFloat => {
                             unbound_tyvars.insert(resolved);
                         },
@@ -2037,7 +2019,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
             // the type variable with a defined fallback.
             for ty in &unsolved_variables {
                 if let Some(_default) = default_map.get(ty) {
-                    let resolved = self.infcx().resolve_type_vars_if_possible(ty);
+                    let resolved = self.resolve_type_vars_if_possible(ty);
 
                     debug!("select_all_obligations_and_apply_defaults: ty: {:?} with default: {:?}",
                              ty, _default);
@@ -2076,22 +2058,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
             // for conflicts and correctly report them.
 
 
-            let _ = self.infcx().commit_if_ok(|_: &infer::CombinedSnapshot| {
+            let _ = self.commit_if_ok(|_: &infer::CombinedSnapshot| {
                 for ty in &unbound_tyvars {
-                    if self.infcx().type_var_diverges(ty) {
-                        self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().mk_nil());
+                    if self.type_var_diverges(ty) {
+                        self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx.mk_nil());
                     } else {
-                        match self.infcx().type_is_unconstrained_numeric(ty) {
+                        match self.type_is_unconstrained_numeric(ty) {
                             UnconstrainedInt => {
-                                self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.i32)
+                                self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx.types.i32)
                             },
                             UnconstrainedFloat => {
-                                self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.f64)
+                                self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx.types.f64)
                             }
                             Neither => {
                                 if let Some(default) = default_map.get(ty) {
                                     let default = default.clone();
-                                    match self.infcx().eq_types(false,
+                                    match self.eq_types(false,
                                             TypeOrigin::Misc(default.origin_span),
                                             ty, default.ty) {
                                         Ok(InferOk { obligations, .. }) => {
@@ -2123,9 +2105,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
                     let conflicting_default =
                         self.find_conflicting_default(&unbound_tyvars, &default_map, conflict)
                             .unwrap_or(type_variable::Default {
-                                ty: self.infcx().next_ty_var(),
+                                ty: self.next_ty_var(),
                                 origin_span: codemap::DUMMY_SP,
-                                def_id: self.tcx().map.local_def_id(0) // what do I put here?
+                                def_id: self.tcx.map.local_def_id(0) // what do I put here?
                             });
 
                     // This is to ensure that we elimnate any non-determinism from the error
@@ -2139,7 +2121,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
                         };
 
 
-                    self.infcx().report_conflicting_default_types(
+                    self.report_conflicting_default_types(
                         first_default.origin_span,
                         first_default,
                         second_default)
@@ -2174,20 +2156,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
         // We also run this inside snapshot that never commits so we can do error
         // reporting for more then one conflict.
         for ty in &unbound_tyvars {
-            if self.infcx().type_var_diverges(ty) {
-                self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().mk_nil());
+            if self.type_var_diverges(ty) {
+                self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx.mk_nil());
             } else {
-                match self.infcx().type_is_unconstrained_numeric(ty) {
+                match self.type_is_unconstrained_numeric(ty) {
                     UnconstrainedInt => {
-                        self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.i32)
+                        self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx.types.i32)
                     },
                     UnconstrainedFloat => {
-                        self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.f64)
+                        self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx.types.f64)
                     },
                     Neither => {
                         if let Some(default) = default_map.get(ty) {
                             let default = default.clone();
-                            match self.infcx().eq_types(false,
+                            match self.eq_types(false,
                                     TypeOrigin::Misc(default.origin_span),
                                     ty, default.ty) {
                                 // FIXME(#32730) propagate obligations
@@ -2210,30 +2192,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx, 'tcx> {
 
         // upvar inference should have ensured that all deferred call
         // resolutions are handled by now.
-        assert!(self.inh.deferred_call_resolutions.borrow().is_empty());
+        assert!(self.deferred_call_resolutions.borrow().is_empty());
 
         self.select_all_obligations_and_apply_defaults();
 
-        let mut fulfillment_cx = self.inh.fulfillment_cx.borrow_mut();
-        match fulfillment_cx.select_all_or_error(self.infcx()) {
+        let mut fulfillment_cx = self.fulfillment_cx.borrow_mut();
+        match fulfillment_cx.select_all_or_error(self) {
             Ok(()) => { }
-            Err(errors) => { self.infcx().report_fulfillment_errors(&errors); }
+            Err(errors) => { self.report_fulfillment_errors(&errors); }
         }
 
-        if let Err(ref errors) = fulfillment_cx.select_rfc1592_obligations(self.infcx()) {
-            self.infcx().report_fulfillment_errors_as_warnings(errors, self.body_id);
+        if let Err(ref errors) = fulfillment_cx.select_rfc1592_obligations(self) {
+            self.report_fulfillment_errors_as_warnings(errors, self.body_id);
         }
     }
 
     /// Select as many obligations as we can at present.
     fn select_obligations_where_possible(&self) {
-        match
-            self.inh.fulfillment_cx
-            .borrow_mut()
-            .select_where_possible(self.infcx())
-        {
+        match self.fulfillment_cx.borrow_mut().select_where_possible(self) {
             Ok(()) => { }
-            Err(errors) => { self.infcx().report_fulfillment_errors(&errors); }
+            Err(errors) => { self.report_fulfillment_errors(&errors); }
         }
     }
 
@@ -2259,7 +2237,7 @@ pub fn autoderef<'b, E, I, T, F>(&self,
            base_ty, lvalue_pref);
 
     let mut t = base_ty;
-    for autoderefs in 0..self.tcx().sess.recursion_limit.get() {
+    for autoderefs in 0..self.tcx.sess.recursion_limit.get() {
         let resolved_t = match unresolved_type_action {
             UnresolvedTypeAction::Error => {
                 self.structurally_resolved_type(sp, t)
@@ -2269,7 +2247,7 @@ pub fn autoderef<'b, E, I, T, F>(&self,
                 // (i.e. it is an inference variable) because `Ty::builtin_deref`
                 // and `try_overloaded_deref` both simply return `None`
                 // in such a case without producing spurious errors.
-                self.infcx().resolve_type_vars_if_possible(&t)
+                self.resolve_type_vars_if_possible(&t)
             }
         };
         if resolved_t.references_error() {
@@ -2300,7 +2278,7 @@ pub fn autoderef<'b, E, I, T, F>(&self,
                                                                resolved_t, lvalue_pref) {
             for expr in maybe_exprs() {
                 let method_call = MethodCall::autoderef(expr.id, autoderefs as u32);
-                self.inh.tables.borrow_mut().method_map.insert(method_call, method);
+                self.tables.borrow_mut().method_map.insert(method_call, method);
             }
             self.make_overloaded_lvalue_return_type(method)
         } else {
@@ -2314,10 +2292,10 @@ pub fn autoderef<'b, E, I, T, F>(&self,
     }
 
     // We've reached the recursion limit, error gracefully.
-    span_err!(self.tcx().sess, sp, E0055,
+    span_err!(self.tcx.sess, sp, E0055,
         "reached the recursion limit while auto-dereferencing {:?}",
         base_ty);
-    (self.tcx().types.err, 0, None)
+    (self.tcx.types.err, 0, None)
 }
 
 fn try_overloaded_deref(&self,
@@ -2328,7 +2306,7 @@ fn try_overloaded_deref(&self,
                         -> Option<MethodCallee<'tcx>>
 {
     // Try DerefMut first, if preferred.
-    let method = match (lvalue_pref, self.tcx().lang_items.deref_mut_trait()) {
+    let method = match (lvalue_pref, self.tcx.lang_items.deref_mut_trait()) {
         (PreferMutLvalue, Some(trait_did)) => {
             self.lookup_method_in_trait(span, base_expr,
                                         token::intern("deref_mut"), trait_did,
@@ -2338,7 +2316,7 @@ fn try_overloaded_deref(&self,
     };
 
     // Otherwise, fall back to Deref.
-    let method = match (method, self.tcx().lang_items.deref_trait()) {
+    let method = match (method, self.tcx.lang_items.deref_trait()) {
         (None, Some(trait_did)) => {
             self.lookup_method_in_trait(span, base_expr,
                                         token::intern("deref"), trait_did,
@@ -2360,7 +2338,7 @@ fn make_overloaded_lvalue_return_type(&self,
     // extract method return type, which will be &T;
     // all LB regions should have been instantiated during method lookup
     let ret_ty = method.ty.fn_ret();
-    let ret_ty = self.tcx().no_late_bound_regions(&ret_ty).unwrap().unwrap();
+    let ret_ty = self.tcx.no_late_bound_regions(&ret_ty).unwrap().unwrap();
 
     // method returns &T, but the type as visible to user is T, so deref
     ret_ty.builtin_deref(true, NoPreference).unwrap()
@@ -2395,7 +2373,7 @@ fn lookup_indexing(&self,
     // After we have fully autoderef'd, if the resulting type is [T; n], then
     // do a final unsized coercion to yield [T].
     if let ty::TyArray(element_ty, _) = ty.sty {
-        let adjusted_ty = self.tcx().mk_slice(element_ty);
+        let adjusted_ty = self.tcx.mk_slice(element_ty);
         self.try_index_step(MethodCall::expr(expr.id), expr, base_expr,
                             adjusted_ty, autoderefs, true, lvalue_pref, idx_ty)
     } else {
@@ -2418,7 +2396,7 @@ fn try_index_step(&self,
                   index_ty: Ty<'tcx>)
                   -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)>
 {
-    let tcx = self.tcx();
+    let tcx = self.tcx;
     debug!("try_index_step(expr={:?}, base_expr.id={:?}, adjusted_ty={:?}, \
                            autoderefs={}, unsize={}, index_ty={:?})",
            expr,
@@ -2428,7 +2406,7 @@ fn try_index_step(&self,
            unsize,
            index_ty);
 
-    let input_ty = self.infcx().next_ty_var();
+    let input_ty = self.next_ty_var();
 
     // First, try built-in indexing.
     match (adjusted_ty.builtin_index(), &index_ty.sty) {
@@ -2477,7 +2455,7 @@ fn try_index_step(&self,
     // If some lookup succeeded, install method in table
     method.map(|method| {
         debug!("try_index_step: success, using overloaded indexing");
-        self.inh.tables.borrow_mut().method_map.insert(method_call, method);
+        self.tables.borrow_mut().method_map.insert(method_call, method);
         (input_ty, self.make_overloaded_lvalue_return_type(method).ty)
     })
 }
@@ -2495,12 +2473,12 @@ fn check_method_argument_types(&self,
 
         let err_inputs = match tuple_arguments {
             DontTupleArguments => err_inputs,
-            TupleArguments => vec![self.tcx().mk_tup(err_inputs)],
+            TupleArguments => vec![self.tcx.mk_tup(err_inputs)],
         };
 
         self.check_argument_types(sp, &err_inputs[..], &[], args_no_rcvr,
                                   false, tuple_arguments);
-        ty::FnConverging(self.tcx().types.err)
+        ty::FnConverging(self.tcx.types.err)
     } else {
         match method_fn_ty.sty {
             ty::TyFnDef(_, _, ref fty) => {
@@ -2528,7 +2506,7 @@ fn check_argument_types(&self,
                         args: &'tcx [P<hir::Expr>],
                         variadic: bool,
                         tuple_arguments: TupleArgumentsFlag) {
-    let tcx = self.tcx();
+    let tcx = self.tcx;
 
     // Grab the argument types, supplying fresh type variables
     // if the wrong number of arguments were supplied
@@ -2606,7 +2584,7 @@ fn check_argument_types(&self,
     };
 
     debug!("check_argument_types: formal_tys={:?}",
-           formal_tys.iter().map(|t| self.infcx().ty_to_string(*t)).collect::<Vec<String>>());
+           formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>());
 
     // Check the arguments.
     // We do this in a pretty awful way: first we typecheck any arguments
@@ -2640,7 +2618,7 @@ fn check_argument_types(&self,
         };
         for (i, arg) in args.iter().take(t).enumerate() {
             if any_diverges && !warned {
-                self.tcx()
+                self.tcx
                     .sess
                     .add_lint(lint::builtin::UNREACHABLE_CODE,
                               arg.id,
@@ -2676,13 +2654,13 @@ fn check_argument_types(&self,
                 coerce_ty.map(|ty| self.demand_suptype(arg.span, formal_ty, ty));
             }
 
-            if let Some(&arg_ty) = self.inh.tables.borrow().node_types.get(&arg.id) {
-                any_diverges = any_diverges || self.infcx().type_var_diverges(arg_ty);
+            if let Some(&arg_ty) = self.tables.borrow().node_types.get(&arg.id) {
+                any_diverges = any_diverges || self.type_var_diverges(arg_ty);
             }
         }
         if any_diverges && !warned {
-            let parent = self.tcx().map.get_parent_node(args[0].id);
-            self.tcx()
+            let parent = self.tcx.map.get_parent_node(args[0].id);
+            self.tcx
                 .sess
                 .add_lint(lint::builtin::UNREACHABLE_CODE,
                           parent,
@@ -2725,8 +2703,8 @@ fn check_argument_types(&self,
                     }, arg_ty, None);
                 }
                 ty::TyFnDef(_, _, f) => {
-                    let ptr_ty = self.tcx().mk_ty(ty::TyFnPtr(f));
-                    let ptr_ty = self.infcx().resolve_type_vars_if_possible(&ptr_ty);
+                    let ptr_ty = self.tcx.mk_ty(ty::TyFnPtr(f));
+                    let ptr_ty = self.resolve_type_vars_if_possible(&ptr_ty);
                     self.type_error_message(arg.span,
                                             |t| {
                         format!("can't pass `{}` to variadic \
@@ -2740,7 +2718,7 @@ fn check_argument_types(&self,
 }
 
 fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> {
-    (0..len).map(|_| self.tcx().types.err).collect()
+    (0..len).map(|_| self.tcx.types.err).collect()
 }
 
 fn write_call(&self,
@@ -2748,7 +2726,7 @@ fn write_call(&self,
               output: ty::FnOutput<'tcx>) {
     self.write_ty(call_expr.id, match output {
         ty::FnConverging(output_ty) => output_ty,
-        ty::FnDiverging => self.infcx().next_diverging_ty_var()
+        ty::FnDiverging => self.next_diverging_ty_var()
     });
 }
 
@@ -2758,7 +2736,7 @@ fn check_lit(&self,
              expected: Expectation<'tcx>)
              -> Ty<'tcx>
 {
-    let tcx = self.tcx();
+    let tcx = self.tcx;
 
     match lit.node {
         ast::LitKind::Str(..) => tcx.mk_static_str(),
@@ -2781,7 +2759,7 @@ fn check_lit(&self,
                 }
             });
             opt_ty.unwrap_or_else(
-                || tcx.mk_int_var(self.infcx().next_int_var_id()))
+                || tcx.mk_int_var(self.next_int_var_id()))
         }
         ast::LitKind::Float(_, t) => tcx.mk_mach_float(t),
         ast::LitKind::FloatUnsuffixed(_) => {
@@ -2792,7 +2770,7 @@ fn check_lit(&self,
                 }
             });
             opt_ty.unwrap_or_else(
-                || tcx.mk_float_var(self.infcx().next_float_var_id()))
+                || tcx.mk_float_var(self.next_float_var_id()))
         }
         ast::LitKind::Bool(_) => tcx.types.bool
     }
@@ -2847,7 +2825,7 @@ pub fn impl_self_ty(&self,
                     span: Span, // (potential) receiver for this impl
                     did: DefId)
                     -> TypeAndSubsts<'tcx> {
-    let tcx = self.tcx();
+    let tcx = self.tcx;
 
     let ity = tcx.lookup_item_type(did);
     let (tps, rps, raw_ty) =
@@ -2857,11 +2835,11 @@ pub fn impl_self_ty(&self,
 
     debug!("impl_self_ty: tps={:?} rps={:?} raw_ty={:?}", tps, rps, raw_ty);
 
-    let rps = self.inh.infcx.region_vars_for_defs(span, rps);
+    let rps = self.region_vars_for_defs(span, rps);
     let mut substs = subst::Substs::new(
         VecPerParamSpace::empty(),
         VecPerParamSpace::new(rps, Vec::new(), Vec::new()));
-    self.inh.infcx.type_vars_for_defs(span, ParamSpace::TypeSpace, &mut substs, tps);
+    self.type_vars_for_defs(span, ParamSpace::TypeSpace, &mut substs, tps);
     let substd_ty = self.instantiate_type_scheme(span, &substs, &raw_ty);
 
     TypeAndSubsts { substs: substs, ty: substd_ty }
@@ -2877,13 +2855,13 @@ fn expected_types_for_fn_args(&self,
                               -> Vec<Ty<'tcx>> {
     let expected_args = expected_ret.only_has_type(self).and_then(|ret_ty| {
         if let ty::FnConverging(formal_ret_ty) = formal_ret {
-            self.infcx().commit_regions_if_ok(|| {
+            self.commit_regions_if_ok(|| {
                 // Attempt to apply a subtyping relationship between the formal
                 // return type (likely containing type variables if the function
                 // is polymorphic) and the expected return type.
                 // No argument expectations are produced if unification fails.
                 let origin = TypeOrigin::Misc(call_span);
-                let ures = self.infcx().sub_types(false, origin, formal_ret_ty, ret_ty);
+                let ures = self.sub_types(false, origin, formal_ret_ty, ret_ty);
                 // FIXME(#15760) can't use try! here, FromError doesn't default
                 // to identity so the resulting type is not constrained.
                 match ures {
@@ -2895,7 +2873,7 @@ fn expected_types_for_fn_args(&self,
                 // Record all the argument types, with the substitutions
                 // produced from the above subtyping unification.
                 Ok(formal_args.iter().map(|ty| {
-                    self.infcx().resolve_type_vars_if_possible(ty)
+                    self.resolve_type_vars_if_possible(ty)
                 }).collect())
             }).ok()
         } else {
@@ -2932,7 +2910,7 @@ fn expected_types_for_fn_args(&self,
             Ok(method) => {
                 let method_ty = method.ty;
                 let method_call = MethodCall::expr(expr.id);
-                self.inh.tables.borrow_mut().method_map.insert(method_call, method);
+                self.tables.borrow_mut().method_map.insert(method_call, method);
                 method_ty
             }
             Err(error) => {
@@ -2941,7 +2919,7 @@ fn expected_types_for_fn_args(&self,
                                              method_name.node, Some(rcvr), error);
                 }
                 self.write_error(expr.id);
-                self.tcx().types.err
+                self.tcx.types.err
             }
         };
 
@@ -2963,13 +2941,13 @@ fn expected_types_for_fn_args(&self,
                        id: ast::NodeId,
                        sp: Span,
                        expected: Expectation<'tcx>) {
-        self.check_expr_has_type(cond_expr, self.tcx().types.bool);
+        self.check_expr_has_type(cond_expr, self.tcx.types.bool);
 
         let expected = expected.adjust_for_branches(self);
         self.check_block_with_expected(then_blk, expected);
         let then_ty = self.node_ty(then_blk.id);
 
-        let unit = self.tcx().mk_nil();
+        let unit = self.tcx.mk_nil();
         let (origin, expected, found, result) =
         if let Some(else_expr) = opt_else_expr {
             self.check_expr_with_expectation(else_expr, expected);
@@ -2984,16 +2962,16 @@ fn expected_types_for_fn_args(&self,
 
                 // In case we did perform an adjustment, we have to update
                 // the type of the block, because old trans still uses it.
-                let adj = self.inh.tables.borrow().adjustments.get(&then.id).cloned();
+                let adj = self.tables.borrow().adjustments.get(&then.id).cloned();
                 if res.is_ok() && adj.is_some() {
                     self.write_ty(then_blk.id, self.adjust_expr_ty(then, adj.as_ref()));
                 }
 
                 res
             } else {
-                self.infcx().commit_if_ok(|_| {
+                self.commit_if_ok(|_| {
                     let trace = TypeTrace::types(origin, true, then_ty, else_ty);
-                    self.infcx().lub(true, trace, &then_ty, &else_ty)
+                    self.lub(true, trace, &then_ty, &else_ty)
                         .map(|InferOk { value, obligations }| {
                             // FIXME(#32730) propagate obligations
                             assert!(obligations.is_empty());
@@ -3005,7 +2983,7 @@ fn expected_types_for_fn_args(&self,
         } else {
             let origin = TypeOrigin::IfExpressionWithNoElse(sp);
             (origin, unit, then_ty,
-             self.infcx().eq_types(true, origin, unit, then_ty)
+             self.eq_types(true, origin, unit, then_ty)
                  .map(|InferOk { obligations, .. }| {
                      // FIXME(#32730) propagate obligations
                      assert!(obligations.is_empty());
@@ -3016,14 +2994,14 @@ fn expected_types_for_fn_args(&self,
         let if_ty = match result {
             Ok(ty) => {
                 if self.expr_ty(cond_expr).references_error() {
-                    self.tcx().types.err
+                    self.tcx.types.err
                 } else {
                     ty
                 }
             }
             Err(e) => {
-                self.infcx().report_mismatched_types(origin, expected, found, e);
-                self.tcx().types.err
+                self.report_mismatched_types(origin, expected, found, e);
+                self.tcx.types.err
             }
         };
 
@@ -3225,7 +3203,7 @@ fn expected_types_for_fn_args(&self,
                                 variant: ty::VariantDef<'tcx>,
                                 ast_fields: &'tcx [hir::Field],
                                 check_completeness: bool) {
-        let tcx = self.tcx();
+        let tcx = self.tcx;
         let substs = match adt_ty.sty {
             ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs,
             _ => span_bug!(span, "non-ADT passed to check_expr_struct_fields")
@@ -3248,7 +3226,7 @@ fn expected_types_for_fn_args(&self,
                 error_happened = true;
                 expected_field_type = tcx.types.err;
                 if let Some(_) = variant.find_field_named(field.name.node) {
-                    span_err!(self.tcx().sess, field.name.span, E0062,
+                    span_err!(self.tcx.sess, field.name.span, E0062,
                         "field `{}` specified more than once",
                         field.name.node);
                 } else {
@@ -3300,19 +3278,19 @@ fn expected_types_for_fn_args(&self,
                          fields: &'tcx [hir::Field],
                          base_expr: &'tcx Option<P<hir::Expr>>)
     {
-        let tcx = self.tcx();
+        let tcx = self.tcx;
 
         // Find the relevant variant
         let def = lookup_full_def(tcx, path.span, expr.id);
         if def == Def::Err {
-            self.infcx().set_tainted_by_errors();
+            self.set_tainted_by_errors();
             self.check_struct_fields_on_error(expr.id, fields, base_expr);
             return;
         }
         let variant = match self.def_struct_variant(def, path.span) {
             Some((_, variant)) => variant,
             None => {
-                span_err!(self.tcx().sess, path.span, E0071,
+                span_err!(self.tcx.sess, path.span, E0071,
                           "`{}` does not name a structure",
                           pprust::path_to_string(path));
                 self.check_struct_fields_on_error(expr.id, fields, base_expr);
@@ -3329,7 +3307,7 @@ fn expected_types_for_fn_args(&self,
             self.check_expr_has_type(base_expr, expr_ty);
             match expr_ty.sty {
                 ty::TyStruct(adt, substs) => {
-                    self.inh.tables.borrow_mut().fru_field_types.insert(
+                    self.tables.borrow_mut().fru_field_types.insert(
                         expr.id,
                         adt.struct_variant().fields.iter().map(|f| {
                             self.normalize_associated_types_in(
@@ -3364,7 +3342,7 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
     debug!(">> typechecking: expr={:?} expected={:?}",
            expr, expected);
 
-    let tcx = self.tcx();
+    let tcx = self.tcx;
     let id = expr.id;
     match expr.node {
       hir::ExprBox(ref subexpr) => {
@@ -3417,7 +3395,7 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
                     } else if let Some(method) = self.try_overloaded_deref(
                             expr.span, Some(&oprnd), oprnd_t, lvalue_pref) {
                         oprnd_t = self.make_overloaded_lvalue_return_type(method).ty;
-                        self.inh.tables.borrow_mut().method_map.insert(MethodCall::expr(expr.id),
+                        self.tables.borrow_mut().method_map.insert(MethodCall::expr(expr.id),
                                                                        method);
                     } else {
                         self.type_error_message(expr.span, |actual| {
@@ -3453,7 +3431,7 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
         let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| {
             match ty.sty {
                 ty::TyRef(_, ref mt) | ty::TyRawPtr(ref mt) => {
-                    if self.tcx().expr_is_lval(&oprnd) {
+                    if self.tcx.expr_is_lval(&oprnd) {
                         // Lvalues may legitimately have unsized types.
                         // For example, dereferences of a fat pointer and
                         // the last field of a struct can be unsized.
@@ -3485,7 +3463,7 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
             // Finally, borrowck is charged with guaranteeing that the
             // value whose address was taken can actually be made to live
             // as long as it needs to live.
-            let region = self.infcx().next_region_var(infer::AddrOfRegion(expr.span));
+            let region = self.next_region_var(infer::AddrOfRegion(expr.span));
             tcx.mk_ref(tcx.mk_region(region), tm)
         };
         self.write_ty(id, oprnd_t);
@@ -3516,8 +3494,8 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
                   self.instantiate_path(segments, scheme, &predicates,
                                         opt_ty, def, expr.span, id);
               } else {
-                  self.infcx().set_tainted_by_errors();
-                  self.write_ty(id, self.tcx().types.err);
+                  self.set_tainted_by_errors();
+                  self.write_ty(id, self.tcx.types.err);
               }
           }
 
@@ -3536,18 +3514,18 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
           }
           self.write_nil(id);
       }
-      hir::ExprBreak(_) => { self.write_ty(id, self.infcx().next_diverging_ty_var()); }
-      hir::ExprAgain(_) => { self.write_ty(id, self.infcx().next_diverging_ty_var()); }
+      hir::ExprBreak(_) => { self.write_ty(id, self.next_diverging_ty_var()); }
+      hir::ExprAgain(_) => { self.write_ty(id, self.next_diverging_ty_var()); }
       hir::ExprRet(ref expr_opt) => {
         match self.ret_ty {
             ty::FnConverging(result_type) => {
                 if let Some(ref e) = *expr_opt {
                     self.check_expr_coercable_to_type(&e, result_type);
                 } else {
-                    let eq_result = self.infcx().eq_types(false,
-                                                          TypeOrigin::Misc(expr.span),
-                                                          result_type,
-                                                          self.tcx().mk_nil())
+                    let eq_result = self.eq_types(false,
+                                                  TypeOrigin::Misc(expr.span),
+                                                  result_type,
+                                                  tcx.mk_nil())
                         // FIXME(#32730) propagate obligations
                         .map(|InferOk { obligations, .. }| assert!(obligations.is_empty()));
                     if eq_result.is_err() {
@@ -3564,12 +3542,12 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
                     "`return` in a function declared as diverging");
             }
         }
-        self.write_ty(id, self.infcx().next_diverging_ty_var());
+        self.write_ty(id, self.next_diverging_ty_var());
       }
       hir::ExprAssign(ref lhs, ref rhs) => {
         self.check_expr_with_lvalue_pref(&lhs, PreferMutLvalue);
 
-        let tcx = self.tcx();
+        let tcx = self.tcx;
         if !tcx.expr_is_lval(&lhs) {
             span_err!(tcx.sess, expr.span, E0070,
                 "invalid left-hand side expression");
@@ -3606,7 +3584,7 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
       hir::ExprLoop(ref body, _) => {
         self.check_block_no_value(&body);
         if !may_break(tcx, expr.id, &body) {
-            self.write_ty(id, self.infcx().next_diverging_ty_var());
+            self.write_ty(id, self.next_diverging_ty_var());
         } else {
             self.write_nil(id);
         }
@@ -3644,10 +3622,10 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
         // Find the type of `e`. Supply hints based on the type we are casting to,
         // if appropriate.
         let t_cast = self.to_ty(t);
-        let t_cast = self.infcx().resolve_type_vars_if_possible(&t_cast);
+        let t_cast = self.resolve_type_vars_if_possible(&t_cast);
         self.check_expr_with_expectation(e, ExpectCastableToType(t_cast));
         let t_expr = self.expr_ty(e);
-        let t_cast = self.infcx().resolve_type_vars_if_possible(&t_cast);
+        let t_cast = self.resolve_type_vars_if_possible(&t_cast);
 
         // Eagerly check for some obvious errors.
         if t_expr.references_error() || t_cast.references_error() {
@@ -3658,7 +3636,7 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
             self.write_ty(id, t_cast);
 
             // Defer other checks until we're done type checking.
-            let mut deferred_cast_checks = self.inh.deferred_cast_checks.borrow_mut();
+            let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
             match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) {
                 Ok(cast_check) => {
                     deferred_cast_checks.push(cast_check);
@@ -3682,7 +3660,7 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
             }
         });
 
-        let mut unified = self.infcx().next_ty_var();
+        let mut unified = self.next_ty_var();
         let coerce_to = uty.unwrap_or(unified);
 
         for (i, e) in args.iter().enumerate() {
@@ -3701,7 +3679,7 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
             match result {
                 Ok(ty) => unified = ty,
                 Err(e) => {
-                    self.infcx().report_mismatched_types(origin, unified, e_ty, e);
+                    self.report_mismatched_types(origin, unified, e_ty, e);
                 }
             }
         }
@@ -3709,7 +3687,7 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
       }
       hir::ExprRepeat(ref element, ref count_expr) => {
         self.check_expr_has_type(&count_expr, tcx.types.usize);
-        let count = eval_repeat_count(self.tcx(), &count_expr);
+        let count = eval_repeat_count(self.tcx, &count_expr);
 
         let uty = match expected {
             ExpectHasType(uty) => {
@@ -3727,7 +3705,7 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
                 (uty, uty)
             }
             None => {
-                let t: Ty = self.infcx().next_ty_var();
+                let t: Ty = self.next_ty_var();
                 self.check_expr_has_type(&element, t);
                 (self.expr_ty(&element), t)
             }
@@ -3808,7 +3786,7 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
                       self.write_ty(id, element_ty);
                   }
                   None => {
-                      self.check_expr_has_type(&idx, self.tcx().types.err);
+                      self.check_expr_has_type(&idx, self.tcx.types.err);
                       let mut err = self.type_error_struct(
                           expr.span,
                           |actual| {
@@ -3910,7 +3888,7 @@ pub fn check_decl_initializer(&self,
                               local: &'tcx hir::Local,
                               init: &'tcx hir::Expr)
 {
-    let ref_bindings = self.tcx().pat_contains_ref_binding(&local.pat);
+    let ref_bindings = self.tcx.pat_contains_ref_binding(&local.pat);
 
     let local_ty = self.local_ty(init.span, local.id);
     if let Some(m) = ref_bindings {
@@ -3931,7 +3909,7 @@ pub fn check_decl_initializer(&self,
 }
 
 pub fn check_decl_local(&self, local: &'tcx hir::Local)  {
-    let tcx = self.tcx();
+    let tcx = self.tcx;
 
     let t = self.local_ty(local.span, local.id);
     self.write_ty(local.id, t);
@@ -3966,7 +3944,7 @@ pub fn check_stmt(&self, stmt: &'tcx hir::Stmt)  {
           hir::DeclLocal(ref l) => {
               self.check_decl_local(&l);
               let l_t = self.node_ty(l.id);
-              saw_bot = saw_bot || self.infcx().type_var_diverges(l_t);
+              saw_bot = saw_bot || self.type_var_diverges(l_t);
               saw_err = saw_err || l_t.references_error();
           }
           hir::DeclItem(_) => {/* ignore for now */ }
@@ -3975,21 +3953,21 @@ pub fn check_stmt(&self, stmt: &'tcx hir::Stmt)  {
       hir::StmtExpr(ref expr, id) => {
         node_id = id;
         // Check with expected type of ()
-        self.check_expr_has_type(&expr, self.tcx().mk_nil());
+        self.check_expr_has_type(&expr, self.tcx.mk_nil());
         let expr_ty = self.expr_ty(&expr);
-        saw_bot = saw_bot || self.infcx().type_var_diverges(expr_ty);
+        saw_bot = saw_bot || self.type_var_diverges(expr_ty);
         saw_err = saw_err || expr_ty.references_error();
       }
       hir::StmtSemi(ref expr, id) => {
         node_id = id;
         self.check_expr(&expr);
         let expr_ty = self.expr_ty(&expr);
-        saw_bot |= self.infcx().type_var_diverges(expr_ty);
+        saw_bot |= self.type_var_diverges(expr_ty);
         saw_err |= expr_ty.references_error();
       }
     }
     if saw_bot {
-        self.write_ty(node_id, self.infcx().next_diverging_ty_var());
+        self.write_ty(node_id, self.next_diverging_ty_var());
     }
     else if saw_err {
         self.write_error(node_id);
@@ -4000,12 +3978,12 @@ pub fn check_stmt(&self, stmt: &'tcx hir::Stmt)  {
 }
 
 pub fn check_block_no_value(&self, blk: &'tcx hir::Block)  {
-    self.check_block_with_expected(blk, ExpectHasType(self.tcx().mk_nil()));
+    self.check_block_with_expected(blk, ExpectHasType(self.tcx.mk_nil()));
     let blkty = self.node_ty(blk.id);
     if blkty.references_error() {
         self.write_error(blk.id);
     } else {
-        let nilty = self.tcx().mk_nil();
+        let nilty = self.tcx.mk_nil();
         self.demand_suptype(blk.span, nilty, blkty);
     }
 }
@@ -4035,7 +4013,7 @@ fn check_block_with_expected(&self,
             }
             hir::StmtExpr(_, _) | hir::StmtSemi(_, _) => true,
         } {
-            self.tcx()
+            self.tcx
                 .sess
                 .add_lint(lint::builtin::UNREACHABLE_CODE,
                           s_id,
@@ -4043,20 +4021,20 @@ fn check_block_with_expected(&self,
                           "unreachable statement".to_string());
             warned = true;
         }
-        any_diverges = any_diverges || self.infcx().type_var_diverges(s_ty);
+        any_diverges = any_diverges || self.type_var_diverges(s_ty);
         any_err = any_err || s_ty.references_error();
     }
     match blk.expr {
         None => if any_err {
             self.write_error(blk.id);
         } else if any_diverges {
-            self.write_ty(blk.id, self.infcx().next_diverging_ty_var());
+            self.write_ty(blk.id, self.next_diverging_ty_var());
         } else {
             self.write_nil(blk.id);
         },
         Some(ref e) => {
             if any_diverges && !warned {
-                self.tcx()
+                self.tcx
                     .sess
                     .add_lint(lint::builtin::UNREACHABLE_CODE,
                               e.id,
@@ -4077,7 +4055,7 @@ fn check_block_with_expected(&self,
             if any_err {
                 self.write_error(blk.id);
             } else if any_diverges {
-                self.write_ty(blk.id, self.infcx().next_diverging_ty_var());
+                self.write_ty(blk.id, self.next_diverging_ty_var());
             } else {
                 self.write_ty(blk.id, ety);
             }
@@ -4124,7 +4102,7 @@ fn type_scheme_and_predicates_for_def(&self,
         Def::Fn(id) | Def::Method(id) |
         Def::Static(id, _) | Def::Variant(_, id) |
         Def::Struct(id) | Def::Const(id) | Def::AssociatedConst(id) => {
-            (self.tcx().lookup_item_type(id), self.tcx().lookup_predicates(id))
+            (self.tcx.lookup_item_type(id), self.tcx.lookup_predicates(id))
         }
         Def::Trait(_) |
         Def::Enum(..) |
@@ -4258,7 +4236,7 @@ pub fn instantiate_path(&self,
 
         // Case 3. Reference to a method.
         Def::Method(def_id) => {
-            let container = self.tcx().impl_or_trait_item(def_id).container();
+            let container = self.tcx.impl_or_trait_item(def_id).container();
             match container {
                 ty::TraitContainer(trait_did) => {
                     callee::check_legal_trait_for_method_call(self.ccx, span, trait_did)
@@ -4279,7 +4257,7 @@ pub fn instantiate_path(&self,
         }
 
         Def::AssociatedConst(def_id) => {
-            let container = self.tcx().impl_or_trait_item(def_id).container();
+            let container = self.tcx.impl_or_trait_item(def_id).container();
             match container {
                 ty::TraitContainer(trait_did) => {
                     callee::check_legal_trait_for_method_call(self.ccx, span, trait_did)
@@ -4311,7 +4289,7 @@ pub fn instantiate_path(&self,
         }
 
         Def::Err => {
-            self.infcx().set_tainted_by_errors();
+            self.set_tainted_by_errors();
             segment_spaces = vec![None; segments.len()];
         }
     }
@@ -4343,7 +4321,7 @@ pub fn instantiate_path(&self,
                                                                  segment,
                                                                  &mut substs);
         } else {
-            self.tcx().prohibit_type_params(slice::ref_slice(segment));
+            self.tcx.prohibit_type_params(slice::ref_slice(segment));
         }
     }
     if let Some(self_ty) = opt_self_ty {
@@ -4389,14 +4367,14 @@ pub fn instantiate_path(&self,
         // is inherent, there is no `Self` parameter, instead, the impl needs
         // type parameters, which we can infer by unifying the provided `Self`
         // with the substituted impl type.
-        let impl_scheme = self.tcx().lookup_item_type(impl_def_id);
+        let impl_scheme = self.tcx.lookup_item_type(impl_def_id);
         assert_eq!(substs.types.len(subst::TypeSpace),
                    impl_scheme.generics.types.len(subst::TypeSpace));
         assert_eq!(substs.regions.len(subst::TypeSpace),
                    impl_scheme.generics.regions.len(subst::TypeSpace));
 
         let impl_ty = self.instantiate_type_scheme(span, &substs, &impl_scheme.ty);
-        match self.infcx().sub_types(false, TypeOrigin::Misc(span), self_ty, impl_ty) {
+        match self.sub_types(false, TypeOrigin::Misc(span), self_ty, impl_ty) {
             Ok(InferOk { obligations, .. }) => {
                 // FIXME(#32730) propagate obligations
                 assert!(obligations.is_empty());
@@ -4441,7 +4419,7 @@ pub fn instantiate_path(&self,
             }
 
             hir::ParenthesizedParameters(ref data) => {
-                span_err!(self.tcx().sess, span, E0238,
+                span_err!(self.tcx.sess, span, E0238,
                     "parenthesized parameters may only be used with a trait");
                 self.push_explicit_parenthesized_parameters_from_segment_to_substs(
                     space, span, type_defs, data, substs);
@@ -4464,7 +4442,7 @@ pub fn instantiate_path(&self,
                 if i < type_count {
                     substs.types.push(space, t);
                 } else if i == type_count {
-                    span_err!(self.tcx().sess, typ.span, E0087,
+                    span_err!(self.tcx.sess, typ.span, E0087,
                         "too many type parameters provided: \
                          expected at most {} parameter{}, \
                          found {} parameter{}",
@@ -4479,7 +4457,7 @@ pub fn instantiate_path(&self,
         }
 
         if !data.bindings.is_empty() {
-            span_err!(self.tcx().sess, data.bindings[0].span, E0182,
+            span_err!(self.tcx.sess, data.bindings[0].span, E0182,
                       "unexpected binding of associated item in expression path \
                        (only allowed in type paths)");
         }
@@ -4488,11 +4466,11 @@ pub fn instantiate_path(&self,
             let region_count = region_defs.len(space);
             assert_eq!(substs.regions.len(space), 0);
             for (i, lifetime) in data.lifetimes.iter().enumerate() {
-                let r = ast_region_to_region(self.tcx(), lifetime);
+                let r = ast_region_to_region(self.tcx, lifetime);
                 if i < region_count {
                     substs.regions.push(space, r);
                 } else if i == region_count {
-                    span_err!(self.tcx().sess, lifetime.span, E0088,
+                    span_err!(self.tcx.sess, lifetime.span, E0088,
                         "too many lifetime parameters provided: \
                          expected {} parameter{}, found {} parameter{}",
                         region_count,
@@ -4521,7 +4499,7 @@ pub fn instantiate_path(&self,
     {
         let type_count = type_defs.len(space);
         if type_count < 2 {
-            span_err!(self.tcx().sess, span, E0167,
+            span_err!(self.tcx.sess, span, E0167,
                       "parenthesized form always supplies 2 type parameters, \
                       but only {} parameter(s) were expected",
                       type_count);
@@ -4530,7 +4508,7 @@ pub fn instantiate_path(&self,
         let input_tys: Vec<Ty> =
             data.inputs.iter().map(|ty| self.to_ty(&ty)).collect();
 
-        let tuple_ty = self.tcx().mk_tup(input_tys);
+        let tuple_ty = self.tcx.mk_tup(input_tys);
 
         if type_count >= 1 {
             substs.types.push(space, tuple_ty);
@@ -4540,7 +4518,7 @@ pub fn instantiate_path(&self,
             data.output.as_ref().map(|ty| self.to_ty(&ty));
 
         let output_ty =
-            output_ty.unwrap_or(self.tcx().mk_nil());
+            output_ty.unwrap_or(self.tcx.mk_nil());
 
         if type_count >= 2 {
             substs.types.push(space, output_ty);
@@ -4576,7 +4554,7 @@ pub fn instantiate_path(&self,
         // everything.
         if provided_len == 0 && !(require_type_space && space == subst::TypeSpace) {
             substs.types.replace(space, Vec::new());
-            self.infcx().type_vars_for_defs(span, space, substs, &desired[..]);
+            self.type_vars_for_defs(span, space, substs, &desired[..]);
             return;
         }
 
@@ -4585,14 +4563,14 @@ pub fn instantiate_path(&self,
         if provided_len < required_len {
             let qualifier =
                 if desired.len() != required_len { "at least " } else { "" };
-            span_err!(self.tcx().sess, span, E0089,
+            span_err!(self.tcx.sess, span, E0089,
                 "too few type parameters provided: expected {}{} parameter{}, \
                  found {} parameter{}",
                 qualifier, required_len,
                 if required_len == 1 {""} else {"s"},
                 provided_len,
                 if provided_len == 1 {""} else {"s"});
-            substs.types.replace(space, vec![self.tcx().types.err; desired.len()]);
+            substs.types.replace(space, vec![self.tcx.types.err; desired.len()]);
             return;
         }
 
@@ -4605,7 +4583,7 @@ pub fn instantiate_path(&self,
         // partial substitution that we have built up.
         for i in provided_len..desired.len() {
             let default = desired[i].default.unwrap();
-            let default = default.subst_spanned(self.tcx(), substs, Some(span));
+            let default = default.subst_spanned(self.tcx, substs, Some(span));
             substs.types.push(space, default);
         }
         assert_eq!(substs.types.len(space), desired.len());
@@ -4629,7 +4607,7 @@ pub fn instantiate_path(&self,
         if provided_len == 0 {
             substs.regions.replace(
                 space,
-                self.infcx().region_vars_for_defs(span, desired));
+                self.region_vars_for_defs(span, desired));
             return;
         }
 
@@ -4640,7 +4618,7 @@ pub fn instantiate_path(&self,
 
         // Otherwise, too few were provided. Report an error and then
         // use inference variables.
-        span_err!(self.tcx().sess, span, E0090,
+        span_err!(self.tcx.sess, span, E0090,
             "too few lifetime parameters provided: expected {} parameter{}, \
              found {} parameter{}",
             desired.len(),
@@ -4650,27 +4628,27 @@ pub fn instantiate_path(&self,
 
         substs.regions.replace(
             space,
-            self.infcx().region_vars_for_defs(span, desired));
+            self.region_vars_for_defs(span, desired));
     }
 
 fn structurally_resolve_type_or_else<F>(&self, sp: Span, ty: Ty<'tcx>, f: F)
                                         -> Ty<'tcx>
     where F: Fn() -> Ty<'tcx>
 {
-    let mut ty = self.resolve_type_vars_if_possible(ty);
+    let mut ty = self.resolve_type_vars_with_obligations(ty);
 
     if ty.is_ty_var() {
         let alternative = f();
 
         // If not, error.
         if alternative.is_ty_var() || alternative.references_error() {
-            if !self.infcx().is_tainted_by_errors() {
+            if !self.is_tainted_by_errors() {
                 self.type_error_message(sp, |_actual| {
                     "the type of this value must be known in this context".to_string()
                 }, ty, None);
             }
-            self.demand_suptype(sp, self.tcx().types.err, ty);
-            ty = self.tcx().types.err;
+            self.demand_suptype(sp, self.tcx.types.err, ty);
+            ty = self.tcx.types.err;
         } else {
             self.demand_suptype(sp, alternative, ty);
             ty = alternative;
@@ -4684,7 +4662,7 @@ fn structurally_resolve_type_or_else<F>(&self, sp: Span, ty: Ty<'tcx>, f: F)
 // resolution is possible, then an error is reported.
 pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
     self.structurally_resolve_type_or_else(sp, ty, || {
-        self.tcx().types.err
+        self.tcx.types.err
     })
 }
 }
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index 977eb4b35ff..9b3823774f7 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -27,10 +27,10 @@ pub fn check_binop_assign(&self,
 {
     self.check_expr_with_lvalue_pref(lhs_expr, PreferMutLvalue);
 
-    let lhs_ty = self.resolve_type_vars_if_possible(self.expr_ty(lhs_expr));
+    let lhs_ty = self.resolve_type_vars_with_obligations(self.expr_ty(lhs_expr));
     let (rhs_ty, return_ty) =
         self.check_overloaded_binop(expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::Yes);
-    let rhs_ty = self.resolve_type_vars_if_possible(rhs_ty);
+    let rhs_ty = self.resolve_type_vars_with_obligations(rhs_ty);
 
     if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) {
         self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op);
@@ -39,7 +39,7 @@ pub fn check_binop_assign(&self,
         self.write_ty(expr.id, return_ty);
     }
 
-    let tcx = self.tcx();
+    let tcx = self.tcx;
     if !tcx.expr_is_lval(lhs_expr) {
         span_err!(tcx.sess, lhs_expr.span, E0067, "invalid left-hand side expression");
     }
@@ -52,7 +52,7 @@ pub fn check_binop(&self,
                    lhs_expr: &'tcx hir::Expr,
                    rhs_expr: &'tcx hir::Expr)
 {
-    let tcx = self.tcx();
+    let tcx = self.tcx;
 
     debug!("check_binop(expr.id={}, expr={:?}, op={:?}, lhs_expr={:?}, rhs_expr={:?})",
            expr.id,
@@ -62,7 +62,7 @@ pub fn check_binop(&self,
            rhs_expr);
 
     self.check_expr(lhs_expr);
-    let lhs_ty = self.resolve_type_vars_if_possible(self.expr_ty(lhs_expr));
+    let lhs_ty = self.resolve_type_vars_with_obligations(self.expr_ty(lhs_expr));
 
     match BinOpCategory::from(op) {
         BinOpCategory::Shortcircuit => {
@@ -90,7 +90,7 @@ pub fn check_binop(&self,
             // deduce that the result type should be `u32`, even
             // though we don't know yet what type 2 has and hence
             // can't pin this down to a specific impl.
-            let rhs_ty = self.resolve_type_vars_if_possible(rhs_ty);
+            let rhs_ty = self.resolve_type_vars_with_obligations(rhs_ty);
             if
                 !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() &&
                 is_builtin_binop(lhs_ty, rhs_ty, op)
@@ -115,7 +115,7 @@ fn enforce_builtin_binop_types(&self,
 {
     debug_assert!(is_builtin_binop(lhs_ty, rhs_ty, op));
 
-    let tcx = self.tcx();
+    let tcx = self.tcx;
     match BinOpCategory::from(op) {
         BinOpCategory::Shortcircuit => {
             self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty);
@@ -165,7 +165,7 @@ fn check_overloaded_binop(&self,
     // using this variable as the expected type, which sometimes lets
     // us do better coercions than we would be able to do otherwise,
     // particularly for things like `String + &String`.
-    let rhs_ty_var = self.infcx().next_ty_var();
+    let rhs_ty_var = self.next_ty_var();
 
     let return_ty = match self.lookup_op_method(expr, lhs_ty, vec![rhs_ty_var],
                                                 token::intern(name), trait_def_id,
@@ -175,12 +175,12 @@ fn check_overloaded_binop(&self,
             // error types are considered "builtin"
             if !lhs_ty.references_error() {
                 if let IsAssign::Yes = is_assign {
-                    span_err!(self.tcx().sess, lhs_expr.span, E0368,
+                    span_err!(self.tcx.sess, lhs_expr.span, E0368,
                               "binary assignment operation `{}=` cannot be applied to type `{}`",
                               op.node.as_str(),
                               lhs_ty);
                 } else {
-                    let mut err = struct_span_err!(self.tcx().sess, lhs_expr.span, E0369,
+                    let mut err = struct_span_err!(self.tcx.sess, lhs_expr.span, E0369,
                         "binary operation `{}` cannot be applied to type `{}`",
                         op.node.as_str(),
                         lhs_ty);
@@ -208,7 +208,7 @@ fn check_overloaded_binop(&self,
                     err.emit();
                 }
             }
-            self.tcx().types.err
+            self.tcx.types.err
         }
     };
 
@@ -238,7 +238,7 @@ pub fn check_user_unop(&self,
                 format!("cannot apply unary operator `{}` to type `{}`",
                         op_str, actual)
             }, operand_ty, None);
-            self.tcx().types.err
+            self.tcx.types.err
         }
     }
 }
@@ -247,7 +247,7 @@ fn name_and_trait_def_id(&self,
                          op: hir::BinOp,
                          is_assign: IsAssign)
                          -> (&'static str, Option<DefId>) {
-    let lang = &self.tcx().lang_items;
+    let lang = &self.tcx.lang_items;
 
     if let IsAssign::Yes = is_assign {
         match op.node {
@@ -329,12 +329,12 @@ fn lookup_op_method(&self,
 
             // HACK(eddyb) Fully qualified path to work around a resolve bug.
             let method_call = ::rustc::ty::MethodCall::expr(expr.id);
-            self.inh.tables.borrow_mut().method_map.insert(method_call, method);
+            self.tables.borrow_mut().method_map.insert(method_call, method);
 
             // extract return type for method; all late bound regions
             // should have been instantiated by now
             let ret_ty = method_ty.fn_ret();
-            Ok(self.tcx().no_late_bound_regions(&ret_ty).unwrap().unwrap())
+            Ok(self.tcx.no_late_bound_regions(&ret_ty).unwrap().unwrap())
         }
         None => {
             Err(())
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index c16a00e723e..b65fcbac8d4 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -90,13 +90,14 @@ use middle::mem_categorization::Categorization;
 use middle::region::{self, CodeExtent};
 use rustc::ty::subst::Substs;
 use rustc::traits;
-use rustc::ty::{self, Ty, TyCtxt, MethodCall, TypeFoldable};
-use rustc::infer::{self, GenericKind, InferCtxt, InferOk, SubregionOrigin, TypeOrigin, VerifyBound};
+use rustc::ty::{self, Ty, MethodCall, TypeFoldable};
+use rustc::infer::{self, GenericKind, InferOk, SubregionOrigin, TypeOrigin, VerifyBound};
 use hir::pat_util;
 use rustc::ty::adjustment;
 use rustc::ty::wf::ImpliedBound;
 
 use std::mem;
+use std::ops::Deref;
 use syntax::ast;
 use syntax::codemap::Span;
 use rustc::hir::intravisit::{self, Visitor};
@@ -132,7 +133,7 @@ pub fn regionck_item(&self,
     debug!("regionck_item(item.id={:?}, wf_tys={:?}", item_id, wf_tys);
     let mut rcx = RegionCtxt::new(self, RepeatingScope(item_id), item_id, Subject(item_id));
     rcx.free_region_map.relate_free_regions_from_predicates(
-        &self.infcx().parameter_environment.caller_bounds);
+        &self.parameter_environment.caller_bounds);
     rcx.relate_free_regions(wf_tys, item_id, span);
     rcx.visit_region_obligations(item_id);
     rcx.resolve_regions_and_report_errors();
@@ -152,14 +153,14 @@ pub fn regionck_fn(&self,
     }
 
     rcx.free_region_map.relate_free_regions_from_predicates(
-        &self.infcx().parameter_environment.caller_bounds);
+        &self.parameter_environment.caller_bounds);
 
     rcx.resolve_regions_and_report_errors();
 
     // For the top-level fn, store the free-region-map. We don't store
     // any map for closures; they just share the same map as the
     // function that created them.
-    self.tcx().store_free_region_map(fn_id, rcx.free_region_map);
+    self.tcx.store_free_region_map(fn_id, rcx.free_region_map);
 }
 }
 
@@ -187,6 +188,13 @@ pub struct RegionCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 
 }
 
+impl<'a, 'gcx, 'tcx> Deref for RegionCtxt<'a, 'gcx, 'tcx> {
+    type Target = FnCtxt<'a, 'gcx, 'tcx>;
+    fn deref(&self) -> &Self::Target {
+        &self.fcx
+    }
+}
+
 pub struct RepeatingScope(ast::NodeId);
 pub enum SubjectNode { Subject(ast::NodeId), None }
 
@@ -207,14 +215,6 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx, 'tcx> {
         }
     }
 
-    pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
-        self.fcx.tcx()
-    }
-
-    pub fn infcx(&self) -> &InferCtxt<'a,'tcx, 'tcx> {
-        self.fcx.infcx()
-    }
-
     fn set_call_site_scope(&mut self, call_site_scope: Option<CodeExtent>) -> Option<CodeExtent> {
         mem::replace(&mut self.call_site_scope, call_site_scope)
     }
@@ -251,17 +251,17 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx, 'tcx> {
     /// of b will be `&<R0>.i32` and then `*b` will require that `<R0>` be bigger than the let and
     /// the `*b` expression, so we will effectively resolve `<R0>` to be the block B.
     pub fn resolve_type(&self, unresolved_ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.fcx.infcx().resolve_type_vars_if_possible(&unresolved_ty)
+        self.resolve_type_vars_if_possible(&unresolved_ty)
     }
 
     /// Try to resolve the type for the given node.
     fn resolve_node_type(&self, id: ast::NodeId) -> Ty<'tcx> {
-        let t = self.fcx.node_ty(id);
+        let t = self.node_ty(id);
         self.resolve_type(t)
     }
 
     fn resolve_method_type(&self, method_call: MethodCall) -> Option<Ty<'tcx>> {
-        let method_ty = self.fcx.inh.tables.borrow().method_map
+        let method_ty = self.tables.borrow().method_map
                             .get(&method_call).map(|method| method.ty);
         method_ty.map(|method_ty| self.resolve_type(method_ty))
     }
@@ -273,8 +273,8 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx, 'tcx> {
             ty_unadjusted
         } else {
             ty_unadjusted.adjust(
-                self.fcx.tcx(), expr.span, expr.id,
-                self.fcx.inh.tables.borrow().adjustments.get(&expr.id),
+                self.tcx, expr.span, expr.id,
+                self.tables.borrow().adjustments.get(&expr.id),
                 |method_call| self.resolve_method_type(method_call))
         }
     }
@@ -288,12 +288,12 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx, 'tcx> {
         // When we enter a function, we can derive
         debug!("visit_fn_body(id={})", id);
 
-        let call_site = self.fcx.tcx().region_maps.lookup_code_extent(
+        let call_site = self.tcx.region_maps.lookup_code_extent(
             region::CodeExtentData::CallSiteScope { fn_id: id, body_id: body.id });
         let old_call_site_scope = self.set_call_site_scope(Some(call_site));
 
         let fn_sig = {
-            let fn_sig_map = &self.infcx().tables.borrow().liberated_fn_sigs;
+            let fn_sig_map = &self.tables.borrow().liberated_fn_sigs;
             match fn_sig_map.get(&id) {
                 Some(f) => f.clone(),
                 None => {
@@ -312,12 +312,12 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx, 'tcx> {
         let fn_sig_tys: Vec<_> =
             fn_sig.inputs.iter()
                          .cloned()
-                         .chain(Some(fn_sig.output.unwrap_or(self.tcx().types.bool)))
+                         .chain(Some(fn_sig.output.unwrap_or(self.tcx.types.bool)))
                          .collect();
 
         let old_body_id = self.set_body_id(body.id);
         self.relate_free_regions(&fn_sig_tys[..], body.id, span);
-        self.link_fn_args(self.tcx().region_maps.node_extent(body.id),
+        self.link_fn_args(self.tcx.region_maps.node_extent(body.id),
                           &fn_decl.inputs[..]);
         self.visit_block(body);
         self.visit_region_obligations(body.id);
@@ -342,14 +342,12 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx, 'tcx> {
         // region checking can introduce new pending obligations
         // which, when processed, might generate new region
         // obligations. So make sure we process those.
-        self.fcx.select_all_obligations_or_error();
+        self.select_all_obligations_or_error();
 
         // Make a copy of the region obligations vec because we'll need
         // to be able to borrow the fulfillment-cx below when projecting.
         let region_obligations =
-            self.fcx
-                .inh
-                .fulfillment_cx
+            self.fulfillment_cx
                 .borrow()
                 .region_obligations(node_id)
                 .to_vec();
@@ -364,7 +362,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx, 'tcx> {
 
         // Processing the region obligations should not cause the list to grow further:
         assert_eq!(region_obligations.len(),
-                   self.fcx.inh.fulfillment_cx.borrow().region_obligations(node_id).len());
+                   self.fulfillment_cx.borrow().region_obligations(node_id).len());
     }
 
     fn code_to_origin(&self,
@@ -399,7 +397,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx, 'tcx> {
         for &ty in fn_sig_tys {
             let ty = self.resolve_type(ty);
             debug!("relate_free_regions(t={:?})", ty);
-            let implied_bounds = ty::wf::implied_bounds(self.fcx.infcx(), body_id, ty, span);
+            let implied_bounds = ty::wf::implied_bounds(self, body_id, ty, span);
 
             // Record any relations between free regions that we observe into the free-region-map.
             self.free_region_map.relate_free_regions_from_implied_bounds(&implied_bounds);
@@ -412,7 +410,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx, 'tcx> {
                 match implication {
                     ImpliedBound::RegionSubRegion(ty::ReFree(free_a),
                                                   ty::ReVar(vid_b)) => {
-                        self.fcx.inh.infcx.add_given(free_a, vid_b);
+                        self.add_given(free_a, vid_b);
                     }
                     ImpliedBound::RegionSubParam(r_a, param_b) => {
                         self.region_bound_pairs.push((r_a, GenericKind::Param(param_b)));
@@ -447,12 +445,12 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx, 'tcx> {
             }
         };
 
-        self.fcx.infcx().resolve_regions_and_report_errors(&self.free_region_map,
-                                                           subject_node_id);
+        self.fcx.resolve_regions_and_report_errors(&self.free_region_map,
+                                                   subject_node_id);
     }
 
 fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat) {
-    let tcx = self.fcx.tcx();
+    let tcx = self.tcx;
     debug!("regionck::visit_pat(pat={:?})", pat);
     pat_util::pat_bindings(&tcx.def_map, pat, |_, id, span, _| {
         // If we have a variable that contains region'd data, that
@@ -528,12 +526,12 @@ fn visit_expr(&mut self, expr: &hir::Expr) {
     // scope of that expression. This also guarantees basic WF.
     let expr_ty = self.resolve_node_type(expr.id);
     // the region corresponding to this expression
-    let expr_region = ty::ReScope(self.tcx().region_maps.node_extent(expr.id));
+    let expr_region = ty::ReScope(self.tcx.region_maps.node_extent(expr.id));
     self.type_must_outlive(infer::ExprTypeIsNotInScope(expr_ty, expr.span),
                            expr_ty, expr_region);
 
     let method_call = MethodCall::expr(expr.id);
-    let opt_method_callee = self.fcx.inh.tables.borrow().method_map.get(&method_call).cloned();
+    let opt_method_callee = self.tables.borrow().method_map.get(&method_call).cloned();
     let has_method_map = opt_method_callee.is_some();
 
     // If we are calling a method (either explicitly or via an
@@ -556,7 +554,7 @@ fn visit_expr(&mut self, expr: &hir::Expr) {
     }
 
     // Check any autoderefs or autorefs that appear.
-    let adjustment = self.fcx.inh.tables.borrow().adjustments.get(&expr.id).map(|a| a.clone());
+    let adjustment = self.tables.borrow().adjustments.get(&expr.id).map(|a| a.clone());
     if let Some(adjustment) = adjustment {
         debug!("adjustment={:?}", adjustment);
         match adjustment {
@@ -592,7 +590,7 @@ fn visit_expr(&mut self, expr: &hir::Expr) {
         // If necessary, constrain destructors in the unadjusted form of this
         // expression.
         let cmt_result = {
-            let mc = mc::MemCategorizationContext::new(self.fcx.infcx());
+            let mc = mc::MemCategorizationContext::new(self);
             mc.cat_expr_unadjusted(expr)
         };
         match cmt_result {
@@ -601,8 +599,7 @@ fn visit_expr(&mut self, expr: &hir::Expr) {
                                                                     expr.span);
             }
             Err(..) => {
-                let tcx = self.fcx.tcx();
-                tcx.sess.delay_span_bug(expr.span, "cat_expr_unadjusted Errd");
+                self.tcx.sess.delay_span_bug(expr.span, "cat_expr_unadjusted Errd");
             }
         }
     }
@@ -610,7 +607,7 @@ fn visit_expr(&mut self, expr: &hir::Expr) {
     // If necessary, constrain destructors in this expression. This will be
     // the adjusted form if there is an adjustment.
     let cmt_result = {
-        let mc = mc::MemCategorizationContext::new(self.fcx.infcx());
+        let mc = mc::MemCategorizationContext::new(self);
         mc.cat_expr(expr)
     };
     match cmt_result {
@@ -618,8 +615,7 @@ fn visit_expr(&mut self, expr: &hir::Expr) {
             self.check_safety_of_rvalue_destructor_if_necessary(head_cmt, expr.span);
         }
         Err(..) => {
-            let tcx = self.fcx.tcx();
-            tcx.sess.delay_span_bug(expr.span, "cat_expr Errd");
+            self.tcx.sess.delay_span_bug(expr.span, "cat_expr Errd");
         }
     }
 
@@ -707,12 +703,12 @@ fn visit_expr(&mut self, expr: &hir::Expr) {
         hir::ExprUnary(hir::UnDeref, ref base) => {
             // For *a, the lifetime of a must enclose the deref
             let method_call = MethodCall::expr(expr.id);
-            let base_ty = match self.fcx.inh.tables.borrow().method_map.get(&method_call) {
+            let base_ty = match self.tables.borrow().method_map.get(&method_call) {
                 Some(method) => {
                     self.constrain_call(expr, Some(&base),
                                         None::<hir::Expr>.iter(), true);
                     let fn_ret = // late-bound regions in overloaded method calls are instantiated
-                        self.tcx().no_late_bound_regions(&method.ty.fn_ret()).unwrap();
+                        self.tcx.no_late_bound_regions(&method.ty.fn_ret()).unwrap();
                     fn_ret.unwrap()
                 }
                 None => self.resolve_node_type(base.id)
@@ -824,7 +820,7 @@ fn constrain_cast(&mut self,
             /*From:*/ (&ty::TyRef(from_r, ref from_mt),
             /*To:  */  &ty::TyRef(to_r, ref to_mt)) => {
                 // Target cannot outlive source, naturally.
-                self.fcx.infcx().sub_regions(infer::Reborrow(cast_expr.span), *to_r, *from_r);
+                self.sub_regions(infer::Reborrow(cast_expr.span), *to_r, *from_r);
                 self.walk_cast(cast_expr, from_mt.ty, to_mt.ty);
             }
 
@@ -893,7 +889,7 @@ fn constrain_call<'b, I: Iterator<Item=&'b hir::Expr>>(&mut self,
     // call occurs.
     //
     // FIXME(#6268) to support nested method calls, should be callee_id
-    let callee_scope = self.tcx().region_maps.node_extent(call_expr.id);
+    let callee_scope = self.tcx.region_maps.node_extent(call_expr.id);
     let callee_region = ty::ReScope(callee_scope);
 
     debug!("callee_region={:?}", callee_region);
@@ -938,13 +934,13 @@ fn constrain_autoderefs(&mut self,
            derefs,
            derefd_ty);
 
-    let s_deref_expr = self.tcx().region_maps.node_extent(deref_expr.id);
+    let s_deref_expr = self.tcx.region_maps.node_extent(deref_expr.id);
     let r_deref_expr = ty::ReScope(s_deref_expr);
     for i in 0..derefs {
         let method_call = MethodCall::autoderef(deref_expr.id, i as u32);
         debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs);
 
-        let method = self.fcx.inh.tables.borrow().method_map.get(&method_call).map(|m| m.clone());
+        let method = self.tables.borrow().method_map.get(&method_call).map(|m| m.clone());
 
         derefd_ty = match method {
             Some(method) => {
@@ -958,7 +954,7 @@ fn constrain_autoderefs(&mut self,
                 // was applied on the base type, as that is always the case.
                 let fn_sig = method.ty.fn_sig();
                 let fn_sig = // late-bound regions should have been instantiated
-                    self.tcx().no_late_bound_regions(fn_sig).unwrap();
+                    self.tcx.no_late_bound_regions(fn_sig).unwrap();
                 let self_ty = fn_sig.inputs[0];
                 let (m, r) = match self_ty.sty {
                     ty::TyRef(r, ref m) => (m.mutbl, r),
@@ -974,7 +970,7 @@ fn constrain_autoderefs(&mut self,
                        r, m);
 
                 {
-                    let mc = mc::MemCategorizationContext::new(self.fcx.infcx());
+                    let mc = mc::MemCategorizationContext::new(self);
                     let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
                     debug!("constrain_autoderefs: self_cmt={:?}",
                            self_cmt);
@@ -1015,8 +1011,8 @@ pub fn mk_subregion_due_to_dereference(&mut self,
                                        deref_span: Span,
                                        minimum_lifetime: ty::Region,
                                        maximum_lifetime: ty::Region) {
-    self.fcx.infcx().sub_regions(infer::DerefPointer(deref_span),
-                                 minimum_lifetime, maximum_lifetime)
+    self.sub_regions(infer::DerefPointer(deref_span),
+                     minimum_lifetime, maximum_lifetime)
 }
 
 fn check_safety_of_rvalue_destructor_if_necessary(&mut self,
@@ -1052,14 +1048,14 @@ fn constrain_index(&mut self,
                    indexed_ty: Ty<'tcx>)
 {
     debug!("constrain_index(index_expr=?, indexed_ty={}",
-           self.fcx.infcx().ty_to_string(indexed_ty));
+           self.ty_to_string(indexed_ty));
 
-    let r_index_expr = ty::ReScope(self.tcx().region_maps.node_extent(index_expr.id));
+    let r_index_expr = ty::ReScope(self.tcx.region_maps.node_extent(index_expr.id));
     if let ty::TyRef(r_ptr, mt) = indexed_ty.sty {
         match mt.ty.sty {
             ty::TySlice(_) | ty::TyStr => {
-                self.fcx.infcx().sub_regions(infer::IndexSlice(index_expr.span),
-                                             r_index_expr, *r_ptr);
+                self.sub_regions(infer::IndexSlice(index_expr.span),
+                                 r_index_expr, *r_ptr);
             }
             _ => {}
         }
@@ -1073,14 +1069,14 @@ fn type_of_node_must_outlive(&mut self,
     id: ast::NodeId,
     minimum_lifetime: ty::Region)
 {
-    let tcx = self.fcx.tcx();
+    let tcx = self.tcx;
 
     // Try to resolve the type.  If we encounter an error, then typeck
     // is going to fail anyway, so just stop here and let typeck
     // report errors later on in the writeback phase.
     let ty0 = self.resolve_node_type(id);
     let ty = ty0.adjust(tcx, origin.span(), id,
-                        self.fcx.inh.tables.borrow().adjustments.get(&id),
+                        self.tables.borrow().adjustments.get(&id),
                         |method_call| self.resolve_method_type(method_call));
     debug!("constrain_regions_in_type_of_node(\
             ty={}, ty0={}, id={}, minimum_lifetime={:?})",
@@ -1096,7 +1092,7 @@ fn link_addr_of(&mut self, expr: &hir::Expr,
     debug!("link_addr_of(expr={:?}, base={:?})", expr, base);
 
     let cmt = {
-        let mc = mc::MemCategorizationContext::new(self.fcx.infcx());
+        let mc = mc::MemCategorizationContext::new(self);
         ignore_err!(mc.cat_expr(base))
     };
 
@@ -1114,7 +1110,7 @@ fn link_local(&self, local: &hir::Local) {
         None => { return; }
         Some(ref expr) => &**expr,
     };
-    let mc = mc::MemCategorizationContext::new(self.fcx.infcx());
+    let mc = mc::MemCategorizationContext::new(self);
     let discr_cmt = ignore_err!(mc.cat_expr(init_expr));
     self.link_pattern(mc, discr_cmt, &local.pat);
 }
@@ -1124,7 +1120,7 @@ fn link_local(&self, local: &hir::Local) {
 /// linked to the lifetime of its guarantor (if any).
 fn link_match(&self, discr: &hir::Expr, arms: &[hir::Arm]) {
     debug!("regionck::for_match()");
-    let mc = mc::MemCategorizationContext::new(self.fcx.infcx());
+    let mc = mc::MemCategorizationContext::new(self);
     let discr_cmt = ignore_err!(mc.cat_expr(discr));
     debug!("discr_cmt={:?}", discr_cmt);
     for arm in arms {
@@ -1139,9 +1135,9 @@ fn link_match(&self, discr: &hir::Expr, arms: &[hir::Arm]) {
 /// linked to the lifetime of its guarantor (if any).
 fn link_fn_args(&self, body_scope: CodeExtent, args: &[hir::Arg]) {
     debug!("regionck::link_fn_args(body_scope={:?})", body_scope);
-    let mc = mc::MemCategorizationContext::new(self.fcx.infcx());
+    let mc = mc::MemCategorizationContext::new(self);
     for arg in args {
-        let arg_ty = self.fcx.node_ty(arg.id);
+        let arg_ty = self.node_ty(arg.id);
         let re_scope = ty::ReScope(body_scope);
         let arg_cmt = mc.cat_rvalue(arg.id, arg.ty.span, re_scope, arg_ty);
         debug!("arg_ty={:?} arg_cmt={:?} arg={:?}",
@@ -1193,7 +1189,7 @@ fn link_autoref(&self,
                 autoref: &adjustment::AutoRef)
 {
     debug!("link_autoref(autoref={:?})", autoref);
-    let mc = mc::MemCategorizationContext::new(self.fcx.infcx());
+    let mc = mc::MemCategorizationContext::new(self);
     let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs));
     debug!("expr_cmt={:?}", expr_cmt);
 
@@ -1204,7 +1200,7 @@ fn link_autoref(&self,
         }
 
         adjustment::AutoUnsafe(m) => {
-            let r = ty::ReScope(self.tcx().region_maps.node_extent(expr.id));
+            let r = ty::ReScope(self.tcx.region_maps.node_extent(expr.id));
             self.link_region(expr.span, &r, ty::BorrowKind::from_mutbl(m), expr_cmt);
         }
     }
@@ -1217,7 +1213,7 @@ fn link_by_ref(&self,
                callee_scope: CodeExtent) {
     debug!("link_by_ref(expr={:?}, callee_scope={:?})",
            expr, callee_scope);
-    let mc = mc::MemCategorizationContext::new(self.fcx.infcx());
+    let mc = mc::MemCategorizationContext::new(self);
     let expr_cmt = ignore_err!(mc.cat_expr(expr));
     let borrow_region = ty::ReScope(callee_scope);
     self.link_region(expr.span, &borrow_region, ty::ImmBorrow, expr_cmt);
@@ -1357,7 +1353,7 @@ fn link_reborrowed_region(&self,
     // Detect by-ref upvar `x`:
     let cause = match note {
         mc::NoteUpvarRef(ref upvar_id) => {
-            let upvar_capture_map = &self.fcx.inh.tables.borrow_mut().upvar_capture_map;
+            let upvar_capture_map = &self.tables.borrow_mut().upvar_capture_map;
             match upvar_capture_map.get(upvar_id) {
                 Some(&ty::UpvarCapture::ByRef(ref upvar_borrow)) => {
                     // The mutability of the upvar may have been modified
@@ -1385,7 +1381,7 @@ fn link_reborrowed_region(&self,
     debug!("link_reborrowed_region: {:?} <= {:?}",
            borrow_region,
            ref_region);
-    self.fcx.infcx().sub_regions(cause, *borrow_region, ref_region);
+    self.sub_regions(cause, *borrow_region, ref_region);
 
     // If we end up needing to recurse and establish a region link
     // with `ref_cmt`, calculate what borrow kind we will end up
@@ -1467,7 +1463,7 @@ fn substs_wf_in_scope(&mut self,
     let origin = infer::ParameterInScope(origin, expr_span);
 
     for &region in &substs.regions {
-        self.fcx.infcx().sub_regions(origin.clone(), expr_region, region);
+        self.sub_regions(origin.clone(), expr_region, region);
     }
 
     for &ty in &substs.types {
@@ -1493,7 +1489,7 @@ pub fn type_must_outlive(&self,
 
     assert!(!ty.has_escaping_regions());
 
-    let components = self.infcx().outlives_components(ty);
+    let components = self.outlives_components(ty);
     self.components_must_outlive(origin, components, region);
 }
 
@@ -1506,7 +1502,7 @@ fn components_must_outlive(&self,
         let origin = origin.clone();
         match component {
             ty::outlives::Component::Region(region1) => {
-                self.fcx.infcx().sub_regions(origin, region, region1);
+                self.sub_regions(origin, region, region1);
             }
             ty::outlives::Component::Param(param_ty) => {
                 self.param_ty_must_outlive(origin, region, param_ty);
@@ -1521,7 +1517,7 @@ fn components_must_outlive(&self,
                 // ignore this, we presume it will yield an error
                 // later, since if a type variable is not resolved by
                 // this point it never will be
-                self.tcx().sess.delay_span_bug(
+                self.tcx.sess.delay_span_bug(
                     origin.span(),
                     &format!("unresolved inference variable in outlives: {:?}", v));
             }
@@ -1538,7 +1534,7 @@ fn param_ty_must_outlive(&self,
 
     let verify_bound = self.param_bound(param_ty);
     let generic = GenericKind::Param(param_ty);
-    self.fcx.infcx().verify_generic_bound(origin, generic, region, verify_bound);
+    self.verify_generic_bound(origin, generic, region, verify_bound);
 }
 
 fn projection_must_outlive(&self,
@@ -1604,7 +1600,7 @@ fn projection_must_outlive(&self,
         }
 
         for &r in &projection_ty.trait_ref.substs.regions {
-            self.fcx.infcx().sub_regions(origin.clone(), region, r);
+            self.sub_regions(origin.clone(), region, r);
         }
 
         return;
@@ -1625,7 +1621,7 @@ fn projection_must_outlive(&self,
                                          .any(|r| env_bounds.contains(r))
         {
             debug!("projection_must_outlive: unique declared bound appears in trait ref");
-            self.fcx.infcx().sub_regions(origin.clone(), region, unique_bound);
+            self.sub_regions(origin.clone(), region, unique_bound);
             return;
         }
     }
@@ -1637,7 +1633,7 @@ fn projection_must_outlive(&self,
     // even though a satisfactory solution exists.
     let verify_bound = self.projection_bound(origin.span(), env_bounds, projection_ty);
     let generic = GenericKind::Projection(projection_ty);
-    self.fcx.infcx().verify_generic_bound(origin, generic.clone(), region, verify_bound);
+    self.verify_generic_bound(origin, generic.clone(), region, verify_bound);
 }
 
 fn type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound {
@@ -1656,7 +1652,7 @@ fn type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound {
 }
 
 fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound {
-    let param_env = &self.infcx().parameter_environment;
+    let param_env = &self.parameter_environment;
 
     debug!("param_bound(param_ty={:?})",
            param_ty);
@@ -1696,7 +1692,7 @@ fn projection_bound(&self,
 
     // see the extensive comment in projection_must_outlive
 
-    let ty = self.tcx().mk_projection(projection_ty.trait_ref, projection_ty.item_name);
+    let ty = self.tcx.mk_projection(projection_ty.trait_ref, projection_ty.item_name);
     let recursive_bound = self.recursive_type_bound(span, ty);
 
     VerifyBound::AnyRegion(declared_bounds).or(recursive_bound)
@@ -1726,11 +1722,11 @@ fn recursive_type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound {
 fn declared_generic_bounds_from_env(&self, generic: GenericKind<'tcx>)
                                     -> Vec<ty::Region>
 {
-    let param_env = &self.infcx().parameter_environment;
+    let param_env = &self.parameter_environment;
 
     // To start, collect bounds from user:
-    let mut param_bounds = self.tcx().required_region_bounds(generic.to_ty(self.tcx()),
-                                                             param_env.caller_bounds.clone());
+    let mut param_bounds = self.tcx.required_region_bounds(generic.to_ty(self.tcx),
+                                                           param_env.caller_bounds.clone());
 
     // Next, collect regions we scraped from the well-formedness
     // constraints in the fn signature. To do that, we walk the list
@@ -1760,14 +1756,11 @@ fn declared_projection_bounds_from_trait(&self,
                                          projection_ty: ty::ProjectionTy<'tcx>)
                                          -> Vec<ty::Region>
 {
-    let fcx = self.fcx;
-    let tcx = fcx.tcx();
-    let infcx = fcx.infcx();
-
     debug!("projection_bounds(projection_ty={:?})",
            projection_ty);
 
-    let ty = tcx.mk_projection(projection_ty.trait_ref.clone(), projection_ty.item_name);
+    let ty = self.tcx.mk_projection(projection_ty.trait_ref.clone(),
+                                    projection_ty.item_name);
 
     // Say we have a projection `<T as SomeTrait<'a>>::SomeType`. We are interested
     // in looking for a trait definition like:
@@ -1779,9 +1772,9 @@ fn declared_projection_bounds_from_trait(&self,
     // ```
     //
     // we can thus deduce that `<T as SomeTrait<'a>>::SomeType : 'a`.
-    let trait_predicates = tcx.lookup_predicates(projection_ty.trait_ref.def_id);
+    let trait_predicates = self.tcx.lookup_predicates(projection_ty.trait_ref.def_id);
     let predicates = trait_predicates.predicates.as_slice().to_vec();
-    traits::elaborate_predicates(tcx, predicates)
+    traits::elaborate_predicates(self.tcx, predicates)
         .filter_map(|predicate| {
             // we're only interesting in `T : 'a` style predicates:
             let outlives = match predicate {
@@ -1793,16 +1786,16 @@ fn declared_projection_bounds_from_trait(&self,
                    outlives);
 
             // apply the substitutions (and normalize any projected types)
-            let outlives = fcx.instantiate_type_scheme(span,
-                                                       projection_ty.trait_ref.substs,
-                                                       &outlives);
+            let outlives = self.instantiate_type_scheme(span,
+                                                        projection_ty.trait_ref.substs,
+                                                        &outlives);
 
             debug!("projection_bounds: outlives={:?} (2)",
                    outlives);
 
-            let region_result = infcx.commit_if_ok(|_| {
+            let region_result = self.commit_if_ok(|_| {
                 let (outlives, _) =
-                    infcx.replace_late_bound_regions_with_fresh_var(
+                    self.replace_late_bound_regions_with_fresh_var(
                         span,
                         infer::AssocTypeProjection(projection_ty.item_name),
                         &outlives);
@@ -1811,7 +1804,7 @@ fn declared_projection_bounds_from_trait(&self,
                        outlives);
 
                 // check whether this predicate applies to our current projection
-                match infcx.eq_types(false, TypeOrigin::Misc(span), ty, outlives.0) {
+                match self.eq_types(false, TypeOrigin::Misc(span), ty, outlives.0) {
                     Ok(InferOk { obligations, .. }) => {
                         // FIXME(#32730) propagate obligations
                         assert!(obligations.is_empty());
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index 414a3157c0e..175171e2f2a 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -45,8 +45,8 @@ use super::FnCtxt;
 use middle::expr_use_visitor as euv;
 use middle::mem_categorization as mc;
 use middle::mem_categorization::Categorization;
-use rustc::ty::{self, Ty, TyCtxt};
-use rustc::infer::{InferCtxt, UpvarRegion};
+use rustc::ty::{self, Ty};
+use rustc::infer::UpvarRegion;
 use std::collections::HashSet;
 use syntax::ast;
 use syntax::codemap::Span;
@@ -66,7 +66,7 @@ pub fn closure_analyze_fn(&self, body: &hir::Block) {
     adjust.visit_block(body);
 
     // it's our job to process these.
-    assert!(self.inh.deferred_call_resolutions.borrow().is_empty());
+    assert!(self.deferred_call_resolutions.borrow().is_empty());
 }
 
 pub fn closure_analyze_const(&self, body: &hir::Expr) {
@@ -78,7 +78,7 @@ pub fn closure_analyze_const(&self, body: &hir::Expr) {
     adjust.visit_expr(body);
 
     // it's our job to process these.
-    assert!(self.inh.deferred_call_resolutions.borrow().is_empty());
+    assert!(self.deferred_call_resolutions.borrow().is_empty());
 }
 }
 
@@ -109,29 +109,21 @@ impl<'a,'tcx> SeedBorrowKind<'a,'tcx, 'tcx> {
         SeedBorrowKind { fcx: fcx, closures_with_inferred_kinds: HashSet::new() }
     }
 
-    fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
-        self.fcx.tcx()
-    }
-
-    fn infcx(&self) -> &'a InferCtxt<'a,'tcx, 'tcx> {
-        self.fcx.infcx()
-    }
-
     fn check_closure(&mut self,
                      expr: &hir::Expr,
                      capture_clause: hir::CaptureClause,
                      _body: &hir::Block)
     {
-        let closure_def_id = self.tcx().map.local_def_id(expr.id);
-        if !self.fcx.inh.tables.borrow().closure_kinds.contains_key(&closure_def_id) {
+        let closure_def_id = self.fcx.tcx.map.local_def_id(expr.id);
+        if !self.fcx.tables.borrow().closure_kinds.contains_key(&closure_def_id) {
             self.closures_with_inferred_kinds.insert(expr.id);
-            self.fcx.inh.tables.borrow_mut().closure_kinds
-                                            .insert(closure_def_id, ty::ClosureKind::Fn);
+            self.fcx.tables.borrow_mut().closure_kinds
+                                        .insert(closure_def_id, ty::ClosureKind::Fn);
             debug!("check_closure: adding closure_id={:?} to closures_with_inferred_kinds",
                    closure_def_id);
         }
 
-        self.tcx().with_freevars(expr.id, |freevars| {
+        self.fcx.tcx.with_freevars(expr.id, |freevars| {
             for freevar in freevars {
                 let var_node_id = freevar.def.var_id();
                 let upvar_id = ty::UpvarId { var_id: var_node_id,
@@ -144,14 +136,14 @@ impl<'a,'tcx> SeedBorrowKind<'a,'tcx, 'tcx> {
                     }
                     hir::CaptureByRef => {
                         let origin = UpvarRegion(upvar_id, expr.span);
-                        let freevar_region = self.infcx().next_region_var(origin);
+                        let freevar_region = self.fcx.next_region_var(origin);
                         let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow,
                                                              region: freevar_region };
                         ty::UpvarCapture::ByRef(upvar_borrow)
                     }
                 };
 
-                self.fcx.inh.tables.borrow_mut().upvar_capture_map.insert(upvar_id, capture_kind);
+                self.fcx.tables.borrow_mut().upvar_capture_map.insert(upvar_id, capture_kind);
             }
         });
     }
@@ -184,7 +176,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx, 'tcx> {
         debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id);
 
         {
-            let mut euv = euv::ExprUseVisitor::new(self, self.fcx.infcx());
+            let mut euv = euv::ExprUseVisitor::new(self, self.fcx);
             euv.walk_fn(decl, body);
         }
 
@@ -221,7 +213,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx, 'tcx> {
 
         // Now we must process and remove any deferred resolutions,
         // since we have a concrete closure kind.
-        let closure_def_id = self.fcx.tcx().map.local_def_id(id);
+        let closure_def_id = self.fcx.tcx.map.local_def_id(id);
         if self.closures_with_inferred_kinds.contains(&id) {
             let mut deferred_call_resolutions =
                 self.fcx.remove_deferred_call_resolutions(closure_def_id);
@@ -238,7 +230,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx, 'tcx> {
         // local crate or were inlined into it along with some function.
         // This may change if abstract return types of some sort are
         // implemented.
-        let tcx = self.fcx.tcx();
+        let tcx = self.fcx.tcx;
         tcx.with_freevars(closure_id, |freevars| {
             freevars.iter()
                     .map(|freevar| {
@@ -248,7 +240,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx, 'tcx> {
                             var_id: freevar_node_id,
                             closure_expr_id: closure_id
                         };
-                        let capture = self.fcx.infcx().upvar_capture(upvar_id).unwrap();
+                        let capture = self.fcx.upvar_capture(upvar_id).unwrap();
 
                         debug!("freevar_node_id={:?} freevar_ty={:?} capture={:?}",
                                freevar_node_id, freevar_ty, capture);
@@ -299,7 +291,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx, 'tcx> {
                         self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnOnce);
 
                         let upvar_capture_map =
-                            &mut self.fcx.inh.tables.borrow_mut().upvar_capture_map;
+                            &mut self.fcx.tables.borrow_mut().upvar_capture_map;
                         upvar_capture_map.insert(upvar_id, ty::UpvarCapture::ByValue);
                     }
                     mc::NoteClosureEnv(upvar_id) => {
@@ -407,7 +399,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx, 'tcx> {
                 // borrow_kind of the upvar to make sure it
                 // is inferred to mutable if necessary
                 {
-                    let upvar_capture_map = &mut self.fcx.inh.tables.borrow_mut().upvar_capture_map;
+                    let upvar_capture_map = &mut self.fcx.tables.borrow_mut().upvar_capture_map;
                     let ub = upvar_capture_map.get_mut(&upvar_id).unwrap();
                     self.adjust_upvar_borrow_kind(upvar_id, ub, borrow_kind);
                 }
@@ -475,8 +467,8 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx, 'tcx> {
             return;
         }
 
-        let closure_def_id = self.fcx.tcx().map.local_def_id(closure_id);
-        let closure_kinds = &mut self.fcx.inh.tables.borrow_mut().closure_kinds;
+        let closure_def_id = self.fcx.tcx.map.local_def_id(closure_id);
+        let closure_kinds = &mut self.fcx.tables.borrow_mut().closure_kinds;
         let existing_kind = *closure_kinds.get(&closure_def_id).unwrap();
 
         debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}",
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index bc99fd7fb64..7ac4e1913ab 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -130,15 +130,15 @@ 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| {
-            let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
-            let free_id_outlive = fcx.inh.infcx.parameter_environment.free_id_outlive;
+            let free_substs = &fcx.parameter_environment.free_substs;
+            let free_id_outlive = fcx.parameter_environment.free_id_outlive;
 
-            let item = fcx.tcx().impl_or_trait_item(fcx.tcx().map.local_def_id(item_id));
+            let item = fcx.tcx.impl_or_trait_item(fcx.tcx.map.local_def_id(item_id));
 
             let (mut implied_bounds, self_ty) = match item.container() {
-                ty::TraitContainer(_) => (vec![], fcx.tcx().mk_self_type()),
+                ty::TraitContainer(_) => (vec![], fcx.tcx.mk_self_type()),
                 ty::ImplContainer(def_id) => (fcx.impl_implied_bounds(def_id, span),
-                                              fcx.tcx().lookup_item_type(def_id).ty)
+                                              fcx.tcx.lookup_item_type(def_id).ty)
             };
 
             match item {
@@ -147,7 +147,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
                     fcx.register_wf_obligation(ty, span, code.clone());
                 }
                 ty::MethodTraitItem(method) => {
-                    reject_shadowing_type_parameters(fcx.tcx(), span, &method.generics);
+                    reject_shadowing_type_parameters(fcx.tcx, span, &method.generics);
                     let method_ty = fcx.instantiate_type_scheme(span, free_substs, &method.fty);
                     let predicates = fcx.instantiate_bounds(span, free_substs, &method.predicates);
                     this.check_fn_or_method(fcx, span, &method_ty, &predicates,
@@ -181,8 +181,8 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
         let ccx = self.ccx;
         let param_env = ty::ParameterEnvironment::for_item(ccx.tcx, id);
         let tables = RefCell::new(ty::Tables::empty());
-        let inh = Inherited::new(ccx.tcx, &tables, param_env);
-        let fcx = FnCtxt::new(ccx, &inh, ty::FnDiverging, id);
+        let inh = Inherited::new(ccx, &tables, param_env);
+        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);
@@ -214,8 +214,8 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
                 }
             }
 
-            let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
-            let predicates = fcx.tcx().lookup_predicates(fcx.tcx().map.local_def_id(item.id));
+            let free_substs = &fcx.parameter_environment.free_substs;
+            let predicates = fcx.tcx.lookup_predicates(fcx.tcx.map.local_def_id(item.id));
             let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates);
             this.check_where_clauses(fcx, item.span, &predicates);
 
@@ -236,8 +236,8 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
         }
 
         self.with_item_fcx(item, |fcx, this| {
-            let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
-            let predicates = fcx.tcx().lookup_predicates(trait_def_id);
+            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);
             this.check_where_clauses(fcx, item.span, &predicates);
             vec![]
@@ -249,8 +249,8 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
                      body: &hir::Block)
     {
         self.with_item_fcx(item, |fcx, this| {
-            let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
-            let type_scheme = fcx.tcx().lookup_item_type(fcx.tcx().map.local_def_id(item.id));
+            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);
             let bare_fn_ty = match item_ty.sty {
                 ty::TyFnDef(_, _, ref bare_fn_ty) => bare_fn_ty,
@@ -259,11 +259,11 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
                 }
             };
 
-            let predicates = fcx.tcx().lookup_predicates(fcx.tcx().map.local_def_id(item.id));
+            let predicates = fcx.tcx.lookup_predicates(fcx.tcx.map.local_def_id(item.id));
             let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates);
 
             let mut implied_bounds = vec![];
-            let free_id_outlive = fcx.tcx().region_maps.call_site_extent(item.id, body.id);
+            let free_id_outlive = fcx.tcx.region_maps.call_site_extent(item.id, body.id);
             this.check_fn_or_method(fcx, item.span, bare_fn_ty, &predicates,
                                     free_id_outlive, &mut implied_bounds);
             implied_bounds
@@ -276,11 +276,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
         debug!("check_item_type: {:?}", item);
 
         self.with_item_fcx(item, |fcx, this| {
-            let type_scheme = fcx.tcx().lookup_item_type(fcx.tcx().map.local_def_id(item.id));
+            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.inh
-                                                          .infcx
-                                                          .parameter_environment
+                                                      &fcx.parameter_environment
                                                           .free_substs,
                                                       &type_scheme.ty);
 
@@ -298,17 +296,17 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
         debug!("check_impl: {:?}", item);
 
         self.with_item_fcx(item, |fcx, this| {
-            let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
-            let item_def_id = fcx.tcx().map.local_def_id(item.id);
+            let free_substs = &fcx.parameter_environment.free_substs;
+            let item_def_id = fcx.tcx.map.local_def_id(item.id);
 
             match *ast_trait_ref {
                 Some(ref ast_trait_ref) => {
-                    let trait_ref = fcx.tcx().impl_trait_ref(item_def_id).unwrap();
+                    let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap();
                     let trait_ref =
                         fcx.instantiate_type_scheme(
                             ast_trait_ref.path.span, free_substs, &trait_ref);
                     let obligations =
-                        ty::wf::trait_obligations(fcx.infcx(),
+                        ty::wf::trait_obligations(fcx,
                                                   fcx.body_id,
                                                   &trait_ref,
                                                   ast_trait_ref.path.span);
@@ -317,17 +315,17 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
                     }
                 }
                 None => {
-                    let self_ty = fcx.tcx().node_id_to_type(item.id);
+                    let self_ty = fcx.tcx.node_id_to_type(item.id);
                     let self_ty = fcx.instantiate_type_scheme(item.span, free_substs, &self_ty);
                     fcx.register_wf_obligation(self_ty, ast_self_ty.span, this.code.clone());
                 }
             }
 
-            let predicates = fcx.tcx().lookup_predicates(item_def_id);
+            let predicates = fcx.tcx.lookup_predicates(item_def_id);
             let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates);
             this.check_where_clauses(fcx, item.span, &predicates);
 
-            fcx.impl_implied_bounds(fcx.tcx().map.local_def_id(item.id), item.span)
+            fcx.impl_implied_bounds(fcx.tcx.map.local_def_id(item.id), item.span)
         });
     }
 
@@ -339,7 +337,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
         let obligations =
             predicates.predicates
                       .iter()
-                      .flat_map(|p| ty::wf::predicate_obligations(fcx.infcx(),
+                      .flat_map(|p| ty::wf::predicate_obligations(fcx,
                                                                   fcx.body_id,
                                                                   p,
                                                                   span));
@@ -357,9 +355,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
                                 free_id_outlive: CodeExtent,
                                 implied_bounds: &mut Vec<Ty<'tcx>>)
     {
-        let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
+        let free_substs = &fcx.parameter_environment.free_substs;
         let fty = fcx.instantiate_type_scheme(span, free_substs, fty);
-        let sig = fcx.tcx().liberate_late_bound_regions(free_id_outlive, &fty.sig);
+        let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.sig);
 
         for &input_ty in &sig.inputs {
             fcx.register_wf_obligation(input_ty, span, self.code.clone());
@@ -389,9 +387,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
         // check that the type of the method's receiver matches the
         // method's first parameter.
 
-        let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
+        let free_substs = &fcx.parameter_environment.free_substs;
         let fty = fcx.instantiate_type_scheme(span, free_substs, &method.fty);
-        let sig = fcx.tcx().liberate_late_bound_regions(free_id_outlive, &fty.sig);
+        let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.sig);
 
         debug!("check_method_receiver({:?},cat={:?},self_ty={:?},sig={:?})",
                method.name, method.explicit_self, self_ty, sig);
@@ -400,21 +398,21 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
             ty::ExplicitSelfCategory::Static => return,
             ty::ExplicitSelfCategory::ByValue => self_ty,
             ty::ExplicitSelfCategory::ByReference(region, mutability) => {
-                fcx.tcx().mk_ref(fcx.tcx().mk_region(region), ty::TypeAndMut {
+                fcx.tcx.mk_ref(fcx.tcx.mk_region(region), ty::TypeAndMut {
                     ty: self_ty,
                     mutbl: mutability
                 })
             }
-            ty::ExplicitSelfCategory::ByBox => fcx.tcx().mk_box(self_ty)
+            ty::ExplicitSelfCategory::ByBox => fcx.tcx.mk_box(self_ty)
         };
         let rcvr_ty = fcx.instantiate_type_scheme(span, free_substs, &rcvr_ty);
-        let rcvr_ty = fcx.tcx().liberate_late_bound_regions(free_id_outlive,
-                                                            &ty::Binder(rcvr_ty));
+        let rcvr_ty = fcx.tcx.liberate_late_bound_regions(free_id_outlive,
+                                                          &ty::Binder(rcvr_ty));
 
         debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty);
 
         let _ = ::require_same_types(
-            fcx.ccx, Some(fcx.infcx()), span,
+            fcx.ccx, Some(fcx), span,
             sig.inputs[0], rcvr_ty,
             "mismatched method receiver");
     }
@@ -559,10 +557,9 @@ fn struct_variant(&self, struct_def: &hir::VariantData) -> AdtVariant<'tcx> {
     let fields =
         struct_def.fields().iter()
         .map(|field| {
-            let field_ty = self.tcx().node_id_to_type(field.id);
+            let field_ty = self.tcx.node_id_to_type(field.id);
             let field_ty = self.instantiate_type_scheme(field.span,
-                                                        &self.infcx()
-                                                             .parameter_environment
+                                                        &self.parameter_environment
                                                              .free_substs,
                                                         &field_ty);
             AdtField { ty: field_ty, span: field.span }
@@ -578,8 +575,8 @@ fn enum_variants(&self, enum_def: &hir::EnumDef) -> Vec<AdtVariant<'tcx>> {
 }
 
 fn impl_implied_bounds(&self, impl_def_id: DefId, span: Span) -> Vec<Ty<'tcx>> {
-    let free_substs = &self.inh.infcx.parameter_environment.free_substs;
-    match self.tcx().impl_trait_ref(impl_def_id) {
+    let free_substs = &self.parameter_environment.free_substs;
+    match self.tcx.impl_trait_ref(impl_def_id) {
         Some(ref trait_ref) => {
             // Trait impl: take implied bounds from all types that
             // appear in the trait reference.
@@ -589,7 +586,7 @@ fn impl_implied_bounds(&self, impl_def_id: DefId, span: Span) -> Vec<Ty<'tcx>> {
 
         None => {
             // Inherent impl: take implied bounds from the self type.
-            let self_ty = self.tcx().lookup_item_type(impl_def_id).ty;
+            let self_ty = self.tcx.lookup_item_type(impl_def_id).ty;
             let self_ty = self.instantiate_type_scheme(span, free_substs, &self_ty);
             vec![self_ty]
         }
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index d1d653df034..b39decff683 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -54,7 +54,7 @@ pub fn resolve_type_vars_in_fn(&self, decl: &hir::FnDecl, blk: &hir::Block) {
         wbcx.visit_pat(&arg.pat);
 
         // Privacy needs the type for the whole pattern, not just each binding
-        if !pat_util::pat_is_binding(&self.tcx().def_map.borrow(), &arg.pat) {
+        if !pat_util::pat_is_binding(&self.tcx.def_map.borrow(), &arg.pat) {
             wbcx.visit_node_id(ResolvingPattern(arg.pat.span),
                                arg.pat.id);
         }
@@ -84,7 +84,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx, 'tcx> {
     }
 
     fn tcx(&self) -> TyCtxt<'cx, 'tcx, 'tcx> {
-        self.fcx.tcx()
+        self.fcx.tcx
     }
 
     // Hacky hack: During type-checking, we treat *all* operators
@@ -96,13 +96,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx, 'tcx> {
             hir::ExprBinary(ref op, ref lhs, ref rhs) |
             hir::ExprAssignOp(ref op, ref lhs, ref rhs) => {
                 let lhs_ty = self.fcx.node_ty(lhs.id);
-                let lhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&lhs_ty);
+                let lhs_ty = self.fcx.resolve_type_vars_if_possible(&lhs_ty);
 
                 let rhs_ty = self.fcx.node_ty(rhs.id);
-                let rhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&rhs_ty);
+                let rhs_ty = self.fcx.resolve_type_vars_if_possible(&rhs_ty);
 
                 if lhs_ty.is_scalar() && rhs_ty.is_scalar() {
-                    self.fcx.inh.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id));
+                    self.fcx.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id));
 
                     // weird but true: the by-ref binops put an
                     // adjustment on the lhs but not the rhs; the
@@ -111,11 +111,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx, 'tcx> {
                     match e.node {
                         hir::ExprBinary(..) => {
                             if !op.node.is_by_value() {
-                                self.fcx.inh.tables.borrow_mut().adjustments.remove(&lhs.id);
+                                self.fcx.tables.borrow_mut().adjustments.remove(&lhs.id);
                             }
                         },
                         hir::ExprAssignOp(..) => {
-                            self.fcx.inh.tables.borrow_mut().adjustments.remove(&lhs.id);
+                            self.fcx.tables.borrow_mut().adjustments.remove(&lhs.id);
                         },
                         _ => {},
                     }
@@ -220,7 +220,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx, 'tcx> {
             return;
         }
 
-        for (upvar_id, upvar_capture) in self.fcx.inh.tables.borrow().upvar_capture_map.iter() {
+        for (upvar_id, upvar_capture) in self.fcx.tables.borrow().upvar_capture_map.iter() {
             let new_upvar_capture = match *upvar_capture {
                 ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue,
                 ty::UpvarCapture::ByRef(ref upvar_borrow) => {
@@ -233,11 +233,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx, 'tcx> {
             debug!("Upvar capture for {:?} resolved to {:?}",
                    upvar_id,
                    new_upvar_capture);
-            self.fcx.tcx()
-                    .tables
-                    .borrow_mut()
-                    .upvar_capture_map
-                    .insert(*upvar_id, new_upvar_capture);
+            self.tcx()
+                .tables
+                .borrow_mut()
+                .upvar_capture_map
+                .insert(*upvar_id, new_upvar_capture);
         }
     }
 
@@ -246,13 +246,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx, 'tcx> {
             return
         }
 
-        for (def_id, closure_ty) in self.fcx.inh.tables.borrow().closure_tys.iter() {
+        for (def_id, closure_ty) in self.fcx.tables.borrow().closure_tys.iter() {
             let closure_ty = self.resolve(closure_ty, ResolvingClosure(*def_id));
-            self.fcx.tcx().tables.borrow_mut().closure_tys.insert(*def_id, closure_ty);
+            self.tcx().tables.borrow_mut().closure_tys.insert(*def_id, closure_ty);
         }
 
-        for (def_id, &closure_kind) in self.fcx.inh.tables.borrow().closure_kinds.iter() {
-            self.fcx.tcx().tables.borrow_mut().closure_kinds.insert(*def_id, closure_kind);
+        for (def_id, &closure_kind) in self.fcx.tables.borrow().closure_kinds.iter() {
+            self.tcx().tables.borrow_mut().closure_kinds.insert(*def_id, closure_kind);
         }
     }
 
@@ -274,7 +274,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx, 'tcx> {
     }
 
     fn visit_adjustments(&self, reason: ResolveReason, id: ast::NodeId) {
-        let adjustments = self.fcx.inh.tables.borrow_mut().adjustments.remove(&id);
+        let adjustments = self.fcx.tables.borrow_mut().adjustments.remove(&id);
         match adjustments {
             None => {
                 debug!("No adjustments for node {}", id);
@@ -318,7 +318,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx, 'tcx> {
                               reason: ResolveReason,
                               method_call: MethodCall) {
         // Resolve any method map entry
-        let new_method = match self.fcx.inh.tables.borrow_mut().method_map.remove(&method_call) {
+        let new_method = match self.fcx.tables.borrow_mut().method_map.remove(&method_call) {
             Some(method) => {
                 debug!("writeback::resolve_method_map_entry(call={:?}, entry={:?})",
                        method_call,
@@ -346,14 +346,14 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx, 'tcx> {
     }
 
     fn visit_liberated_fn_sigs(&self) {
-        for (&node_id, fn_sig) in self.fcx.inh.tables.borrow().liberated_fn_sigs.iter() {
+        for (&node_id, fn_sig) in self.fcx.tables.borrow().liberated_fn_sigs.iter() {
             let fn_sig = self.resolve(fn_sig, ResolvingFnSig(node_id));
             self.tcx().tables.borrow_mut().liberated_fn_sigs.insert(node_id, fn_sig.clone());
         }
     }
 
     fn visit_fru_field_types(&self) {
-        for (&node_id, ftys) in self.fcx.inh.tables.borrow().fru_field_types.iter() {
+        for (&node_id, ftys) in self.fcx.tables.borrow().fru_field_types.iter() {
             let ftys = self.resolve(ftys, ResolvingFieldTypes(node_id));
             self.tcx().tables.borrow_mut().fru_field_types.insert(node_id, ftys);
         }
@@ -420,7 +420,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx, 'tcx> {
            reason: ResolveReason)
            -> Resolver<'cx, 'tcx, 'tcx>
     {
-        Resolver::from_infcx(fcx.infcx(), &fcx.writeback_errors, reason)
+        Resolver::from_infcx(fcx, &fcx.writeback_errors, reason)
     }
 
     fn from_infcx(infcx: &'cx InferCtxt<'cx, 'tcx, 'tcx>,