about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEduard Burtescu <edy.burt@gmail.com>2016-03-12 03:06:24 +0200
committerEduard Burtescu <edy.burt@gmail.com>2016-05-11 04:14:58 +0300
commitd7ee56e862071c3cea4c5fb7cf12444591e0b3f2 (patch)
treeceb62935ab793fb42b30ea382b5ebb6d4926a188 /src
parentef2f5f6d8ef51010d060d6f8cff6cac2ef83fd42 (diff)
downloadrust-d7ee56e862071c3cea4c5fb7cf12444591e0b3f2.tar.gz
rust-d7ee56e862071c3cea4c5fb7cf12444591e0b3f2.zip
typeck: Turn everything operating on FnCtxt into a method.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_trans/callee.rs2
-rw-r--r--src/librustc_typeck/check/_match.rs391
-rw-r--r--src/librustc_typeck/check/callee.rs279
-rw-r--r--src/librustc_typeck/check/cast.rs100
-rw-r--r--src/librustc_typeck/check/closure.rs118
-rw-r--r--src/librustc_typeck/check/coercion.rs86
-rw-r--r--src/librustc_typeck/check/demand.rs33
-rw-r--r--src/librustc_typeck/check/method/confirm.rs88
-rw-r--r--src/librustc_typeck/check/method/mod.rs160
-rw-r--r--src/librustc_typeck/check/method/probe.rs54
-rw-r--r--src/librustc_typeck/check/method/suggest.rs241
-rw-r--r--src/librustc_typeck/check/mod.rs2083
-rw-r--r--src/librustc_typeck/check/op.rs202
-rw-r--r--src/librustc_typeck/check/regionck.rs40
-rw-r--r--src/librustc_typeck/check/upvar.rs27
-rw-r--r--src/librustc_typeck/check/wfcheck.rs57
-rw-r--r--src/librustc_typeck/check/writeback.rs18
17 files changed, 1914 insertions, 2065 deletions
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index 656fac54a82..8634c8cf9bd 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -154,7 +154,7 @@ impl<'tcx> Callee<'tcx> {
         let method_item = tcx.impl_or_trait_item(def_id);
         let trait_id = method_item.container().id();
         let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id));
-        let trait_ref = infer::normalize_associated_type(tcx, &trait_ref);
+        let trait_ref = tcx.normalize_associated_type(&trait_ref);
         match common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref) {
             traits::VtableImpl(vtable_impl) => {
                 let impl_did = vtable_impl.impl_def_id;
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index b07437d299b..8e9138cf779 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -14,11 +14,7 @@ use hir::pat_util::{PatIdMap, pat_id_map, pat_is_binding};
 use hir::pat_util::pat_is_resolved_const;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference};
-use check::{check_expr, check_expr_has_type, check_expr_with_expectation};
-use check::{demand, FnCtxt, Expectation};
-use check::{check_expr_with_lvalue_pref};
-use check::{instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_type};
-use check::coercion;
+use check::{FnCtxt, Expectation};
 use lint;
 use require_same_types;
 use util::nodemap::FnvHashMap;
@@ -26,6 +22,7 @@ use session::Session;
 
 use std::cmp;
 use std::collections::hash_map::Entry::{Occupied, Vacant};
+use std::ops::Deref;
 use syntax::ast;
 use syntax::codemap::{Span, Spanned};
 use syntax::ptr::P;
@@ -33,31 +30,52 @@ use syntax::ptr::P;
 use rustc::hir::{self, PatKind};
 use rustc::hir::print as pprust;
 
-pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
-                           pat: &'tcx hir::Pat,
-                           expected: Ty<'tcx>)
-{
-    let fcx = pcx.fcx;
-    let tcx = pcx.fcx.ccx.tcx;
+pub struct PatCtxt<'a, 'tcx: 'a> {
+    pub fcx: &'a FnCtxt<'a, 'tcx>,
+    pub map: PatIdMap,
+}
+
+impl<'a, 'tcx> Deref for PatCtxt<'a, 'tcx> {
+    type Target = FnCtxt<'a, 'tcx>;
+    fn deref(&self) -> &Self::Target {
+        self.fcx
+    }
+}
+
+// This function exists due to the warning "diagnostic code E0164 already used"
+fn bad_struct_kind_err(sess: &Session, pat: &hir::Pat, path: &hir::Path, lint: bool) {
+    let name = pprust::path_to_string(path);
+    let msg = format!("`{}` does not name a tuple variant or a tuple struct", name);
+    if lint {
+        sess.add_lint(lint::builtin::MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
+                      pat.id,
+                      pat.span,
+                      msg);
+    } else {
+        span_err!(sess, pat.span, E0164, "{}", msg);
+    }
+}
 
-    debug!("check_pat(pat={:?},expected={:?})",
-           pat,
-           expected);
+impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
+pub fn check_pat(&self, pat: &'tcx hir::Pat, expected: Ty<'tcx>) {
+    let tcx = self.tcx();
+
+    debug!("check_pat(pat={:?},expected={:?})", pat, expected);
 
     match pat.node {
         PatKind::Wild => {
-            fcx.write_ty(pat.id, expected);
+            self.write_ty(pat.id, expected);
         }
         PatKind::Lit(ref lt) => {
-            check_expr(fcx, &lt);
-            let expr_ty = fcx.expr_ty(&lt);
+            self.check_expr(&lt);
+            let expr_ty = self.expr_ty(&lt);
 
             // Byte string patterns behave the same way as array patterns
             // They can denote both statically and dynamically sized byte arrays
             let mut pat_ty = expr_ty;
             if let hir::ExprLit(ref lt) = lt.node {
                 if let ast::LitKind::ByteStr(_) = lt.node {
-                    let expected_ty = structurally_resolved_type(fcx, pat.span, expected);
+                    let expected_ty = self.structurally_resolved_type(pat.span, expected);
                     if let ty::TyRef(_, mt) = expected_ty.sty {
                         if let ty::TySlice(_) = mt.ty.sty {
                             pat_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic),
@@ -67,7 +85,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
                 }
             }
 
-            fcx.write_ty(pat.id, pat_ty);
+            self.write_ty(pat.id, pat_ty);
 
             // somewhat surprising: in this case, the subtyping
             // relation goes the opposite way as the other
@@ -81,14 +99,14 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
             //     &'static str <: expected
             //
             // that's equivalent to there existing a LUB.
-            demand::suptype(fcx, pat.span, expected, pat_ty);
+            self.demand_suptype(pat.span, expected, pat_ty);
         }
         PatKind::Range(ref begin, ref end) => {
-            check_expr(fcx, begin);
-            check_expr(fcx, end);
+            self.check_expr(begin);
+            self.check_expr(end);
 
-            let lhs_ty = fcx.expr_ty(begin);
-            let rhs_ty = fcx.expr_ty(end);
+            let lhs_ty = self.expr_ty(begin);
+            let rhs_ty = self.expr_ty(end);
 
             // Check that both end-points are of numeric or char type.
             let numeric_or_char = |ty: Ty| ty.is_numeric() || ty.is_char();
@@ -108,15 +126,15 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
                 span_err!(tcx.sess, span, E0029,
                           "only char and numeric types are allowed in range patterns\n \
                            start type: {}\n end type: {}",
-                          fcx.infcx().ty_to_string(lhs_ty),
-                          fcx.infcx().ty_to_string(rhs_ty)
+                          self.infcx().ty_to_string(lhs_ty),
+                          self.infcx().ty_to_string(rhs_ty)
                 );
                 return;
             }
 
             // Check that the types of the end-points can be unified.
             let types_unify = require_same_types(
-                fcx.ccx, Some(fcx.infcx()), pat.span, rhs_ty, lhs_ty,
+                self.ccx, Some(self.infcx()), pat.span, rhs_ty, lhs_ty,
                 "mismatched types in range",
             );
 
@@ -127,12 +145,12 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, '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 = fcx.infcx().resolve_type_vars_if_possible(&lhs_ty);
+            let common_type = self.infcx().resolve_type_vars_if_possible(&lhs_ty);
 
-            fcx.write_ty(pat.id, common_type);
+            self.write_ty(pat.id, common_type);
 
             // subtyping doesn't matter here, as the value is some kind of scalar
-            demand::eqtype(fcx, pat.span, expected, lhs_ty);
+            self.demand_eqtype(pat.span, expected, lhs_ty);
         }
         PatKind::Path(..) | PatKind::Ident(..)
                 if pat_is_resolved_const(&tcx.def_map.borrow(), pat) => {
@@ -140,141 +158,140 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
                 let const_did = pat_def.def_id();
                 let const_scheme = tcx.lookup_item_type(const_did);
                 assert!(const_scheme.generics.is_empty());
-                let const_ty = pcx.fcx.instantiate_type_scheme(pat.span,
-                                                               &Substs::empty(),
-                                                               &const_scheme.ty);
-                fcx.write_ty(pat.id, const_ty);
+                let const_ty = self.instantiate_type_scheme(pat.span,
+                                                            &Substs::empty(),
+                                                            &const_scheme.ty);
+                self.write_ty(pat.id, const_ty);
 
                 // FIXME(#20489) -- we should limit the types here to scalars or something!
 
                 // As with PatKind::Lit, what we really want here is that there
                 // exist a LUB, but for the cases that can occur, subtype
                 // is good enough.
-                demand::suptype(fcx, pat.span, expected, const_ty);
+                self.demand_suptype(pat.span, expected, const_ty);
             } else {
-                fcx.write_error(pat.id);
+                self.write_error(pat.id);
             }
         }
         PatKind::Ident(bm, ref path, ref sub) if pat_is_binding(&tcx.def_map.borrow(), pat) => {
-            let typ = fcx.local_ty(pat.span, pat.id);
+            let typ = self.local_ty(pat.span, pat.id);
             match bm {
                 hir::BindByRef(mutbl) => {
                     // if the binding is like
                     //    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 = fcx.infcx().next_region_var(infer::PatternRegion(pat.span));
+                    let region_var = self.infcx().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);
 
                     // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is
                     // required. However, we use equality, which is stronger. See (*) for
                     // an explanation.
-                    demand::eqtype(fcx, pat.span, region_ty, typ);
+                    self.demand_eqtype(pat.span, region_ty, typ);
                 }
                 // otherwise the type of x is the expected type T
                 hir::BindByValue(_) => {
                     // As above, `T <: typeof(x)` is required but we
                     // use equality, see (*) below.
-                    demand::eqtype(fcx, pat.span, expected, typ);
+                    self.demand_eqtype(pat.span, expected, typ);
                 }
             }
 
-            fcx.write_ty(pat.id, typ);
+            self.write_ty(pat.id, typ);
 
             // if there are multiple arms, make sure they all agree on
             // what the type of the binding `x` ought to be
-            if let Some(&canon_id) = pcx.map.get(&path.node.name) {
+            if let Some(&canon_id) = self.map.get(&path.node.name) {
                 if canon_id != pat.id {
-                    let ct = fcx.local_ty(pat.span, canon_id);
-                    demand::eqtype(fcx, pat.span, ct, typ);
+                    let ct = self.local_ty(pat.span, canon_id);
+                    self.demand_eqtype(pat.span, ct, typ);
                 }
 
                 if let Some(ref p) = *sub {
-                    check_pat(pcx, &p, expected);
+                    self.check_pat(&p, expected);
                 }
             }
         }
         PatKind::Ident(_, ref path, _) => {
             let path = hir::Path::from_ident(path.span, path.node);
-            check_pat_enum(pcx, pat, &path, Some(&[]), expected, false);
+            self.check_pat_enum(pat, &path, Some(&[]), expected, false);
         }
         PatKind::TupleStruct(ref path, ref subpats) => {
-            check_pat_enum(pcx, pat, path, subpats.as_ref().map(|v| &v[..]), expected, true);
+            self.check_pat_enum(pat, path, subpats.as_ref().map(|v| &v[..]), expected, true);
         }
         PatKind::Path(ref path) => {
-            check_pat_enum(pcx, pat, path, Some(&[]), expected, false);
+            self.check_pat_enum(pat, path, Some(&[]), expected, false);
         }
         PatKind::QPath(ref qself, ref path) => {
-            let self_ty = fcx.to_ty(&qself.ty);
+            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 {
-                    fcx.infcx().set_tainted_by_errors();
-                    fcx.write_error(pat.id);
+                    self.infcx().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 = fcx.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()
                 }
             } else {
                 debug!("unbound path {:?}", pat);
-                fcx.write_error(pat.id);
+                self.write_error(pat.id);
                 return;
             };
             if let Some((opt_ty, segments, def)) =
-                    resolve_ty_and_def_ufcs(fcx, path_res, Some(self_ty),
-                                            path, pat.span, pat.id) {
-                if check_assoc_item_is_const(pcx, def, pat.span) {
+                    self.resolve_ty_and_def_ufcs(path_res, Some(self_ty),
+                                                 path, pat.span, pat.id) {
+                if self.check_assoc_item_is_const(def, pat.span) {
                     let scheme = tcx.lookup_item_type(def.def_id());
                     let predicates = tcx.lookup_predicates(def.def_id());
-                    instantiate_path(fcx, segments,
-                                     scheme, &predicates,
-                                     opt_ty, def, pat.span, pat.id);
-                    let const_ty = fcx.node_ty(pat.id);
-                    demand::suptype(fcx, pat.span, expected, const_ty);
+                    self.instantiate_path(segments, scheme, &predicates,
+                                          opt_ty, def, pat.span, pat.id);
+                    let const_ty = self.node_ty(pat.id);
+                    self.demand_suptype(pat.span, expected, const_ty);
                 } else {
-                    fcx.write_error(pat.id)
+                    self.write_error(pat.id)
                 }
             }
         }
         PatKind::Struct(ref path, ref fields, etc) => {
-            check_pat_struct(pcx, pat, path, fields, etc, expected);
+            self.check_pat_struct(pat, path, fields, etc, expected);
         }
         PatKind::Tup(ref elements) => {
             let element_tys: Vec<_> =
-                (0..elements.len()).map(|_| fcx.infcx().next_ty_var())
+                (0..elements.len()).map(|_| self.infcx().next_ty_var())
                                         .collect();
             let pat_ty = tcx.mk_tup(element_tys.clone());
-            fcx.write_ty(pat.id, pat_ty);
-            demand::eqtype(fcx, pat.span, expected, pat_ty);
+            self.write_ty(pat.id, pat_ty);
+            self.demand_eqtype(pat.span, expected, pat_ty);
             for (element_pat, element_ty) in elements.iter().zip(element_tys) {
-                check_pat(pcx, &element_pat, element_ty);
+                self.check_pat(&element_pat, element_ty);
             }
         }
         PatKind::Box(ref inner) => {
-            let inner_ty = fcx.infcx().next_ty_var();
+            let inner_ty = self.infcx().next_ty_var();
             let uniq_ty = tcx.mk_box(inner_ty);
 
-            if check_dereferencable(pcx, pat.span, expected, &inner) {
+            if self.check_dereferencable(pat.span, expected, &inner) {
                 // Here, `demand::subtype` is good enough, but I don't
                 // think any errors can be introduced by using
                 // `demand::eqtype`.
-                demand::eqtype(fcx, pat.span, expected, uniq_ty);
-                fcx.write_ty(pat.id, uniq_ty);
-                check_pat(pcx, &inner, inner_ty);
+                self.demand_eqtype(pat.span, expected, uniq_ty);
+                self.write_ty(pat.id, uniq_ty);
+                self.check_pat(&inner, inner_ty);
             } else {
-                fcx.write_error(pat.id);
-                check_pat(pcx, &inner, tcx.types.err);
+                self.write_error(pat.id);
+                self.check_pat(&inner, tcx.types.err);
             }
         }
         PatKind::Ref(ref inner, mutbl) => {
-            let expected = fcx.infcx().shallow_resolve(expected);
-            if check_dereferencable(pcx, pat.span, expected, &inner) {
+            let expected = self.infcx().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 (*)
                 // below for details.
@@ -288,25 +305,25 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
                         (expected, mt.ty)
                     }
                     _ => {
-                        let inner_ty = fcx.infcx().next_ty_var();
+                        let inner_ty = self.infcx().next_ty_var();
                         let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl };
-                        let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span));
+                        let region = self.infcx().next_region_var(infer::PatternRegion(pat.span));
                         let rptr_ty = tcx.mk_ref(tcx.mk_region(region), mt);
-                        demand::eqtype(fcx, pat.span, expected, rptr_ty);
+                        self.demand_eqtype(pat.span, expected, rptr_ty);
                         (rptr_ty, inner_ty)
                     }
                 };
 
-                fcx.write_ty(pat.id, rptr_ty);
-                check_pat(pcx, &inner, inner_ty);
+                self.write_ty(pat.id, rptr_ty);
+                self.check_pat(&inner, inner_ty);
             } else {
-                fcx.write_error(pat.id);
-                check_pat(pcx, &inner, tcx.types.err);
+                self.write_error(pat.id);
+                self.check_pat(&inner, tcx.types.err);
             }
         }
         PatKind::Vec(ref before, ref slice, ref after) => {
-            let expected_ty = structurally_resolved_type(fcx, pat.span, expected);
-            let inner_ty = fcx.infcx().next_ty_var();
+            let expected_ty = self.structurally_resolved_type(pat.span, expected);
+            let inner_ty = self.infcx().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();
@@ -316,7 +333,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
                     }
                 }),
                 _ => {
-                    let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span));
+                    let region = self.infcx().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)
@@ -325,18 +342,18 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
                 }
             };
 
-            fcx.write_ty(pat.id, pat_ty);
+            self.write_ty(pat.id, pat_ty);
 
             // `demand::subtype` would be good enough, but using
             // `eqtype` turns out to be equally general. See (*)
             // below for details.
-            demand::eqtype(fcx, pat.span, expected, pat_ty);
+            self.demand_eqtype(pat.span, expected, pat_ty);
 
             for elt in before {
-                check_pat(pcx, &elt, inner_ty);
+                self.check_pat(&elt, inner_ty);
             }
             if let Some(ref slice) = *slice {
-                let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span));
+                let region = self.infcx().next_region_var(infer::PatternRegion(pat.span));
                 let mutbl = expected_ty.builtin_deref(true, ty::NoPreference)
                     .map_or(hir::MutImmutable, |mt| mt.mutbl);
 
@@ -344,10 +361,10 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
                     ty: tcx.mk_slice(inner_ty),
                     mutbl: mutbl
                 });
-                check_pat(pcx, &slice, slice_ty);
+                self.check_pat(&slice, slice_ty);
             }
             for elt in after {
-                check_pat(pcx, &elt, inner_ty);
+                self.check_pat(&elt, inner_ty);
             }
         }
     }
@@ -404,11 +421,11 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
     // subtyping.
 }
 
-fn check_assoc_item_is_const(pcx: &pat_ctxt, def: Def, span: Span) -> bool {
+fn check_assoc_item_is_const(&self, def: Def, span: Span) -> bool {
     match def {
         Def::AssociatedConst(..) => true,
         Def::Method(..) => {
-            span_err!(pcx.fcx.ccx.tcx.sess, span, E0327,
+            span_err!(self.tcx().sess, span, E0327,
                       "associated items in match patterns must be constants");
             false
         }
@@ -418,20 +435,17 @@ fn check_assoc_item_is_const(pcx: &pat_ctxt, def: Def, span: Span) -> bool {
     }
 }
 
-pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
-                                      span: Span, expected: Ty<'tcx>,
-                                      inner: &hir::Pat) -> bool {
-    let fcx = pcx.fcx;
-    let tcx = pcx.fcx.ccx.tcx;
+pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool {
+    let tcx = self.tcx();
     if pat_is_binding(&tcx.def_map.borrow(), inner) {
-        let expected = fcx.infcx().shallow_resolve(expected);
+        let expected = self.infcx().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",
-                          fcx.infcx().ty_to_string(expected));
+                          self.infcx().ty_to_string(expected));
                 false
             }
             _ => true
@@ -440,14 +454,16 @@ pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
         true
     }
 }
+}
 
-pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                             expr: &'tcx hir::Expr,
-                             discrim: &'tcx hir::Expr,
-                             arms: &'tcx [hir::Arm],
-                             expected: Expectation<'tcx>,
-                             match_src: hir::MatchSource) {
-    let tcx = fcx.ccx.tcx;
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+pub fn check_match(&self,
+                   expr: &'tcx hir::Expr,
+                   discrim: &'tcx hir::Expr,
+                   arms: &'tcx [hir::Arm],
+                   expected: Expectation<'tcx>,
+                   match_src: hir::MatchSource) {
+    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
@@ -460,25 +476,25 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                     });
     let discrim_ty;
     if let Some(m) = contains_ref_bindings {
-        check_expr_with_lvalue_pref(fcx, discrim, LvaluePreference::from_mutbl(m));
-        discrim_ty = fcx.expr_ty(discrim);
+        self.check_expr_with_lvalue_pref(discrim, LvaluePreference::from_mutbl(m));
+        discrim_ty = self.expr_ty(discrim);
     } else {
         // ...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 = fcx.infcx().next_ty_var();
-        check_expr_has_type(fcx, discrim, discrim_ty);
+        discrim_ty = self.infcx().next_ty_var();
+        self.check_expr_has_type(discrim, discrim_ty);
     };
 
     // Typecheck the patterns first, so that we get types for all the
     // bindings.
     for arm in arms {
-        let mut pcx = pat_ctxt {
-            fcx: fcx,
+        let pcx = PatCtxt {
+            fcx: self,
             map: pat_id_map(&tcx.def_map, &arm.pats[0]),
         };
         for p in &arm.pats {
-            check_pat(&mut pcx, &p, discrim_ty);
+            pcx.check_pat(&p, discrim_ty);
         }
     }
 
@@ -491,25 +507,25 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     // on any empty type and is therefore unreachable; should the flow
     // of execution reach it, we will panic, so bottom is an appropriate
     // type in that case)
-    let expected = expected.adjust_for_branches(fcx);
-    let mut result_ty = fcx.infcx().next_diverging_ty_var();
+    let expected = expected.adjust_for_branches(self);
+    let mut result_ty = self.infcx().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 != fcx.tcx().mk_nil() => {
+        Expectation::ExpectHasType(ety) if ety != self.tcx().mk_nil() => {
             ety
         }
         _ => result_ty
     };
     for (i, arm) in arms.iter().enumerate() {
         if let Some(ref e) = arm.guard {
-            check_expr_has_type(fcx, e, tcx.types.bool);
+            self.check_expr_has_type(e, tcx.types.bool);
         }
-        check_expr_with_expectation(fcx, &arm.body, expected);
-        let arm_ty = fcx.expr_ty(&arm.body);
+        self.check_expr_with_expectation(&arm.body, expected);
+        let arm_ty = self.expr_ty(&arm.body);
 
         if result_ty.references_error() || arm_ty.references_error() {
             result_ty = tcx.types.err;
@@ -531,7 +547,7 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         };
 
         let result = if is_if_let_fallback {
-            fcx.infcx().eq_types(true, origin, arm_ty, result_ty)
+            self.infcx().eq_types(true, origin, arm_ty, result_ty)
                 .map(|InferOk { obligations, .. }| {
                     // FIXME(#32730) propagate obligations
                     assert!(obligations.is_empty());
@@ -539,10 +555,10 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                 })
         } else if i == 0 {
             // Special-case the first arm, as it has no "previous expressions".
-            coercion::try(fcx, &arm.body, coerce_first)
+            self.try_coerce(&arm.body, coerce_first)
         } else {
             let prev_arms = || arms[..i].iter().map(|arm| &*arm.body);
-            coercion::try_find_lub(fcx, origin, prev_arms, result_ty, &arm.body)
+            self.try_find_coercion_lub(origin, prev_arms, result_ty, &arm.body)
         };
 
         result_ty = match result {
@@ -553,88 +569,69 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                 } else {
                     (result_ty, arm_ty)
                 };
-                fcx.infcx().report_mismatched_types(origin, expected, found, e);
-                fcx.tcx().types.err
+                self.infcx().report_mismatched_types(origin, expected, found, e);
+                self.tcx().types.err
             }
         };
     }
 
-    fcx.write_ty(expr.id, result_ty);
+    self.write_ty(expr.id, result_ty);
 }
-
-pub struct pat_ctxt<'a, 'tcx: 'a> {
-    pub fcx: &'a FnCtxt<'a, 'tcx>,
-    pub map: PatIdMap,
 }
 
-pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx hir::Pat,
-                                  path: &hir::Path, fields: &'tcx [Spanned<hir::FieldPat>],
-                                  etc: bool, expected: Ty<'tcx>) {
-    let fcx = pcx.fcx;
-    let tcx = pcx.fcx.ccx.tcx;
+impl<'a, 'tcx> PatCtxt<'a, '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 def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
-    let variant = match fcx.def_struct_variant(def, path.span) {
+    let variant = match self.def_struct_variant(def, path.span) {
         Some((_, variant)) => variant,
         None => {
             let name = pprust::path_to_string(path);
             span_err!(tcx.sess, pat.span, E0163,
                       "`{}` does not name a struct or a struct variant", name);
-            fcx.write_error(pat.id);
+            self.write_error(pat.id);
 
             for field in fields {
-                check_pat(pcx, &field.node.pat, tcx.types.err);
+                self.check_pat(&field.node.pat, tcx.types.err);
             }
             return;
         }
     };
 
-    let pat_ty = pcx.fcx.instantiate_type(def.def_id(), path);
+    let pat_ty = self.instantiate_type(def.def_id(), path);
     let item_substs = match pat_ty.sty {
         ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs,
         _ => span_bug!(pat.span, "struct variant is not an ADT")
     };
-    demand::eqtype(fcx, pat.span, expected, pat_ty);
-    check_struct_pat_fields(pcx, pat.span, fields, variant, &item_substs, etc);
+    self.demand_eqtype(pat.span, expected, pat_ty);
+    self.check_struct_pat_fields(pat.span, fields, variant, &item_substs, etc);
 
-    fcx.write_ty(pat.id, pat_ty);
-    fcx.write_substs(pat.id, ty::ItemSubsts { substs: item_substs.clone() });
-}
-
-// This function exists due to the warning "diagnostic code E0164 already used"
-fn bad_struct_kind_err(sess: &Session, pat: &hir::Pat, path: &hir::Path, lint: bool) {
-    let name = pprust::path_to_string(path);
-    let msg = format!("`{}` does not name a tuple variant or a tuple struct", name);
-    if lint {
-        sess.add_lint(lint::builtin::MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
-                      pat.id,
-                      pat.span,
-                      msg);
-    } else {
-        span_err!(sess, pat.span, E0164, "{}", msg);
-    }
+    self.write_ty(pat.id, pat_ty);
+    self.write_substs(pat.id, ty::ItemSubsts { substs: item_substs.clone() });
 }
 
-fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
-                            pat: &hir::Pat,
-                            path: &hir::Path,
-                            subpats: Option<&'tcx [P<hir::Pat>]>,
-                            expected: Ty<'tcx>,
-                            is_tuple_struct_pat: bool)
+fn check_pat_enum(&self,
+                  pat: &hir::Pat,
+                  path: &hir::Path,
+                  subpats: Option<&'tcx [P<hir::Pat>]>,
+                  expected: Ty<'tcx>,
+                  is_tuple_struct_pat: bool)
 {
     // Typecheck the path.
-    let fcx = pcx.fcx;
-    let tcx = pcx.fcx.ccx.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,
         _ => {
-            fcx.infcx().set_tainted_by_errors();
-            fcx.write_error(pat.id);
+            self.infcx().set_tainted_by_errors();
+            self.write_error(pat.id);
 
             if let Some(subpats) = subpats {
                 for pat in subpats {
-                    check_pat(pcx, &pat, tcx.types.err);
+                    self.check_pat(&pat, tcx.types.err);
                 }
             }
 
@@ -642,9 +639,9 @@ fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
         }
     };
 
-    let (opt_ty, segments, def) = match resolve_ty_and_def_ufcs(fcx, path_res,
-                                                                None, path,
-                                                                pat.span, pat.id) {
+    let (opt_ty, segments, def) = match self.resolve_ty_and_def_ufcs(path_res,
+                                                                     None, path,
+                                                                     pat.span, pat.id) {
         Some(resolution) => resolution,
         // Error handling done inside resolve_ty_and_def_ufcs, so if
         // resolution fails just return.
@@ -653,8 +650,8 @@ fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
 
     // Items that were partially resolved before should have been resolved to
     // associated constants (i.e. not methods).
-    if path_res.depth != 0 && !check_assoc_item_is_const(pcx, def, pat.span) {
-        fcx.write_error(pat.id);
+    if path_res.depth != 0 && !self.check_assoc_item_is_const(def, pat.span) {
+        self.write_error(pat.id);
         return;
     }
 
@@ -672,17 +669,16 @@ fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
     } else {
         ctor_scheme
     };
-    instantiate_path(pcx.fcx, segments,
-                     path_scheme, &ctor_predicates,
-                     opt_ty, def, pat.span, pat.id);
+    self.instantiate_path(segments, path_scheme, &ctor_predicates,
+                          opt_ty, def, pat.span, pat.id);
 
     let report_bad_struct_kind = |is_warning| {
         bad_struct_kind_err(tcx.sess, pat, path, is_warning);
         if is_warning { return; }
-        fcx.write_error(pat.id);
+        self.write_error(pat.id);
         if let Some(subpats) = subpats {
             for pat in subpats {
-                check_pat(pcx, &pat, tcx.types.err);
+                self.check_pat(&pat, tcx.types.err);
             }
         }
     };
@@ -694,16 +690,16 @@ fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
         if is_tuple_struct_pat {
             report_bad_struct_kind(false);
         } else {
-            let pat_ty = fcx.node_ty(pat.id);
-            demand::suptype(fcx, pat.span, expected, pat_ty);
+            let pat_ty = self.node_ty(pat.id);
+            self.demand_suptype(pat.span, expected, pat_ty);
         }
         return;
     }
 
-    let pat_ty = fcx.node_ty(pat.id);
-    demand::eqtype(fcx, pat.span, expected, pat_ty);
+    let pat_ty = self.node_ty(pat.id);
+    self.demand_eqtype(pat.span, expected, pat_ty);
 
-    let real_path_ty = fcx.node_ty(pat.id);
+    let real_path_ty = self.node_ty(pat.id);
     let (kind_name, variant, expected_substs) = match real_path_ty.sty {
         ty::TyEnum(enum_def, expected_substs) => {
             let variant = enum_def.variant_of_def(def);
@@ -735,8 +731,8 @@ fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
     if let Some(subpats) = subpats {
         if subpats.len() == variant.fields.len() {
             for (subpat, field) in subpats.iter().zip(&variant.fields) {
-                let field_ty = fcx.field_ty(subpat.span, field, expected_substs);
-                check_pat(pcx, &subpat, field_ty);
+                let field_ty = self.field_ty(subpat.span, field, expected_substs);
+                self.check_pat(&subpat, field_ty);
             }
         } else if variant.fields.is_empty() {
             span_err!(tcx.sess, pat.span, E0024,
@@ -744,7 +740,7 @@ fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
                       subpats.len(), if subpats.len() == 1 {""} else {"s"}, kind_name);
 
             for pat in subpats {
-                check_pat(pcx, &pat, tcx.types.err);
+                self.check_pat(&pat, tcx.types.err);
             }
         } else {
             span_err!(tcx.sess, pat.span, E0023,
@@ -754,7 +750,7 @@ fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
                       variant.fields.len(), if variant.fields.len() == 1 {""} else {"s"});
 
             for pat in subpats {
-                check_pat(pcx, &pat, tcx.types.err);
+                self.check_pat(&pat, tcx.types.err);
             }
         }
     }
@@ -765,13 +761,13 @@ fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
 /// `struct_fields` describes the type of each field of the struct.
 /// `struct_id` is the ID of the struct.
 /// `etc` is true if the pattern said '...' and false otherwise.
-pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
-                                         span: Span,
-                                         fields: &'tcx [Spanned<hir::FieldPat>],
-                                         variant: ty::VariantDef<'tcx>,
-                                         substs: &Substs<'tcx>,
-                                         etc: bool) {
-    let tcx = pcx.fcx.ccx.tcx;
+pub fn check_struct_pat_fields(&self,
+                               span: Span,
+                               fields: &'tcx [Spanned<hir::FieldPat>],
+                               variant: ty::VariantDef<'tcx>,
+                               substs: &Substs<'tcx>,
+                               etc: bool) {
+    let tcx = self.tcx();
 
     // Index the struct fields' types.
     let field_map = variant.fields
@@ -798,7 +794,7 @@ pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
             Vacant(vacant) => {
                 vacant.insert(span);
                 field_map.get(&field.name)
-                    .map(|f| pcx.fcx.field_ty(span, f, substs))
+                    .map(|f| self.field_ty(span, f, substs))
                     .unwrap_or_else(|| {
                         span_err!(tcx.sess, span, E0026,
                             "struct `{}` does not have a field named `{}`",
@@ -809,7 +805,7 @@ pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
             }
         };
 
-        check_pat(pcx, &field.pat, field_ty);
+        self.check_pat(&field.pat, field_ty);
     }
 
     // Report an error if not all the fields were specified.
@@ -823,3 +819,4 @@ pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
         }
     }
 }
+}
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 5d37d5123e4..15307864a42 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -8,21 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use super::autoderef;
-use super::check_argument_types;
-use super::check_expr;
-use super::check_method_argument_types;
-use super::demand;
-use super::DeferredCallResolution;
-use super::err_args;
-use super::Expectation;
-use super::expected_types_for_fn_args;
-use super::FnCtxt;
-use super::method;
-use super::structurally_resolved_type;
-use super::TupleArgumentsFlag;
-use super::UnresolvedTypeAction;
-use super::write_call;
+use super::{DeferredCallResolution, Expectation, FnCtxt,
+            TupleArgumentsFlag, UnresolvedTypeAction};
 
 use CrateCtxt;
 use middle::cstore::LOCAL_CRATE;
@@ -70,58 +57,58 @@ pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id:
     }
 }
 
-pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                            call_expr: &'tcx hir::Expr,
-                            callee_expr: &'tcx hir::Expr,
-                            arg_exprs: &'tcx [P<hir::Expr>],
-                            expected: Expectation<'tcx>)
+enum CallStep<'tcx> {
+    Builtin,
+    DeferredClosure(ty::FnSig<'tcx>),
+    Overloaded(ty::MethodCallee<'tcx>)
+}
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+pub fn check_call(&self,
+                  call_expr: &'tcx hir::Expr,
+                  callee_expr: &'tcx hir::Expr,
+                  arg_exprs: &'tcx [P<hir::Expr>],
+                  expected: Expectation<'tcx>)
 {
-    check_expr(fcx, callee_expr);
-    let original_callee_ty = fcx.expr_ty(callee_expr);
+    self.check_expr(callee_expr);
+    let original_callee_ty = self.expr_ty(callee_expr);
     let (callee_ty, _, result) =
-        autoderef(fcx,
-                  callee_expr.span,
-                  original_callee_ty,
-                  || Some(callee_expr),
-                  UnresolvedTypeAction::Error,
-                  LvaluePreference::NoPreference,
-                  |adj_ty, idx| {
-                      try_overloaded_call_step(fcx, call_expr, callee_expr, adj_ty, idx)
-                  });
+        self.autoderef(callee_expr.span,
+                       original_callee_ty,
+                       || Some(callee_expr),
+                       UnresolvedTypeAction::Error,
+                       LvaluePreference::NoPreference,
+                       |adj_ty, idx| {
+            self.try_overloaded_call_step(call_expr, callee_expr, adj_ty, idx)
+    });
 
     match result {
         None => {
             // this will report an error since original_callee_ty is not a fn
-            confirm_builtin_call(fcx, call_expr, original_callee_ty, arg_exprs, expected);
+            self.confirm_builtin_call(call_expr, original_callee_ty, arg_exprs, expected);
         }
 
         Some(CallStep::Builtin) => {
-            confirm_builtin_call(fcx, call_expr, callee_ty, arg_exprs, expected);
+            self.confirm_builtin_call(call_expr, callee_ty, arg_exprs, expected);
         }
 
         Some(CallStep::DeferredClosure(fn_sig)) => {
-            confirm_deferred_closure_call(fcx, call_expr, arg_exprs, expected, fn_sig);
+            self.confirm_deferred_closure_call(call_expr, arg_exprs, expected, fn_sig);
         }
 
         Some(CallStep::Overloaded(method_callee)) => {
-            confirm_overloaded_call(fcx, call_expr, callee_expr,
-                                    arg_exprs, expected, method_callee);
+            self.confirm_overloaded_call(call_expr, callee_expr,
+                                         arg_exprs, expected, method_callee);
         }
     }
 }
 
-enum CallStep<'tcx> {
-    Builtin,
-    DeferredClosure(ty::FnSig<'tcx>),
-    Overloaded(ty::MethodCallee<'tcx>)
-}
-
-fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                      call_expr: &'tcx hir::Expr,
-                                      callee_expr: &'tcx hir::Expr,
-                                      adjusted_ty: Ty<'tcx>,
-                                      autoderefs: usize)
-                                      -> Option<CallStep<'tcx>>
+fn try_overloaded_call_step(&self,
+                            call_expr: &'tcx hir::Expr,
+                            callee_expr: &'tcx hir::Expr,
+                            adjusted_ty: Ty<'tcx>,
+                            autoderefs: usize)
+                            -> Option<CallStep<'tcx>>
 {
     debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?}, autoderefs={})",
            call_expr,
@@ -129,9 +116,9 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
            autoderefs);
 
     // If the callee is a bare function or a closure, then we're all set.
-    match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty {
+    match self.structurally_resolved_type(callee_expr.span, adjusted_ty).sty {
         ty::TyFnDef(..) | ty::TyFnPtr(_) => {
-            fcx.write_autoderef_adjustment(callee_expr.id, autoderefs);
+            self.write_autoderef_adjustment(callee_expr.id, autoderefs);
             return Some(CallStep::Builtin);
         }
 
@@ -141,14 +128,14 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             // Check whether this is a call to a closure where we
             // haven't yet decided on whether the closure is fn vs
             // fnmut vs fnonce. If so, we have to defer further processing.
-            if fcx.infcx().closure_kind(def_id).is_none() {
+            if self.infcx().closure_kind(def_id).is_none() {
                 let closure_ty =
-                    fcx.infcx().closure_type(def_id, substs);
+                    self.infcx().closure_type(def_id, substs);
                 let fn_sig =
-                    fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
-                                                                          infer::FnCall,
-                                                                          &closure_ty.sig).0;
-                fcx.record_deferred_call_resolution(def_id, Box::new(CallResolution {
+                    self.infcx().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,
                     adjusted_ty: adjusted_ty,
@@ -175,37 +162,36 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         _ => {}
     }
 
-    try_overloaded_call_traits(fcx, call_expr, callee_expr, adjusted_ty, autoderefs)
+    self.try_overloaded_call_traits(call_expr, callee_expr, adjusted_ty, autoderefs)
         .map(|method_callee| CallStep::Overloaded(method_callee))
 }
 
-fn try_overloaded_call_traits<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                       call_expr: &hir::Expr,
-                                       callee_expr: &hir::Expr,
-                                       adjusted_ty: Ty<'tcx>,
-                                       autoderefs: usize)
-                                       -> Option<ty::MethodCallee<'tcx>>
+fn try_overloaded_call_traits(&self,
+                              call_expr: &hir::Expr,
+                              callee_expr: &hir::Expr,
+                              adjusted_ty: Ty<'tcx>,
+                              autoderefs: usize)
+                              -> Option<ty::MethodCallee<'tcx>>
 {
     // Try the options that are least restrictive on the caller first.
     for &(opt_trait_def_id, method_name) in &[
-        (fcx.tcx().lang_items.fn_trait(), token::intern("call")),
-        (fcx.tcx().lang_items.fn_mut_trait(), token::intern("call_mut")),
-        (fcx.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,
             None => continue,
         };
 
-        match method::lookup_in_trait_adjusted(fcx,
-                                               call_expr.span,
-                                               Some(&callee_expr),
-                                               method_name,
-                                               trait_def_id,
-                                               autoderefs,
-                                               false,
-                                               adjusted_ty,
-                                               None) {
+        match self.lookup_method_in_trait_adjusted(call_expr.span,
+                                                   Some(&callee_expr),
+                                                   method_name,
+                                                   trait_def_id,
+                                                   autoderefs,
+                                                   false,
+                                                   adjusted_ty,
+                                                   None) {
             None => continue,
             Some(method_callee) => {
                 return Some(method_callee);
@@ -216,11 +202,11 @@ fn try_overloaded_call_traits<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     None
 }
 
-fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
-                                 call_expr: &hir::Expr,
-                                 callee_ty: Ty<'tcx>,
-                                 arg_exprs: &'tcx [P<hir::Expr>],
-                                 expected: Expectation<'tcx>)
+fn confirm_builtin_call(&self,
+                        call_expr: &hir::Expr,
+                        callee_ty: Ty<'tcx>,
+                        arg_exprs: &'tcx [P<hir::Expr>],
+                        expected: Expectation<'tcx>)
 {
     let error_fn_sig;
 
@@ -230,12 +216,12 @@ fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
             sig
         }
         _ => {
-            let mut err = fcx.type_error_struct(call_expr.span, |actual| {
+            let mut err = self.type_error_struct(call_expr.span, |actual| {
                 format!("expected function, found `{}`", actual)
             }, callee_ty, None);
 
             if let hir::ExprCall(ref expr, _) = call_expr.node {
-                let tcx = fcx.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()) {
@@ -251,8 +237,8 @@ fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
             // In that case, we check each argument against "error" in order to
             // set up all the node type bindings.
             error_fn_sig = ty::Binder(ty::FnSig {
-                inputs: err_args(fcx, arg_exprs.len()),
-                output: ty::FnConverging(fcx.tcx().types.err),
+                inputs: self.err_args(arg_exprs.len()),
+                output: ty::FnConverging(self.tcx().types.err),
                 variadic: false
             });
 
@@ -266,34 +252,32 @@ fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
     // previously appeared within a `Binder<>` and hence would not
     // have been normalized before.
     let fn_sig =
-        fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
-                                                              infer::FnCall,
-                                                              fn_sig).0;
+        self.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
+                                                               infer::FnCall,
+                                                               fn_sig).0;
     let fn_sig =
-        fcx.normalize_associated_types_in(call_expr.span, &fn_sig);
+        self.normalize_associated_types_in(call_expr.span, &fn_sig);
 
     // Call the generic checker.
-    let expected_arg_tys = expected_types_for_fn_args(fcx,
-                                                      call_expr.span,
-                                                      expected,
-                                                      fn_sig.output,
-                                                      &fn_sig.inputs);
-    check_argument_types(fcx,
-                         call_expr.span,
-                         &fn_sig.inputs,
-                         &expected_arg_tys[..],
-                         arg_exprs,
-                         fn_sig.variadic,
-                         TupleArgumentsFlag::DontTupleArguments);
-
-    write_call(fcx, call_expr, fn_sig.output);
+    let expected_arg_tys = self.expected_types_for_fn_args(call_expr.span,
+                                                           expected,
+                                                           fn_sig.output,
+                                                           &fn_sig.inputs);
+    self.check_argument_types(call_expr.span,
+                              &fn_sig.inputs,
+                              &expected_arg_tys[..],
+                              arg_exprs,
+                              fn_sig.variadic,
+                              TupleArgumentsFlag::DontTupleArguments);
+
+    self.write_call(call_expr, fn_sig.output);
 }
 
-fn confirm_deferred_closure_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
-                                          call_expr: &hir::Expr,
-                                          arg_exprs: &'tcx [P<hir::Expr>],
-                                          expected: Expectation<'tcx>,
-                                          fn_sig: ty::FnSig<'tcx>)
+fn confirm_deferred_closure_call(&self,
+                                 call_expr: &hir::Expr,
+                                 arg_exprs: &'tcx [P<hir::Expr>],
+                                 expected: Expectation<'tcx>,
+                                 fn_sig: ty::FnSig<'tcx>)
 {
     // `fn_sig` is the *signature* of the cosure being called. We
     // don't know the full details yet (`Fn` vs `FnMut` etc), but we
@@ -301,48 +285,46 @@ fn confirm_deferred_closure_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
     // type.
 
     let expected_arg_tys =
-        expected_types_for_fn_args(fcx,
-                                   call_expr.span,
-                                   expected,
-                                   fn_sig.output.clone(),
-                                   &fn_sig.inputs);
-
-    check_argument_types(fcx,
-                         call_expr.span,
-                         &fn_sig.inputs,
-                         &expected_arg_tys,
-                         arg_exprs,
-                         fn_sig.variadic,
-                         TupleArgumentsFlag::TupleArguments);
-
-    write_call(fcx, call_expr, fn_sig.output);
+        self.expected_types_for_fn_args(call_expr.span,
+                                        expected,
+                                        fn_sig.output.clone(),
+                                        &fn_sig.inputs);
+
+    self.check_argument_types(call_expr.span,
+                              &fn_sig.inputs,
+                              &expected_arg_tys,
+                              arg_exprs,
+                              fn_sig.variadic,
+                              TupleArgumentsFlag::TupleArguments);
+
+    self.write_call(call_expr, fn_sig.output);
 }
 
-fn confirm_overloaded_call<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                    call_expr: &hir::Expr,
-                                    callee_expr: &'tcx hir::Expr,
-                                    arg_exprs: &'tcx [P<hir::Expr>],
-                                    expected: Expectation<'tcx>,
-                                    method_callee: ty::MethodCallee<'tcx>)
+fn confirm_overloaded_call(&self,
+                           call_expr: &hir::Expr,
+                           callee_expr: &'tcx hir::Expr,
+                           arg_exprs: &'tcx [P<hir::Expr>],
+                           expected: Expectation<'tcx>,
+                           method_callee: ty::MethodCallee<'tcx>)
 {
     let output_type =
-        check_method_argument_types(fcx,
-                                    call_expr.span,
-                                    method_callee.ty,
-                                    callee_expr,
-                                    arg_exprs,
-                                    TupleArgumentsFlag::TupleArguments,
-                                    expected);
-    write_call(fcx, call_expr, output_type);
-
-    write_overloaded_call_method_map(fcx, call_expr, method_callee);
+        self.check_method_argument_types(call_expr.span,
+                                         method_callee.ty,
+                                         callee_expr,
+                                         arg_exprs,
+                                         TupleArgumentsFlag::TupleArguments,
+                                         expected);
+    self.write_call(call_expr, output_type);
+
+    self.write_overloaded_call_method_map(call_expr, method_callee);
 }
 
-fn write_overloaded_call_method_map<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                             call_expr: &hir::Expr,
-                                             method_callee: ty::MethodCallee<'tcx>) {
+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);
-    fcx.inh.tables.borrow_mut().method_map.insert(method_call, method_callee);
+    self.inh.tables.borrow_mut().method_map.insert(method_call, method_callee);
+}
 }
 
 #[derive(Debug)]
@@ -365,7 +347,7 @@ impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> {
         assert!(fcx.infcx().closure_kind(self.closure_def_id).is_some());
 
         // We may now know enough to figure out fn vs fnmut etc.
-        match try_overloaded_call_traits(fcx, self.call_expr, self.callee_expr,
+        match fcx.try_overloaded_call_traits(self.call_expr, self.callee_expr,
                                          self.adjusted_ty, self.autoderefs) {
             Some(method_callee) => {
                 // One problem is that when we get here, we are going
@@ -385,16 +367,15 @@ impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> {
                 for (&method_arg_ty, &self_arg_ty) in
                     method_sig.inputs[1..].iter().zip(&self.fn_sig.inputs)
                 {
-                    demand::eqtype(fcx, self.call_expr.span, self_arg_ty, method_arg_ty);
+                    fcx.demand_eqtype(self.call_expr.span, self_arg_ty, method_arg_ty);
                 }
 
                 let nilty = fcx.tcx().mk_nil();
-                demand::eqtype(fcx,
-                               self.call_expr.span,
-                               method_sig.output.unwrap_or(nilty),
-                               self.fn_sig.output.unwrap_or(nilty));
+                fcx.demand_eqtype(self.call_expr.span,
+                                  method_sig.output.unwrap_or(nilty),
+                                  self.fn_sig.output.unwrap_or(nilty));
 
-                write_overloaded_call_method_map(fcx, self.call_expr, method_callee);
+                fcx.write_overloaded_call_method_map(self.call_expr, method_callee);
             }
             None => {
                 span_bug!(
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 249ab27ec59..506347679a4 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -38,10 +38,7 @@
 //! expression, `e as U2` is not necessarily so (in fact it will only be valid if
 //! `U1` coerces to `U2`).
 
-use super::coercion;
-use super::demand;
 use super::FnCtxt;
-use super::structurally_resolved_type;
 
 use lint;
 use hir::def_id::DefId;
@@ -75,11 +72,10 @@ enum UnsizeKind<'tcx> {
     OfParam(&'tcx ty::ParamTy)
 }
 
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 /// Returns the kind of unsize information of t, or None
 /// if t is sized or it is unknown.
-fn unsize_kind<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                        t: Ty<'tcx>)
-                        -> Option<UnsizeKind<'tcx>> {
+fn unsize_kind(&self, t: Ty<'tcx>) -> Option<UnsizeKind<'tcx>> {
     match t.sty {
         ty::TySlice(_) | ty::TyStr => Some(UnsizeKind::Length),
         ty::TyTrait(ref tty) => Some(UnsizeKind::Vtable(tty.principal_def_id())),
@@ -87,7 +83,7 @@ fn unsize_kind<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             // FIXME(arielb1): do some kind of normalization
             match def.struct_variant().fields.last() {
                 None => None,
-                Some(f) => unsize_kind(fcx, f.ty(fcx.tcx(), substs))
+                Some(f) => self.unsize_kind(f.ty(self.tcx(), substs))
             }
         }
         // We should really try to normalize here.
@@ -96,6 +92,7 @@ fn unsize_kind<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         _ => None
     }
 }
+}
 
 #[derive(Copy, Clone)]
 enum CastError {
@@ -112,14 +109,14 @@ enum CastError {
     NonScalar,
 }
 
-impl<'tcx> CastCheck<'tcx> {
-    pub fn new<'a>(fcx: &FnCtxt<'a, 'tcx>,
-                   expr: &'tcx hir::Expr,
-                   expr_ty: Ty<'tcx>,
-                   cast_ty: Ty<'tcx>,
-                   cast_span: Span,
-                   span: Span)
-                   -> Result<CastCheck<'tcx>, ErrorReported> {
+impl<'a, 'tcx> CastCheck<'tcx> {
+    pub fn new(fcx: &FnCtxt<'a, 'tcx>,
+               expr: &'tcx hir::Expr,
+               expr_ty: Ty<'tcx>,
+               cast_ty: Ty<'tcx>,
+               cast_span: Span,
+               span: Span)
+               -> Result<CastCheck<'tcx>, ErrorReported> {
         let check = CastCheck {
             expr: expr,
             expr_ty: expr_ty,
@@ -142,9 +139,7 @@ impl<'tcx> CastCheck<'tcx> {
         }
     }
 
-    fn report_cast_error<'a>(&self,
-                             fcx: &FnCtxt<'a, 'tcx>,
-                             e: CastError) {
+    fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
         match e {
             CastError::NeedViaPtr |
             CastError::NeedViaThinPtr |
@@ -207,8 +202,7 @@ impl<'tcx> CastCheck<'tcx> {
         }
     }
 
-    fn report_cast_to_unsized_type<'a>(&self,
-                                       fcx: &FnCtxt<'a, 'tcx>) {
+    fn report_cast_to_unsized_type(&self, fcx: &FnCtxt<'a, 'tcx>) {
         if
             self.cast_ty.references_error() ||
             self.expr_ty.references_error()
@@ -262,7 +256,7 @@ impl<'tcx> CastCheck<'tcx> {
         err.emit();
     }
 
-    fn trivial_cast_lint<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) {
+    fn trivial_cast_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
         let t_cast = self.cast_ty;
         let t_expr = self.expr_ty;
         if t_cast.is_numeric() && t_expr.is_numeric() {
@@ -287,9 +281,9 @@ impl<'tcx> CastCheck<'tcx> {
 
     }
 
-    pub fn check<'a>(mut self, fcx: &FnCtxt<'a, 'tcx>) {
-        self.expr_ty = structurally_resolved_type(fcx, self.span, self.expr_ty);
-        self.cast_ty = structurally_resolved_type(fcx, self.span, self.cast_ty);
+    pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) {
+        self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty);
+        self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty);
 
         debug!("check_cast({}, {:?} as {:?})", self.expr.id, self.expr_ty,
                self.cast_ty);
@@ -315,7 +309,7 @@ impl<'tcx> CastCheck<'tcx> {
     /// Check a cast, and report an error if one exists. In some cases, this
     /// can return Ok and create type errors in the fcx rather than returning
     /// directly. coercion-cast is handled in check instead of here.
-    fn do_check<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
+    fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
         use rustc::ty::cast::IntTy::*;
         use rustc::ty::cast::CastTy::*;
 
@@ -326,8 +320,8 @@ impl<'tcx> CastCheck<'tcx> {
             (None, Some(t_cast)) => {
                 if let ty::TyFnDef(_, _, f) = self.expr_ty.sty {
                     // Attempt a coercion to a fn pointer type.
-                    let res = coercion::try(fcx, self.expr,
-                                            fcx.tcx().mk_ty(ty::TyFnPtr(f)));
+                    let res = fcx.try_coerce(self.expr,
+                                             fcx.tcx().mk_ty(ty::TyFnPtr(f)));
                     if !res.is_ok() {
                         return Err(CastError::NonScalar);
                     }
@@ -382,11 +376,11 @@ impl<'tcx> CastCheck<'tcx> {
         }
     }
 
-    fn check_ptr_ptr_cast<'a>(&self,
-                              fcx: &FnCtxt<'a, 'tcx>,
-                              m_expr: &'tcx ty::TypeAndMut<'tcx>,
-                              m_cast: &'tcx ty::TypeAndMut<'tcx>)
-                              -> Result<CastKind, CastError>
+    fn check_ptr_ptr_cast(&self,
+                          fcx: &FnCtxt<'a, 'tcx>,
+                          m_expr: &'tcx ty::TypeAndMut<'tcx>,
+                          m_cast: &'tcx ty::TypeAndMut<'tcx>)
+                          -> Result<CastKind, CastError>
     {
         debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}",
                m_expr, m_cast);
@@ -403,16 +397,16 @@ impl<'tcx> CastCheck<'tcx> {
         }
 
         // vtable kinds must match
-        match (unsize_kind(fcx, m_cast.ty), unsize_kind(fcx, m_expr.ty)) {
+        match (fcx.unsize_kind(m_cast.ty), fcx.unsize_kind(m_expr.ty)) {
             (Some(a), Some(b)) if a == b => Ok(CastKind::PtrPtrCast),
             _ => Err(CastError::DifferingKinds)
         }
     }
 
-    fn check_fptr_ptr_cast<'a>(&self,
-                               fcx: &FnCtxt<'a, 'tcx>,
-                               m_cast: &'tcx ty::TypeAndMut<'tcx>)
-                               -> Result<CastKind, CastError>
+    fn check_fptr_ptr_cast(&self,
+                           fcx: &FnCtxt<'a, 'tcx>,
+                           m_cast: &'tcx ty::TypeAndMut<'tcx>)
+                           -> Result<CastKind, CastError>
     {
         // fptr-ptr cast. must be to sized ptr
 
@@ -423,10 +417,10 @@ impl<'tcx> CastCheck<'tcx> {
         }
     }
 
-    fn check_ptr_addr_cast<'a>(&self,
-                               fcx: &FnCtxt<'a, 'tcx>,
-                               m_expr: &'tcx ty::TypeAndMut<'tcx>)
-                               -> Result<CastKind, CastError>
+    fn check_ptr_addr_cast(&self,
+                           fcx: &FnCtxt<'a, 'tcx>,
+                           m_expr: &'tcx ty::TypeAndMut<'tcx>)
+                           -> Result<CastKind, CastError>
     {
         // ptr-addr cast. must be from sized ptr
 
@@ -437,11 +431,11 @@ impl<'tcx> CastCheck<'tcx> {
         }
     }
 
-    fn check_ref_cast<'a>(&self,
-                          fcx: &FnCtxt<'a, 'tcx>,
-                          m_expr: &'tcx ty::TypeAndMut<'tcx>,
-                          m_cast: &'tcx ty::TypeAndMut<'tcx>)
-                          -> Result<CastKind, CastError>
+    fn check_ref_cast(&self,
+                      fcx: &FnCtxt<'a, 'tcx>,
+                      m_expr: &'tcx ty::TypeAndMut<'tcx>,
+                      m_cast: &'tcx ty::TypeAndMut<'tcx>)
+                      -> Result<CastKind, CastError>
     {
         // array-ptr-cast.
 
@@ -455,7 +449,7 @@ impl<'tcx> CastCheck<'tcx> {
                 // from a region pointer to a vector.
 
                 // this will report a type mismatch if needed
-                demand::eqtype(fcx, self.span, ety, m_cast.ty);
+                fcx.demand_eqtype(self.span, ety, m_cast.ty);
                 return Ok(CastKind::ArrayPtrCast);
             }
         }
@@ -463,10 +457,10 @@ impl<'tcx> CastCheck<'tcx> {
         Err(CastError::IllegalCast)
     }
 
-    fn check_addr_ptr_cast<'a>(&self,
-                               fcx: &FnCtxt<'a, 'tcx>,
-                               m_cast: &'tcx ty::TypeAndMut<'tcx>)
-                               -> Result<CastKind, CastError>
+    fn check_addr_ptr_cast(&self,
+                           fcx: &FnCtxt<'a, 'tcx>,
+                           m_cast: &'tcx ty::TypeAndMut<'tcx>)
+                           -> Result<CastKind, CastError>
     {
         // ptr-addr cast. pointer must be thin.
         if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
@@ -476,8 +470,8 @@ impl<'tcx> CastCheck<'tcx> {
         }
     }
 
-    fn try_coercion_cast<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) -> bool {
-        coercion::try(fcx, self.expr, self.cast_ty).is_ok()
+    fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'tcx>) -> bool {
+        fcx.try_coerce(self.expr, self.cast_ty).is_ok()
     }
 
 }
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index b84ded1ea7a..7632f58f057 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -19,12 +19,13 @@ use std::cmp;
 use syntax::abi::Abi;
 use rustc::hir;
 
-pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
-                                   expr: &hir::Expr,
-                                   _capture: hir::CaptureClause,
-                                   decl: &'tcx hir::FnDecl,
-                                   body: &'tcx hir::Block,
-                                   expected: Expectation<'tcx>) {
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+pub fn check_expr_closure(&self,
+                          expr: &hir::Expr,
+                          _capture: hir::CaptureClause,
+                          decl: &'tcx hir::FnDecl,
+                          body: &'tcx hir::Block,
+                          expected: Expectation<'tcx>) {
     debug!("check_expr_closure(expr={:?},expected={:?})",
            expr,
            expected);
@@ -32,26 +33,26 @@ pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
     // It's always helpful for inference if we know the kind of
     // closure sooner rather than later, so first examine the expected
     // type, and see if can glean a closure kind from there.
-    let (expected_sig,expected_kind) = match expected.to_option(fcx) {
-        Some(ty) => deduce_expectations_from_expected_type(fcx, ty),
+    let (expected_sig,expected_kind) = match expected.to_option(self) {
+        Some(ty) => self.deduce_expectations_from_expected_type(ty),
         None => (None, None)
     };
-    check_closure(fcx, expr, expected_kind, decl, body, expected_sig)
+    self.check_closure(expr, expected_kind, decl, body, expected_sig)
 }
 
-fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
-                          expr: &hir::Expr,
-                          opt_kind: Option<ty::ClosureKind>,
-                          decl: &'tcx hir::FnDecl,
-                          body: &'tcx hir::Block,
-                          expected_sig: Option<ty::FnSig<'tcx>>) {
-    let expr_def_id = fcx.tcx().map.local_def_id(expr.id);
+fn check_closure(&self,
+                 expr: &hir::Expr,
+                 opt_kind: Option<ty::ClosureKind>,
+                 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);
 
     debug!("check_closure opt_kind={:?} expected_sig={:?}",
            opt_kind,
            expected_sig);
 
-    let mut fn_ty = astconv::ty_of_closure(fcx,
+    let mut fn_ty = astconv::ty_of_closure(self,
                                            hir::Unsafety::Normal,
                                            decl,
                                            Abi::RustCall,
@@ -60,51 +61,47 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
     // 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 = fcx.tcx().with_freevars(expr.id, |fv| fv.len());
-    let upvar_tys = fcx.infcx().next_ty_vars(num_upvars);
+    let num_upvars = self.tcx().with_freevars(expr.id, |fv| fv.len());
+    let upvar_tys = self.infcx().next_ty_vars(num_upvars);
 
     debug!("check_closure: expr.id={:?} upvar_tys={:?}",
            expr.id, upvar_tys);
 
-    let closure_type =
-        fcx.ccx.tcx.mk_closure(
-            expr_def_id,
-            fcx.ccx.tcx.mk_substs(fcx.inh.infcx.parameter_environment.free_substs.clone()),
-            upvar_tys);
+    let closure_type = self.tcx().mk_closure(expr_def_id,
+        self.tcx().mk_substs(self.inh.infcx.parameter_environment.free_substs.clone()),
+        upvar_tys);
 
-    fcx.write_ty(expr.id, closure_type);
+    self.write_ty(expr.id, closure_type);
 
-    let fn_sig = fcx.tcx().liberate_late_bound_regions(
-        fcx.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(fcx.ccx,
+    check_fn(self.ccx,
              hir::Unsafety::Normal,
              expr.id,
              &fn_sig,
              decl,
              expr.id,
              &body,
-             fcx.inh);
+             self.inh);
 
     // Tuple up the arguments and insert the resulting function type into
     // the `closures` table.
-    fn_ty.sig.0.inputs = vec![fcx.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);
 
-    fcx.inh.tables.borrow_mut().closure_tys.insert(expr_def_id, fn_ty);
+    self.inh.tables.borrow_mut().closure_tys.insert(expr_def_id, fn_ty);
     match opt_kind {
-        Some(kind) => { fcx.inh.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); }
+        Some(kind) => { self.inh.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); }
         None => { }
     }
 }
 
-fn deduce_expectations_from_expected_type<'a,'tcx>(
-    fcx: &FnCtxt<'a,'tcx>,
-    expected_ty: Ty<'tcx>)
+fn deduce_expectations_from_expected_type(&self, expected_ty: Ty<'tcx>)
     -> (Option<ty::FnSig<'tcx>>,Option<ty::ClosureKind>)
 {
     debug!("deduce_expectations_from_expected_type(expected_ty={:?})",
@@ -112,16 +109,16 @@ fn deduce_expectations_from_expected_type<'a,'tcx>(
 
     match expected_ty.sty {
         ty::TyTrait(ref object_type) => {
-            let proj_bounds = object_type.projection_bounds_with_self_ty(fcx.tcx(),
-                                                                         fcx.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| deduce_sig_from_projection(fcx, pb))
+                                 .filter_map(|pb| self.deduce_sig_from_projection(pb))
                                  .next();
-            let kind = fcx.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)) => {
-            deduce_expectations_from_obligations(fcx, vid)
+            self.deduce_expectations_from_obligations(vid)
         }
         _ => {
             (None, None)
@@ -129,12 +126,10 @@ fn deduce_expectations_from_expected_type<'a,'tcx>(
     }
 }
 
-fn deduce_expectations_from_obligations<'a,'tcx>(
-    fcx: &FnCtxt<'a,'tcx>,
-    expected_vid: ty::TyVid)
+fn deduce_expectations_from_obligations(&self, expected_vid: ty::TyVid)
     -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>)
 {
-    let fulfillment_cx = fcx.inh.fulfillment_cx.borrow();
+    let fulfillment_cx = self.inh.fulfillment_cx.borrow();
     // Here `expected_ty` is known to be a type inference variable.
 
     let expected_sig =
@@ -151,8 +146,8 @@ fn deduce_expectations_from_obligations<'a,'tcx>(
                 // the complete signature.
                 ty::Predicate::Projection(ref proj_predicate) => {
                     let trait_ref = proj_predicate.to_poly_trait_ref();
-                    self_type_matches_expected_vid(fcx, trait_ref, expected_vid)
-                        .and_then(|_| deduce_sig_from_projection(fcx, proj_predicate))
+                    self.self_type_matches_expected_vid(trait_ref, expected_vid)
+                        .and_then(|_| self.deduce_sig_from_projection(proj_predicate))
                 }
                 _ => {
                     None
@@ -192,32 +187,21 @@ fn deduce_expectations_from_obligations<'a,'tcx>(
                 ty::Predicate::ClosureKind(..) => None,
             };
             opt_trait_ref
-                .and_then(|trait_ref| self_type_matches_expected_vid(fcx, trait_ref, expected_vid))
-                .and_then(|trait_ref| fcx.tcx().lang_items.fn_trait_kind(trait_ref.def_id()))
+                .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()))
         })
-        .fold(None, pick_most_restrictive_closure_kind);
+        .fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));
 
     (expected_sig, expected_kind)
 }
 
-fn pick_most_restrictive_closure_kind(best: Option<ty::ClosureKind>,
-                                      cur: ty::ClosureKind)
-                                      -> Option<ty::ClosureKind>
-{
-    match best {
-        None => Some(cur),
-        Some(best) => Some(cmp::min(best, cur))
-    }
-}
-
 /// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
 /// everything we need to know about a closure.
-fn deduce_sig_from_projection<'a,'tcx>(
-    fcx: &FnCtxt<'a,'tcx>,
+fn deduce_sig_from_projection(&self,
     projection: &ty::PolyProjectionPredicate<'tcx>)
     -> Option<ty::FnSig<'tcx>>
 {
-    let tcx = fcx.tcx();
+    let tcx = self.tcx();
 
     debug!("deduce_sig_from_projection({:?})",
            projection);
@@ -229,7 +213,7 @@ fn deduce_sig_from_projection<'a,'tcx>(
     }
 
     let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0);
-    let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty);
+    let arg_param_ty = self.infcx().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 {
@@ -239,7 +223,7 @@ fn deduce_sig_from_projection<'a,'tcx>(
     debug!("deduce_sig_from_projection: input_tys {:?}", input_tys);
 
     let ret_param_ty = projection.0.ty;
-    let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty);
+    let ret_param_ty = self.infcx().resolve_type_vars_if_possible(&ret_param_ty);
     debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty);
 
     let fn_sig = ty::FnSig {
@@ -252,13 +236,12 @@ fn deduce_sig_from_projection<'a,'tcx>(
     Some(fn_sig)
 }
 
-fn self_type_matches_expected_vid<'a,'tcx>(
-    fcx: &FnCtxt<'a,'tcx>,
+fn self_type_matches_expected_vid(&self,
     trait_ref: ty::PolyTraitRef<'tcx>,
     expected_vid: ty::TyVid)
     -> Option<ty::PolyTraitRef<'tcx>>
 {
-    let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty());
+    let self_ty = self.infcx().shallow_resolve(trait_ref.self_ty());
     debug!("self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})",
            trait_ref,
            self_ty);
@@ -267,3 +250,4 @@ fn self_type_matches_expected_vid<'a,'tcx>(
         _ => None,
     }
 }
+}
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index b30277d745e..ae23ee79e91 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -60,7 +60,7 @@
 //! sort of a minor point so I've opted to leave it for later---after all
 //! we may want to adjust precisely when coercions occur.
 
-use check::{autoderef, FnCtxt, UnresolvedTypeAction};
+use check::{FnCtxt, UnresolvedTypeAction};
 
 use rustc::infer::{Coercion, InferOk, TypeOrigin, TypeTrace};
 use rustc::traits::{self, ObligationCause};
@@ -241,10 +241,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         let lvalue_pref = LvaluePreference::from_mutbl(mt_b.mutbl);
         let mut first_error = None;
         let mut r_borrow_var = None;
-        let (_, autoderefs, success) = autoderef(self.fcx, span, a, exprs,
-                                                 UnresolvedTypeAction::Ignore,
-                                                 lvalue_pref,
-                                                 |referent_ty, autoderef|
+        let (_, autoderefs, success) = self.fcx.autoderef(span, a, exprs,
+                                                          UnresolvedTypeAction::Ignore,
+                                                          lvalue_pref,
+                                                          |referent_ty, autoderef|
         {
             if autoderef == 0 {
                 // Don't let this pass, otherwise it would cause
@@ -616,25 +616,26 @@ fn apply<'a, 'b, 'tcx, E, I>(coerce: &mut Coerce<'a, 'tcx>,
     Ok((ty, adjustment))
 }
 
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 /// Attempt to coerce an expression to a type, and return the
 /// adjusted type of the expression, if successful.
 /// Adjustments are only recorded if the coercion succeeded.
 /// The expressions *must not* have any pre-existing adjustments.
-pub fn try<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                     expr: &hir::Expr,
-                     target: Ty<'tcx>)
-                     -> RelateResult<'tcx, Ty<'tcx>> {
-    let source = fcx.resolve_type_vars_if_possible(fcx.expr_ty(expr));
+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));
     debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
 
-    let mut coerce = Coerce::new(fcx, TypeOrigin::ExprAssignable(expr.span));
-    fcx.infcx().commit_if_ok(|_| {
+    let mut coerce = Coerce::new(self, TypeOrigin::ExprAssignable(expr.span));
+    self.infcx().commit_if_ok(|_| {
         let (ty, adjustment) =
             apply(&mut coerce, &|| Some(expr), source, target)?;
         if !adjustment.is_identity() {
             debug!("Success, coerced with {:?}", adjustment);
-            assert!(!fcx.inh.tables.borrow().adjustments.contains_key(&expr.id));
-            fcx.write_adjustment(expr.id, adjustment);
+            assert!(!self.inh.tables.borrow().adjustments.contains_key(&expr.id));
+            self.write_adjustment(expr.id, adjustment);
         }
         Ok(ty)
     })
@@ -643,18 +644,18 @@ pub fn try<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 /// Given some expressions, their known unified type and another expression,
 /// tries to unify the types, potentially inserting coercions on any of the
 /// provided expressions and returns their LUB (aka "common supertype").
-pub fn try_find_lub<'a, 'b, 'tcx, E, I>(fcx: &FnCtxt<'a, 'tcx>,
-                                        origin: TypeOrigin,
-                                        exprs: E,
-                                        prev_ty: Ty<'tcx>,
-                                        new: &'b hir::Expr)
-                                        -> RelateResult<'tcx, Ty<'tcx>>
+pub fn try_find_coercion_lub<'b, E, I>(&self,
+                                       origin: TypeOrigin,
+                                       exprs: E,
+                                       prev_ty: Ty<'tcx>,
+                                       new: &'b hir::Expr)
+                                       -> RelateResult<'tcx, Ty<'tcx>>
     // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
     where E: Fn() -> I,
           I: IntoIterator<Item=&'b hir::Expr> {
 
-    let prev_ty = fcx.resolve_type_vars_if_possible(prev_ty);
-    let new_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(new));
+    let prev_ty = self.resolve_type_vars_if_possible(prev_ty);
+    let new_ty = self.resolve_type_vars_if_possible(self.expr_ty(new));
     debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty);
 
     let trace = TypeTrace::types(origin, true, prev_ty, new_ty);
@@ -665,7 +666,7 @@ pub fn try_find_lub<'a, 'b, 'tcx, E, I>(fcx: &FnCtxt<'a, 'tcx>,
         (&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 = fcx.infcx().lub(true, trace.clone(), a_fty, b_fty)
+            let fty = self.infcx().lub(true, trace.clone(), a_fty, b_fty)
                 .map(|InferOk { value, obligations }| {
                     // FIXME(#32730) propagate obligations
                     assert!(obligations.is_empty());
@@ -674,46 +675,46 @@ pub fn try_find_lub<'a, 'b, 'tcx, E, I>(fcx: &FnCtxt<'a, 'tcx>,
 
             if a_def_id == b_def_id {
                 // Same function, maybe the parameters match.
-                let substs = fcx.infcx().commit_if_ok(|_| {
-                    fcx.infcx().lub(true, trace.clone(), a_substs, b_substs)
+                let substs = self.infcx().commit_if_ok(|_| {
+                    self.infcx().lub(true, trace.clone(), a_substs, b_substs)
                         .map(|InferOk { value, obligations }| {
                             // FIXME(#32730) propagate obligations
                             assert!(obligations.is_empty());
                             value
                         })
-                }).map(|s| fcx.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(fcx.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!(!fcx.inh.tables.borrow().adjustments.contains_key(&expr.id));
-                fcx.write_adjustment(expr.id, AdjustReifyFnPointer);
+                assert!(!self.inh.tables.borrow().adjustments.contains_key(&expr.id));
+                self.write_adjustment(expr.id, AdjustReifyFnPointer);
             }
-            return Ok(fcx.tcx().mk_fn_ptr(fty));
+            return Ok(self.tcx().mk_fn_ptr(fty));
         }
         _ => {}
     }
 
-    let mut coerce = Coerce::new(fcx, origin);
+    let mut coerce = Coerce::new(self, origin);
     coerce.use_lub = true;
 
     // 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 !fcx.inh.tables.borrow().adjustments.contains_key(&new.id) {
-        let result = fcx.infcx().commit_if_ok(|_| {
+    if !self.inh.tables.borrow().adjustments.contains_key(&new.id) {
+        let result = self.infcx().commit_if_ok(|_| {
             apply(&mut coerce, &|| Some(new), new_ty, prev_ty)
         });
         match result {
             Ok((ty, adjustment)) => {
                 if !adjustment.is_identity() {
-                    fcx.write_adjustment(new.id, adjustment);
+                    self.write_adjustment(new.id, adjustment);
                 }
                 return Ok(ty);
             }
@@ -725,12 +726,12 @@ pub fn try_find_lub<'a, 'b, 'tcx, E, I>(fcx: &FnCtxt<'a, 'tcx>,
     // 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 fcx.inh.tables.borrow().adjustments.get(&expr.id) {
+        let noop = match self.inh.tables.borrow().adjustments.get(&expr.id) {
             Some(&AdjustDerefRef(AutoDerefRef {
                 autoderefs: 1,
                 autoref: Some(AutoPtr(_, mutbl_adj)),
                 unsize: None
-            })) => match fcx.expr_ty(expr).sty {
+            })) => match self.expr_ty(expr).sty {
                 ty::TyRef(_, mt_orig) => {
                     // Reborrow that we can safely ignore.
                     mutbl_adj == mt_orig.mutbl
@@ -742,8 +743,8 @@ pub fn try_find_lub<'a, 'b, 'tcx, E, I>(fcx: &FnCtxt<'a, 'tcx>,
         };
 
         if !noop {
-            return fcx.infcx().commit_if_ok(|_| {
-                fcx.infcx().lub(true, trace.clone(), &prev_ty, &new_ty)
+            return self.infcx().commit_if_ok(|_| {
+                self.infcx().lub(true, trace.clone(), &prev_ty, &new_ty)
                     .map(|InferOk { value, obligations }| {
                         // FIXME(#32730) propagate obligations
                         assert!(obligations.is_empty());
@@ -753,14 +754,14 @@ pub fn try_find_lub<'a, 'b, 'tcx, E, I>(fcx: &FnCtxt<'a, 'tcx>,
         }
     }
 
-    match fcx.infcx().commit_if_ok(|_| apply(&mut coerce, &exprs, prev_ty, new_ty)) {
+    match self.infcx().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 {
-                fcx.infcx().commit_if_ok(|_| {
-                    fcx.infcx().lub(true, trace, &prev_ty, &new_ty)
+                self.infcx().commit_if_ok(|_| {
+                    self.infcx().lub(true, trace, &prev_ty, &new_ty)
                         .map(|InferOk { value, obligations }| {
                             // FIXME(#32730) propagate obligations
                             assert!(obligations.is_empty());
@@ -772,10 +773,11 @@ pub fn try_find_lub<'a, 'b, 'tcx, E, I>(fcx: &FnCtxt<'a, 'tcx>,
         Ok((ty, adjustment)) => {
             if !adjustment.is_identity() {
                 for expr in exprs() {
-                    fcx.write_adjustment(expr.id, adjustment);
+                    self.write_adjustment(expr.id, adjustment);
                 }
             }
             Ok(ty)
         }
     }
 }
+}
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 5b163eb7de4..8dfd62e1a66 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -9,52 +9,49 @@
 // except according to those terms.
 
 
-use check::{coercion, FnCtxt};
+use check::FnCtxt;
 use rustc::ty::Ty;
 use rustc::infer::{InferOk, TypeOrigin};
 
 use syntax::codemap::Span;
 use rustc::hir;
 
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 // Requires that the two types unify, and prints an error message if
 // they don't.
-pub fn suptype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
-                         expected: Ty<'tcx>, actual: Ty<'tcx>) {
+pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
     let origin = TypeOrigin::Misc(sp);
-    match fcx.infcx().sub_types(false, origin, actual, expected) {
+    match self.infcx().sub_types(false, origin, actual, expected) {
         Ok(InferOk { obligations, .. }) => {
             // FIXME(#32730) propagate obligations
             assert!(obligations.is_empty());
         },
         Err(e) => {
-            fcx.infcx().report_mismatched_types(origin, expected, actual, e);
+            self.infcx().report_mismatched_types(origin, expected, actual, e);
         }
     }
 }
 
-pub fn eqtype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
-                        expected: Ty<'tcx>, actual: Ty<'tcx>) {
+pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
     let origin = TypeOrigin::Misc(sp);
-    match fcx.infcx().eq_types(false, origin, actual, expected) {
+    match self.infcx().eq_types(false, origin, actual, expected) {
         Ok(InferOk { obligations, .. }) => {
             // FIXME(#32730) propagate obligations
             assert!(obligations.is_empty());
         },
         Err(e) => {
-            fcx.infcx().report_mismatched_types(origin, expected, actual, e);
+            self.infcx().report_mismatched_types(origin, expected, actual, e);
         }
     }
 }
 
 // Checks that the type of `expr` can be coerced to `expected`.
-pub fn coerce<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                        sp: Span,
-                        expected: Ty<'tcx>,
-                        expr: &hir::Expr) {
-    let expected = fcx.resolve_type_vars_if_possible(expected);
-    if let Err(e) = coercion::try(fcx, expr, expected) {
-        let origin = TypeOrigin::Misc(sp);
-        let expr_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(expr));
-        fcx.infcx().report_mismatched_types(origin, expected, expr_ty, e);
+pub fn demand_coerce(&self, expr: &hir::Expr, expected: Ty<'tcx>) {
+    let expected = self.resolve_type_vars_if_possible(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);
     }
 }
+}
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index b98f1884f01..77c74078de7 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -10,7 +10,7 @@
 
 use super::probe;
 
-use check::{self, FnCtxt, callee, demand};
+use check::{FnCtxt, callee};
 use check::UnresolvedTypeAction;
 use hir::def_id::DefId;
 use rustc::ty::subst::{self};
@@ -44,23 +44,25 @@ struct InstantiatedMethodSig<'tcx> {
     method_predicates: ty::InstantiatedPredicates<'tcx>,
 }
 
-pub fn confirm<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                         span: Span,
-                         self_expr: &'tcx hir::Expr,
-                         call_expr: &'tcx hir::Expr,
-                         unadjusted_self_ty: Ty<'tcx>,
-                         pick: probe::Pick<'tcx>,
-                         supplied_method_types: Vec<Ty<'tcx>>)
-                         -> ty::MethodCallee<'tcx>
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+pub fn confirm_method(&self,
+                      span: Span,
+                      self_expr: &'tcx hir::Expr,
+                      call_expr: &'tcx hir::Expr,
+                      unadjusted_self_ty: Ty<'tcx>,
+                      pick: probe::Pick<'tcx>,
+                      supplied_method_types: Vec<Ty<'tcx>>)
+                      -> ty::MethodCallee<'tcx>
 {
     debug!("confirm(unadjusted_self_ty={:?}, pick={:?}, supplied_method_types={:?})",
            unadjusted_self_ty,
            pick,
            supplied_method_types);
 
-    let mut confirm_cx = ConfirmContext::new(fcx, span, self_expr, call_expr);
+    let mut confirm_cx = ConfirmContext::new(self, span, self_expr, call_expr);
     confirm_cx.confirm(unadjusted_self_ty, pick, supplied_method_types)
 }
+}
 
 impl<'a,'tcx> ConfirmContext<'a,'tcx> {
     fn new(fcx: &'a FnCtxt<'a, 'tcx>,
@@ -155,13 +157,12 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
 
         // Commit the autoderefs by calling `autoderef again, but this
         // time writing the results into the various tables.
-        let (autoderefd_ty, n, result) = check::autoderef(self.fcx,
-                                                          self.span,
-                                                          unadjusted_self_ty,
-                                                          || Some(self.self_expr),
-                                                          UnresolvedTypeAction::Error,
-                                                          NoPreference,
-                                                          |_, n| {
+        let (autoderefd_ty, n, result) = self.fcx.autoderef(self.span,
+                                                            unadjusted_self_ty,
+                                                            || Some(self.self_expr),
+                                                            UnresolvedTypeAction::Error,
+                                                            NoPreference,
+                                                            |_, n| {
             if n == pick.autoderefs {
                 Some(())
             } else {
@@ -205,7 +206,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                 let impl_def_id = pick.item.container().id();
                 assert!(self.tcx().impl_trait_ref(impl_def_id).is_none(),
                         "impl {:?} is not an inherent impl", impl_def_id);
-                check::impl_self_ty(self.fcx, self.span, impl_def_id).substs
+                self.fcx.impl_self_ty(self.span, impl_def_id).substs
             }
 
             probe::ObjectPick => {
@@ -245,7 +246,7 @@ impl<'a,'tcx> ConfirmContext<'a,'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 = check::impl_self_ty(self.fcx, self.span, impl_def_id);
+                let impl_polytype = self.fcx.impl_self_ty(self.span, impl_def_id);
                 let impl_trait_ref =
                     self.fcx.instantiate_type_scheme(
                         self.span,
@@ -284,13 +285,12 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
         // yield an object-type (e.g., `&Object` or `Box<Object>`
         // etc).
 
-        let (_, _, result) = check::autoderef(self.fcx,
-                                              self.span,
-                                              self_ty,
-                                              || None,
-                                              UnresolvedTypeAction::Error,
-                                              NoPreference,
-                                              |ty, _| {
+        let (_, _, result) = self.fcx.autoderef(self.span,
+                                                self_ty,
+                                                || None,
+                                                UnresolvedTypeAction::Error,
+                                                NoPreference,
+                                                |ty, _| {
             match ty.sty {
                 ty::TyTrait(ref data) => Some(closure(self, ty, &data)),
                 _ => None,
@@ -506,19 +506,18 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                    i, expr, autoderef_count);
 
             if autoderef_count > 0 {
-                check::autoderef(self.fcx,
-                                 expr.span,
-                                 self.fcx.expr_ty(expr),
-                                 || Some(expr),
-                                 UnresolvedTypeAction::Error,
-                                 PreferMutLvalue,
-                                 |_, autoderefs| {
-                                     if autoderefs == autoderef_count + 1 {
-                                         Some(())
-                                     } else {
-                                         None
-                                     }
-                                 });
+                self.fcx.autoderef(expr.span,
+                                   self.fcx.expr_ty(expr),
+                                   || Some(expr),
+                                   UnresolvedTypeAction::Error,
+                                   PreferMutLvalue,
+                                   |_, autoderefs| {
+                    if autoderefs == autoderef_count + 1 {
+                        Some(())
+                    } else {
+                        None
+                    }
+                });
             }
 
             // Don't retry the first one or we might infinite loop!
@@ -576,8 +575,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                     };
                     let index_expr_ty = self.fcx.expr_ty(&index_expr);
 
-                    let result = check::try_index_step(
-                        self.fcx,
+                    let result = self.fcx.try_index_step(
                         ty::MethodCall::expr(expr.id),
                         expr,
                         &base_expr,
@@ -588,10 +586,10 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                         index_expr_ty);
 
                     if let Some((input_ty, return_ty)) = result {
-                        demand::suptype(self.fcx, index_expr.span, input_ty, index_expr_ty);
+                        self.fcx.demand_suptype(index_expr.span, input_ty, index_expr_ty);
 
                         let expr_ty = self.fcx.expr_ty(&expr);
-                        demand::suptype(self.fcx, expr.span, expr_ty, return_ty);
+                        self.fcx.demand_suptype(expr.span, expr_ty, return_ty);
                     }
                 }
                 hir::ExprUnary(hir::UnDeref, ref base_expr) => {
@@ -599,9 +597,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                     // 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 = check::try_overloaded_deref(
-                            self.fcx,
-                            expr.span,
+                        let method = self.fcx.try_overloaded_deref(expr.span,
                             Some(&base_expr),
                             self.fcx.expr_ty(&base_expr),
                             PreferMutLvalue);
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index 467956b6497..63df0021852 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -27,7 +27,7 @@ use rustc::hir;
 pub use self::MethodError::*;
 pub use self::CandidateSource::*;
 
-pub use self::suggest::{report_error, AllTraitsVec};
+pub use self::suggest::AllTraitsVec;
 
 mod confirm;
 mod probe;
@@ -78,16 +78,17 @@ pub enum CandidateSource {
     TraitSource(/* trait id */ DefId),
 }
 
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 /// Determines whether the type `self_ty` supports a method name `method_name` or not.
-pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                        span: Span,
-                        method_name: ast::Name,
-                        self_ty: ty::Ty<'tcx>,
-                        call_expr_id: ast::NodeId)
-                        -> bool
+pub fn method_exists(&self,
+                     span: Span,
+                     method_name: ast::Name,
+                     self_ty: ty::Ty<'tcx>,
+                     call_expr_id: ast::NodeId)
+                     -> bool
 {
     let mode = probe::Mode::MethodCall;
-    match probe::probe(fcx, span, mode, method_name, self_ty, call_expr_id) {
+    match self.probe_method(span, mode, method_name, self_ty, call_expr_id) {
         Ok(..) => true,
         Err(NoMatch(..)) => false,
         Err(Ambiguity(..)) => true,
@@ -110,14 +111,14 @@ pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 /// * `self_ty`:               the (unadjusted) type of the self expression (`foo`)
 /// * `supplied_method_types`: the explicit method type parameters, if any (`T1..Tn`)
 /// * `self_expr`:             the self expression (`foo`)
-pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                        span: Span,
-                        method_name: ast::Name,
-                        self_ty: ty::Ty<'tcx>,
-                        supplied_method_types: Vec<ty::Ty<'tcx>>,
-                        call_expr: &'tcx hir::Expr,
-                        self_expr: &'tcx hir::Expr)
-                        -> Result<ty::MethodCallee<'tcx>, MethodError<'tcx>>
+pub fn lookup_method(&self,
+                     span: Span,
+                     method_name: ast::Name,
+                     self_ty: ty::Ty<'tcx>,
+                     supplied_method_types: Vec<ty::Ty<'tcx>>,
+                     call_expr: &'tcx hir::Expr,
+                     self_expr: &'tcx hir::Expr)
+                     -> Result<ty::MethodCallee<'tcx>, MethodError<'tcx>>
 {
     debug!("lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
            method_name,
@@ -126,27 +127,27 @@ pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
            self_expr);
 
     let mode = probe::Mode::MethodCall;
-    let self_ty = fcx.infcx().resolve_type_vars_if_possible(&self_ty);
-    let pick = probe::probe(fcx, span, mode, method_name, self_ty, call_expr.id)?;
+    let self_ty = self.infcx().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 {
-        fcx.tcx().used_trait_imports.borrow_mut().insert(import_id);
+        self.tcx().used_trait_imports.borrow_mut().insert(import_id);
     }
 
-    Ok(confirm::confirm(fcx, span, self_expr, call_expr, self_ty, pick, supplied_method_types))
+    Ok(self.confirm_method(span, self_expr, call_expr, self_ty, pick, supplied_method_types))
 }
 
-pub fn lookup_in_trait<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                 span: Span,
-                                 self_expr: Option<&hir::Expr>,
-                                 m_name: ast::Name,
-                                 trait_def_id: DefId,
-                                 self_ty: ty::Ty<'tcx>,
-                                 opt_input_types: Option<Vec<ty::Ty<'tcx>>>)
-                                 -> Option<ty::MethodCallee<'tcx>>
+pub fn lookup_method_in_trait(&self,
+                              span: Span,
+                              self_expr: Option<&hir::Expr>,
+                              m_name: ast::Name,
+                              trait_def_id: DefId,
+                              self_ty: ty::Ty<'tcx>,
+                              opt_input_types: Option<Vec<ty::Ty<'tcx>>>)
+                              -> Option<ty::MethodCallee<'tcx>>
 {
-    lookup_in_trait_adjusted(fcx, span, self_expr, m_name, trait_def_id,
-                             0, false, self_ty, opt_input_types)
+    self.lookup_method_in_trait_adjusted(span, self_expr, m_name, trait_def_id,
+                                         0, false, self_ty, opt_input_types)
 }
 
 /// `lookup_in_trait_adjusted` is used for overloaded operators. It does a very narrow slice of
@@ -158,16 +159,16 @@ pub fn lookup_in_trait<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 /// method-lookup code. In particular, autoderef on index is basically identical to autoderef with
 /// normal probes, except that the test also looks for built-in indexing. Also, the second half of
 /// this method is basically the same as confirmation.
-pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                          span: Span,
-                                          self_expr: Option<&hir::Expr>,
-                                          m_name: ast::Name,
-                                          trait_def_id: DefId,
-                                          autoderefs: usize,
-                                          unsize: bool,
-                                          self_ty: ty::Ty<'tcx>,
-                                          opt_input_types: Option<Vec<ty::Ty<'tcx>>>)
-                                          -> Option<ty::MethodCallee<'tcx>>
+pub fn lookup_method_in_trait_adjusted(&self,
+                                       span: Span,
+                                       self_expr: Option<&hir::Expr>,
+                                       m_name: ast::Name,
+                                       trait_def_id: DefId,
+                                       autoderefs: usize,
+                                       unsize: bool,
+                                       self_ty: ty::Ty<'tcx>,
+                                       opt_input_types: Option<Vec<ty::Ty<'tcx>>>)
+                                       -> Option<ty::MethodCallee<'tcx>>
 {
     debug!("lookup_in_trait_adjusted(self_ty={:?}, self_expr={:?}, m_name={}, trait_def_id={:?})",
            self_ty,
@@ -175,7 +176,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
            m_name,
            trait_def_id);
 
-    let trait_def = fcx.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();
@@ -193,7 +194,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         }
 
         None => {
-            fcx.inh.infcx.type_vars_for_defs(
+            self.inh.infcx.type_vars_for_defs(
                 span,
                 subst::ParamSpace::TypeSpace,
                 &mut substs,
@@ -201,16 +202,16 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         }
     }
 
-    let trait_ref = ty::TraitRef::new(trait_def_id, fcx.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();
     let obligation = traits::Obligation::misc(span,
-                                              fcx.body_id,
+                                              self.body_id,
                                               poly_trait_ref.to_predicate());
 
     // Now we want to know if this can be matched
-    let mut selcx = traits::SelectionContext::new(fcx.infcx());
+    let mut selcx = traits::SelectionContext::new(self.infcx());
     if !selcx.evaluate_obligation(&obligation) {
         debug!("--> Cannot match obligation");
         return None; // Cannot be matched, no such method resolution is possible.
@@ -218,8 +219,8 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 
     // Trait must have a method named `m_name` and it should not have
     // type parameters or early-bound regions.
-    let tcx = fcx.tcx();
-    let method_item = trait_item(fcx, trait_def_id, m_name).unwrap();
+    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);
     assert_eq!(method_ty.generics.regions.len(subst::FnSpace), 0);
@@ -233,10 +234,10 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     // NB: Instantiate late-bound regions first so that
     // `instantiate_type_scheme` can normalize associated types that
     // may reference those regions.
-    let fn_sig = fcx.infcx().replace_late_bound_regions_with_fresh_var(span,
-                                                                       infer::FnCall,
-                                                                       &method_ty.fty.sig).0;
-    let fn_sig = fcx.instantiate_type_scheme(span, trait_ref.substs, &fn_sig);
+    let fn_sig = self.infcx().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();
     let fty = tcx.mk_fn_def(def_id, trait_ref.substs, ty::BareFnTy {
@@ -257,19 +258,19 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     //
     // Note that as the method comes from a trait, it should not have
     // any late-bound regions appearing in its bounds.
-    let method_bounds = fcx.instantiate_bounds(span, trait_ref.substs, &method_ty.predicates);
+    let method_bounds = self.instantiate_bounds(span, trait_ref.substs, &method_ty.predicates);
     assert!(!method_bounds.has_escaping_regions());
-    fcx.add_obligations_for_parameters(
-        traits::ObligationCause::misc(span, fcx.body_id),
+    self.add_obligations_for_parameters(
+        traits::ObligationCause::misc(span, self.body_id),
         &method_bounds);
 
     // Also register an obligation for the method type being well-formed.
-    fcx.register_wf_obligation(fty, span, traits::MiscObligation);
+    self.register_wf_obligation(fty, span, traits::MiscObligation);
 
     // FIXME(#18653) -- Try to resolve obligations, giving us more
     // typing information, which can sometimes be needed to avoid
     // pathological region inference failures.
-    fcx.select_obligations_where_possible();
+    self.select_obligations_where_possible();
 
     // Insert any adjustments needed (always an autoref of some mutability).
     match self_expr {
@@ -285,7 +286,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                 ty::ExplicitSelfCategory::ByValue => {
                     // Trait method is fn(self), no transformation needed.
                     assert!(!unsize);
-                    fcx.write_autoderef_adjustment(self_expr.id, autoderefs);
+                    self.write_autoderef_adjustment(self_expr.id, autoderefs);
                 }
 
                 ty::ExplicitSelfCategory::ByReference(..) => {
@@ -293,7 +294,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                     // autoref. Pull the region etc out of the type of first argument.
                     match transformed_self_ty.sty {
                         ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ }) => {
-                            fcx.write_adjustment(self_expr.id,
+                            self.write_adjustment(self_expr.id,
                                 AdjustDerefRef(AutoDerefRef {
                                     autoderefs: autoderefs,
                                     autoref: Some(AutoPtr(region, mutbl)),
@@ -335,25 +336,25 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     Some(callee)
 }
 
-pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                              span: Span,
-                              method_name: ast::Name,
-                              self_ty: ty::Ty<'tcx>,
-                              expr_id: ast::NodeId)
-                              -> Result<Def, MethodError<'tcx>>
+pub fn resolve_ufcs(&self,
+                    span: Span,
+                    method_name: ast::Name,
+                    self_ty: ty::Ty<'tcx>,
+                    expr_id: ast::NodeId)
+                    -> Result<Def, MethodError<'tcx>>
 {
     let mode = probe::Mode::Path;
-    let pick = probe::probe(fcx, span, mode, method_name, self_ty, expr_id)?;
+    let pick = self.probe_method(span, mode, method_name, self_ty, expr_id)?;
 
     if let Some(import_id) = pick.import_id {
-        fcx.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(fcx.body_id, &fcx.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());
-            fcx.tcx().sess.span_err(span, &msg);
+            self.tcx().sess.span_err(span, &msg);
         }
     }
     Ok(def)
@@ -361,26 +362,27 @@ pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 
 /// Find item with name `item_name` defined in `trait_def_id`
 /// and return it, or `None`, if no such item.
-pub fn trait_item<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                            trait_def_id: DefId,
-                            item_name: ast::Name)
-                            -> Option<ty::ImplOrTraitItem<'tcx>>
+pub fn trait_item(&self,
+                  trait_def_id: DefId,
+                  item_name: ast::Name)
+                  -> Option<ty::ImplOrTraitItem<'tcx>>
 {
-    let trait_items = fcx.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()
 }
 
-pub fn impl_item<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                           impl_def_id: DefId,
-                           item_name: ast::Name)
-                           -> Option<ty::ImplOrTraitItem<'tcx>>
+pub fn impl_item(&self,
+                 impl_def_id: DefId,
+                 item_name: ast::Name)
+                 -> Option<ty::ImplOrTraitItem<'tcx>>
 {
-    let impl_items = fcx.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| fcx.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 96cedc76d05..56f1f4677c6 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -13,7 +13,6 @@ use super::NoMatchData;
 use super::{CandidateSource, ImplSource, TraitSource};
 use super::suggest;
 
-use check;
 use check::{FnCtxt, UnresolvedTypeAction};
 use hir::def_id::DefId;
 use hir::def::Def;
@@ -129,13 +128,14 @@ pub enum Mode {
     Path
 }
 
-pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                       span: Span,
-                       mode: Mode,
-                       item_name: ast::Name,
-                       self_ty: Ty<'tcx>,
-                       scope_expr_id: ast::NodeId)
-                       -> PickResult<'tcx>
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+pub fn probe_method(&self,
+                    span: Span,
+                    mode: Mode,
+                    item_name: ast::Name,
+                    self_ty: Ty<'tcx>,
+                    scope_expr_id: ast::NodeId)
+                    -> PickResult<'tcx>
 {
     debug!("probe(self_ty={:?}, item_name={}, scope_expr_id={})",
            self_ty,
@@ -148,9 +148,9 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     // 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 `fcx.infcx().probe` below.
+    // take place in the `self.infcx().probe` below.
     let steps = if mode == Mode::MethodCall {
-        match create_steps(fcx, span, self_ty) {
+        match self.create_steps(span, self_ty) {
             Some(steps) => steps,
             None =>return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(), Vec::new(),
                                                                     Vec::new(), mode))),
@@ -166,7 +166,7 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     // 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(fcx.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,8 +184,8 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 
     // this creates one big transaction so that all type variables etc
     // that we create during the probe process are removed later
-    fcx.infcx().probe(|_| {
-        let mut probe_cx = ProbeContext::new(fcx,
+    self.infcx().probe(|_| {
+        let mut probe_cx = ProbeContext::new(self,
                                              span,
                                              mode,
                                              item_name,
@@ -197,19 +197,18 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     })
 }
 
-fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                          span: Span,
-                          self_ty: Ty<'tcx>)
-                          -> Option<Vec<CandidateStep<'tcx>>> {
+fn create_steps(&self,
+                span: Span,
+                self_ty: Ty<'tcx>)
+                -> Option<Vec<CandidateStep<'tcx>>> {
     let mut steps = Vec::new();
 
-    let (final_ty, dereferences, _) = check::autoderef(fcx,
-                                                       span,
-                                                       self_ty,
-                                                       || None,
-                                                       UnresolvedTypeAction::Error,
-                                                       NoPreference,
-                                                       |t, d| {
+    let (final_ty, dereferences, _) = self.autoderef(span,
+                                                     self_ty,
+                                                     || None,
+                                                     UnresolvedTypeAction::Error,
+                                                     NoPreference,
+                                                     |t, d| {
         steps.push(CandidateStep {
             self_ty: t,
             autoderefs: d,
@@ -221,7 +220,7 @@ fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     match final_ty.sty {
         ty::TyArray(elem_ty, _) => {
             steps.push(CandidateStep {
-                self_ty: fcx.tcx().mk_slice(elem_ty),
+                self_ty: self.tcx().mk_slice(elem_ty),
                 autoderefs: dereferences,
                 unsize: true
             });
@@ -232,6 +231,7 @@ fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 
     Some(steps)
 }
+}
 
 impl<'a,'tcx> ProbeContext<'a,'tcx> {
     fn new(fcx: &'a FnCtxt<'a,'tcx>,
@@ -1313,7 +1313,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
     fn impl_item(&self, impl_def_id: DefId)
                  -> Option<ty::ImplOrTraitItem<'tcx>>
     {
-        super::impl_item(self.fcx, impl_def_id, self.item_name)
+        self.fcx.impl_item(impl_def_id, self.item_name)
     }
 
     /// Find item with name `item_name` defined in `trait_def_id`
@@ -1321,7 +1321,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
     fn trait_item(&self, trait_def_id: DefId)
                   -> Option<ty::ImplOrTraitItem<'tcx>>
     {
-        super::trait_item(self.fcx, trait_def_id, self.item_name)
+        self.fcx.trait_item(trait_def_id, self.item_name)
     }
 }
 
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 9b81c4e2e92..d9af3552d85 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -13,7 +13,7 @@
 
 use CrateCtxt;
 
-use check::{self, FnCtxt, UnresolvedTypeAction, autoderef};
+use check::{self, FnCtxt, UnresolvedTypeAction};
 use rustc::hir::map as hir_map;
 use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TypeFoldable};
 use middle::cstore;
@@ -36,11 +36,12 @@ use rustc::hir::Expr_;
 use std::cell;
 use std::cmp::Ordering;
 
-use super::{MethodError, NoMatchData, CandidateSource, impl_item, trait_item};
+use super::{MethodError, NoMatchData, CandidateSource};
 use super::probe::Mode;
 
-fn is_fn_ty<'a, 'tcx>(ty: &Ty<'tcx>, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> bool {
-    let cx = fcx.tcx();
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+fn is_fn_ty(&self, ty: &Ty<'tcx>, span: Span) -> bool {
+    let tcx = self.tcx();
     match ty.sty {
         // Not all of these (e.g. unsafe fns) implement FnOnce
         // so we look for these beforehand
@@ -48,26 +49,23 @@ fn is_fn_ty<'a, 'tcx>(ty: &Ty<'tcx>, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> bool
         // If it's not a simple function, look for things which implement FnOnce
         _ => {
             if let Ok(fn_once_trait_did) =
-                    cx.lang_items.require(FnOnceTraitLangItem) {
-                let infcx = fcx.infcx();
-                let (_, _, opt_is_fn) = autoderef(fcx,
-                                                  span,
-                                                  ty,
-                                                  || None,
-                                                  UnresolvedTypeAction::Ignore,
-                                                  LvaluePreference::NoPreference,
-                                                  |ty, _| {
+                    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(|_| {
                         let fn_once_substs =
-                            Substs::new_trait(vec![infcx.next_ty_var()],
-                                              Vec::new(),
-                                              ty);
+                            Substs::new_trait(vec![infcx.next_ty_var()], vec![], ty);
                         let trait_ref =
-                          ty::TraitRef::new(fn_once_trait_did,
-                                            cx.mk_substs(fn_once_substs));
+                            ty::TraitRef::new(fn_once_trait_did,
+                                              tcx.mk_substs(fn_once_substs));
                         let poly_trait_ref = trait_ref.to_poly_trait_ref();
                         let obligation = Obligation::misc(span,
-                                                          fcx.body_id,
+                                                          self.body_id,
                                                           poly_trait_ref
                                                              .to_predicate());
                         let mut selcx = SelectionContext::new(infcx);
@@ -87,27 +85,83 @@ fn is_fn_ty<'a, 'tcx>(ty: &Ty<'tcx>, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> bool
         }
     }
 }
-
-pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                              span: Span,
-                              rcvr_ty: Ty<'tcx>,
-                              item_name: ast::Name,
-                              rcvr_expr: Option<&hir::Expr>,
-                              error: MethodError<'tcx>)
+pub fn report_method_error(&self,
+                           span: Span,
+                           rcvr_ty: Ty<'tcx>,
+                           item_name: ast::Name,
+                           rcvr_expr: Option<&hir::Expr>,
+                           error: MethodError<'tcx>)
 {
     // avoid suggestions when we don't know what's going on.
     if rcvr_ty.references_error() {
         return
     }
 
+    let report_candidates = |err: &mut DiagnosticBuilder,
+                             mut sources: Vec<CandidateSource>| {
+
+        sources.sort();
+        sources.dedup();
+
+        for (idx, source) in sources.iter().enumerate() {
+            match *source {
+                CandidateSource::ImplSource(impl_did) => {
+                    // Provide the best span we can. Use the item, if local to crate, else
+                    // the impl, if local to crate (item may be defaulted), else nothing.
+                    let item = self.impl_item(impl_did, item_name)
+                        .or_else(|| {
+                            self.trait_item(
+                                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 impl_ty = self.impl_self_ty(span, impl_did).ty;
+
+                    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))
+                        }
+                    };
+
+                    let note_str = format!("candidate #{} is defined in an impl{} \
+                                            for the type `{}`",
+                                           idx + 1,
+                                           insertion,
+                                           impl_ty);
+                    if let Some(note_span) = note_span {
+                        // We have a span pointing to the method. Show note with snippet.
+                        err.span_note(note_span, &note_str);
+                    } else {
+                        err.note(&note_str);
+                    }
+                }
+                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);
+                    span_note!(err, item_span,
+                               "candidate #{} is defined in the trait `{}`",
+                               idx + 1,
+                               self.tcx().item_path_str(trait_did));
+                }
+            }
+        }
+    };
+
     match error {
         MethodError::NoMatch(NoMatchData { static_candidates: static_sources,
                                            unsatisfied_predicates,
                                            out_of_scope_traits,
                                            mode, .. }) => {
-            let cx = fcx.tcx();
+            let tcx = self.tcx();
 
-            let mut err = fcx.type_error_struct(
+            let mut err = self.type_error_struct(
                 span,
                 |actual| {
                     format!("no {} named `{}` found for type `{}` \
@@ -123,16 +177,16 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             // If the item has the name of a field, give a help note
             if let (&ty::TyStruct(def, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) {
                 if let Some(field) = def.struct_variant().find_field_named(item_name) {
-                    let expr_string = match cx.sess.codemap().span_to_snippet(expr.span) {
+                    let expr_string = match tcx.sess.codemap().span_to_snippet(expr.span) {
                         Ok(expr_string) => expr_string,
                         _ => "s".into() // Default to a generic placeholder for the
                                         // expression when we can't generate a string
                                         // snippet
                     };
 
-                    let field_ty = field.ty(cx, substs);
+                    let field_ty = field.ty(tcx, substs);
 
-                    if is_fn_ty(&field_ty, &fcx, span) {
+                    if self.is_fn_ty(&field_ty, span) {
                         err.span_note(span,
                                       &format!("use `({0}.{1})(...)` if you meant to call \
                                                the function stored in the `{1}` field",
@@ -144,7 +198,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                 }
             }
 
-            if is_fn_ty(&rcvr_ty, &fcx, span) {
+            if self.is_fn_ty(&rcvr_ty, span) {
                 macro_rules! report_function {
                     ($span:expr, $name:expr) => {
                         err.note(&format!("{} is a function, perhaps you wish to call it",
@@ -153,7 +207,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                 }
 
                 if let Some(expr) = rcvr_expr {
-                    if let Ok (expr_string) = cx.sess.codemap().span_to_snippet(expr.span) {
+                    if let Ok (expr_string) = tcx.sess.codemap().span_to_snippet(expr.span) {
                         report_function!(expr.span, expr_string);
                     }
                     else if let Expr_::ExprPath(_, path) = expr.node.clone() {
@@ -169,7 +223,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                     "found the following associated functions; to be used as \
                      methods, functions must have a `self` parameter");
 
-                report_candidates(fcx, &mut err, span, item_name, static_sources);
+                report_candidates(&mut err, static_sources);
             }
 
             if !unsatisfied_predicates.is_empty() {
@@ -186,16 +240,16 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                              bound_list));
             }
 
-            suggest_traits_to_import(fcx, &mut err, span, rcvr_ty, item_name,
-                                     rcvr_expr, out_of_scope_traits);
+            self.suggest_traits_to_import(&mut err, span, rcvr_ty, item_name,
+                                          rcvr_expr, out_of_scope_traits);
             err.emit();
         }
 
         MethodError::Ambiguity(sources) => {
-            let mut err = struct_span_err!(fcx.sess(), span, E0034,
+            let mut err = struct_span_err!(self.sess(), span, E0034,
                                            "multiple applicable items in scope");
 
-            report_candidates(fcx, &mut err, span, item_name, sources);
+            report_candidates(&mut err, sources);
             err.emit();
         }
 
@@ -204,92 +258,30 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                invoked on this closure as we have not yet inferred what \
                                kind of closure it is",
                                item_name,
-                               fcx.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))
             } else {
                 msg
             };
-            fcx.sess().span_err(span, &msg);
+            self.sess().span_err(span, &msg);
         }
 
         MethodError::PrivateMatch(def) => {
             let msg = format!("{} `{}` is private", def.kind_name(), item_name);
-            fcx.tcx().sess.span_err(span, &msg);
-        }
-    }
-
-    fn report_candidates(fcx: &FnCtxt,
-                         err: &mut DiagnosticBuilder,
-                         span: Span,
-                         item_name: ast::Name,
-                         mut sources: Vec<CandidateSource>) {
-        sources.sort();
-        sources.dedup();
-
-        for (idx, source) in sources.iter().enumerate() {
-            match *source {
-                CandidateSource::ImplSource(impl_did) => {
-                    // Provide the best span we can. Use the item, if local to crate, else
-                    // the impl, if local to crate (item may be defaulted), else nothing.
-                    let item = impl_item(fcx, impl_did, item_name)
-                        .or_else(|| {
-                            trait_item(
-                                fcx,
-                                fcx.tcx().impl_trait_ref(impl_did).unwrap().def_id,
-                                item_name
-                            )
-                        }).unwrap();
-                    let note_span = fcx.tcx().map.span_if_local(item.def_id()).or_else(|| {
-                        fcx.tcx().map.span_if_local(impl_did)
-                    });
-
-                    let impl_ty = check::impl_self_ty(fcx, span, impl_did).ty;
-
-                    let insertion = match fcx.tcx().impl_trait_ref(impl_did) {
-                        None => format!(""),
-                        Some(trait_ref) => {
-                            format!(" of the trait `{}`",
-                                    fcx.tcx().item_path_str(trait_ref.def_id))
-                        }
-                    };
-
-                    let note_str = format!("candidate #{} is defined in an impl{} \
-                                            for the type `{}`",
-                                           idx + 1,
-                                           insertion,
-                                           impl_ty);
-                    if let Some(note_span) = note_span {
-                        // We have a span pointing to the method. Show note with snippet.
-                        err.span_note(note_span, &note_str);
-                    } else {
-                        err.note(&note_str);
-                    }
-                }
-                CandidateSource::TraitSource(trait_did) => {
-                    let item = trait_item(fcx, trait_did, item_name).unwrap();
-                    let item_span = fcx.tcx().map.def_id_span(item.def_id(), span);
-                    span_note!(err, item_span,
-                               "candidate #{} is defined in the trait `{}`",
-                               idx + 1,
-                               fcx.tcx().item_path_str(trait_did));
-                }
-            }
+            self.tcx().sess.span_err(span, &msg);
         }
     }
 }
 
-
-pub type AllTraitsVec = Vec<TraitInfo>;
-
-fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                      err: &mut DiagnosticBuilder,
-                                      span: Span,
-                                      rcvr_ty: Ty<'tcx>,
-                                      item_name: ast::Name,
-                                      rcvr_expr: Option<&hir::Expr>,
-                                      valid_out_of_scope_traits: Vec<DefId>)
+fn suggest_traits_to_import(&self,
+                            err: &mut DiagnosticBuilder,
+                            span: Span,
+                            rcvr_ty: Ty<'tcx>,
+                            item_name: ast::Name,
+                            rcvr_expr: Option<&hir::Expr>,
+                            valid_out_of_scope_traits: Vec<DefId>)
 {
     if !valid_out_of_scope_traits.is_empty() {
         let mut candidates = valid_out_of_scope_traits;
@@ -307,17 +299,17 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         for (i, trait_did) in candidates.iter().enumerate() {
             err.help(&format!("candidate #{}: `use {}`",
                               i + 1,
-                              fcx.tcx().item_path_str(*trait_did)));
+                              self.tcx().item_path_str(*trait_did)));
         }
         return
     }
 
-    let type_is_local = type_derefs_to_local(fcx, span, rcvr_ty, rcvr_expr);
+    let type_is_local = self.type_derefs_to_local(span, rcvr_ty, rcvr_expr);
 
     // there's no implemented traits, so lets suggest some traits to
     // implement, by finding ones that have the item name, and are
     // legal to implement.
-    let mut candidates = all_traits(fcx.ccx)
+    let mut candidates = all_traits(self.ccx)
         .filter(|info| {
             // we approximate the coherence rules to only suggest
             // traits that are legal to implement by requiring that
@@ -326,7 +318,7 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             // implementing a trait would be legal but is rejected
             // here).
             (type_is_local || info.def_id.is_local())
-                && trait_item(fcx, info.def_id, item_name).is_some()
+                && self.trait_item(info.def_id, item_name).is_some()
         })
         .collect::<Vec<_>>();
 
@@ -351,17 +343,17 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         for (i, trait_info) in candidates.iter().enumerate() {
             err.help(&format!("candidate #{}: `{}`",
                               i + 1,
-                              fcx.tcx().item_path_str(trait_info.def_id)));
+                              self.tcx().item_path_str(trait_info.def_id)));
         }
     }
 }
 
 /// Checks whether there is a local type somewhere in the chain of
 /// autoderefs of `rcvr_ty`.
-fn type_derefs_to_local<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                  span: Span,
-                                  rcvr_ty: Ty<'tcx>,
-                                  rcvr_expr: Option<&hir::Expr>) -> bool {
+fn type_derefs_to_local(&self,
+                        span: Span,
+                        rcvr_ty: Ty<'tcx>,
+                        rcvr_expr: Option<&hir::Expr>) -> bool {
     fn is_local(ty: Ty) -> bool {
         match ty.sty {
             ty::TyEnum(def, _) | ty::TyStruct(def, _) => def.did.is_local(),
@@ -381,12 +373,12 @@ fn type_derefs_to_local<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     // 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(fcx.resolve_type_vars_if_possible(rcvr_ty));
+        return is_local(self.resolve_type_vars_if_possible(rcvr_ty));
     }
 
-    check::autoderef(fcx, span, rcvr_ty, || None,
-                     check::UnresolvedTypeAction::Ignore, ty::NoPreference,
-                     |ty, _| {
+    self.autoderef(span, rcvr_ty, || None,
+                   check::UnresolvedTypeAction::Ignore, ty::NoPreference,
+                   |ty, _| {
         if is_local(ty) {
             Some(())
         } else {
@@ -394,6 +386,9 @@ fn type_derefs_to_local<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         }
     }).2.is_some()
 }
+}
+
+pub type AllTraitsVec = Vec<TraitInfo>;
 
 #[derive(Copy, Clone)]
 pub struct TraitInfo {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index d9807cc7bae..0da41ba41e4 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -81,7 +81,7 @@ pub use self::compare_method::{compare_impl_method, compare_const_impl};
 use self::TupleArgumentsFlag::*;
 
 use astconv::{self, ast_region_to_region, ast_ty_to_ty, AstConv, PathParamMode};
-use check::_match::pat_ctxt;
+use check::_match::PatCtxt;
 use dep_graph::DepNode;
 use fmt_macros::{Parser, Piece, Position};
 use middle::astconv_util::prohibit_type_params;
@@ -199,7 +199,7 @@ pub enum Expectation<'tcx> {
     ExpectRvalueLikeUnsized(Ty<'tcx>),
 }
 
-impl<'tcx> Expectation<'tcx> {
+impl<'a, 'tcx> Expectation<'tcx> {
     // Disregard "castable to" expectations because they
     // can lead us astray. Consider for example `if cond
     // {22} else {c} as u8` -- if we propagate the
@@ -216,7 +216,7 @@ impl<'tcx> Expectation<'tcx> {
     // an expected type. Otherwise, we might write parts of the type
     // when checking the 'then' block which are incompatible with the
     // 'else' branch.
-    fn adjust_for_branches<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
+    fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
         match *self {
             ExpectHasType(ety) => {
                 let ety = fcx.infcx().shallow_resolve(ety);
@@ -232,6 +232,73 @@ impl<'tcx> Expectation<'tcx> {
             _ => NoExpectation
         }
     }
+
+    /// Provide an expectation for an rvalue expression given an *optional*
+    /// hint, which is not required for type safety (the resulting type might
+    /// be checked higher up, as is the case with `&expr` and `box expr`), but
+    /// is useful in determining the concrete type.
+    ///
+    /// The primary use case is where the expected type is a fat pointer,
+    /// like `&[isize]`. For example, consider the following statement:
+    ///
+    ///    let x: &[isize] = &[1, 2, 3];
+    ///
+    /// In this case, the expected type for the `&[1, 2, 3]` expression is
+    /// `&[isize]`. If however we were to say that `[1, 2, 3]` has the
+    /// expectation `ExpectHasType([isize])`, that would be too strong --
+    /// `[1, 2, 3]` does not have the type `[isize]` but rather `[isize; 3]`.
+    /// It is only the `&[1, 2, 3]` expression as a whole that can be coerced
+    /// to the type `&[isize]`. Therefore, we propagate this more limited hint,
+    /// which still is useful, because it informs integer literals and the like.
+    /// 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>, ty: Ty<'tcx>) -> Expectation<'tcx> {
+        match fcx.tcx().struct_tail(ty).sty {
+            ty::TySlice(_) | ty::TyStr | ty::TyTrait(..) => {
+                ExpectRvalueLikeUnsized(ty)
+            }
+            _ => ExpectHasType(ty)
+        }
+    }
+
+    // Resolves `expected` by a single level if it is a variable. If
+    // there is no expected type or resolution is not possible (e.g.,
+    // no constraints yet present), just returns `None`.
+    fn resolve(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
+        match self {
+            NoExpectation => {
+                NoExpectation
+            }
+            ExpectCastableToType(t) => {
+                ExpectCastableToType(
+                    fcx.infcx().resolve_type_vars_if_possible(&t))
+            }
+            ExpectHasType(t) => {
+                ExpectHasType(
+                    fcx.infcx().resolve_type_vars_if_possible(&t))
+            }
+            ExpectRvalueLikeUnsized(t) => {
+                ExpectRvalueLikeUnsized(
+                    fcx.infcx().resolve_type_vars_if_possible(&t))
+            }
+        }
+    }
+
+    fn to_option(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> {
+        match self.resolve(fcx) {
+            NoExpectation => None,
+            ExpectCastableToType(ty) |
+            ExpectHasType(ty) |
+            ExpectRvalueLikeUnsized(ty) => Some(ty),
+        }
+    }
+
+    fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> {
+        match self.resolve(fcx) {
+            ExpectHasType(ty) => Some(ty),
+            _ => None
+        }
+    }
 }
 
 #[derive(Copy, Clone)]
@@ -330,23 +397,6 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
 
 }
 
-// Used by check_const and check_enum_variants
-pub fn blank_fn_ctxt<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
-                               inh: &'a Inherited<'a, 'tcx>,
-                               rty: ty::FnOutput<'tcx>,
-                               body_id: ast::NodeId)
-                               -> FnCtxt<'a, 'tcx> {
-    FnCtxt {
-        body_id: body_id,
-        writeback_errors: Cell::new(false),
-        err_count_on_creation: ccx.tcx.sess.err_count(),
-        ret_ty: rty,
-        ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, 0)),
-        inh: inh,
-        ccx: ccx
-    }
-}
-
 fn static_inherited_fields<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
                                      tables: &'a RefCell<ty::Tables<'tcx>>)
                                     -> Inherited<'a, 'tcx> {
@@ -452,13 +502,13 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                decl, fn_id, body, &inh);
 
             fcx.select_all_obligations_and_apply_defaults();
-            upvar::closure_analyze_fn(&fcx, fn_id, decl, body);
+            fcx.closure_analyze_fn(body);
             fcx.select_obligations_where_possible();
             fcx.check_casts();
             fcx.select_all_obligations_or_error(); // Casts can introduce new obligations.
 
-            regionck::regionck_fn(&fcx, fn_id, fn_span, decl, body);
-            writeback::resolve_type_vars_in_fn(&fcx, decl, body);
+            fcx.regionck_fn(fn_id, fn_span, decl, body);
+            fcx.resolve_type_vars_in_fn(decl, body);
         }
         _ => span_bug!(body.span, "check_bare_fn: function type expected")
     }
@@ -504,7 +554,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
     // 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.ccx.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,
@@ -533,7 +583,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
         match t.node {
             hir::TyFixedLengthVec(ref ty, ref count_expr) => {
                 self.visit_ty(&ty);
-                check_expr_with_hint(self.fcx, &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);
@@ -565,7 +615,6 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
                       -> FnCtxt<'a, 'tcx>
 {
     let tcx = ccx.tcx;
-    let err_count_on_creation = tcx.sess.err_count();
 
     let arg_tys = &fn_sig.inputs;
     let ret_ty = fn_sig.output;
@@ -577,15 +626,8 @@ 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 {
-        body_id: body.id,
-        writeback_errors: Cell::new(false),
-        err_count_on_creation: err_count_on_creation,
-        ret_ty: ret_ty,
-        ps: RefCell::new(UnsafetyState::function(unsafety, unsafety_id)),
-        inh: inherited,
-        ccx: ccx
-    };
+    let fcx = FnCtxt::new(ccx, inherited, ret_ty, body.id);
+    *fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id);
 
     if let ty::FnConverging(ret_ty) = ret_ty {
         fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType);
@@ -619,17 +661,17 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
                 });
 
             // Check the pattern.
-            let pcx = pat_ctxt {
+            let pcx = PatCtxt {
                 fcx: &fcx,
                 map: pat_id_map(&tcx.def_map, &input.pat),
             };
-            _match::check_pat(&pcx, &input.pat, *arg_ty);
+            pcx.check_pat(&input.pat, *arg_ty);
         }
 
         visit.visit_block(body);
     }
 
-    check_block_with_expected(&fcx, body, match ret_ty {
+    fcx.check_block_with_expected(body, match ret_ty {
         ty::FnConverging(result_type) => ExpectHasType(result_type),
         ty::FnDiverging => NoExpectation
     });
@@ -1075,8 +1117,144 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 }
 
+/// Checks a constant appearing in a type. At the moment this is just the
+/// length expression in a fixed-length vector, but someday it might be
+/// extended to type-level numeric literals.
+fn check_const_in_type<'a,'tcx>(ccx: &'a CrateCtxt<'a,'tcx>,
+                                expr: &'tcx hir::Expr,
+                                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);
+    fcx.check_const_with_ty(expr.span, expr, expected_type);
+}
+
+fn check_const<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
+                        sp: Span,
+                        e: &'tcx hir::Expr,
+                        id: ast::NodeId) {
+    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;
+    fcx.check_const_with_ty(sp, e, declty);
+}
+
+/// Checks whether a type can be represented in memory. In particular, it
+/// identifies types that contain themselves without indirection through a
+/// pointer, which would mean their size is unbounded.
+pub fn check_representable(tcx: &TyCtxt,
+                           sp: Span,
+                           item_id: ast::NodeId,
+                           _designation: &str) -> bool {
+    let rty = tcx.node_id_to_type(item_id);
+
+    // Check that it is possible to represent this type. This call identifies
+    // (1) types that contain themselves and (2) types that contain a different
+    // recursive type. It is only necessary to throw an error on those that
+    // contain themselves. For case 2, there must be an inner type that will be
+    // caught by case 1.
+    match rty.is_representable(tcx, sp) {
+        Representability::SelfRecursive => {
+            let item_def_id = tcx.map.local_def_id(item_id);
+            traits::recursive_type_with_infinite_size_error(tcx, item_def_id).emit();
+            return false
+        }
+        Representability::Representable | Representability::ContainsRecursive => (),
+    }
+    return true
+}
+
+pub fn check_simd(tcx: &TyCtxt, sp: Span, id: ast::NodeId) {
+    let t = tcx.node_id_to_type(id);
+    match t.sty {
+        ty::TyStruct(def, substs) => {
+            let fields = &def.struct_variant().fields;
+            if fields.is_empty() {
+                span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty");
+                return;
+            }
+            let e = fields[0].ty(tcx, substs);
+            if !fields.iter().all(|f| f.ty(tcx, substs) == e) {
+                span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous");
+                return;
+            }
+            match e.sty {
+                ty::TyParam(_) => { /* struct<T>(T, T, T, T) is ok */ }
+                _ if e.is_machine()  => { /* struct(u8, u8, u8, u8) is ok */ }
+                _ => {
+                    span_err!(tcx.sess, sp, E0077,
+                              "SIMD vector element type should be machine type");
+                    return;
+                }
+            }
+        }
+        _ => ()
+    }
+}
+
+pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
+                                    sp: Span,
+                                    vs: &'tcx [hir::Variant],
+                                    id: ast::NodeId) {
+    fn do_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                          vs: &'tcx [hir::Variant],
+                          id: ast::NodeId,
+                          hint: attr::ReprAttr) {
+        #![allow(trivial_numeric_casts)]
+
+        let rty = ccx.tcx.node_id_to_type(id);
+        let mut disr_vals: Vec<ty::Disr> = Vec::new();
+
+        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 repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(ccx.tcx);
+        for v in vs {
+            if let Some(ref e) = v.node.disr_expr {
+                fcx.check_const_with_ty(e.span, e, repr_type_ty);
+            }
+        }
+
+        let def_id = ccx.tcx.map.local_def_id(id);
+
+        let variants = &ccx.tcx.lookup_adt_def(def_id).variants;
+        for (v, variant) in vs.iter().zip(variants.iter()) {
+            let current_disr_val = variant.disr_val;
+
+            // Check for duplicate discriminant values
+            match disr_vals.iter().position(|&x| x == current_disr_val) {
+                Some(i) => {
+                    let mut err = struct_span_err!(ccx.tcx.sess, v.span, E0081,
+                        "discriminant value `{}` already exists", disr_vals[i]);
+                    let variant_i_node_id = ccx.tcx.map.as_local_node_id(variants[i].did).unwrap();
+                    span_note!(&mut err, ccx.tcx.map.span(variant_i_node_id),
+                        "conflicting discriminant here");
+                    err.emit();
+                }
+                None => {}
+            }
+            disr_vals.push(current_disr_val);
+        }
+    }
+
+    let def_id = ccx.tcx.map.local_def_id(id);
+    let hint = *ccx.tcx.lookup_repr_hints(def_id).get(0).unwrap_or(&attr::ReprAny);
+
+    if hint != attr::ReprAny && vs.is_empty() {
+        span_err!(ccx.tcx.sess, sp, E0084,
+            "unsupported representation for zero-variant enum");
+    }
+
+    do_check(ccx, vs, id, hint);
+
+    check_representable(ccx.tcx, sp, id, "enum");
+}
+
 impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
-    fn tcx(&self) -> &TyCtxt<'tcx> { self.ccx.tcx }
+    fn tcx(&self) -> &TyCtxt<'tcx> { self.infcx().tcx }
 
     fn get_item_type_scheme(&self, _: Span, id: DefId)
                             -> Result<ty::TypeScheme<'tcx>, ErrorReported>
@@ -1131,7 +1309,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
                                            assoc_name: ast::Name)
                                            -> bool
     {
-        let trait_def = self.ccx.tcx.lookup_trait_def(trait_def_id);
+        let trait_def = self.tcx().lookup_trait_def(trait_def_id);
         trait_def.associated_type_names.contains(&assoc_name)
     }
 
@@ -1187,8 +1365,81 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
     }
 }
 
+impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> {
+    fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
+        Some(self.base_object_lifetime_default(span))
+    }
+
+    fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
+        // RFC #599 specifies that object lifetime defaults take
+        // precedence over other defaults. But within a fn body we
+        // don't have a *default* region, rather we use inference to
+        // find the *correct* region, which is strictly more general
+        // (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))
+    }
+
+    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))
+        }).collect())
+    }
+}
+
+/// Whether `autoderef` requires types to resolve.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum UnresolvedTypeAction {
+    /// Produce an error and return `TyError` whenever a type cannot
+    /// be resolved (i.e. it is `TyInfer`).
+    Error,
+    /// Go on without emitting any errors, and return the unresolved
+    /// type. Useful for probing, e.g. in coercions.
+    Ignore
+}
+
+/// Controls whether the arguments are tupled. This is used for the call
+/// operator.
+///
+/// Tupling means that all call-side arguments are packed into a tuple and
+/// passed as a single parameter. For example, if tupling is enabled, this
+/// function:
+///
+///     fn f(x: (isize, isize))
+///
+/// Can be called as:
+///
+///     f(1, 2);
+///
+/// Instead of:
+///
+///     f((1, 2));
+#[derive(Clone, Eq, PartialEq)]
+enum TupleArgumentsFlag {
+    DontTupleArguments,
+    TupleArguments,
+}
+
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
-    fn tcx(&self) -> &TyCtxt<'tcx> { self.ccx.tcx }
+    pub fn new(ccx: &'a CrateCtxt<'a, 'tcx>,
+               inh: &'a Inherited<'a, 'tcx>,
+               rty: ty::FnOutput<'tcx>,
+               body_id: ast::NodeId)
+               -> FnCtxt<'a, 'tcx> {
+        FnCtxt {
+            body_id: body_id,
+            writeback_errors: Cell::new(false),
+            err_count_on_creation: ccx.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<'tcx> { self.infcx().tcx }
 
     pub fn infcx(&self) -> &InferCtxt<'a,'tcx> {
         &self.inh.infcx
@@ -1203,7 +1454,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     pub fn err_count_since_creation(&self) -> usize {
-        self.ccx.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
@@ -1714,7 +1965,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             for ty in &self.infcx().unsolved_variables() {
                 if let ty::TyInfer(_) = self.infcx().shallow_resolve(ty).sty {
                     debug!("default_type_parameters: defaulting `{:?}` to error", ty);
-                    demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.err);
+                    self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.err);
                 }
             }
             return;
@@ -1725,18 +1976,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if self.infcx().type_var_diverges(resolved) {
                 debug!("default_type_parameters: defaulting `{:?}` to `()` because it diverges",
                        resolved);
-                demand::eqtype(self, 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) {
                     UnconstrainedInt => {
                         debug!("default_type_parameters: defaulting `{:?}` to `i32`",
                                resolved);
-                        demand::eqtype(self, 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);
-                        demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.f64)
+                        self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.f64)
                     }
                     Neither => { }
                 }
@@ -1799,7 +2050,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             for ty in &unsolved_variables {
                 let resolved = self.infcx().resolve_type_vars_if_possible(ty);
                 if self.infcx().type_var_diverges(resolved) {
-                    demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil());
+                    self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().mk_nil());
                 } else {
                     match self.infcx().type_is_unconstrained_numeric(resolved) {
                         UnconstrainedInt | UnconstrainedFloat => {
@@ -1856,14 +2107,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let _ = self.infcx().commit_if_ok(|_: &infer::CombinedSnapshot| {
                 for ty in &unbound_tyvars {
                     if self.infcx().type_var_diverges(ty) {
-                        demand::eqtype(self, 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(ty) {
                             UnconstrainedInt => {
-                                demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.i32)
+                                self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.i32)
                             },
                             UnconstrainedFloat => {
-                                demand::eqtype(self, 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) {
@@ -1952,14 +2203,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // reporting for more then one conflict.
         for ty in &unbound_tyvars {
             if self.infcx().type_var_diverges(ty) {
-                demand::eqtype(self, 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(ty) {
                     UnconstrainedInt => {
-                        demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.i32)
+                        self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.i32)
                     },
                     UnconstrainedFloat => {
-                        demand::eqtype(self, 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) {
@@ -2014,56 +2265,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             Err(errors) => { report_fulfillment_errors(self.infcx(), &errors); }
         }
     }
-}
-
-impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> {
-    fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
-        Some(self.base_object_lifetime_default(span))
-    }
-
-    fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
-        // RFC #599 specifies that object lifetime defaults take
-        // precedence over other defaults. But within a fn body we
-        // don't have a *default* region, rather we use inference to
-        // find the *correct* region, which is strictly more general
-        // (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))
-    }
-
-    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))
-        }).collect())
-    }
-}
-
-/// Whether `autoderef` requires types to resolve.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum UnresolvedTypeAction {
-    /// Produce an error and return `TyError` whenever a type cannot
-    /// be resolved (i.e. it is `TyInfer`).
-    Error,
-    /// Go on without emitting any errors, and return the unresolved
-    /// type. Useful for probing, e.g. in coercions.
-    Ignore
-}
 
 /// Executes an autoderef loop for the type `t`. At each step, invokes `should_stop` to decide
 /// whether to terminate the loop. Returns the final type and number of derefs that it performed.
 ///
 /// Note: this method does not modify the adjustments table. The caller is responsible for
-/// inserting an AutoAdjustment record into the `fcx` using one of the suitable methods.
-pub fn autoderef<'a, 'b, 'tcx, E, I, T, F>(fcx: &FnCtxt<'a, 'tcx>,
-                                           sp: Span,
-                                           base_ty: Ty<'tcx>,
-                                           maybe_exprs: E,
-                                           unresolved_type_action: UnresolvedTypeAction,
-                                           mut lvalue_pref: LvaluePreference,
-                                           mut should_stop: F)
-                                           -> (Ty<'tcx>, usize, Option<T>)
+/// inserting an AutoAdjustment record into the `self` using one of the suitable methods.
+pub fn autoderef<'b, E, I, T, F>(&self,
+                                 sp: Span,
+                                 base_ty: Ty<'tcx>,
+                                 maybe_exprs: E,
+                                 unresolved_type_action: UnresolvedTypeAction,
+                                 mut lvalue_pref: LvaluePreference,
+                                 mut should_stop: F)
+                                 -> (Ty<'tcx>, usize, Option<T>)
     // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
     where E: Fn() -> I,
           I: IntoIterator<Item=&'b hir::Expr>,
@@ -2073,17 +2288,17 @@ pub fn autoderef<'a, 'b, 'tcx, E, I, T, F>(fcx: &FnCtxt<'a, 'tcx>,
            base_ty, lvalue_pref);
 
     let mut t = base_ty;
-    for autoderefs in 0..fcx.tcx().sess.recursion_limit.get() {
+    for autoderefs in 0..self.tcx().sess.recursion_limit.get() {
         let resolved_t = match unresolved_type_action {
             UnresolvedTypeAction::Error => {
-                structurally_resolved_type(fcx, sp, t)
+                self.structurally_resolved_type(sp, t)
             }
             UnresolvedTypeAction::Ignore => {
                 // We can continue even when the type cannot be resolved
                 // (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.
-                fcx.infcx().resolve_type_vars_if_possible(&t)
+                self.infcx().resolve_type_vars_if_possible(&t)
             }
         };
         if resolved_t.references_error() {
@@ -2110,13 +2325,13 @@ pub fn autoderef<'a, 'b, 'tcx, E, I, T, F>(fcx: &FnCtxt<'a, 'tcx>,
         // complex mess that is begging for a proper MIR.
         let mt = if let Some(mt) = resolved_t.builtin_deref(false, lvalue_pref) {
             mt
-        } else if let Some(method) = try_overloaded_deref(fcx, sp, None,
-                                                          resolved_t, lvalue_pref) {
+        } else if let Some(method) = self.try_overloaded_deref(sp, None,
+                                                               resolved_t, lvalue_pref) {
             for expr in maybe_exprs() {
                 let method_call = MethodCall::autoderef(expr.id, autoderefs as u32);
-                fcx.inh.tables.borrow_mut().method_map.insert(method_call, method);
+                self.inh.tables.borrow_mut().method_map.insert(method_call, method);
             }
-            make_overloaded_lvalue_return_type(fcx, method)
+            self.make_overloaded_lvalue_return_type(method)
         } else {
             return (resolved_t, autoderefs, None);
         };
@@ -2128,35 +2343,35 @@ pub fn autoderef<'a, 'b, 'tcx, E, I, T, F>(fcx: &FnCtxt<'a, 'tcx>,
     }
 
     // We've reached the recursion limit, error gracefully.
-    span_err!(fcx.tcx().sess, sp, E0055,
+    span_err!(self.tcx().sess, sp, E0055,
         "reached the recursion limit while auto-dereferencing {:?}",
         base_ty);
-    (fcx.tcx().types.err, 0, None)
+    (self.tcx().types.err, 0, None)
 }
 
-fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                  span: Span,
-                                  base_expr: Option<&hir::Expr>,
-                                  base_ty: Ty<'tcx>,
-                                  lvalue_pref: LvaluePreference)
-                                  -> Option<MethodCallee<'tcx>>
+fn try_overloaded_deref(&self,
+                        span: Span,
+                        base_expr: Option<&hir::Expr>,
+                        base_ty: Ty<'tcx>,
+                        lvalue_pref: LvaluePreference)
+                        -> Option<MethodCallee<'tcx>>
 {
     // Try DerefMut first, if preferred.
-    let method = match (lvalue_pref, fcx.tcx().lang_items.deref_mut_trait()) {
+    let method = match (lvalue_pref, self.tcx().lang_items.deref_mut_trait()) {
         (PreferMutLvalue, Some(trait_did)) => {
-            method::lookup_in_trait(fcx, span, base_expr,
-                                    token::intern("deref_mut"), trait_did,
-                                    base_ty, None)
+            self.lookup_method_in_trait(span, base_expr,
+                                        token::intern("deref_mut"), trait_did,
+                                        base_ty, None)
         }
         _ => None
     };
 
     // Otherwise, fall back to Deref.
-    let method = match (method, fcx.tcx().lang_items.deref_trait()) {
+    let method = match (method, self.tcx().lang_items.deref_trait()) {
         (None, Some(trait_did)) => {
-            method::lookup_in_trait(fcx, span, base_expr,
-                                    token::intern("deref"), trait_did,
-                                    base_ty, None)
+            self.lookup_method_in_trait(span, base_expr,
+                                        token::intern("deref"), trait_did,
+                                        base_ty, None)
         }
         (method, _) => method
     };
@@ -2167,40 +2382,39 @@ fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 /// For the overloaded lvalue expressions (`*x`, `x[3]`), the trait returns a type of `&T`, but the
 /// actual type we assign to the *expression* is `T`. So this function just peels off the return
 /// type by one layer to yield `T`.
-fn make_overloaded_lvalue_return_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                                method: MethodCallee<'tcx>)
-                                                -> ty::TypeAndMut<'tcx>
+fn make_overloaded_lvalue_return_type(&self,
+                                      method: MethodCallee<'tcx>)
+                                      -> ty::TypeAndMut<'tcx>
 {
     // 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 = fcx.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()
 }
 
-fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                             expr: &hir::Expr,
-                             base_expr: &'tcx hir::Expr,
-                             base_ty: Ty<'tcx>,
-                             idx_ty: Ty<'tcx>,
-                             lvalue_pref: LvaluePreference)
-                             -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)>
+fn lookup_indexing(&self,
+                   expr: &hir::Expr,
+                   base_expr: &'tcx hir::Expr,
+                   base_ty: Ty<'tcx>,
+                   idx_ty: Ty<'tcx>,
+                   lvalue_pref: LvaluePreference)
+                   -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)>
 {
     // FIXME(#18741) -- this is almost but not quite the same as the
     // autoderef that normal method probing does. They could likely be
     // consolidated.
 
-    let (ty, autoderefs, final_mt) = autoderef(fcx,
-                                               base_expr.span,
-                                               base_ty,
-                                               || Some(base_expr),
-                                               UnresolvedTypeAction::Error,
-                                               lvalue_pref,
-                                               |adj_ty, idx| {
-        try_index_step(fcx, MethodCall::expr(expr.id), expr, base_expr,
-                       adj_ty, idx, false, lvalue_pref, idx_ty)
+    let (ty, autoderefs, final_mt) = self.autoderef(base_expr.span,
+                                                    base_ty,
+                                                    || Some(base_expr),
+                                                    UnresolvedTypeAction::Error,
+                                                    lvalue_pref,
+                                                    |adj_ty, idx| {
+        self.try_index_step(MethodCall::expr(expr.id), expr, base_expr,
+                            adj_ty, idx, false, lvalue_pref, idx_ty)
     });
 
     if final_mt.is_some() {
@@ -2210,9 +2424,9 @@ fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     // 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 = fcx.tcx().mk_slice(element_ty);
-        try_index_step(fcx, MethodCall::expr(expr.id), expr, base_expr,
-                       adjusted_ty, autoderefs, true, lvalue_pref, idx_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 {
         None
     }
@@ -2222,18 +2436,18 @@ fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 /// `base_expr`, looking for a type which either supports builtin indexing or overloaded indexing.
 /// This loop implements one step in that search; the autoderef loop is implemented by
 /// `lookup_indexing`.
-fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                            method_call: MethodCall,
-                            expr: &hir::Expr,
-                            base_expr: &'tcx hir::Expr,
-                            adjusted_ty: Ty<'tcx>,
-                            autoderefs: usize,
-                            unsize: bool,
-                            lvalue_pref: LvaluePreference,
-                            index_ty: Ty<'tcx>)
-                            -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)>
+fn try_index_step(&self,
+                  method_call: MethodCall,
+                  expr: &hir::Expr,
+                  base_expr: &'tcx hir::Expr,
+                  adjusted_ty: Ty<'tcx>,
+                  autoderefs: usize,
+                  unsize: bool,
+                  lvalue_pref: LvaluePreference,
+                  index_ty: Ty<'tcx>)
+                  -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)>
 {
-    let tcx = fcx.tcx();
+    let tcx = self.tcx();
     debug!("try_index_step(expr={:?}, base_expr.id={:?}, adjusted_ty={:?}, \
                            autoderefs={}, unsize={}, index_ty={:?})",
            expr,
@@ -2243,7 +2457,7 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
            unsize,
            index_ty);
 
-    let input_ty = fcx.infcx().next_ty_var();
+    let input_ty = self.infcx().next_ty_var();
 
     // First, try built-in indexing.
     match (adjusted_ty.builtin_index(), &index_ty.sty) {
@@ -2251,7 +2465,7 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             debug!("try_index_step: success, using built-in indexing");
             // If we had `[T; N]`, we should've caught it before unsizing to `[T]`.
             assert!(!unsize);
-            fcx.write_autoderef_adjustment(base_expr.id, autoderefs);
+            self.write_autoderef_adjustment(base_expr.id, autoderefs);
             return Some((tcx.types.usize, ty));
         }
         _ => {}
@@ -2260,15 +2474,14 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     // Try `IndexMut` first, if preferred.
     let method = match (lvalue_pref, tcx.lang_items.index_mut_trait()) {
         (PreferMutLvalue, Some(trait_did)) => {
-            method::lookup_in_trait_adjusted(fcx,
-                                             expr.span,
-                                             Some(&base_expr),
-                                             token::intern("index_mut"),
-                                             trait_did,
-                                             autoderefs,
-                                             unsize,
-                                             adjusted_ty,
-                                             Some(vec![input_ty]))
+            self.lookup_method_in_trait_adjusted(expr.span,
+                                                 Some(&base_expr),
+                                                 token::intern("index_mut"),
+                                                 trait_did,
+                                                 autoderefs,
+                                                 unsize,
+                                                 adjusted_ty,
+                                                 Some(vec![input_ty]))
         }
         _ => None,
     };
@@ -2276,15 +2489,14 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     // Otherwise, fall back to `Index`.
     let method = match (method, tcx.lang_items.index_trait()) {
         (None, Some(trait_did)) => {
-            method::lookup_in_trait_adjusted(fcx,
-                                             expr.span,
-                                             Some(&base_expr),
-                                             token::intern("index"),
-                                             trait_did,
-                                             autoderefs,
-                                             unsize,
-                                             adjusted_ty,
-                                             Some(vec![input_ty]))
+            self.lookup_method_in_trait_adjusted(expr.span,
+                                                 Some(&base_expr),
+                                                 token::intern("index"),
+                                                 trait_did,
+                                                 autoderefs,
+                                                 unsize,
+                                                 adjusted_ty,
+                                                 Some(vec![input_ty]))
         }
         (method, _) => method,
     };
@@ -2294,51 +2506,39 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     // If some lookup succeeded, install method in table
     method.map(|method| {
         debug!("try_index_step: success, using overloaded indexing");
-        fcx.inh.tables.borrow_mut().method_map.insert(method_call, method);
-        (input_ty, make_overloaded_lvalue_return_type(fcx, method).ty)
+        self.inh.tables.borrow_mut().method_map.insert(method_call, method);
+        (input_ty, self.make_overloaded_lvalue_return_type(method).ty)
     })
 }
 
-fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                         sp: Span,
-                                         method_fn_ty: Ty<'tcx>,
-                                         callee_expr: &'tcx hir::Expr,
-                                         args_no_rcvr: &'tcx [P<hir::Expr>],
-                                         tuple_arguments: TupleArgumentsFlag,
-                                         expected: Expectation<'tcx>)
-                                         -> ty::FnOutput<'tcx> {
+fn check_method_argument_types(&self,
+                               sp: Span,
+                               method_fn_ty: Ty<'tcx>,
+                               callee_expr: &'tcx hir::Expr,
+                               args_no_rcvr: &'tcx [P<hir::Expr>],
+                               tuple_arguments: TupleArgumentsFlag,
+                               expected: Expectation<'tcx>)
+                               -> ty::FnOutput<'tcx> {
     if method_fn_ty.references_error() {
-        let err_inputs = err_args(fcx, args_no_rcvr.len());
+        let err_inputs = self.err_args(args_no_rcvr.len());
 
         let err_inputs = match tuple_arguments {
             DontTupleArguments => err_inputs,
-            TupleArguments => vec![fcx.tcx().mk_tup(err_inputs)],
+            TupleArguments => vec![self.tcx().mk_tup(err_inputs)],
         };
 
-        check_argument_types(fcx,
-                             sp,
-                             &err_inputs[..],
-                             &[],
-                             args_no_rcvr,
-                             false,
-                             tuple_arguments);
-        ty::FnConverging(fcx.tcx().types.err)
+        self.check_argument_types(sp, &err_inputs[..], &[], args_no_rcvr,
+                                  false, tuple_arguments);
+        ty::FnConverging(self.tcx().types.err)
     } else {
         match method_fn_ty.sty {
             ty::TyFnDef(_, _, ref fty) => {
                 // HACK(eddyb) ignore self in the definition (see above).
-                let expected_arg_tys = expected_types_for_fn_args(fcx,
-                                                                  sp,
-                                                                  expected,
-                                                                  fty.sig.0.output,
-                                                                  &fty.sig.0.inputs[1..]);
-                check_argument_types(fcx,
-                                     sp,
-                                     &fty.sig.0.inputs[1..],
-                                     &expected_arg_tys[..],
-                                     args_no_rcvr,
-                                     fty.sig.0.variadic,
-                                     tuple_arguments);
+                let expected_arg_tys = self.expected_types_for_fn_args(sp, expected,
+                                                                       fty.sig.0.output,
+                                                                       &fty.sig.0.inputs[1..]);
+                self.check_argument_types(sp, &fty.sig.0.inputs[1..], &expected_arg_tys[..],
+                                          args_no_rcvr, fty.sig.0.variadic, tuple_arguments);
                 fty.sig.0.output
             }
             _ => {
@@ -2350,14 +2550,14 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 
 /// Generic function that factors out common logic from function calls, method calls and overloaded
 /// operators.
-fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                  sp: Span,
-                                  fn_inputs: &[Ty<'tcx>],
-                                  expected_arg_tys: &[Ty<'tcx>],
-                                  args: &'tcx [P<hir::Expr>],
-                                  variadic: bool,
-                                  tuple_arguments: TupleArgumentsFlag) {
-    let tcx = fcx.ccx.tcx;
+fn check_argument_types(&self,
+                        sp: Span,
+                        fn_inputs: &[Ty<'tcx>],
+                        expected_arg_tys: &[Ty<'tcx>],
+                        args: &'tcx [P<hir::Expr>],
+                        variadic: bool,
+                        tuple_arguments: TupleArgumentsFlag) {
+    let tcx = self.tcx();
 
     // Grab the argument types, supplying fresh type variables
     // if the wrong number of arguments were supplied
@@ -2370,13 +2570,13 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     // All the input types from the fn signature must outlive the call
     // so as to validate implied bounds.
     for &fn_input_ty in fn_inputs {
-        fcx.register_wf_obligation(fn_input_ty, sp, traits::MiscObligation);
+        self.register_wf_obligation(fn_input_ty, sp, traits::MiscObligation);
     }
 
     let mut expected_arg_tys = expected_arg_tys;
     let expected_arg_count = fn_inputs.len();
     let formal_tys = if tuple_arguments == TupleArguments {
-        let tuple_type = structurally_resolved_type(fcx, sp, fn_inputs[0]);
+        let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]);
         match tuple_type.sty {
             ty::TyTuple(ref arg_types) => {
                 if arg_types.len() != args.len() {
@@ -2387,7 +2587,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                         args.len(),
                         if args.len() == 1 {" was"} else {"s were"});
                     expected_arg_tys = &[];
-                    err_args(fcx, args.len())
+                    self.err_args(args.len())
                 } else {
                     expected_arg_tys = match expected_arg_tys.get(0) {
                         Some(&ty) => match ty.sty {
@@ -2404,7 +2604,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                     "cannot use call notation; the first type parameter \
                      for the function trait is neither a tuple nor unit");
                 expected_arg_tys = &[];
-                err_args(fcx, args.len())
+                self.err_args(args.len())
             }
         }
     } else if expected_arg_count == supplied_arg_count {
@@ -2421,7 +2621,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                 supplied_arg_count,
                 if supplied_arg_count == 1 {" was"} else {"s were"});
             expected_arg_tys = &[];
-            err_args(fcx, supplied_arg_count)
+            self.err_args(supplied_arg_count)
         }
     } else {
         span_err!(tcx.sess, sp, E0061,
@@ -2431,11 +2631,11 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             supplied_arg_count,
             if supplied_arg_count == 1 {" was"} else {"s were"});
         expected_arg_tys = &[];
-        err_args(fcx, supplied_arg_count)
+        self.err_args(supplied_arg_count)
     };
 
     debug!("check_argument_types: formal_tys={:?}",
-           formal_tys.iter().map(|t| fcx.infcx().ty_to_string(*t)).collect::<Vec<String>>());
+           formal_tys.iter().map(|t| self.infcx().ty_to_string(*t)).collect::<Vec<String>>());
 
     // Check the arguments.
     // We do this in a pretty awful way: first we typecheck any arguments
@@ -2454,7 +2654,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         // an "opportunistic" vtable resolution of any trait bounds on
         // the call. This helps coercions.
         if check_blocks {
-            fcx.select_obligations_where_possible();
+            self.select_obligations_where_possible();
         }
 
         // For variadic functions, we don't have a declared type for all of
@@ -2469,8 +2669,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         };
         for (i, arg) in args.iter().take(t).enumerate() {
             if any_diverges && !warned {
-                fcx.ccx
-                    .tcx
+                self.tcx()
                     .sess
                     .add_lint(lint::builtin::UNREACHABLE_CODE,
                               arg.id,
@@ -2490,30 +2689,29 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                 // The special-cased logic below has three functions:
                 // 1. Provide as good of an expected type as possible.
                 let expected = expected_arg_tys.get(i).map(|&ty| {
-                    Expectation::rvalue_hint(fcx, ty)
+                    Expectation::rvalue_hint(self, ty)
                 });
 
-                check_expr_with_expectation(fcx, &arg,
+                self.check_expr_with_expectation(&arg,
                     expected.unwrap_or(ExpectHasType(formal_ty)));
                 // 2. Coerce to the most detailed type that could be coerced
                 //    to, which is `expected_ty` if `rvalue_hint` returns an
                 //    `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
-                let coerce_ty = expected.and_then(|e| e.only_has_type(fcx));
-                demand::coerce(fcx, arg.span, coerce_ty.unwrap_or(formal_ty), &arg);
+                let coerce_ty = expected.and_then(|e| e.only_has_type(self));
+                self.demand_coerce(&arg, coerce_ty.unwrap_or(formal_ty));
 
                 // 3. Relate the expected type and the formal one,
                 //    if the expected type was used for the coercion.
-                coerce_ty.map(|ty| demand::suptype(fcx, arg.span, formal_ty, ty));
+                coerce_ty.map(|ty| self.demand_suptype(arg.span, formal_ty, ty));
             }
 
-            if let Some(&arg_ty) = fcx.inh.tables.borrow().node_types.get(&arg.id) {
-                any_diverges = any_diverges || fcx.infcx().type_var_diverges(arg_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 any_diverges && !warned {
-            let parent = fcx.ccx.tcx.map.get_parent_node(args[0].id);
-            fcx.ccx
-                .tcx
+            let parent = self.tcx().map.get_parent_node(args[0].id);
+            self.tcx()
                 .sess
                 .add_lint(lint::builtin::UNREACHABLE_CODE,
                           parent,
@@ -2528,39 +2726,38 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     // arguments which we skipped above.
     if variadic {
         for arg in args.iter().skip(expected_arg_count) {
-            check_expr(fcx, &arg);
+            self.check_expr(&arg);
 
             // There are a few types which get autopromoted when passed via varargs
             // in C but we just error out instead and require explicit casts.
-            let arg_ty = structurally_resolved_type(fcx, arg.span,
-                                                    fcx.expr_ty(&arg));
+            let arg_ty = self.structurally_resolved_type(arg.span,
+                                                         self.expr_ty(&arg));
             match arg_ty.sty {
                 ty::TyFloat(ast::FloatTy::F32) => {
-                    fcx.type_error_message(arg.span,
-                                           |t| {
+                    self.type_error_message(arg.span, |t| {
                         format!("can't pass an `{}` to variadic \
                                  function, cast to `c_double`", t)
                     }, arg_ty, None);
                 }
                 ty::TyInt(ast::IntTy::I8) | ty::TyInt(ast::IntTy::I16) | ty::TyBool => {
-                    fcx.type_error_message(arg.span, |t| {
+                    self.type_error_message(arg.span, |t| {
                         format!("can't pass `{}` to variadic \
                                  function, cast to `c_int`",
                                        t)
                     }, arg_ty, None);
                 }
                 ty::TyUint(ast::UintTy::U8) | ty::TyUint(ast::UintTy::U16) => {
-                    fcx.type_error_message(arg.span, |t| {
+                    self.type_error_message(arg.span, |t| {
                         format!("can't pass `{}` to variadic \
                                  function, cast to `c_uint`",
                                        t)
                     }, arg_ty, None);
                 }
                 ty::TyFnDef(_, _, f) => {
-                    let ptr_ty = fcx.tcx().mk_ty(ty::TyFnPtr(f));
-                    let ptr_ty = fcx.infcx().resolve_type_vars_if_possible(&ptr_ty);
-                    fcx.type_error_message(arg.span,
-                                           |t| {
+                    let ptr_ty = self.tcx().mk_ty(ty::TyFnPtr(f));
+                    let ptr_ty = self.infcx().resolve_type_vars_if_possible(&ptr_ty);
+                    self.type_error_message(arg.span,
+                                            |t| {
                         format!("can't pass `{}` to variadic \
                                  function, cast to `{}`", t, ptr_ty)
                     }, arg_ty, None);
@@ -2571,26 +2768,26 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     }
 }
 
-fn err_args<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, len: usize) -> Vec<Ty<'tcx>> {
-    (0..len).map(|_| fcx.tcx().types.err).collect()
+fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> {
+    (0..len).map(|_| self.tcx().types.err).collect()
 }
 
-fn write_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                        call_expr: &hir::Expr,
-                        output: ty::FnOutput<'tcx>) {
-    fcx.write_ty(call_expr.id, match output {
+fn write_call(&self,
+              call_expr: &hir::Expr,
+              output: ty::FnOutput<'tcx>) {
+    self.write_ty(call_expr.id, match output {
         ty::FnConverging(output_ty) => output_ty,
-        ty::FnDiverging => fcx.infcx().next_diverging_ty_var()
+        ty::FnDiverging => self.infcx().next_diverging_ty_var()
     });
 }
 
 // AST fragment checking
-fn check_lit<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                       lit: &ast::Lit,
-                       expected: Expectation<'tcx>)
-                       -> Ty<'tcx>
+fn check_lit(&self,
+             lit: &ast::Lit,
+             expected: Expectation<'tcx>)
+             -> Ty<'tcx>
 {
-    let tcx = fcx.ccx.tcx;
+    let tcx = self.tcx();
 
     match lit.node {
         ast::LitKind::Str(..) => tcx.mk_static_str(),
@@ -2603,7 +2800,7 @@ fn check_lit<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(t),
         ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(t),
         ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
-            let opt_ty = expected.to_option(fcx).and_then(|ty| {
+            let opt_ty = expected.to_option(self).and_then(|ty| {
                 match ty.sty {
                     ty::TyInt(_) | ty::TyUint(_) => Some(ty),
                     ty::TyChar => Some(tcx.types.u8),
@@ -2613,73 +2810,73 @@ fn check_lit<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                 }
             });
             opt_ty.unwrap_or_else(
-                || tcx.mk_int_var(fcx.infcx().next_int_var_id()))
+                || tcx.mk_int_var(self.infcx().next_int_var_id()))
         }
         ast::LitKind::Float(_, t) => tcx.mk_mach_float(t),
         ast::LitKind::FloatUnsuffixed(_) => {
-            let opt_ty = expected.to_option(fcx).and_then(|ty| {
+            let opt_ty = expected.to_option(self).and_then(|ty| {
                 match ty.sty {
                     ty::TyFloat(_) => Some(ty),
                     _ => None
                 }
             });
             opt_ty.unwrap_or_else(
-                || tcx.mk_float_var(fcx.infcx().next_float_var_id()))
+                || tcx.mk_float_var(self.infcx().next_float_var_id()))
         }
         ast::LitKind::Bool(_) => tcx.types.bool
     }
 }
 
-fn check_expr_eq_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                expr: &'tcx hir::Expr,
-                                expected: Ty<'tcx>) {
-    check_expr_with_hint(fcx, expr, expected);
-    demand::eqtype(fcx, expr.span, expected, fcx.expr_ty(expr));
+fn check_expr_eq_type(&self,
+                      expr: &'tcx hir::Expr,
+                      expected: Ty<'tcx>) {
+    self.check_expr_with_hint(expr, expected);
+    self.demand_eqtype(expr.span, expected, self.expr_ty(expr));
 }
 
-pub fn check_expr_has_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                     expr: &'tcx hir::Expr,
-                                     expected: Ty<'tcx>) {
-    check_expr_with_hint(fcx, expr, expected);
-    demand::suptype(fcx, expr.span, expected, fcx.expr_ty(expr));
+pub fn check_expr_has_type(&self,
+                           expr: &'tcx hir::Expr,
+                           expected: Ty<'tcx>) {
+    self.check_expr_with_hint(expr, expected);
+    self.demand_suptype(expr.span, expected, self.expr_ty(expr));
 }
 
-fn check_expr_coercable_to_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                          expr: &'tcx hir::Expr,
-                                          expected: Ty<'tcx>) {
-    check_expr_with_hint(fcx, expr, expected);
-    demand::coerce(fcx, expr.span, expected, expr);
+fn check_expr_coercable_to_type(&self,
+                                expr: &'tcx hir::Expr,
+                                expected: Ty<'tcx>) {
+    self.check_expr_with_hint(expr, expected);
+    self.demand_coerce(expr, expected);
 }
 
-fn check_expr_with_hint<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx hir::Expr,
-                                  expected: Ty<'tcx>) {
-    check_expr_with_expectation(fcx, expr, ExpectHasType(expected))
+fn check_expr_with_hint(&self, expr: &'tcx hir::Expr,
+                        expected: Ty<'tcx>) {
+    self.check_expr_with_expectation(expr, ExpectHasType(expected))
 }
 
-fn check_expr_with_expectation<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                         expr: &'tcx hir::Expr,
-                                         expected: Expectation<'tcx>) {
-    check_expr_with_expectation_and_lvalue_pref(fcx, expr, expected, NoPreference)
+fn check_expr_with_expectation(&self,
+                               expr: &'tcx hir::Expr,
+                               expected: Expectation<'tcx>) {
+    self.check_expr_with_expectation_and_lvalue_pref(expr, expected, NoPreference)
 }
 
-fn check_expr<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, expr: &'tcx hir::Expr)  {
-    check_expr_with_expectation(fcx, expr, NoExpectation)
+fn check_expr(&self, expr: &'tcx hir::Expr)  {
+    self.check_expr_with_expectation(expr, NoExpectation)
 }
 
-fn check_expr_with_lvalue_pref<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, expr: &'tcx hir::Expr,
-                                        lvalue_pref: LvaluePreference)  {
-    check_expr_with_expectation_and_lvalue_pref(fcx, expr, NoExpectation, lvalue_pref)
+fn check_expr_with_lvalue_pref(&self, expr: &'tcx hir::Expr,
+                               lvalue_pref: LvaluePreference)  {
+    self.check_expr_with_expectation_and_lvalue_pref(expr, NoExpectation, lvalue_pref)
 }
 
 // determine the `self` type, using fresh variables for all variables
 // declared on the impl declaration e.g., `impl<A,B> for Vec<(A,B)>`
 // would return ($0, $1) where $0 and $1 are freshly instantiated type
 // variables.
-pub fn impl_self_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                              span: Span, // (potential) receiver for this impl
-                              did: DefId)
-                              -> TypeAndSubsts<'tcx> {
-    let tcx = fcx.tcx();
+pub fn impl_self_ty(&self,
+                    span: Span, // (potential) receiver for this impl
+                    did: DefId)
+                    -> TypeAndSubsts<'tcx> {
+    let tcx = self.tcx();
 
     let ity = tcx.lookup_item_type(did);
     let (tps, rps, raw_ty) =
@@ -2689,55 +2886,33 @@ pub fn impl_self_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 
     debug!("impl_self_ty: tps={:?} rps={:?} raw_ty={:?}", tps, rps, raw_ty);
 
-    let rps = fcx.inh.infcx.region_vars_for_defs(span, rps);
+    let rps = self.inh.infcx.region_vars_for_defs(span, rps);
     let mut substs = subst::Substs::new(
         VecPerParamSpace::empty(),
         VecPerParamSpace::new(rps, Vec::new(), Vec::new()));
-    fcx.inh.infcx.type_vars_for_defs(span, ParamSpace::TypeSpace, &mut substs, tps);
-    let substd_ty = fcx.instantiate_type_scheme(span, &substs, &raw_ty);
+    self.inh.infcx.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 }
 }
 
-/// Controls whether the arguments are tupled. This is used for the call
-/// operator.
-///
-/// Tupling means that all call-side arguments are packed into a tuple and
-/// passed as a single parameter. For example, if tupling is enabled, this
-/// function:
-///
-///     fn f(x: (isize, isize))
-///
-/// Can be called as:
-///
-///     f(1, 2);
-///
-/// Instead of:
-///
-///     f((1, 2));
-#[derive(Clone, Eq, PartialEq)]
-enum TupleArgumentsFlag {
-    DontTupleArguments,
-    TupleArguments,
-}
-
 /// Unifies the return type with the expected type early, for more coercions
 /// and forward type information on the argument expressions.
-fn expected_types_for_fn_args<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                        call_span: Span,
-                                        expected_ret: Expectation<'tcx>,
-                                        formal_ret: ty::FnOutput<'tcx>,
-                                        formal_args: &[Ty<'tcx>])
-                                        -> Vec<Ty<'tcx>> {
-    let expected_args = expected_ret.only_has_type(fcx).and_then(|ret_ty| {
+fn expected_types_for_fn_args(&self,
+                              call_span: Span,
+                              expected_ret: Expectation<'tcx>,
+                              formal_ret: ty::FnOutput<'tcx>,
+                              formal_args: &[Ty<'tcx>])
+                              -> 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 {
-            fcx.infcx().commit_regions_if_ok(|| {
+            self.infcx().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 = fcx.infcx().sub_types(false, origin, formal_ret_ty, ret_ty);
+                let ures = self.infcx().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 {
@@ -2749,7 +2924,7 @@ fn expected_types_for_fn_args<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                 // Record all the argument types, with the substitutions
                 // produced from the above subtyping unification.
                 Ok(formal_args.iter().map(|ty| {
-                    fcx.infcx().resolve_type_vars_if_possible(ty)
+                    self.infcx().resolve_type_vars_if_possible(ty)
                 }).collect())
             }).ok()
         } else {
@@ -2762,115 +2937,92 @@ fn expected_types_for_fn_args<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     expected_args
 }
 
-/// Invariant:
-/// If an expression has any sub-expressions that result in a type error,
-/// inspecting that expression's type with `ty.references_error()` will return
-/// true. Likewise, if an expression is known to diverge, inspecting its
-/// type with `ty::type_is_bot` will return true (n.b.: since Rust is
-/// strict, _|_ can appear in the type of an expression that does not,
-/// itself, diverge: for example, fn() -> _|_.)
-/// Note that inspecting a type's structure *directly* may expose the fact
-/// that there are actually multiple representations for `TyError`, so avoid
-/// that when err needs to be handled differently.
-fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                                         expr: &'tcx hir::Expr,
-                                                         expected: Expectation<'tcx>,
-                                                         lvalue_pref: LvaluePreference) {
-    debug!(">> typechecking: expr={:?} expected={:?}",
-           expr, expected);
-
     // Checks a method call.
-    fn check_method_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                   expr: &'tcx hir::Expr,
-                                   method_name: Spanned<ast::Name>,
-                                   args: &'tcx [P<hir::Expr>],
-                                   tps: &[P<hir::Ty>],
-                                   expected: Expectation<'tcx>,
-                                   lvalue_pref: LvaluePreference) {
+    fn check_method_call(&self,
+                         expr: &'tcx hir::Expr,
+                         method_name: Spanned<ast::Name>,
+                         args: &'tcx [P<hir::Expr>],
+                         tps: &[P<hir::Ty>],
+                         expected: Expectation<'tcx>,
+                         lvalue_pref: LvaluePreference) {
         let rcvr = &args[0];
-        check_expr_with_lvalue_pref(fcx, &rcvr, lvalue_pref);
+        self.check_expr_with_lvalue_pref(&rcvr, lvalue_pref);
 
         // no need to check for bot/err -- callee does that
-        let expr_t = structurally_resolved_type(fcx,
-                                                expr.span,
-                                                fcx.expr_ty(&rcvr));
-
-        let tps = tps.iter().map(|ast_ty| fcx.to_ty(&ast_ty)).collect::<Vec<_>>();
-        let fn_ty = match method::lookup(fcx,
-                                         method_name.span,
-                                         method_name.node,
-                                         expr_t,
-                                         tps,
-                                         expr,
-                                         rcvr) {
+        let expr_t = self.structurally_resolved_type(expr.span, self.expr_ty(&rcvr));
+
+        let tps = tps.iter().map(|ast_ty| self.to_ty(&ast_ty)).collect::<Vec<_>>();
+        let fn_ty = match self.lookup_method(method_name.span,
+                                             method_name.node,
+                                             expr_t,
+                                             tps,
+                                             expr,
+                                             rcvr) {
             Ok(method) => {
                 let method_ty = method.ty;
                 let method_call = MethodCall::expr(expr.id);
-                fcx.inh.tables.borrow_mut().method_map.insert(method_call, method);
+                self.inh.tables.borrow_mut().method_map.insert(method_call, method);
                 method_ty
             }
             Err(error) => {
                 if method_name.node != keywords::Invalid.name() {
-                    method::report_error(fcx, method_name.span, expr_t,
-                                         method_name.node, Some(rcvr), error);
+                    self.report_method_error(method_name.span, expr_t,
+                                             method_name.node, Some(rcvr), error);
                 }
-                fcx.write_error(expr.id);
-                fcx.tcx().types.err
+                self.write_error(expr.id);
+                self.tcx().types.err
             }
         };
 
         // Call the generic checker.
-        let ret_ty = check_method_argument_types(fcx,
-                                                 method_name.span,
-                                                 fn_ty,
-                                                 expr,
-                                                 &args[1..],
-                                                 DontTupleArguments,
-                                                 expected);
+        let ret_ty = self.check_method_argument_types(method_name.span, fn_ty,
+                                                      expr, &args[1..],
+                                                      DontTupleArguments,
+                                                      expected);
 
-        write_call(fcx, expr, ret_ty);
+        self.write_call(expr, ret_ty);
     }
 
     // A generic function for checking the then and else in an if
     // or if-else.
-    fn check_then_else<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                 cond_expr: &'tcx hir::Expr,
-                                 then_blk: &'tcx hir::Block,
-                                 opt_else_expr: Option<&'tcx hir::Expr>,
-                                 id: ast::NodeId,
-                                 sp: Span,
-                                 expected: Expectation<'tcx>) {
-        check_expr_has_type(fcx, cond_expr, fcx.tcx().types.bool);
-
-        let expected = expected.adjust_for_branches(fcx);
-        check_block_with_expected(fcx, then_blk, expected);
-        let then_ty = fcx.node_ty(then_blk.id);
-
-        let unit = fcx.tcx().mk_nil();
+    fn check_then_else(&self,
+                       cond_expr: &'tcx hir::Expr,
+                       then_blk: &'tcx hir::Block,
+                       opt_else_expr: Option<&'tcx hir::Expr>,
+                       id: ast::NodeId,
+                       sp: Span,
+                       expected: Expectation<'tcx>) {
+        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 (origin, expected, found, result) =
         if let Some(else_expr) = opt_else_expr {
-            check_expr_with_expectation(fcx, else_expr, expected);
-            let else_ty = fcx.expr_ty(else_expr);
+            self.check_expr_with_expectation(else_expr, expected);
+            let else_ty = self.expr_ty(else_expr);
             let origin = TypeOrigin::IfExpression(sp);
 
             // Only try to coerce-unify if we have a then expression
             // to assign coercions to, otherwise it's () or diverging.
             let result = if let Some(ref then) = then_blk.expr {
-                let res = coercion::try_find_lub(fcx, origin, || Some(&**then),
-                                                 then_ty, else_expr);
+                let res = self.try_find_coercion_lub(origin, || Some(&**then),
+                                                     then_ty, else_expr);
 
                 // In case we did perform an adjustment, we have to update
                 // the type of the block, because old trans still uses it.
-                let adj = fcx.inh.tables.borrow().adjustments.get(&then.id).cloned();
+                let adj = self.inh.tables.borrow().adjustments.get(&then.id).cloned();
                 if res.is_ok() && adj.is_some() {
-                    fcx.write_ty(then_blk.id, fcx.adjust_expr_ty(then, adj.as_ref()));
+                    self.write_ty(then_blk.id, self.adjust_expr_ty(then, adj.as_ref()));
                 }
 
                 res
             } else {
-                fcx.infcx().commit_if_ok(|_| {
+                self.infcx().commit_if_ok(|_| {
                     let trace = TypeTrace::types(origin, true, then_ty, else_ty);
-                    fcx.infcx().lub(true, trace, &then_ty, &else_ty)
+                    self.infcx().lub(true, trace, &then_ty, &else_ty)
                         .map(|InferOk { value, obligations }| {
                             // FIXME(#32730) propagate obligations
                             assert!(obligations.is_empty());
@@ -2882,7 +3034,7 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         } else {
             let origin = TypeOrigin::IfExpressionWithNoElse(sp);
             (origin, unit, then_ty,
-             fcx.infcx().eq_types(true, origin, unit, then_ty)
+             self.infcx().eq_types(true, origin, unit, then_ty)
                  .map(|InferOk { obligations, .. }| {
                      // FIXME(#32730) propagate obligations
                      assert!(obligations.is_empty());
@@ -2892,42 +3044,42 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 
         let if_ty = match result {
             Ok(ty) => {
-                if fcx.expr_ty(cond_expr).references_error() {
-                    fcx.tcx().types.err
+                if self.expr_ty(cond_expr).references_error() {
+                    self.tcx().types.err
                 } else {
                     ty
                 }
             }
             Err(e) => {
-                fcx.infcx().report_mismatched_types(origin, expected, found, e);
-                fcx.tcx().types.err
+                self.infcx().report_mismatched_types(origin, expected, found, e);
+                self.tcx().types.err
             }
         };
 
-        fcx.write_ty(id, if_ty);
+        self.write_ty(id, if_ty);
     }
 
     // Check field access expressions
-    fn check_field<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
-                            expr: &'tcx hir::Expr,
-                            lvalue_pref: LvaluePreference,
-                            base: &'tcx hir::Expr,
-                            field: &Spanned<ast::Name>) {
-        check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
-        let expr_t = structurally_resolved_type(fcx, expr.span, fcx.expr_ty(base));
+    fn check_field(&self,
+                   expr: &'tcx hir::Expr,
+                   lvalue_pref: LvaluePreference,
+                   base: &'tcx hir::Expr,
+                   field: &Spanned<ast::Name>) {
+        self.check_expr_with_lvalue_pref(base, lvalue_pref);
+        let expr_t = self.structurally_resolved_type(expr.span,
+                                                     self.expr_ty(base));
         let mut private_candidate = None;
-        let (_, autoderefs, field_ty) = autoderef(fcx,
-                                                  expr.span,
-                                                  expr_t,
-                                                  || Some(base),
-                                                  UnresolvedTypeAction::Error,
-                                                  lvalue_pref,
-                                                  |base_t, _| {
+        let (_, autoderefs, field_ty) = self.autoderef(expr.span,
+                                                       expr_t,
+                                                       || Some(base),
+                                                       UnresolvedTypeAction::Error,
+                                                       lvalue_pref,
+                                                       |base_t, _| {
                 if let ty::TyStruct(base_def, substs) = base_t.sty {
                     debug!("struct named {:?}",  base_t);
                     if let Some(field) = base_def.struct_variant().find_field_named(field.node) {
-                        let field_ty = fcx.field_ty(expr.span, field, substs);
-                        if field.vis.is_accessible_from(fcx.body_id, &fcx.tcx().map) {
+                        let field_ty = self.field_ty(expr.span, field, substs);
+                        if field.vis.is_accessible_from(self.body_id, &self.tcx().map) {
                             return Some(field_ty);
                         }
                         private_candidate = Some((base_def.did, field_ty));
@@ -2937,68 +3089,59 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             });
         match field_ty {
             Some(field_ty) => {
-                fcx.write_ty(expr.id, field_ty);
-                fcx.write_autoderef_adjustment(base.id, autoderefs);
+                self.write_ty(expr.id, field_ty);
+                self.write_autoderef_adjustment(base.id, autoderefs);
                 return;
             }
             None => {}
         }
 
         if let Some((did, field_ty)) = private_candidate {
-            let struct_path = fcx.tcx().item_path_str(did);
+            let struct_path = self.tcx().item_path_str(did);
             let msg = format!("field `{}` of struct `{}` is private", field.node, struct_path);
-            fcx.tcx().sess.span_err(expr.span, &msg);
-            fcx.write_ty(expr.id, field_ty);
+            self.tcx().sess.span_err(expr.span, &msg);
+            self.write_ty(expr.id, field_ty);
         } else if field.node == keywords::Invalid.name() {
-            fcx.write_error(expr.id);
-        } else if method::exists(fcx, field.span, field.node, expr_t, expr.id) {
-            fcx.type_error_struct(field.span,
-                                  |actual| {
-                                       format!("attempted to take value of method `{}` on type \
-                                               `{}`", field.node, actual)
-                                   },
-                                   expr_t, None)
+            self.write_error(expr.id);
+        } else if self.method_exists(field.span, field.node, expr_t, expr.id) {
+            self.type_error_struct(field.span, |actual| {
+                format!("attempted to take value of method `{}` on type \
+                         `{}`", field.node, actual)
+            }, expr_t, None)
                 .help(
                        "maybe a `()` to call it is missing? \
                        If not, try an anonymous function")
                 .emit();
-            fcx.write_error(expr.id);
+            self.write_error(expr.id);
         } else {
-            let mut err = fcx.type_error_struct(
-                expr.span,
-                |actual| {
-                    format!("attempted access of field `{}` on \
-                            type `{}`, but no field with that \
-                            name was found",
-                            field.node,
-                            actual)
-                },
-                expr_t, None);
+            let mut err = self.type_error_struct(expr.span, |actual| {
+                format!("attempted access of field `{}` on type `{}`, \
+                         but no field with that name was found",
+                        field.node, actual)
+            }, expr_t, None);
             if let ty::TyStruct(def, _) = expr_t.sty {
-                suggest_field_names(&mut err, def.struct_variant(), field, vec![]);
+                Self::suggest_field_names(&mut err, def.struct_variant(), field, vec![]);
             }
             err.emit();
-            fcx.write_error(expr.id);
+            self.write_error(expr.id);
         }
     }
 
     // displays hints about the closest matches in field names
-    fn suggest_field_names<'tcx>(err: &mut DiagnosticBuilder,
-                                 variant: ty::VariantDef<'tcx>,
-                                 field: &Spanned<ast::Name>,
-                                 skip : Vec<InternedString>) {
+    fn suggest_field_names(err: &mut DiagnosticBuilder,
+                           variant: ty::VariantDef<'tcx>,
+                           field: &Spanned<ast::Name>,
+                           skip : Vec<InternedString>) {
         let name = field.node.as_str();
-        let names = variant.fields
-                    .iter()
-                    .filter_map(|ref field| {
-                        // ignore already set fields and private fields from non-local crates
-                        if skip.iter().any(|x| *x == field.name.as_str()) ||
-                           (variant.did.krate != LOCAL_CRATE && field.vis != Visibility::Public) {
-                               None
-                        } else {
-                            Some(&field.name)
-                        }
-                    });
+        let names = variant.fields.iter().filter_map(|field| {
+            // ignore already set fields and private fields from non-local crates
+            if skip.iter().any(|x| *x == field.name.as_str()) ||
+               (variant.did.krate != LOCAL_CRATE && field.vis != Visibility::Public) {
+                None
+            } else {
+                Some(&field.name)
+            }
+        });
 
         // only find fits with at least one matching letter
         if let Some(name) = find_best_match_for_name(names, &name, Some(name.len())) {
@@ -3008,22 +3151,22 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     }
 
     // Check tuple index expressions
-    fn check_tup_field<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
-                                expr: &'tcx hir::Expr,
-                                lvalue_pref: LvaluePreference,
-                                base: &'tcx hir::Expr,
-                                idx: codemap::Spanned<usize>) {
-        check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
-        let expr_t = structurally_resolved_type(fcx, expr.span, fcx.expr_ty(base));
+    fn check_tup_field(&self,
+                       expr: &'tcx hir::Expr,
+                       lvalue_pref: LvaluePreference,
+                       base: &'tcx hir::Expr,
+                       idx: codemap::Spanned<usize>) {
+        self.check_expr_with_lvalue_pref(base, lvalue_pref);
+        let expr_t = self.structurally_resolved_type(expr.span,
+                                                     self.expr_ty(base));
         let mut private_candidate = None;
         let mut tuple_like = false;
-        let (_, autoderefs, field_ty) = autoderef(fcx,
-                                                  expr.span,
-                                                  expr_t,
-                                                  || Some(base),
-                                                  UnresolvedTypeAction::Error,
-                                                  lvalue_pref,
-                                                  |base_t, _| {
+        let (_, autoderefs, field_ty) = self.autoderef(expr.span,
+                                                       expr_t,
+                                                       || Some(base),
+                                                       UnresolvedTypeAction::Error,
+                                                       lvalue_pref,
+                                                       |base_t, _| {
                 let (base_def, substs) = match base_t.sty {
                     ty::TyStruct(base_def, substs) => (base_def, substs),
                     ty::TyTuple(ref v) => {
@@ -3038,8 +3181,8 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 
                 debug!("tuple struct named {:?}",  base_t);
                 if let Some(field) = base_def.struct_variant().fields.get(idx.node) {
-                    let field_ty = fcx.field_ty(expr.span, field, substs);
-                    if field.vis.is_accessible_from(fcx.body_id, &fcx.tcx().map) {
+                    let field_ty = self.field_ty(expr.span, field, substs);
+                    if field.vis.is_accessible_from(self.body_id, &self.tcx().map) {
                         return Some(field_ty);
                     }
                     private_candidate = Some((base_def.did, field_ty));
@@ -3048,22 +3191,22 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             });
         match field_ty {
             Some(field_ty) => {
-                fcx.write_ty(expr.id, field_ty);
-                fcx.write_autoderef_adjustment(base.id, autoderefs);
+                self.write_ty(expr.id, field_ty);
+                self.write_autoderef_adjustment(base.id, autoderefs);
                 return;
             }
             None => {}
         }
 
         if let Some((did, field_ty)) = private_candidate {
-            let struct_path = fcx.tcx().item_path_str(did);
+            let struct_path = self.tcx().item_path_str(did);
             let msg = format!("field `{}` of struct `{}` is private", idx.node, struct_path);
-            fcx.tcx().sess.span_err(expr.span, &msg);
-            fcx.write_ty(expr.id, field_ty);
+            self.tcx().sess.span_err(expr.span, &msg);
+            self.write_ty(expr.id, field_ty);
             return;
         }
 
-        fcx.type_error_message(
+        self.type_error_message(
             expr.span,
             |actual| {
                 if tuple_like {
@@ -3080,15 +3223,15 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             },
             expr_t, None);
 
-        fcx.write_error(expr.id);
+        self.write_error(expr.id);
     }
 
-    fn report_unknown_field<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                      ty: Ty<'tcx>,
-                                      variant: ty::VariantDef<'tcx>,
-                                      field: &hir::Field,
-                                      skip_fields: &[hir::Field]) {
-        let mut err = fcx.type_error_struct(
+    fn report_unknown_field(&self,
+                            ty: Ty<'tcx>,
+                            variant: ty::VariantDef<'tcx>,
+                            field: &hir::Field,
+                            skip_fields: &[hir::Field]) {
+        let mut err = self.type_error_struct(
             field.name.span,
             |actual| if let ty::TyEnum(..) = ty.sty {
                 format!("struct variant `{}::{}` has no field named `{}`",
@@ -3101,17 +3244,17 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             None);
         // prevent all specified fields from being suggested
         let skip_fields = skip_fields.iter().map(|ref x| x.name.node.as_str());
-        suggest_field_names(&mut err, variant, &field.name, skip_fields.collect());
+        Self::suggest_field_names(&mut err, variant, &field.name, skip_fields.collect());
         err.emit();
     }
 
-    fn check_expr_struct_fields<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                          adt_ty: Ty<'tcx>,
-                                          span: Span,
-                                          variant: ty::VariantDef<'tcx>,
-                                          ast_fields: &'tcx [hir::Field],
-                                          check_completeness: bool) {
-        let tcx = fcx.ccx.tcx;
+    fn check_expr_struct_fields(&self,
+                                adt_ty: Ty<'tcx>,
+                                span: Span,
+                                variant: ty::VariantDef<'tcx>,
+                                ast_fields: &'tcx [hir::Field],
+                                check_completeness: bool) {
+        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")
@@ -3129,22 +3272,22 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             let expected_field_type;
 
             if let Some(v_field) = remaining_fields.remove(&field.name.node) {
-                expected_field_type = fcx.field_ty(field.span, v_field, substs);
+                expected_field_type = self.field_ty(field.span, v_field, substs);
             } else {
                 error_happened = true;
                 expected_field_type = tcx.types.err;
                 if let Some(_) = variant.find_field_named(field.name.node) {
-                    span_err!(fcx.tcx().sess, field.name.span, E0062,
+                    span_err!(self.tcx().sess, field.name.span, E0062,
                         "field `{}` specified more than once",
                         field.name.node);
                 } else {
-                    report_unknown_field(fcx, adt_ty, variant, field, ast_fields);
+                    self.report_unknown_field(adt_ty, variant, field, ast_fields);
                 }
             }
 
             // Make sure to give a type to the field even if there's
             // an error, so we can continue typechecking
-            check_expr_coercable_to_type(fcx, &field.expr, expected_field_type);
+            self.check_expr_coercable_to_type(&field.expr, expected_field_type);
         }
 
             // Make sure the programmer specified all the fields.
@@ -3164,61 +3307,61 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 
     }
 
-    fn check_struct_fields_on_error<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
-                                             id: ast::NodeId,
-                                             fields: &'tcx [hir::Field],
-                                             base_expr: &'tcx Option<P<hir::Expr>>) {
+    fn check_struct_fields_on_error(&self,
+                                    id: ast::NodeId,
+                                    fields: &'tcx [hir::Field],
+                                    base_expr: &'tcx Option<P<hir::Expr>>) {
         // Make sure to still write the types
         // otherwise we might ICE
-        fcx.write_error(id);
+        self.write_error(id);
         for field in fields {
-            check_expr(fcx, &field.expr);
+            self.check_expr(&field.expr);
         }
         match *base_expr {
-            Some(ref base) => check_expr(fcx, &base),
+            Some(ref base) => self.check_expr(&base),
             None => {}
         }
     }
 
-    fn check_expr_struct<'a, 'tcx>(fcx: &FnCtxt<'a,'tcx>,
-                                   expr: &hir::Expr,
-                                   path: &hir::Path,
-                                   fields: &'tcx [hir::Field],
-                                   base_expr: &'tcx Option<P<hir::Expr>>)
+    fn check_expr_struct(&self,
+                         expr: &hir::Expr,
+                         path: &hir::Path,
+                         fields: &'tcx [hir::Field],
+                         base_expr: &'tcx Option<P<hir::Expr>>)
     {
-        let tcx = fcx.tcx();
+        let tcx = self.tcx();
 
         // Find the relevant variant
         let def = lookup_full_def(tcx, path.span, expr.id);
         if def == Def::Err {
-            fcx.infcx().set_tainted_by_errors();
-            check_struct_fields_on_error(fcx, expr.id, fields, base_expr);
+            self.infcx().set_tainted_by_errors();
+            self.check_struct_fields_on_error(expr.id, fields, base_expr);
             return;
         }
-        let variant = match fcx.def_struct_variant(def, path.span) {
+        let variant = match self.def_struct_variant(def, path.span) {
             Some((_, variant)) => variant,
             None => {
-                span_err!(fcx.tcx().sess, path.span, E0071,
+                span_err!(self.tcx().sess, path.span, E0071,
                           "`{}` does not name a structure",
                           pprust::path_to_string(path));
-                check_struct_fields_on_error(fcx, expr.id, fields, base_expr);
+                self.check_struct_fields_on_error(expr.id, fields, base_expr);
                 return;
             }
         };
 
-        let expr_ty = fcx.instantiate_type(def.def_id(), path);
-        fcx.write_ty(expr.id, expr_ty);
+        let expr_ty = self.instantiate_type(def.def_id(), path);
+        self.write_ty(expr.id, expr_ty);
 
-        check_expr_struct_fields(fcx, expr_ty, expr.span, variant, fields,
-                                 base_expr.is_none());
+        self.check_expr_struct_fields(expr_ty, expr.span, variant, fields,
+                                      base_expr.is_none());
         if let &Some(ref base_expr) = base_expr {
-            check_expr_has_type(fcx, base_expr, expr_ty);
+            self.check_expr_has_type(base_expr, expr_ty);
             match expr_ty.sty {
                 ty::TyStruct(adt, substs) => {
-                    fcx.inh.tables.borrow_mut().fru_field_types.insert(
+                    self.inh.tables.borrow_mut().fru_field_types.insert(
                         expr.id,
                         adt.struct_variant().fields.iter().map(|f| {
-                            fcx.normalize_associated_types_in(
+                            self.normalize_associated_types_in(
                                 expr.span, &f.ty(tcx, substs)
                             )
                         }).collect()
@@ -3232,32 +3375,48 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         }
     }
 
-    type ExprCheckerWithTy = fn(&FnCtxt, &hir::Expr, Ty);
 
-    let tcx = fcx.ccx.tcx;
+/// Invariant:
+/// If an expression has any sub-expressions that result in a type error,
+/// inspecting that expression's type with `ty.references_error()` will return
+/// true. Likewise, if an expression is known to diverge, inspecting its
+/// type with `ty::type_is_bot` will return true (n.b.: since Rust is
+/// strict, _|_ can appear in the type of an expression that does not,
+/// itself, diverge: for example, fn() -> _|_.)
+/// Note that inspecting a type's structure *directly* may expose the fact
+/// that there are actually multiple representations for `TyError`, so avoid
+/// that when err needs to be handled differently.
+fn check_expr_with_expectation_and_lvalue_pref(&self,
+                                               expr: &'tcx hir::Expr,
+                                               expected: Expectation<'tcx>,
+                                               lvalue_pref: LvaluePreference) {
+    debug!(">> typechecking: expr={:?} expected={:?}",
+           expr, expected);
+
+    let tcx = self.tcx();
     let id = expr.id;
     match expr.node {
       hir::ExprBox(ref subexpr) => {
-        let expected_inner = expected.to_option(fcx).map_or(NoExpectation, |ty| {
+        let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| {
             match ty.sty {
-                ty::TyBox(ty) => Expectation::rvalue_hint(fcx, ty),
+                ty::TyBox(ty) => Expectation::rvalue_hint(self, ty),
                 _ => NoExpectation
             }
         });
-        check_expr_with_expectation(fcx, subexpr, expected_inner);
-        let referent_ty = fcx.expr_ty(&subexpr);
-        fcx.write_ty(id, tcx.mk_box(referent_ty));
+        self.check_expr_with_expectation(subexpr, expected_inner);
+        let referent_ty = self.expr_ty(&subexpr);
+        self.write_ty(id, tcx.mk_box(referent_ty));
       }
 
       hir::ExprLit(ref lit) => {
-        let typ = check_lit(fcx, &lit, expected);
-        fcx.write_ty(id, typ);
+        let typ = self.check_lit(&lit, expected);
+        self.write_ty(id, typ);
       }
       hir::ExprBinary(op, ref lhs, ref rhs) => {
-        op::check_binop(fcx, expr, op, lhs, rhs);
+        self.check_binop(expr, op, lhs, rhs);
       }
       hir::ExprAssignOp(op, ref lhs, ref rhs) => {
-        op::check_binop_assign(fcx, expr, op, lhs, rhs);
+        self.check_binop_assign(expr, op, lhs, rhs);
       }
       hir::ExprUnary(unop, ref oprnd) => {
         let expected_inner = match unop {
@@ -3272,24 +3431,25 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             hir::UnDeref => lvalue_pref,
             _ => NoPreference
         };
-        check_expr_with_expectation_and_lvalue_pref(
-            fcx, &oprnd, expected_inner, lvalue_pref);
-        let mut oprnd_t = fcx.expr_ty(&oprnd);
+        self.check_expr_with_expectation_and_lvalue_pref(&oprnd,
+                                                         expected_inner,
+                                                         lvalue_pref);
+        let mut oprnd_t = self.expr_ty(&oprnd);
 
         if !oprnd_t.references_error() {
             match unop {
                 hir::UnDeref => {
-                    oprnd_t = structurally_resolved_type(fcx, expr.span, oprnd_t);
+                    oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t);
 
                     if let Some(mt) = oprnd_t.builtin_deref(true, NoPreference) {
                         oprnd_t = mt.ty;
-                    } else if let Some(method) = try_overloaded_deref(
-                            fcx, expr.span, Some(&oprnd), oprnd_t, lvalue_pref) {
-                        oprnd_t = make_overloaded_lvalue_return_type(fcx, method).ty;
-                        fcx.inh.tables.borrow_mut().method_map.insert(MethodCall::expr(expr.id),
-                                                                      method);
+                    } 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),
+                                                                       method);
                     } else {
-                        fcx.type_error_message(expr.span, |actual| {
+                        self.type_error_message(expr.span, |actual| {
                             format!("type `{}` cannot be \
                                     dereferenced", actual)
                         }, oprnd_t, None);
@@ -3297,50 +3457,47 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                     }
                 }
                 hir::UnNot => {
-                    oprnd_t = structurally_resolved_type(fcx, oprnd.span,
-                                                         oprnd_t);
+                    oprnd_t = self.structurally_resolved_type(oprnd.span,
+                                                              oprnd_t);
                     if !(oprnd_t.is_integral() || oprnd_t.sty == ty::TyBool) {
-                        oprnd_t = op::check_user_unop(fcx, "!", "not",
-                                                      tcx.lang_items.not_trait(),
-                                                      expr, &oprnd, oprnd_t, unop);
+                        oprnd_t = self.check_user_unop("!", "not",
+                                                       tcx.lang_items.not_trait(),
+                                                       expr, &oprnd, oprnd_t, unop);
                     }
                 }
                 hir::UnNeg => {
-                    oprnd_t = structurally_resolved_type(fcx, oprnd.span,
-                                                         oprnd_t);
+                    oprnd_t = self.structurally_resolved_type(oprnd.span,
+                                                              oprnd_t);
                     if !(oprnd_t.is_integral() || oprnd_t.is_fp()) {
-                        oprnd_t = op::check_user_unop(fcx, "-", "neg",
-                                                      tcx.lang_items.neg_trait(),
-                                                      expr, &oprnd, oprnd_t, unop);
+                        oprnd_t = self.check_user_unop("-", "neg",
+                                                       tcx.lang_items.neg_trait(),
+                                                       expr, &oprnd, oprnd_t, unop);
                     }
                 }
             }
         }
-        fcx.write_ty(id, oprnd_t);
+        self.write_ty(id, oprnd_t);
       }
       hir::ExprAddrOf(mutbl, ref oprnd) => {
-        let hint = expected.only_has_type(fcx).map_or(NoExpectation, |ty| {
+        let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| {
             match ty.sty {
                 ty::TyRef(_, ref mt) | ty::TyRawPtr(ref mt) => {
-                    if fcx.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.
                         ExpectHasType(mt.ty)
                     } else {
-                        Expectation::rvalue_hint(fcx, mt.ty)
+                        Expectation::rvalue_hint(self, mt.ty)
                     }
                 }
                 _ => NoExpectation
             }
         });
         let lvalue_pref = LvaluePreference::from_mutbl(mutbl);
-        check_expr_with_expectation_and_lvalue_pref(fcx,
-                                                    &oprnd,
-                                                    hint,
-                                                    lvalue_pref);
+        self.check_expr_with_expectation_and_lvalue_pref(&oprnd, hint, lvalue_pref);
 
-        let tm = ty::TypeAndMut { ty: fcx.expr_ty(&oprnd), mutbl: mutbl };
+        let tm = ty::TypeAndMut { ty: self.expr_ty(&oprnd), mutbl: mutbl };
         let oprnd_t = if tm.ty.references_error() {
             tcx.types.err
         } else {
@@ -3357,14 +3514,14 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             // 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 = fcx.infcx().next_region_var(infer::AddrOfRegion(expr.span));
+            let region = self.infcx().next_region_var(infer::AddrOfRegion(expr.span));
             tcx.mk_ref(tcx.mk_region(region), tm)
         };
-        fcx.write_ty(id, oprnd_t);
+        self.write_ty(id, oprnd_t);
       }
       hir::ExprPath(ref maybe_qself, ref path) => {
           let opt_self_ty = maybe_qself.as_ref().map(|qself| {
-              fcx.to_ty(&qself.ty)
+              self.to_ty(&qself.ty)
           });
 
           let path_res = if let Some(&d) = tcx.def_map.borrow().get(&id) {
@@ -3380,213 +3537,206 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
           };
 
           if let Some((opt_ty, segments, def)) =
-                  resolve_ty_and_def_ufcs(fcx, path_res, opt_self_ty, path,
-                                          expr.span, expr.id) {
+                  self.resolve_ty_and_def_ufcs(path_res, opt_self_ty, path,
+                                               expr.span, expr.id) {
               if def != Def::Err {
-                  let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx,
-                                                                                expr.span,
-                                                                                def);
-                  instantiate_path(fcx,
-                                   segments,
-                                   scheme,
-                                   &predicates,
-                                   opt_ty,
-                                   def,
-                                   expr.span,
-                                   id);
+                  let (scheme, predicates) = self.type_scheme_and_predicates_for_def(expr.span,
+                                                                                     def);
+                  self.instantiate_path(segments, scheme, &predicates,
+                                        opt_ty, def, expr.span, id);
               } else {
-                  fcx.infcx().set_tainted_by_errors();
-                  fcx.write_ty(id, fcx.tcx().types.err);
+                  self.infcx().set_tainted_by_errors();
+                  self.write_ty(id, self.tcx().types.err);
               }
           }
 
           // We always require that the type provided as the value for
           // a type parameter outlives the moment of instantiation.
-          fcx.opt_node_ty_substs(expr.id, |item_substs| {
-              fcx.add_wf_bounds(&item_substs.substs, expr);
+          self.opt_node_ty_substs(expr.id, |item_substs| {
+              self.add_wf_bounds(&item_substs.substs, expr);
           });
       }
       hir::ExprInlineAsm(_, ref outputs, ref inputs) => {
           for output in outputs {
-              check_expr(fcx, output);
+              self.check_expr(output);
           }
           for input in inputs {
-              check_expr(fcx, input);
+              self.check_expr(input);
           }
-          fcx.write_nil(id);
+          self.write_nil(id);
       }
-      hir::ExprBreak(_) => { fcx.write_ty(id, fcx.infcx().next_diverging_ty_var()); }
-      hir::ExprAgain(_) => { fcx.write_ty(id, fcx.infcx().next_diverging_ty_var()); }
+      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::ExprRet(ref expr_opt) => {
-        match fcx.ret_ty {
+        match self.ret_ty {
             ty::FnConverging(result_type) => {
                 match *expr_opt {
                     None =>
-                        if let Err(_) = fcx.mk_eqty(false, TypeOrigin::Misc(expr.span),
-                                                    result_type, fcx.tcx().mk_nil()) {
+                        if let Err(_) = self.mk_eqty(false, TypeOrigin::Misc(expr.span),
+                                                     result_type, self.tcx().mk_nil()) {
                             span_err!(tcx.sess, expr.span, E0069,
                                 "`return;` in a function whose return type is \
                                  not `()`");
                         },
                     Some(ref e) => {
-                        check_expr_coercable_to_type(fcx, &e, result_type);
+                        self.check_expr_coercable_to_type(&e, result_type);
                     }
                 }
             }
             ty::FnDiverging => {
                 if let Some(ref e) = *expr_opt {
-                    check_expr(fcx, &e);
+                    self.check_expr(&e);
                 }
                 span_err!(tcx.sess, expr.span, E0166,
                     "`return` in a function declared as diverging");
             }
         }
-        fcx.write_ty(id, fcx.infcx().next_diverging_ty_var());
+        self.write_ty(id, self.infcx().next_diverging_ty_var());
       }
       hir::ExprAssign(ref lhs, ref rhs) => {
-        check_expr_with_lvalue_pref(fcx, &lhs, PreferMutLvalue);
+        self.check_expr_with_lvalue_pref(&lhs, PreferMutLvalue);
 
-        let tcx = fcx.tcx();
+        let tcx = self.tcx();
         if !tcx.expr_is_lval(&lhs) {
             span_err!(tcx.sess, expr.span, E0070,
                 "invalid left-hand side expression");
         }
 
-        let lhs_ty = fcx.expr_ty(&lhs);
-        check_expr_coercable_to_type(fcx, &rhs, lhs_ty);
-        let rhs_ty = fcx.expr_ty(&rhs);
+        let lhs_ty = self.expr_ty(&lhs);
+        self.check_expr_coercable_to_type(&rhs, lhs_ty);
+        let rhs_ty = self.expr_ty(&rhs);
 
-        fcx.require_expr_have_sized_type(&lhs, traits::AssignmentLhsSized);
+        self.require_expr_have_sized_type(&lhs, traits::AssignmentLhsSized);
 
         if lhs_ty.references_error() || rhs_ty.references_error() {
-            fcx.write_error(id);
+            self.write_error(id);
         } else {
-            fcx.write_nil(id);
+            self.write_nil(id);
         }
       }
       hir::ExprIf(ref cond, ref then_blk, ref opt_else_expr) => {
-        check_then_else(fcx, &cond, &then_blk, opt_else_expr.as_ref().map(|e| &**e),
-                        id, expr.span, expected);
+        self.check_then_else(&cond, &then_blk, opt_else_expr.as_ref().map(|e| &**e),
+                             id, expr.span, expected);
       }
       hir::ExprWhile(ref cond, ref body, _) => {
-        check_expr_has_type(fcx, &cond, tcx.types.bool);
-        check_block_no_value(fcx, &body);
-        let cond_ty = fcx.expr_ty(&cond);
-        let body_ty = fcx.node_ty(body.id);
+        self.check_expr_has_type(&cond, tcx.types.bool);
+        self.check_block_no_value(&body);
+        let cond_ty = self.expr_ty(&cond);
+        let body_ty = self.node_ty(body.id);
         if cond_ty.references_error() || body_ty.references_error() {
-            fcx.write_error(id);
+            self.write_error(id);
         }
         else {
-            fcx.write_nil(id);
+            self.write_nil(id);
         }
       }
       hir::ExprLoop(ref body, _) => {
-        check_block_no_value(fcx, &body);
+        self.check_block_no_value(&body);
         if !may_break(tcx, expr.id, &body) {
-            fcx.write_ty(id, fcx.infcx().next_diverging_ty_var());
+            self.write_ty(id, self.infcx().next_diverging_ty_var());
         } else {
-            fcx.write_nil(id);
+            self.write_nil(id);
         }
       }
       hir::ExprMatch(ref discrim, ref arms, match_src) => {
-        _match::check_match(fcx, expr, &discrim, arms, expected, match_src);
+        self.check_match(expr, &discrim, arms, expected, match_src);
       }
       hir::ExprClosure(capture, ref decl, ref body, _) => {
-          closure::check_expr_closure(fcx, expr, capture, &decl, &body, expected);
+          self.check_expr_closure(expr, capture, &decl, &body, expected);
       }
       hir::ExprBlock(ref b) => {
-        check_block_with_expected(fcx, &b, expected);
-        fcx.write_ty(id, fcx.node_ty(b.id));
+        self.check_block_with_expected(&b, expected);
+        self.write_ty(id, self.node_ty(b.id));
       }
       hir::ExprCall(ref callee, ref args) => {
-          callee::check_call(fcx, expr, &callee, &args[..], expected);
+          self.check_call(expr, &callee, &args[..], expected);
 
           // we must check that return type of called functions is WF:
-          let ret_ty = fcx.expr_ty(expr);
-          fcx.register_wf_obligation(ret_ty, expr.span, traits::MiscObligation);
+          let ret_ty = self.expr_ty(expr);
+          self.register_wf_obligation(ret_ty, expr.span, traits::MiscObligation);
       }
       hir::ExprMethodCall(name, ref tps, ref args) => {
-          check_method_call(fcx, expr, name, &args[..], &tps[..], expected, lvalue_pref);
-          let arg_tys = args.iter().map(|a| fcx.expr_ty(&a));
+          self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref);
+          let arg_tys = args.iter().map(|a| self.expr_ty(&a));
           let args_err = arg_tys.fold(false, |rest_err, a| rest_err || a.references_error());
           if args_err {
-              fcx.write_error(id);
+              self.write_error(id);
           }
       }
       hir::ExprCast(ref e, ref t) => {
         if let hir::TyFixedLengthVec(_, ref count_expr) = t.node {
-            check_expr_with_hint(fcx, &count_expr, tcx.types.usize);
+            self.check_expr_with_hint(&count_expr, tcx.types.usize);
         }
 
         // Find the type of `e`. Supply hints based on the type we are casting to,
         // if appropriate.
-        let t_cast = fcx.to_ty(t);
-        let t_cast = fcx.infcx().resolve_type_vars_if_possible(&t_cast);
-        check_expr_with_expectation(fcx, e, ExpectCastableToType(t_cast));
-        let t_expr = fcx.expr_ty(e);
-        let t_cast = fcx.infcx().resolve_type_vars_if_possible(&t_cast);
+        let t_cast = self.to_ty(t);
+        let t_cast = self.infcx().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);
 
         // Eagerly check for some obvious errors.
         if t_expr.references_error() || t_cast.references_error() {
-            fcx.write_error(id);
+            self.write_error(id);
         } else {
             // Write a type for the whole expression, assuming everything is going
             // to work out Ok.
-            fcx.write_ty(id, t_cast);
+            self.write_ty(id, t_cast);
 
             // Defer other checks until we're done type checking.
-            let mut deferred_cast_checks = fcx.inh.deferred_cast_checks.borrow_mut();
-            match cast::CastCheck::new(fcx, e, t_expr, t_cast, t.span, expr.span) {
+            let mut deferred_cast_checks = self.inh.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);
                 }
                 Err(ErrorReported) => {
-                    fcx.write_error(id);
+                    self.write_error(id);
                 }
             }
         }
       }
       hir::ExprType(ref e, ref t) => {
-        let typ = fcx.to_ty(&t);
-        check_expr_eq_type(fcx, &e, typ);
-        fcx.write_ty(id, typ);
+        let typ = self.to_ty(&t);
+        self.check_expr_eq_type(&e, typ);
+        self.write_ty(id, typ);
       }
       hir::ExprVec(ref args) => {
-        let uty = expected.to_option(fcx).and_then(|uty| {
+        let uty = expected.to_option(self).and_then(|uty| {
             match uty.sty {
                 ty::TyArray(ty, _) | ty::TySlice(ty) => Some(ty),
                 _ => None
             }
         });
 
-        let mut unified = fcx.infcx().next_ty_var();
+        let mut unified = self.infcx().next_ty_var();
         let coerce_to = uty.unwrap_or(unified);
 
         for (i, e) in args.iter().enumerate() {
-            check_expr_with_hint(fcx, e, coerce_to);
-            let e_ty = fcx.expr_ty(e);
+            self.check_expr_with_hint(e, coerce_to);
+            let e_ty = self.expr_ty(e);
             let origin = TypeOrigin::Misc(e.span);
 
             // Special-case the first element, as it has no "previous expressions".
             let result = if i == 0 {
-                coercion::try(fcx, e, coerce_to)
+                self.try_coerce(e, coerce_to)
             } else {
                 let prev_elems = || args[..i].iter().map(|e| &**e);
-                coercion::try_find_lub(fcx, origin, prev_elems, unified, e)
+                self.try_find_coercion_lub(origin, prev_elems, unified, e)
             };
 
             match result {
                 Ok(ty) => unified = ty,
                 Err(e) => {
-                    fcx.infcx().report_mismatched_types(origin, unified, e_ty, e);
+                    self.infcx().report_mismatched_types(origin, unified, e_ty, e);
                 }
             }
         }
-        fcx.write_ty(id, tcx.mk_array(unified, args.len()));
+        self.write_ty(id, tcx.mk_array(unified, args.len()));
       }
       hir::ExprRepeat(ref element, ref count_expr) => {
-        check_expr_has_type(fcx, &count_expr, tcx.types.usize);
-        let count = eval_repeat_count(fcx.tcx(), &count_expr);
+        self.check_expr_has_type(&count_expr, tcx.types.usize);
+        let count = eval_repeat_count(self.tcx(), &count_expr);
 
         let uty = match expected {
             ExpectHasType(uty) => {
@@ -3600,35 +3750,31 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 
         let (element_ty, t) = match uty {
             Some(uty) => {
-                check_expr_coercable_to_type(fcx, &element, uty);
+                self.check_expr_coercable_to_type(&element, uty);
                 (uty, uty)
             }
             None => {
-                let t: Ty = fcx.infcx().next_ty_var();
-                check_expr_has_type(fcx, &element, t);
-                (fcx.expr_ty(&element), t)
+                let t: Ty = self.infcx().next_ty_var();
+                self.check_expr_has_type(&element, t);
+                (self.expr_ty(&element), t)
             }
         };
 
         if count > 1 {
             // For [foo, ..n] where n > 1, `foo` must have
             // Copy type:
-            fcx.require_type_meets(
-                t,
-                expr.span,
-                traits::RepeatVec,
-                ty::BoundCopy);
+            self.require_type_meets(t, expr.span, traits::RepeatVec, ty::BoundCopy);
         }
 
         if element_ty.references_error() {
-            fcx.write_error(id);
+            self.write_error(id);
         } else {
             let t = tcx.mk_array(t, count);
-            fcx.write_ty(id, t);
+            self.write_ty(id, t);
         }
       }
       hir::ExprTup(ref elts) => {
-        let flds = expected.only_has_type(fcx).and_then(|ty| {
+        let flds = expected.only_has_type(self).and_then(|ty| {
             match ty.sty {
                 ty::TyTuple(ref flds) => Some(&flds[..]),
                 _ => None
@@ -3640,57 +3786,57 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             let t = match flds {
                 Some(ref fs) if i < fs.len() => {
                     let ety = fs[i];
-                    check_expr_coercable_to_type(fcx, &e, ety);
+                    self.check_expr_coercable_to_type(&e, ety);
                     ety
                 }
                 _ => {
-                    check_expr_with_expectation(fcx, &e, NoExpectation);
-                    fcx.expr_ty(&e)
+                    self.check_expr_with_expectation(&e, NoExpectation);
+                    self.expr_ty(&e)
                 }
             };
             err_field = err_field || t.references_error();
             t
         }).collect();
         if err_field {
-            fcx.write_error(id);
+            self.write_error(id);
         } else {
             let typ = tcx.mk_tup(elt_ts);
-            fcx.write_ty(id, typ);
+            self.write_ty(id, typ);
         }
       }
       hir::ExprStruct(ref path, ref fields, ref base_expr) => {
-        check_expr_struct(fcx, expr, path, fields, base_expr);
+        self.check_expr_struct(expr, path, fields, base_expr);
 
-        fcx.require_expr_have_sized_type(expr, traits::StructInitializerSized);
+        self.require_expr_have_sized_type(expr, traits::StructInitializerSized);
       }
       hir::ExprField(ref base, ref field) => {
-        check_field(fcx, expr, lvalue_pref, &base, field);
+        self.check_field(expr, lvalue_pref, &base, field);
       }
       hir::ExprTupField(ref base, idx) => {
-        check_tup_field(fcx, expr, lvalue_pref, &base, idx);
+        self.check_tup_field(expr, lvalue_pref, &base, idx);
       }
       hir::ExprIndex(ref base, ref idx) => {
-          check_expr_with_lvalue_pref(fcx, &base, lvalue_pref);
-          check_expr(fcx, &idx);
+          self.check_expr_with_lvalue_pref(&base, lvalue_pref);
+          self.check_expr(&idx);
 
-          let base_t = fcx.expr_ty(&base);
-          let idx_t = fcx.expr_ty(&idx);
+          let base_t = self.expr_ty(&base);
+          let idx_t = self.expr_ty(&idx);
 
           if base_t.references_error() {
-              fcx.write_ty(id, base_t);
+              self.write_ty(id, base_t);
           } else if idx_t.references_error() {
-              fcx.write_ty(id, idx_t);
+              self.write_ty(id, idx_t);
           } else {
-              let base_t = structurally_resolved_type(fcx, expr.span, base_t);
-              match lookup_indexing(fcx, expr, base, base_t, idx_t, lvalue_pref) {
+              let base_t = self.structurally_resolved_type(expr.span, base_t);
+              match self.lookup_indexing(expr, base, base_t, idx_t, lvalue_pref) {
                   Some((index_ty, element_ty)) => {
-                      let idx_expr_ty = fcx.expr_ty(idx);
-                      demand::eqtype(fcx, expr.span, index_ty, idx_expr_ty);
-                      fcx.write_ty(id, element_ty);
+                      let idx_expr_ty = self.expr_ty(idx);
+                      self.demand_eqtype(expr.span, index_ty, idx_expr_ty);
+                      self.write_ty(id, element_ty);
                   }
                   None => {
-                      check_expr_has_type(fcx, &idx, fcx.tcx().types.err);
-                      let mut err = fcx.type_error_struct(
+                      self.check_expr_has_type(&idx, self.tcx().types.err);
+                      let mut err = self.type_error_struct(
                           expr.span,
                           |actual| {
                               format!("cannot index a value of type `{}`",
@@ -3705,7 +3851,7 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                           // fixed expression:
                           if let hir::ExprLit(ref lit) = idx.node {
                               if let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node {
-                                  let snip = fcx.tcx().sess.codemap().span_to_snippet(base.span);
+                                  let snip = tcx.sess.codemap().span_to_snippet(base.span);
                                   if let Ok(snip) = snip {
                                       err.span_suggestion(expr.span,
                                                           "to access tuple elements, use tuple \
@@ -3721,7 +3867,7 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                           }
                       }
                       err.emit();
-                      fcx.write_ty(id, fcx.tcx().types.err);
+                      self.write_ty(id, self.tcx().types.err);
                   }
               }
           }
@@ -3731,19 +3877,17 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     debug!("type of expr({}) {} is...", expr.id,
            pprust::expr_to_string(expr));
     debug!("... {:?}, expected is {:?}",
-           fcx.expr_ty(expr),
+           self.expr_ty(expr),
            expected);
 }
 
-pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>,
-                                             path_res: def::PathResolution,
-                                             opt_self_ty: Option<Ty<'tcx>>,
-                                             path: &'a hir::Path,
-                                             span: Span,
-                                             node_id: ast::NodeId)
-                                             -> Option<(Option<Ty<'tcx>>,
-                                                        &'a [hir::PathSegment],
-                                                        Def)>
+pub fn resolve_ty_and_def_ufcs<'b>(&self,
+                                   path_res: def::PathResolution,
+                                   opt_self_ty: Option<Ty<'tcx>>,
+                                   path: &'b hir::Path,
+                                   span: Span,
+                                   node_id: ast::NodeId)
+                                   -> Option<(Option<Ty<'tcx>>, &'b [hir::PathSegment], Def)>
 {
 
     // If fully resolved already, we don't have to do anything.
@@ -3753,7 +3897,7 @@ pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>,
         let mut def = path_res.base_def;
         let ty_segments = path.segments.split_last().unwrap().1;
         let base_ty_end = path.segments.len() - path_res.depth;
-        let ty = astconv::finish_resolving_def_to_ty(fcx, fcx, span,
+        let ty = astconv::finish_resolving_def_to_ty(self, self, span,
                                                      PathParamMode::Optional,
                                                      &mut def,
                                                      opt_self_ty,
@@ -3761,7 +3905,7 @@ pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>,
                                                      &ty_segments[base_ty_end..]);
         let item_segment = path.segments.last().unwrap();
         let item_name = item_segment.identifier.name;
-        let def = match method::resolve_ufcs(fcx, span, item_name, ty, node_id) {
+        let def = match self.resolve_ufcs(span, item_name, ty, node_id) {
             Ok(def) => Some(def),
             Err(error) => {
                 let def = match error {
@@ -3769,7 +3913,7 @@ pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>,
                     _ => None,
                 };
                 if item_name != keywords::Invalid.name() {
-                    method::report_error(fcx, span, ty, item_name, None, error);
+                    self.report_method_error(span, ty, item_name, None, error);
                 }
                 def
             }
@@ -3777,94 +3921,25 @@ pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>,
 
         if let Some(def) = def {
             // Write back the new resolution.
-            fcx.ccx.tcx.def_map.borrow_mut().insert(node_id, def::PathResolution {
+            self.tcx().def_map.borrow_mut().insert(node_id, def::PathResolution {
                 base_def: def,
                 depth: 0,
             });
             Some((Some(ty), slice::ref_slice(item_segment), def))
         } else {
-            fcx.write_error(node_id);
+            self.write_error(node_id);
             None
         }
     }
 }
 
-impl<'tcx> Expectation<'tcx> {
-    /// Provide an expectation for an rvalue expression given an *optional*
-    /// hint, which is not required for type safety (the resulting type might
-    /// be checked higher up, as is the case with `&expr` and `box expr`), but
-    /// is useful in determining the concrete type.
-    ///
-    /// The primary use case is where the expected type is a fat pointer,
-    /// like `&[isize]`. For example, consider the following statement:
-    ///
-    ///    let x: &[isize] = &[1, 2, 3];
-    ///
-    /// In this case, the expected type for the `&[1, 2, 3]` expression is
-    /// `&[isize]`. If however we were to say that `[1, 2, 3]` has the
-    /// expectation `ExpectHasType([isize])`, that would be too strong --
-    /// `[1, 2, 3]` does not have the type `[isize]` but rather `[isize; 3]`.
-    /// It is only the `&[1, 2, 3]` expression as a whole that can be coerced
-    /// to the type `&[isize]`. Therefore, we propagate this more limited hint,
-    /// which still is useful, because it informs integer literals and the like.
-    /// See the test case `test/run-pass/coerce-expect-unsized.rs` and #20169
-    /// for examples of where this comes up,.
-    fn rvalue_hint<'a>(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> {
-        match fcx.tcx().struct_tail(ty).sty {
-            ty::TySlice(_) | ty::TyStr | ty::TyTrait(..) => {
-                ExpectRvalueLikeUnsized(ty)
-            }
-            _ => ExpectHasType(ty)
-        }
-    }
-
-    // Resolves `expected` by a single level if it is a variable. If
-    // there is no expected type or resolution is not possible (e.g.,
-    // no constraints yet present), just returns `None`.
-    fn resolve<'a>(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
-        match self {
-            NoExpectation => {
-                NoExpectation
-            }
-            ExpectCastableToType(t) => {
-                ExpectCastableToType(
-                    fcx.infcx().resolve_type_vars_if_possible(&t))
-            }
-            ExpectHasType(t) => {
-                ExpectHasType(
-                    fcx.infcx().resolve_type_vars_if_possible(&t))
-            }
-            ExpectRvalueLikeUnsized(t) => {
-                ExpectRvalueLikeUnsized(
-                    fcx.infcx().resolve_type_vars_if_possible(&t))
-            }
-        }
-    }
-
-    fn to_option<'a>(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> {
-        match self.resolve(fcx) {
-            NoExpectation => None,
-            ExpectCastableToType(ty) |
-            ExpectHasType(ty) |
-            ExpectRvalueLikeUnsized(ty) => Some(ty),
-        }
-    }
-
-    fn only_has_type<'a>(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> {
-        match self.resolve(fcx) {
-            ExpectHasType(ty) => Some(ty),
-            _ => None
-        }
-    }
-}
-
-pub fn check_decl_initializer<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
-                                       local: &'tcx hir::Local,
-                                       init: &'tcx hir::Expr)
+pub fn check_decl_initializer(&self,
+                              local: &'tcx hir::Local,
+                              init: &'tcx hir::Expr)
 {
-    let ref_bindings = fcx.tcx().pat_contains_ref_binding(&local.pat);
+    let ref_bindings = self.tcx().pat_contains_ref_binding(&local.pat);
 
-    let local_ty = fcx.local_ty(init.span, local.id);
+    let local_ty = self.local_ty(init.span, local.id);
     if let Some(m) = ref_bindings {
         // Somewhat subtle: if we have a `ref` binding in the pattern,
         // we want to avoid introducing coercions for the RHS. This is
@@ -3874,40 +3949,40 @@ pub fn check_decl_initializer<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
         // referent for the reference that results is *equal to* the
         // type of the lvalue it is referencing, and not some
         // supertype thereof.
-        check_expr_with_lvalue_pref(fcx, init, LvaluePreference::from_mutbl(m));
-        let init_ty = fcx.expr_ty(init);
-        demand::eqtype(fcx, init.span, init_ty, local_ty);
+        self.check_expr_with_lvalue_pref(init, LvaluePreference::from_mutbl(m));
+        let init_ty = self.expr_ty(init);
+        self.demand_eqtype(init.span, init_ty, local_ty);
     } else {
-        check_expr_coercable_to_type(fcx, init, local_ty)
+        self.check_expr_coercable_to_type(init, local_ty)
     };
 }
 
-pub fn check_decl_local<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, local: &'tcx hir::Local)  {
-    let tcx = fcx.ccx.tcx;
+pub fn check_decl_local(&self, local: &'tcx hir::Local)  {
+    let tcx = self.tcx();
 
-    let t = fcx.local_ty(local.span, local.id);
-    fcx.write_ty(local.id, t);
+    let t = self.local_ty(local.span, local.id);
+    self.write_ty(local.id, t);
 
     if let Some(ref init) = local.init {
-        check_decl_initializer(fcx, local, &init);
-        let init_ty = fcx.expr_ty(&init);
+        self.check_decl_initializer(local, &init);
+        let init_ty = self.expr_ty(&init);
         if init_ty.references_error() {
-            fcx.write_ty(local.id, init_ty);
+            self.write_ty(local.id, init_ty);
         }
     }
 
-    let pcx = pat_ctxt {
-        fcx: fcx,
+    let pcx = PatCtxt {
+        fcx: self,
         map: pat_id_map(&tcx.def_map, &local.pat),
     };
-    _match::check_pat(&pcx, &local.pat, t);
-    let pat_ty = fcx.node_ty(local.pat.id);
+    pcx.check_pat(&local.pat, t);
+    let pat_ty = self.node_ty(local.pat.id);
     if pat_ty.references_error() {
-        fcx.write_ty(local.id, pat_ty);
+        self.write_ty(local.id, pat_ty);
     }
 }
 
-pub fn check_stmt<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, stmt: &'tcx hir::Stmt)  {
+pub fn check_stmt(&self, stmt: &'tcx hir::Stmt)  {
     let node_id;
     let mut saw_bot = false;
     let mut saw_err = false;
@@ -3916,9 +3991,9 @@ pub fn check_stmt<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, stmt: &'tcx hir::Stmt)  {
         node_id = id;
         match decl.node {
           hir::DeclLocal(ref l) => {
-              check_decl_local(fcx, &l);
-              let l_t = fcx.node_ty(l.id);
-              saw_bot = saw_bot || fcx.infcx().type_var_diverges(l_t);
+              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_err = saw_err || l_t.references_error();
           }
           hir::DeclItem(_) => {/* ignore for now */ }
@@ -3927,46 +4002,46 @@ pub fn check_stmt<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, stmt: &'tcx hir::Stmt)  {
       hir::StmtExpr(ref expr, id) => {
         node_id = id;
         // Check with expected type of ()
-        check_expr_has_type(fcx, &expr, fcx.tcx().mk_nil());
-        let expr_ty = fcx.expr_ty(&expr);
-        saw_bot = saw_bot || fcx.infcx().type_var_diverges(expr_ty);
+        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_err = saw_err || expr_ty.references_error();
       }
       hir::StmtSemi(ref expr, id) => {
         node_id = id;
-        check_expr(fcx, &expr);
-        let expr_ty = fcx.expr_ty(&expr);
-        saw_bot |= fcx.infcx().type_var_diverges(expr_ty);
+        self.check_expr(&expr);
+        let expr_ty = self.expr_ty(&expr);
+        saw_bot |= self.infcx().type_var_diverges(expr_ty);
         saw_err |= expr_ty.references_error();
       }
     }
     if saw_bot {
-        fcx.write_ty(node_id, fcx.infcx().next_diverging_ty_var());
+        self.write_ty(node_id, self.infcx().next_diverging_ty_var());
     }
     else if saw_err {
-        fcx.write_error(node_id);
+        self.write_error(node_id);
     }
     else {
-        fcx.write_nil(node_id)
+        self.write_nil(node_id)
     }
 }
 
-pub fn check_block_no_value<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, blk: &'tcx hir::Block)  {
-    check_block_with_expected(fcx, blk, ExpectHasType(fcx.tcx().mk_nil()));
-    let blkty = fcx.node_ty(blk.id);
+pub fn check_block_no_value(&self, blk: &'tcx hir::Block)  {
+    self.check_block_with_expected(blk, ExpectHasType(self.tcx().mk_nil()));
+    let blkty = self.node_ty(blk.id);
     if blkty.references_error() {
-        fcx.write_error(blk.id);
+        self.write_error(blk.id);
     } else {
-        let nilty = fcx.tcx().mk_nil();
-        demand::suptype(fcx, blk.span, nilty, blkty);
+        let nilty = self.tcx().mk_nil();
+        self.demand_suptype(blk.span, nilty, blkty);
     }
 }
 
-fn check_block_with_expected<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                       blk: &'tcx hir::Block,
-                                       expected: Expectation<'tcx>) {
+fn check_block_with_expected(&self,
+                             blk: &'tcx hir::Block,
+                             expected: Expectation<'tcx>) {
     let prev = {
-        let mut fcx_ps = fcx.ps.borrow_mut();
+        let mut fcx_ps = self.ps.borrow_mut();
         let unsafety_state = fcx_ps.recurse(blk);
         replace(&mut *fcx_ps, unsafety_state)
     };
@@ -3975,9 +4050,9 @@ fn check_block_with_expected<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     let mut any_diverges = false;
     let mut any_err = false;
     for s in &blk.stmts {
-        check_stmt(fcx, s);
+        self.check_stmt(s);
         let s_id = s.node.id();
-        let s_ty = fcx.node_ty(s_id);
+        let s_ty = self.node_ty(s_id);
         if any_diverges && !warned && match s.node {
             hir::StmtDecl(ref decl, _) => {
                 match decl.node {
@@ -3987,8 +4062,7 @@ fn check_block_with_expected<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             }
             hir::StmtExpr(_, _) | hir::StmtSemi(_, _) => true,
         } {
-            fcx.ccx
-                .tcx
+            self.tcx()
                 .sess
                 .add_lint(lint::builtin::UNREACHABLE_CODE,
                           s_id,
@@ -3996,21 +4070,20 @@ fn check_block_with_expected<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                           "unreachable statement".to_string());
             warned = true;
         }
-        any_diverges = any_diverges || fcx.infcx().type_var_diverges(s_ty);
+        any_diverges = any_diverges || self.infcx().type_var_diverges(s_ty);
         any_err = any_err || s_ty.references_error();
     }
     match blk.expr {
         None => if any_err {
-            fcx.write_error(blk.id);
+            self.write_error(blk.id);
         } else if any_diverges {
-            fcx.write_ty(blk.id, fcx.infcx().next_diverging_ty_var());
+            self.write_ty(blk.id, self.infcx().next_diverging_ty_var());
         } else {
-            fcx.write_nil(blk.id);
+            self.write_nil(blk.id);
         },
         Some(ref e) => {
             if any_diverges && !warned {
-                fcx.ccx
-                    .tcx
+                self.tcx()
                     .sess
                     .add_lint(lint::builtin::UNREACHABLE_CODE,
                               e.id,
@@ -4019,202 +4092,66 @@ fn check_block_with_expected<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             }
             let ety = match expected {
                 ExpectHasType(ety) => {
-                    check_expr_coercable_to_type(fcx, &e, ety);
+                    self.check_expr_coercable_to_type(&e, ety);
                     ety
                 }
                 _ => {
-                    check_expr_with_expectation(fcx, &e, expected);
-                    fcx.expr_ty(&e)
+                    self.check_expr_with_expectation(&e, expected);
+                    self.expr_ty(&e)
                 }
             };
 
             if any_err {
-                fcx.write_error(blk.id);
+                self.write_error(blk.id);
             } else if any_diverges {
-                fcx.write_ty(blk.id, fcx.infcx().next_diverging_ty_var());
+                self.write_ty(blk.id, self.infcx().next_diverging_ty_var());
             } else {
-                fcx.write_ty(blk.id, ety);
+                self.write_ty(blk.id, ety);
             }
         }
     };
 
-    *fcx.ps.borrow_mut() = prev;
-}
-
-/// Checks a constant appearing in a type. At the moment this is just the
-/// length expression in a fixed-length vector, but someday it might be
-/// extended to type-level numeric literals.
-fn check_const_in_type<'a,'tcx>(ccx: &'a CrateCtxt<'a,'tcx>,
-                                expr: &'tcx hir::Expr,
-                                expected_type: Ty<'tcx>) {
-    let tables = RefCell::new(ty::Tables::empty());
-    let inh = static_inherited_fields(ccx, &tables);
-    let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(expected_type), expr.id);
-    check_const_with_ty(&fcx, expr.span, expr, expected_type);
+    *self.ps.borrow_mut() = prev;
 }
 
-fn check_const<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
-                        sp: Span,
-                        e: &'tcx hir::Expr,
-                        id: ast::NodeId) {
-    let tables = RefCell::new(ty::Tables::empty());
-    let inh = static_inherited_fields(ccx, &tables);
-    let rty = ccx.tcx.node_id_to_type(id);
-    let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), e.id);
-    let declty = fcx.ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(id)).ty;
-    check_const_with_ty(&fcx, sp, e, declty);
-}
 
-fn check_const_with_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                 _: Span,
-                                 e: &'tcx hir::Expr,
-                                 declty: Ty<'tcx>) {
+fn check_const_with_ty(&self,
+                       _: Span,
+                       e: &'tcx hir::Expr,
+                       declty: Ty<'tcx>) {
     // Gather locals in statics (because of block expressions).
     // This is technically unnecessary because locals in static items are forbidden,
     // but prevents type checking from blowing up before const checking can properly
     // emit an error.
-    GatherLocalsVisitor { fcx: fcx }.visit_expr(e);
+    GatherLocalsVisitor { fcx: self }.visit_expr(e);
 
-    check_expr_with_hint(fcx, e, declty);
-    demand::coerce(fcx, e.span, declty, e);
+    self.check_expr_coercable_to_type(e, declty);
 
-    fcx.select_all_obligations_and_apply_defaults();
-    upvar::closure_analyze_const(&fcx, e);
-    fcx.select_obligations_where_possible();
-    fcx.check_casts();
-    fcx.select_all_obligations_or_error();
+    self.select_all_obligations_and_apply_defaults();
+    self.closure_analyze_const(e);
+    self.select_obligations_where_possible();
+    self.check_casts();
+    self.select_all_obligations_or_error();
 
-    regionck::regionck_expr(fcx, e);
-    writeback::resolve_type_vars_in_expr(fcx, e);
-}
-
-/// Checks whether a type can be represented in memory. In particular, it
-/// identifies types that contain themselves without indirection through a
-/// pointer, which would mean their size is unbounded.
-pub fn check_representable(tcx: &TyCtxt,
-                           sp: Span,
-                           item_id: ast::NodeId,
-                           _designation: &str) -> bool {
-    let rty = tcx.node_id_to_type(item_id);
-
-    // Check that it is possible to represent this type. This call identifies
-    // (1) types that contain themselves and (2) types that contain a different
-    // recursive type. It is only necessary to throw an error on those that
-    // contain themselves. For case 2, there must be an inner type that will be
-    // caught by case 1.
-    match rty.is_representable(tcx, sp) {
-        Representability::SelfRecursive => {
-            let item_def_id = tcx.map.local_def_id(item_id);
-            traits::recursive_type_with_infinite_size_error(tcx, item_def_id).emit();
-            return false
-        }
-        Representability::Representable | Representability::ContainsRecursive => (),
-    }
-    return true
-}
-
-pub fn check_simd(tcx: &TyCtxt, sp: Span, id: ast::NodeId) {
-    let t = tcx.node_id_to_type(id);
-    match t.sty {
-        ty::TyStruct(def, substs) => {
-            let fields = &def.struct_variant().fields;
-            if fields.is_empty() {
-                span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty");
-                return;
-            }
-            let e = fields[0].ty(tcx, substs);
-            if !fields.iter().all(|f| f.ty(tcx, substs) == e) {
-                span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous");
-                return;
-            }
-            match e.sty {
-                ty::TyParam(_) => { /* struct<T>(T, T, T, T) is ok */ }
-                _ if e.is_machine()  => { /* struct(u8, u8, u8, u8) is ok */ }
-                _ => {
-                    span_err!(tcx.sess, sp, E0077,
-                              "SIMD vector element type should be machine type");
-                    return;
-                }
-            }
-        }
-        _ => ()
-    }
-}
-
-pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
-                                    sp: Span,
-                                    vs: &'tcx [hir::Variant],
-                                    id: ast::NodeId) {
-    fn do_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                          vs: &'tcx [hir::Variant],
-                          id: ast::NodeId,
-                          hint: attr::ReprAttr) {
-        #![allow(trivial_numeric_casts)]
-
-        let rty = ccx.tcx.node_id_to_type(id);
-        let mut disr_vals: Vec<ty::Disr> = Vec::new();
-
-        let tables = RefCell::new(ty::Tables::empty());
-        let inh = static_inherited_fields(ccx, &tables);
-        let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), id);
-
-        let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(&ccx.tcx);
-        for v in vs {
-            if let Some(ref e) = v.node.disr_expr {
-                check_const_with_ty(&fcx, e.span, e, repr_type_ty);
-            }
-        }
-
-        let def_id = ccx.tcx.map.local_def_id(id);
-
-        let variants = &ccx.tcx.lookup_adt_def(def_id).variants;
-        for (v, variant) in vs.iter().zip(variants.iter()) {
-            let current_disr_val = variant.disr_val;
-
-            // Check for duplicate discriminant values
-            match disr_vals.iter().position(|&x| x == current_disr_val) {
-                Some(i) => {
-                    let mut err = struct_span_err!(ccx.tcx.sess, v.span, E0081,
-                        "discriminant value `{}` already exists", disr_vals[i]);
-                    let variant_i_node_id = ccx.tcx.map.as_local_node_id(variants[i].did).unwrap();
-                    span_note!(&mut err, ccx.tcx.map.span(variant_i_node_id),
-                        "conflicting discriminant here");
-                    err.emit();
-                }
-                None => {}
-            }
-            disr_vals.push(current_disr_val);
-        }
-    }
-
-    let def_id = ccx.tcx.map.local_def_id(id);
-    let hint = *ccx.tcx.lookup_repr_hints(def_id).get(0).unwrap_or(&attr::ReprAny);
-
-    if hint != attr::ReprAny && vs.is_empty() {
-        span_err!(ccx.tcx.sess, sp, E0084,
-            "unsupported representation for zero-variant enum");
-    }
-
-    do_check(ccx, vs, id, hint);
-
-    check_representable(ccx.tcx, sp, id, "enum");
+    self.regionck_expr(e);
+    self.resolve_type_vars_in_expr(e);
 }
 
 // Returns the type parameter count and the type for the given definition.
-fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                                sp: Span,
-                                                defn: Def)
-                                                -> (TypeScheme<'tcx>, GenericPredicates<'tcx>) {
+fn type_scheme_and_predicates_for_def(&self,
+                                      sp: Span,
+                                      defn: Def)
+                                      -> (TypeScheme<'tcx>, GenericPredicates<'tcx>) {
     match defn {
         Def::Local(_, nid) | Def::Upvar(_, nid, _, _) => {
-            let typ = fcx.local_ty(sp, nid);
+            let typ = self.local_ty(sp, nid);
             (ty::TypeScheme { generics: ty::Generics::empty(), ty: typ },
              ty::GenericPredicates::empty())
         }
         Def::Fn(id) | Def::Method(id) |
         Def::Static(id, _) | Def::Variant(_, id) |
         Def::Struct(id) | Def::Const(id) | Def::AssociatedConst(id) => {
-            (fcx.tcx().lookup_item_type(id), fcx.tcx().lookup_predicates(id))
+            (self.tcx().lookup_item_type(id), self.tcx().lookup_predicates(id))
         }
         Def::Trait(_) |
         Def::Enum(..) |
@@ -4234,14 +4171,14 @@ fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 
 // Instantiates the given path, which must refer to an item with the given
 // number of type parameters and type.
-pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                  segments: &[hir::PathSegment],
-                                  type_scheme: TypeScheme<'tcx>,
-                                  type_predicates: &ty::GenericPredicates<'tcx>,
-                                  opt_self_ty: Option<Ty<'tcx>>,
-                                  def: Def,
-                                  span: Span,
-                                  node_id: ast::NodeId) {
+pub fn instantiate_path(&self,
+                        segments: &[hir::PathSegment],
+                        type_scheme: TypeScheme<'tcx>,
+                        type_predicates: &ty::GenericPredicates<'tcx>,
+                        opt_self_ty: Option<Ty<'tcx>>,
+                        def: Def,
+                        span: Span,
+                        node_id: ast::NodeId) {
     debug!("instantiate_path(path={:?}, def={:?}, node_id={}, type_scheme={:?})",
            segments,
            def,
@@ -4348,10 +4285,10 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 
         // Case 3. Reference to a method.
         Def::Method(def_id) => {
-            let container = fcx.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(fcx.ccx, span, trait_did)
+                    callee::check_legal_trait_for_method_call(self.ccx, span, trait_did)
                 }
                 ty::ImplContainer(_) => {}
             }
@@ -4369,10 +4306,10 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         }
 
         Def::AssociatedConst(def_id) => {
-            let container = fcx.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(fcx.ccx, span, trait_did)
+                    callee::check_legal_trait_for_method_call(self.ccx, span, trait_did)
                 }
                 ty::ImplContainer(_) => {}
             }
@@ -4401,7 +4338,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         }
 
         Def::Err => {
-            fcx.infcx().set_tainted_by_errors();
+            self.infcx().set_tainted_by_errors();
             segment_spaces = vec![None; segments.len()];
         }
     }
@@ -4424,21 +4361,16 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     // provided (if any) into their appropriate spaces. We'll also report
     // errors if type parameters are provided in an inappropriate place.
     let mut substs = Substs::empty();
-    for (opt_space, segment) in segment_spaces.iter().zip(segments) {
-        match *opt_space {
-            None => {
-                prohibit_type_params(fcx.tcx(), slice::ref_slice(segment));
-            }
-
-            Some(space) => {
-                push_explicit_parameters_from_segment_to_substs(fcx,
-                                                                space,
-                                                                span,
-                                                                type_defs,
-                                                                region_defs,
-                                                                segment,
-                                                                &mut substs);
-            }
+    for (&opt_space, segment) in segment_spaces.iter().zip(segments) {
+        if let Some(space) = opt_space {
+            self.push_explicit_parameters_from_segment_to_substs(space,
+                                                                 span,
+                                                                 type_defs,
+                                                                 region_defs,
+                                                                 segment,
+                                                                 &mut substs);
+        } else {
+            prohibit_type_params(self.tcx(), slice::ref_slice(segment));
         }
     }
     if let Some(self_ty) = opt_self_ty {
@@ -4454,11 +4386,11 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     // to add defaults. If the user provided *too many* types, that's
     // a problem.
     for &space in &[subst::SelfSpace, subst::TypeSpace, subst::FnSpace] {
-        adjust_type_parameters(fcx, span, space, type_defs,
-                               require_type_space, &mut substs);
+        self.adjust_type_parameters(span, space, type_defs,
+                                    require_type_space, &mut substs);
         assert_eq!(substs.types.len(space), type_defs.len(space));
 
-        adjust_region_parameters(fcx, span, space, region_defs, &mut substs);
+        self.adjust_region_parameters(span, space, region_defs, &mut substs);
         assert_eq!(substs.regions.len(space), region_defs.len(space));
     }
 
@@ -4469,14 +4401,14 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 
     // Add all the obligations that are required, substituting and
     // normalized appropriately.
-    let bounds = fcx.instantiate_bounds(span, &substs, &type_predicates);
-    fcx.add_obligations_for_parameters(
-        traits::ObligationCause::new(span, fcx.body_id, traits::ItemObligation(def.def_id())),
+    let bounds = self.instantiate_bounds(span, &substs, &type_predicates);
+    self.add_obligations_for_parameters(
+        traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def.def_id())),
         &bounds);
 
     // Substitute the values for the type parameters into the type of
     // the referenced item.
-    let ty_substituted = fcx.instantiate_type_scheme(span, &substs, &type_scheme.ty);
+    let ty_substituted = self.instantiate_type_scheme(span, &substs, &type_scheme.ty);
 
 
     if let Some((ty::ImplContainer(impl_def_id), self_ty)) = ufcs_associated {
@@ -4484,14 +4416,14 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         // 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 = fcx.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 = fcx.instantiate_type_scheme(span, &substs, &impl_scheme.ty);
-        if fcx.mk_subty(false, TypeOrigin::Misc(span), self_ty, impl_ty).is_err() {
+        let impl_ty = self.instantiate_type_scheme(span, &substs, &impl_scheme.ty);
+        if self.mk_subty(false, TypeOrigin::Misc(span), self_ty, impl_ty).is_err() {
             span_bug!(span,
                 "instantiate_path: (UFCS) {:?} was a subtype of {:?} but now is not?",
                 self_ty,
@@ -4502,9 +4434,9 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     debug!("instantiate_path: type of {:?} is {:?}",
            node_id,
            ty_substituted);
-    fcx.write_ty(node_id, ty_substituted);
-    fcx.write_substs(node_id, ty::ItemSubsts { substs: substs });
-    return;
+    self.write_ty(node_id, ty_substituted);
+    self.write_substs(node_id, ty::ItemSubsts { substs: substs });
+}
 
     /// Finds the parameters that the user provided and adds them to `substs`. If too many
     /// parameters are provided, then reports an error and clears the output vector.
@@ -4515,8 +4447,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     /// Note that we *do not* check for *too few* parameters here. Due to the presence of defaults
     /// etc that is more complicated. I wanted however to do the reporting of *too many* parameters
     /// here because we can easily use the precise span of the N+1'th parameter.
-    fn push_explicit_parameters_from_segment_to_substs<'a, 'tcx>(
-        fcx: &FnCtxt<'a, 'tcx>,
+    fn push_explicit_parameters_from_segment_to_substs(&self,
         space: subst::ParamSpace,
         span: Span,
         type_defs: &VecPerParamSpace<ty::TypeParameterDef<'tcx>>,
@@ -4526,21 +4457,20 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     {
         match segment.parameters {
             hir::AngleBracketedParameters(ref data) => {
-                push_explicit_angle_bracketed_parameters_from_segment_to_substs(
-                    fcx, space, type_defs, region_defs, data, substs);
+                self.push_explicit_angle_bracketed_parameters_from_segment_to_substs(
+                    space, type_defs, region_defs, data, substs);
             }
 
             hir::ParenthesizedParameters(ref data) => {
-                span_err!(fcx.tcx().sess, span, E0238,
+                span_err!(self.tcx().sess, span, E0238,
                     "parenthesized parameters may only be used with a trait");
-                push_explicit_parenthesized_parameters_from_segment_to_substs(
-                    fcx, space, span, type_defs, data, substs);
+                self.push_explicit_parenthesized_parameters_from_segment_to_substs(
+                    space, span, type_defs, data, substs);
             }
         }
     }
 
-    fn push_explicit_angle_bracketed_parameters_from_segment_to_substs<'a, 'tcx>(
-        fcx: &FnCtxt<'a, 'tcx>,
+    fn push_explicit_angle_bracketed_parameters_from_segment_to_substs(&self,
         space: subst::ParamSpace,
         type_defs: &VecPerParamSpace<ty::TypeParameterDef<'tcx>>,
         region_defs: &VecPerParamSpace<ty::RegionParameterDef>,
@@ -4551,11 +4481,11 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             let type_count = type_defs.len(space);
             assert_eq!(substs.types.len(space), 0);
             for (i, typ) in data.types.iter().enumerate() {
-                let t = fcx.to_ty(&typ);
+                let t = self.to_ty(&typ);
                 if i < type_count {
                     substs.types.push(space, t);
                 } else if i == type_count {
-                    span_err!(fcx.tcx().sess, typ.span, E0087,
+                    span_err!(self.tcx().sess, typ.span, E0087,
                         "too many type parameters provided: \
                          expected at most {} parameter{}, \
                          found {} parameter{}",
@@ -4570,7 +4500,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         }
 
         if !data.bindings.is_empty() {
-            span_err!(fcx.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)");
         }
@@ -4579,11 +4509,11 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             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(fcx.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!(fcx.tcx().sess, lifetime.span, E0088,
+                    span_err!(self.tcx().sess, lifetime.span, E0088,
                         "too many lifetime parameters provided: \
                          expected {} parameter{}, found {} parameter{}",
                         region_count,
@@ -4603,8 +4533,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     /// roughly the same thing as `Foo<(A,B),C>`. One important
     /// difference has to do with the treatment of anonymous
     /// regions, which are translated into bound regions (NYI).
-    fn push_explicit_parenthesized_parameters_from_segment_to_substs<'a, 'tcx>(
-        fcx: &FnCtxt<'a, 'tcx>,
+    fn push_explicit_parenthesized_parameters_from_segment_to_substs(&self,
         space: subst::ParamSpace,
         span: Span,
         type_defs: &VecPerParamSpace<ty::TypeParameterDef<'tcx>>,
@@ -4613,34 +4542,33 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     {
         let type_count = type_defs.len(space);
         if type_count < 2 {
-            span_err!(fcx.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);
         }
 
         let input_tys: Vec<Ty> =
-            data.inputs.iter().map(|ty| fcx.to_ty(&ty)).collect();
+            data.inputs.iter().map(|ty| self.to_ty(&ty)).collect();
 
-        let tuple_ty = fcx.tcx().mk_tup(input_tys);
+        let tuple_ty = self.tcx().mk_tup(input_tys);
 
         if type_count >= 1 {
             substs.types.push(space, tuple_ty);
         }
 
         let output_ty: Option<Ty> =
-            data.output.as_ref().map(|ty| fcx.to_ty(&ty));
+            data.output.as_ref().map(|ty| self.to_ty(&ty));
 
         let output_ty =
-            output_ty.unwrap_or(fcx.tcx().mk_nil());
+            output_ty.unwrap_or(self.tcx().mk_nil());
 
         if type_count >= 2 {
             substs.types.push(space, output_ty);
         }
     }
 
-    fn adjust_type_parameters<'a, 'tcx>(
-        fcx: &FnCtxt<'a, 'tcx>,
+    fn adjust_type_parameters(&self,
         span: Span,
         space: ParamSpace,
         defs: &VecPerParamSpace<ty::TypeParameterDef<'tcx>>,
@@ -4669,7 +4597,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         // everything.
         if provided_len == 0 && !(require_type_space && space == subst::TypeSpace) {
             substs.types.replace(space, Vec::new());
-            fcx.infcx().type_vars_for_defs(span, space, substs, &desired[..]);
+            self.infcx().type_vars_for_defs(span, space, substs, &desired[..]);
             return;
         }
 
@@ -4678,14 +4606,14 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         if provided_len < required_len {
             let qualifier =
                 if desired.len() != required_len { "at least " } else { "" };
-            span_err!(fcx.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![fcx.tcx().types.err; desired.len()]);
+            substs.types.replace(space, vec![self.tcx().types.err; desired.len()]);
             return;
         }
 
@@ -4698,7 +4626,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         // 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(fcx.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());
@@ -4706,8 +4634,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         debug!("Final substs: {:?}", substs);
     }
 
-    fn adjust_region_parameters(
-        fcx: &FnCtxt,
+    fn adjust_region_parameters(&self,
         span: Span,
         space: ParamSpace,
         defs: &VecPerParamSpace<ty::RegionParameterDef>,
@@ -4723,7 +4650,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         if provided_len == 0 {
             substs.regions.replace(
                 space,
-                fcx.infcx().region_vars_for_defs(span, desired));
+                self.infcx().region_vars_for_defs(span, desired));
             return;
         }
 
@@ -4734,7 +4661,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 
         // Otherwise, too few were provided. Report an error and then
         // use inference variables.
-        span_err!(fcx.tcx().sess, span, E0090,
+        span_err!(self.tcx().sess, span, E0090,
             "too few lifetime parameters provided: expected {} parameter{}, \
              found {} parameter{}",
             desired.len(),
@@ -4744,32 +4671,29 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 
         substs.regions.replace(
             space,
-            fcx.infcx().region_vars_for_defs(span, desired));
+            self.infcx().region_vars_for_defs(span, desired));
     }
-}
 
-fn structurally_resolve_type_or_else<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
-                                                  sp: Span,
-                                                  ty: Ty<'tcx>,
-                                                  f: F) -> Ty<'tcx>
+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 = fcx.resolve_type_vars_if_possible(ty);
+    let mut ty = self.resolve_type_vars_if_possible(ty);
 
     if ty.is_ty_var() {
         let alternative = f();
 
         // If not, error.
         if alternative.is_ty_var() || alternative.references_error() {
-            if !fcx.infcx().is_tainted_by_errors() {
-                fcx.type_error_message(sp, |_actual| {
+            if !self.infcx().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);
             }
-            demand::suptype(fcx, sp, fcx.tcx().types.err, ty);
-            ty = fcx.tcx().types.err;
+            self.demand_suptype(sp, self.tcx().types.err, ty);
+            ty = self.tcx().types.err;
         } else {
-            demand::suptype(fcx, sp, alternative, ty);
+            self.demand_suptype(sp, alternative, ty);
             ty = alternative;
         }
     }
@@ -4779,15 +4703,12 @@ fn structurally_resolve_type_or_else<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
 
 // Resolves `typ` by a single level if `typ` is a type variable.  If no
 // resolution is possible, then an error is reported.
-pub fn structurally_resolved_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                            sp: Span,
-                                            ty: Ty<'tcx>)
-                                            -> Ty<'tcx>
-{
-    structurally_resolve_type_or_else(fcx, sp, ty, || {
-        fcx.tcx().types.err
+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
     })
 }
+}
 
 // Returns true if b contains a break that can exit from b
 pub fn may_break(tcx: &TyCtxt, id: ast::NodeId, b: &hir::Block) -> bool {
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index debf9258757..d86813e2807 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -10,55 +10,49 @@
 
 //! Code related to processing overloaded binary and unary operators.
 
-use super::{
-    check_expr,
-    check_expr_coercable_to_type,
-    check_expr_with_lvalue_pref,
-    demand,
-    method,
-    FnCtxt,
-};
+use super::FnCtxt;
 use hir::def_id::DefId;
 use rustc::ty::{Ty, TypeFoldable, PreferMutLvalue};
 use syntax::ast;
 use syntax::parse::token;
 use rustc::hir;
 
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 /// Check a `a <op>= b`
-pub fn check_binop_assign<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
-                                   expr: &'tcx hir::Expr,
-                                   op: hir::BinOp,
-                                   lhs_expr: &'tcx hir::Expr,
-                                   rhs_expr: &'tcx hir::Expr)
+pub fn check_binop_assign(&self,
+                          expr: &'tcx hir::Expr,
+                          op: hir::BinOp,
+                          lhs_expr: &'tcx hir::Expr,
+                          rhs_expr: &'tcx hir::Expr)
 {
-    check_expr_with_lvalue_pref(fcx, lhs_expr, PreferMutLvalue);
+    self.check_expr_with_lvalue_pref(lhs_expr, PreferMutLvalue);
 
-    let lhs_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(lhs_expr));
+    let lhs_ty = self.resolve_type_vars_if_possible(self.expr_ty(lhs_expr));
     let (rhs_ty, return_ty) =
-        check_overloaded_binop(fcx, expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::Yes);
-    let rhs_ty = fcx.resolve_type_vars_if_possible(rhs_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);
 
     if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) {
-        enforce_builtin_binop_types(fcx, lhs_expr, lhs_ty, rhs_expr, rhs_ty, op);
-        fcx.write_nil(expr.id);
+        self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op);
+        self.write_nil(expr.id);
     } else {
-        fcx.write_ty(expr.id, return_ty);
+        self.write_ty(expr.id, return_ty);
     }
 
-    let tcx = fcx.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");
     }
 }
 
 /// Check a potentially overloaded binary operator.
-pub fn check_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                             expr: &'tcx hir::Expr,
-                             op: hir::BinOp,
-                             lhs_expr: &'tcx hir::Expr,
-                             rhs_expr: &'tcx hir::Expr)
+pub fn check_binop(&self,
+                   expr: &'tcx hir::Expr,
+                   op: hir::BinOp,
+                   lhs_expr: &'tcx hir::Expr,
+                   rhs_expr: &'tcx hir::Expr)
 {
-    let tcx = fcx.ccx.tcx;
+    let tcx = self.tcx();
 
     debug!("check_binop(expr.id={}, expr={:?}, op={:?}, lhs_expr={:?}, rhs_expr={:?})",
            expr.id,
@@ -67,22 +61,22 @@ pub fn check_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
            lhs_expr,
            rhs_expr);
 
-    check_expr(fcx, lhs_expr);
-    let lhs_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(lhs_expr));
+    self.check_expr(lhs_expr);
+    let lhs_ty = self.resolve_type_vars_if_possible(self.expr_ty(lhs_expr));
 
     match BinOpCategory::from(op) {
         BinOpCategory::Shortcircuit => {
             // && and || are a simple case.
-            demand::suptype(fcx, lhs_expr.span, tcx.mk_bool(), lhs_ty);
-            check_expr_coercable_to_type(fcx, rhs_expr, tcx.mk_bool());
-            fcx.write_ty(expr.id, tcx.mk_bool());
+            self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty);
+            self.check_expr_coercable_to_type(rhs_expr, tcx.mk_bool());
+            self.write_ty(expr.id, tcx.mk_bool());
         }
         _ => {
             // Otherwise, we always treat operators as if they are
             // overloaded. This is the way to be most flexible w/r/t
             // types that get inferred.
             let (rhs_ty, return_ty) =
-                check_overloaded_binop(fcx, expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::No);
+                self.check_overloaded_binop(expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::No);
 
             // Supply type inference hints if relevant. Probably these
             // hints should be enforced during select as part of the
@@ -96,36 +90,36 @@ pub fn check_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             // 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 = fcx.resolve_type_vars_if_possible(rhs_ty);
+            let rhs_ty = self.resolve_type_vars_if_possible(rhs_ty);
             if
                 !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() &&
                 is_builtin_binop(lhs_ty, rhs_ty, op)
             {
                 let builtin_return_ty =
-                    enforce_builtin_binop_types(fcx, lhs_expr, lhs_ty, rhs_expr, rhs_ty, op);
-                demand::suptype(fcx, expr.span, builtin_return_ty, return_ty);
+                    self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op);
+                self.demand_suptype(expr.span, builtin_return_ty, return_ty);
             }
 
-            fcx.write_ty(expr.id, return_ty);
+            self.write_ty(expr.id, return_ty);
         }
     }
 }
 
-fn enforce_builtin_binop_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                         lhs_expr: &'tcx hir::Expr,
-                                         lhs_ty: Ty<'tcx>,
-                                         rhs_expr: &'tcx hir::Expr,
-                                         rhs_ty: Ty<'tcx>,
-                                         op: hir::BinOp)
-                                         -> Ty<'tcx>
+fn enforce_builtin_binop_types(&self,
+                               lhs_expr: &'tcx hir::Expr,
+                               lhs_ty: Ty<'tcx>,
+                               rhs_expr: &'tcx hir::Expr,
+                               rhs_ty: Ty<'tcx>,
+                               op: hir::BinOp)
+                               -> Ty<'tcx>
 {
     debug_assert!(is_builtin_binop(lhs_ty, rhs_ty, op));
 
-    let tcx = fcx.tcx();
+    let tcx = self.tcx();
     match BinOpCategory::from(op) {
         BinOpCategory::Shortcircuit => {
-            demand::suptype(fcx, lhs_expr.span, tcx.mk_bool(), lhs_ty);
-            demand::suptype(fcx, rhs_expr.span, tcx.mk_bool(), rhs_ty);
+            self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty);
+            self.demand_suptype(rhs_expr.span, tcx.mk_bool(), rhs_ty);
             tcx.mk_bool()
         }
 
@@ -137,33 +131,33 @@ fn enforce_builtin_binop_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         BinOpCategory::Math |
         BinOpCategory::Bitwise => {
             // both LHS and RHS and result will have the same type
-            demand::suptype(fcx, rhs_expr.span, lhs_ty, rhs_ty);
+            self.demand_suptype(rhs_expr.span, lhs_ty, rhs_ty);
             lhs_ty
         }
 
         BinOpCategory::Comparison => {
             // both LHS and RHS and result will have the same type
-            demand::suptype(fcx, rhs_expr.span, lhs_ty, rhs_ty);
+            self.demand_suptype(rhs_expr.span, lhs_ty, rhs_ty);
             tcx.mk_bool()
         }
     }
 }
 
-fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                    expr: &'tcx hir::Expr,
-                                    lhs_expr: &'tcx hir::Expr,
-                                    lhs_ty: Ty<'tcx>,
-                                    rhs_expr: &'tcx hir::Expr,
-                                    op: hir::BinOp,
-                                    is_assign: IsAssign)
-                                    -> (Ty<'tcx>, Ty<'tcx>)
+fn check_overloaded_binop(&self,
+                          expr: &'tcx hir::Expr,
+                          lhs_expr: &'tcx hir::Expr,
+                          lhs_ty: Ty<'tcx>,
+                          rhs_expr: &'tcx hir::Expr,
+                          op: hir::BinOp,
+                          is_assign: IsAssign)
+                          -> (Ty<'tcx>, Ty<'tcx>)
 {
     debug!("check_overloaded_binop(expr.id={}, lhs_ty={:?}, is_assign={:?})",
            expr.id,
            lhs_ty,
            is_assign);
 
-    let (name, trait_def_id) = name_and_trait_def_id(fcx, op, is_assign);
+    let (name, trait_def_id) = self.name_and_trait_def_id(op, is_assign);
 
     // NB: As we have not yet type-checked the RHS, we don't have the
     // type at hand. Make a variable to represent it. The whole reason
@@ -171,22 +165,22 @@ fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     // 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 = fcx.infcx().next_ty_var();
+    let rhs_ty_var = self.infcx().next_ty_var();
 
-    let return_ty = match lookup_op_method(fcx, expr, lhs_ty, vec![rhs_ty_var],
-                                           token::intern(name), trait_def_id,
-                                           lhs_expr) {
+    let return_ty = match self.lookup_op_method(expr, lhs_ty, vec![rhs_ty_var],
+                                                token::intern(name), trait_def_id,
+                                                lhs_expr) {
         Ok(return_ty) => return_ty,
         Err(()) => {
             // error types are considered "builtin"
             if !lhs_ty.references_error() {
                 if let IsAssign::Yes = is_assign {
-                    span_err!(fcx.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!(fcx.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);
@@ -214,46 +208,46 @@ fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                     err.emit();
                 }
             }
-            fcx.tcx().types.err
+            self.tcx().types.err
         }
     };
 
     // see `NB` above
-    check_expr_coercable_to_type(fcx, rhs_expr, rhs_ty_var);
+    self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var);
 
     (rhs_ty_var, return_ty)
 }
 
-pub fn check_user_unop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                 op_str: &str,
-                                 mname: &str,
-                                 trait_did: Option<DefId>,
-                                 ex: &'tcx hir::Expr,
-                                 operand_expr: &'tcx hir::Expr,
-                                 operand_ty: Ty<'tcx>,
-                                 op: hir::UnOp)
-                                 -> Ty<'tcx>
+pub fn check_user_unop(&self,
+                       op_str: &str,
+                       mname: &str,
+                       trait_did: Option<DefId>,
+                       ex: &'tcx hir::Expr,
+                       operand_expr: &'tcx hir::Expr,
+                       operand_ty: Ty<'tcx>,
+                       op: hir::UnOp)
+                       -> Ty<'tcx>
 {
     assert!(op.is_by_value());
-    match lookup_op_method(fcx, ex, operand_ty, vec![],
-                           token::intern(mname), trait_did,
-                           operand_expr) {
+    match self.lookup_op_method(ex, operand_ty, vec![],
+                                token::intern(mname), trait_did,
+                                operand_expr) {
         Ok(t) => t,
         Err(()) => {
-            fcx.type_error_message(ex.span, |actual| {
+            self.type_error_message(ex.span, |actual| {
                 format!("cannot apply unary operator `{}` to type `{}`",
                         op_str, actual)
             }, operand_ty, None);
-            fcx.tcx().types.err
+            self.tcx().types.err
         }
     }
 }
 
-fn name_and_trait_def_id(fcx: &FnCtxt,
+fn name_and_trait_def_id(&self,
                          op: hir::BinOp,
                          is_assign: IsAssign)
                          -> (&'static str, Option<DefId>) {
-    let lang = &fcx.tcx().lang_items;
+    let lang = &self.tcx().lang_items;
 
     if let IsAssign::Yes = is_assign {
         match op.node {
@@ -299,14 +293,14 @@ fn name_and_trait_def_id(fcx: &FnCtxt,
     }
 }
 
-fn lookup_op_method<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
-                              expr: &'tcx hir::Expr,
-                              lhs_ty: Ty<'tcx>,
-                              other_tys: Vec<Ty<'tcx>>,
-                              opname: ast::Name,
-                              trait_did: Option<DefId>,
-                              lhs_expr: &'a hir::Expr)
-                              -> Result<Ty<'tcx>,()>
+fn lookup_op_method(&self,
+                    expr: &'tcx hir::Expr,
+                    lhs_ty: Ty<'tcx>,
+                    other_tys: Vec<Ty<'tcx>>,
+                    opname: ast::Name,
+                    trait_did: Option<DefId>,
+                    lhs_expr: &'a hir::Expr)
+                    -> Result<Ty<'tcx>,()>
 {
     debug!("lookup_op_method(expr={:?}, lhs_ty={:?}, opname={:?}, trait_did={:?}, lhs_expr={:?})",
            expr,
@@ -317,15 +311,14 @@ fn lookup_op_method<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
 
     let method = match trait_did {
         Some(trait_did) => {
-            method::lookup_in_trait_adjusted(fcx,
-                                             expr.span,
-                                             Some(lhs_expr),
-                                             opname,
-                                             trait_did,
-                                             0,
-                                             false,
-                                             lhs_ty,
-                                             Some(other_tys))
+            self.lookup_method_in_trait_adjusted(expr.span,
+                                                 Some(lhs_expr),
+                                                 opname,
+                                                 trait_did,
+                                                 0,
+                                                 false,
+                                                 lhs_ty,
+                                                 Some(other_tys))
         }
         None => None
     };
@@ -336,18 +329,19 @@ fn lookup_op_method<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
 
             // HACK(eddyb) Fully qualified path to work around a resolve bug.
             let method_call = ::rustc::ty::MethodCall::expr(expr.id);
-            fcx.inh.tables.borrow_mut().method_map.insert(method_call, method);
+            self.inh.tables.borrow_mut().method_map.insert(method_call, method);
 
             // extract return type for method; all late bound regions
             // should have been instantiated by now
             let ret_ty = method_ty.fn_ret();
-            Ok(fcx.tcx().no_late_bound_regions(&ret_ty).unwrap().unwrap())
+            Ok(self.tcx().no_late_bound_regions(&ret_ty).unwrap().unwrap())
         }
         None => {
             Err(())
         }
     }
 }
+}
 
 // Binary operator categories. These categories summarize the behavior
 // with respect to the builtin operationrs supported.
@@ -428,11 +422,7 @@ enum IsAssign {
 /// Reason #2 is the killer. I tried for a while to always use
 /// overloaded logic and just check the types in constants/trans after
 /// the fact, and it worked fine, except for SIMD types. -nmatsakis
-fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>,
-                          rhs: Ty<'tcx>,
-                          op: hir::BinOp)
-                          -> bool
-{
+fn is_builtin_binop(lhs: Ty, rhs: Ty, op: hir::BinOp) -> bool {
     match BinOpCategory::from(op) {
         BinOpCategory::Shortcircuit => {
             true
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index bda4c422880..76c387ccc2c 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -112,9 +112,10 @@ macro_rules! ignore_err {
 ///////////////////////////////////////////////////////////////////////////
 // PUBLIC ENTRY POINTS
 
-pub fn regionck_expr(fcx: &FnCtxt, e: &hir::Expr) {
-    let mut rcx = Rcx::new(fcx, RepeatingScope(e.id), e.id, Subject(e.id));
-    if fcx.err_count_since_creation() == 0 {
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+pub fn regionck_expr(&self, e: &hir::Expr) {
+    let mut rcx = Rcx::new(self, RepeatingScope(e.id), e.id, Subject(e.id));
+    if self.err_count_since_creation() == 0 {
         // regionck assumes typeck succeeded
         rcx.visit_expr(e);
         rcx.visit_region_obligations(e.id);
@@ -124,43 +125,44 @@ pub fn regionck_expr(fcx: &FnCtxt, e: &hir::Expr) {
 
 /// Region checking during the WF phase for items. `wf_tys` are the
 /// types from which we should derive implied bounds, if any.
-pub fn regionck_item<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
-                              item_id: ast::NodeId,
-                              span: Span,
-                              wf_tys: &[Ty<'tcx>]) {
+pub fn regionck_item(&self,
+                     item_id: ast::NodeId,
+                     span: Span,
+                     wf_tys: &[Ty<'tcx>]) {
     debug!("regionck_item(item.id={:?}, wf_tys={:?}", item_id, wf_tys);
-    let mut rcx = Rcx::new(fcx, RepeatingScope(item_id), item_id, Subject(item_id));
-    let tcx = fcx.tcx();
-    rcx.free_region_map
-       .relate_free_regions_from_predicates(tcx, &fcx.infcx().parameter_environment.caller_bounds);
+    let mut rcx = Rcx::new(self, RepeatingScope(item_id), item_id, Subject(item_id));
+    let tcx = self.tcx();
+    rcx.free_region_map.relate_free_regions_from_predicates(tcx,
+        &self.infcx().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();
 }
 
-pub fn regionck_fn(fcx: &FnCtxt,
+pub fn regionck_fn(&self,
                    fn_id: ast::NodeId,
                    fn_span: Span,
                    decl: &hir::FnDecl,
                    blk: &hir::Block) {
     debug!("regionck_fn(id={})", fn_id);
-    let mut rcx = Rcx::new(fcx, RepeatingScope(blk.id), blk.id, Subject(fn_id));
+    let mut rcx = Rcx::new(self, RepeatingScope(blk.id), blk.id, Subject(fn_id));
 
-    if fcx.err_count_since_creation() == 0 {
+    if self.err_count_since_creation() == 0 {
         // regionck assumes typeck succeeded
         rcx.visit_fn_body(fn_id, decl, blk, fn_span);
     }
 
-    let tcx = fcx.tcx();
-    rcx.free_region_map
-       .relate_free_regions_from_predicates(tcx, &fcx.infcx().parameter_environment.caller_bounds);
+    let tcx = self.tcx();
+    rcx.free_region_map.relate_free_regions_from_predicates(tcx,
+        &self.infcx().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.
-    fcx.tcx().store_free_region_map(fn_id, rcx.free_region_map);
+    self.tcx().store_free_region_map(fn_id, rcx.free_region_map);
+}
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -207,7 +209,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
     }
 
     pub fn tcx(&self) -> &'a TyCtxt<'tcx> {
-        self.fcx.ccx.tcx
+        self.fcx.tcx()
     }
 
     pub fn infcx(&self) -> &InferCtxt<'a,'tcx> {
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index c39e992eb36..629b3035404 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -42,7 +42,6 @@
 
 use super::FnCtxt;
 
-use check::demand;
 use middle::expr_use_visitor as euv;
 use middle::mem_categorization as mc;
 use middle::mem_categorization::Categorization;
@@ -57,34 +56,30 @@ use rustc::hir::intravisit::{self, Visitor};
 ///////////////////////////////////////////////////////////////////////////
 // PUBLIC ENTRY POINTS
 
-pub fn closure_analyze_fn(fcx: &FnCtxt,
-                          _id: ast::NodeId,
-                          _decl: &hir::FnDecl,
-                          body: &hir::Block)
-{
-    let mut seed = SeedBorrowKind::new(fcx);
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+pub fn closure_analyze_fn(&self, body: &hir::Block) {
+    let mut seed = SeedBorrowKind::new(self);
     seed.visit_block(body);
     let closures_with_inferred_kinds = seed.closures_with_inferred_kinds;
 
-    let mut adjust = AdjustBorrowKind::new(fcx, &closures_with_inferred_kinds);
+    let mut adjust = AdjustBorrowKind::new(self, &closures_with_inferred_kinds);
     adjust.visit_block(body);
 
     // it's our job to process these.
-    assert!(fcx.inh.deferred_call_resolutions.borrow().is_empty());
+    assert!(self.inh.deferred_call_resolutions.borrow().is_empty());
 }
 
-pub fn closure_analyze_const(fcx: &FnCtxt,
-                             body: &hir::Expr)
-{
-    let mut seed = SeedBorrowKind::new(fcx);
+pub fn closure_analyze_const(&self, body: &hir::Expr) {
+    let mut seed = SeedBorrowKind::new(self);
     seed.visit_expr(body);
     let closures_with_inferred_kinds = seed.closures_with_inferred_kinds;
 
-    let mut adjust = AdjustBorrowKind::new(fcx, &closures_with_inferred_kinds);
+    let mut adjust = AdjustBorrowKind::new(self, &closures_with_inferred_kinds);
     adjust.visit_expr(body);
 
     // it's our job to process these.
-    assert!(fcx.inh.deferred_call_resolutions.borrow().is_empty());
+    assert!(self.inh.deferred_call_resolutions.borrow().is_empty());
+}
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -221,7 +216,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
         debug!("analyze_closure: id={:?} closure_substs={:?} final_upvar_tys={:?}",
                id, closure_substs, final_upvar_tys);
         for (&upvar_ty, final_upvar_ty) in closure_substs.upvar_tys.iter().zip(final_upvar_tys) {
-            demand::eqtype(self.fcx, span, final_upvar_ty, upvar_ty);
+            self.fcx.demand_eqtype(span, final_upvar_ty, upvar_ty);
         }
 
         // Now we must process and remove any deferred resolutions,
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 17856dc4255..9e8cfa42f4e 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use check::{FnCtxt, Inherited, blank_fn_ctxt, regionck};
+use check::{FnCtxt, Inherited};
 use constrained_type_params::{identify_constrained_type_params, Parameter};
 use CrateCtxt;
 use hir::def_id::DefId;
@@ -108,14 +108,14 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
             }
             hir::ItemStruct(ref struct_def, ref ast_generics) => {
                 self.check_type_defn(item, |fcx| {
-                    vec![struct_variant(fcx, struct_def)]
+                    vec![fcx.struct_variant(struct_def)]
                 });
 
                 self.check_variances_for_type_defn(item, ast_generics);
             }
             hir::ItemEnum(ref enum_def, ref ast_generics) => {
                 self.check_type_defn(item, |fcx| {
-                    enum_variants(fcx, enum_def)
+                    fcx.enum_variants(enum_def)
                 });
 
                 self.check_variances_for_type_defn(item, ast_generics);
@@ -137,7 +137,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
 
             let (mut implied_bounds, self_ty) = match item.container() {
                 ty::TraitContainer(_) => (vec![], fcx.tcx().mk_self_type()),
-                ty::ImplContainer(def_id) => (impl_implied_bounds(fcx, def_id, span),
+                ty::ImplContainer(def_id) => (fcx.impl_implied_bounds(def_id, span),
                                               fcx.tcx().lookup_item_type(def_id).ty)
             };
 
@@ -182,10 +182,10 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
         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 = blank_fn_ctxt(ccx, &inh, ty::FnDiverging, id);
+        let fcx = FnCtxt::new(ccx, &inh, ty::FnDiverging, id);
         let wf_tys = f(&fcx, self);
         fcx.select_all_obligations_or_error();
-        regionck::regionck_item(&fcx, id, span, &wf_tys);
+        fcx.regionck_item(id, span, &wf_tys);
     }
 
     /// In a type definition, we check that to ensure that the types of the fields are well-formed.
@@ -229,7 +229,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
     {
         let trait_def_id = self.tcx().map.local_def_id(item.id);
 
-        if self.ccx.tcx.trait_has_default_impl(trait_def_id) {
+        if self.tcx().trait_has_default_impl(trait_def_id) {
             if !items.is_empty() {
                 error_380(self.ccx, item.span);
             }
@@ -327,7 +327,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
             let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates);
             this.check_where_clauses(fcx, item.span, &predicates);
 
-            impl_implied_bounds(fcx, fcx.tcx().map.local_def_id(item.id), item.span)
+            fcx.impl_implied_bounds(fcx.tcx().map.local_def_id(item.id), item.span)
         });
     }
 
@@ -554,55 +554,48 @@ struct AdtField<'tcx> {
     span: Span,
 }
 
-fn struct_variant<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                            struct_def: &hir::VariantData)
-                            -> AdtVariant<'tcx> {
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+fn struct_variant(&self, struct_def: &hir::VariantData) -> AdtVariant<'tcx> {
     let fields =
         struct_def.fields().iter()
         .map(|field| {
-            let field_ty = fcx.tcx().node_id_to_type(field.id);
-            let field_ty = fcx.instantiate_type_scheme(field.span,
-                                                       &fcx.inh
-                                                           .infcx
-                                                           .parameter_environment
-                                                           .free_substs,
-                                                       &field_ty);
+            let field_ty = self.tcx().node_id_to_type(field.id);
+            let field_ty = self.instantiate_type_scheme(field.span,
+                                                        &self.infcx()
+                                                             .parameter_environment
+                                                             .free_substs,
+                                                        &field_ty);
             AdtField { ty: field_ty, span: field.span }
         })
         .collect();
     AdtVariant { fields: fields }
 }
 
-fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                           enum_def: &hir::EnumDef)
-                           -> Vec<AdtVariant<'tcx>> {
+fn enum_variants(&self, enum_def: &hir::EnumDef) -> Vec<AdtVariant<'tcx>> {
     enum_def.variants.iter()
-        .map(|variant| struct_variant(fcx, &variant.node.data))
+        .map(|variant| self.struct_variant(&variant.node.data))
         .collect()
 }
 
-fn impl_implied_bounds<'fcx,'tcx>(fcx: &FnCtxt<'fcx, 'tcx>,
-                                  impl_def_id: DefId,
-                                  span: Span)
-                                  -> Vec<Ty<'tcx>>
-{
-    let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
-    match fcx.tcx().impl_trait_ref(impl_def_id) {
+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) {
         Some(ref trait_ref) => {
             // Trait impl: take implied bounds from all types that
             // appear in the trait reference.
-            let trait_ref = fcx.instantiate_type_scheme(span, free_substs, trait_ref);
+            let trait_ref = self.instantiate_type_scheme(span, free_substs, trait_ref);
             trait_ref.substs.types.as_slice().to_vec()
         }
 
         None => {
             // Inherent impl: take implied bounds from the self type.
-            let self_ty = fcx.tcx().lookup_item_type(impl_def_id).ty;
-            let self_ty = fcx.instantiate_type_scheme(span, free_substs, &self_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]
         }
     }
 }
+}
 
 fn error_192(ccx: &CrateCtxt, span: Span) {
     span_err!(ccx.tcx.sess, span, E0192,
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index a7039dcd91c..f8e4cb0eb65 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -34,9 +34,10 @@ use rustc::hir;
 ///////////////////////////////////////////////////////////////////////////
 // Entry point functions
 
-pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &hir::Expr) {
-    assert_eq!(fcx.writeback_errors.get(), false);
-    let mut wbcx = WritebackCx::new(fcx);
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+pub fn resolve_type_vars_in_expr(&self, e: &hir::Expr) {
+    assert_eq!(self.writeback_errors.get(), false);
+    let mut wbcx = WritebackCx::new(self);
     wbcx.visit_expr(e);
     wbcx.visit_upvar_borrow_map();
     wbcx.visit_closures();
@@ -44,18 +45,16 @@ pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &hir::Expr) {
     wbcx.visit_fru_field_types();
 }
 
-pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
-                               decl: &hir::FnDecl,
-                               blk: &hir::Block) {
-    assert_eq!(fcx.writeback_errors.get(), false);
-    let mut wbcx = WritebackCx::new(fcx);
+pub fn resolve_type_vars_in_fn(&self, decl: &hir::FnDecl, blk: &hir::Block) {
+    assert_eq!(self.writeback_errors.get(), false);
+    let mut wbcx = WritebackCx::new(self);
     wbcx.visit_block(blk);
     for arg in &decl.inputs {
         wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id);
         wbcx.visit_pat(&arg.pat);
 
         // Privacy needs the type for the whole pattern, not just each binding
-        if !pat_util::pat_is_binding(&fcx.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);
         }
@@ -65,6 +64,7 @@ pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
     wbcx.visit_liberated_fn_sigs();
     wbcx.visit_fru_field_types();
 }
+}
 
 ///////////////////////////////////////////////////////////////////////////
 // The Writerback context. This visitor walks the AST, checking the