about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_typeck/check/_match.rs96
-rw-r--r--src/librustc_typeck/check/callee.rs36
-rw-r--r--src/librustc_typeck/check/cast.rs4
-rw-r--r--src/librustc_typeck/check/closure.rs8
-rw-r--r--src/librustc_typeck/check/coercion.rs10
-rw-r--r--src/librustc_typeck/check/demand.rs6
-rw-r--r--src/librustc_typeck/check/method/confirm.rs8
-rw-r--r--src/librustc_typeck/check/mod.rs405
-rw-r--r--src/librustc_typeck/check/op.rs26
9 files changed, 272 insertions, 327 deletions
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 12fce4b928e..c67b98761aa 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -32,17 +32,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         debug!("check_pat(pat={:?},expected={:?})", pat, expected);
 
-        match pat.node {
+        let ty = match pat.node {
             PatKind::Wild => {
-                self.write_ty(pat.id, expected);
+                expected
             }
             PatKind::Lit(ref lt) => {
-                self.check_expr(&lt);
-                let expr_ty = self.expr_ty(&lt);
+                let ty = self.check_expr(&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;
+                let mut pat_ty = ty;
                 if let hir::ExprLit(ref lt) = lt.node {
                     if let ast::LitKind::ByteStr(_) = lt.node {
                         let expected_ty = self.structurally_resolved_type(pat.span, expected);
@@ -55,28 +54,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
 
-                self.write_ty(pat.id, pat_ty);
-
                 // somewhat surprising: in this case, the subtyping
                 // relation goes the opposite way as the other
                 // cases. Actually what we really want is not a subtyping
                 // relation at all but rather that there exists a LUB (so
                 // that they can be compared). However, in practice,
                 // constants are always scalars or strings.  For scalars
-                // subtyping is irrelevant, and for strings `expr_ty` is
+                // subtyping is irrelevant, and for strings `ty` is
                 // type is `&'static str`, so if we say that
                 //
                 //     &'static str <: expected
                 //
                 // that's equivalent to there existing a LUB.
                 self.demand_suptype(pat.span, expected, pat_ty);
+                pat_ty
             }
             PatKind::Range(ref begin, ref end) => {
-                self.check_expr(begin);
-                self.check_expr(end);
-
-                let lhs_ty = self.expr_ty(begin);
-                let rhs_ty = self.expr_ty(end);
+                let lhs_ty = self.check_expr(begin);
+                let rhs_ty = self.check_expr(end);
 
                 // Check that both end-points are of numeric or char type.
                 let numeric_or_char = |ty: Ty| ty.is_numeric() || ty.is_char();
@@ -105,11 +100,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // it to type the entire expression.
                 let common_type = self.resolve_type_vars_if_possible(&lhs_ty);
 
-                self.write_ty(pat.id, common_type);
-
                 // subtyping doesn't matter here, as the value is some kind of scalar
                 self.demand_eqtype(pat.span, expected, lhs_ty);
                 self.demand_eqtype(pat.span, expected, rhs_ty);
+                common_type
             }
             PatKind::Binding(bm, _, ref sub) => {
                 let typ = self.local_ty(pat.span, pat.id);
@@ -136,8 +130,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
 
-                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
                 match tcx.expect_def(pat.id) {
@@ -154,16 +146,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 if let Some(ref p) = *sub {
                     self.check_pat(&p, expected);
                 }
+
+                typ
             }
             PatKind::TupleStruct(ref path, ref subpats, ddpos) => {
-                self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected);
+                self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected)
             }
             PatKind::Path(ref opt_qself, ref path) => {
                 let opt_qself_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty));
-                self.check_pat_path(pat, opt_qself_ty, path, expected);
+                self.check_pat_path(pat, opt_qself_ty, path, expected)
             }
             PatKind::Struct(ref path, ref fields, etc) => {
-                self.check_pat_struct(pat, path, fields, etc, expected);
+                self.check_pat_struct(pat, path, fields, etc, expected)
             }
             PatKind::Tuple(ref elements, ddpos) => {
                 let mut expected_len = elements.len();
@@ -178,11 +172,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
                 let element_tys: Vec<_> = (0 .. max_len).map(|_| self.next_ty_var()).collect();
                 let pat_ty = tcx.mk_tup(element_tys.clone());
-                self.write_ty(pat.id, pat_ty);
                 self.demand_eqtype(pat.span, expected, pat_ty);
                 for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
                     self.check_pat(elem, &element_tys[i]);
                 }
+                pat_ty
             }
             PatKind::Box(ref inner) => {
                 let inner_ty = self.next_ty_var();
@@ -193,11 +187,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     // think any errors can be introduced by using
                     // `demand::eqtype`.
                     self.demand_eqtype(pat.span, expected, uniq_ty);
-                    self.write_ty(pat.id, uniq_ty);
                     self.check_pat(&inner, inner_ty);
+                    uniq_ty
                 } else {
-                    self.write_error(pat.id);
                     self.check_pat(&inner, tcx.types.err);
+                    tcx.types.err
                 }
             }
             PatKind::Ref(ref inner, mutbl) => {
@@ -225,11 +219,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         }
                     };
 
-                    self.write_ty(pat.id, rptr_ty);
                     self.check_pat(&inner, inner_ty);
+                    rptr_ty
                 } else {
-                    self.write_error(pat.id);
                     self.check_pat(&inner, tcx.types.err);
+                    tcx.types.err
                 }
             }
             PatKind::Vec(ref before, ref slice, ref after) => {
@@ -281,8 +275,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     }
                 };
 
-                self.write_ty(pat.id, expected_ty);
-
                 for elt in before {
                     self.check_pat(&elt, inner_ty);
                 }
@@ -292,8 +284,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 for elt in after {
                     self.check_pat(&elt, inner_ty);
                 }
+                expected_ty
             }
-        }
+        };
+
+        self.write_ty(pat.id, ty);
 
         // (*) In most of the cases above (literals and constants being
         // the exception), we relate types using strict equality, evewn
@@ -371,7 +366,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                        discrim: &'gcx hir::Expr,
                        arms: &'gcx [hir::Arm],
                        expected: Expectation<'tcx>,
-                       match_src: hir::MatchSource) {
+                       match_src: hir::MatchSource) -> Ty<'tcx> {
         let tcx = self.tcx;
 
         // Not entirely obvious: if matches may create ref bindings, we
@@ -385,8 +380,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                         });
         let discrim_ty;
         if let Some(m) = contains_ref_bindings {
-            self.check_expr_with_lvalue_pref(discrim, LvaluePreference::from_mutbl(m));
-            discrim_ty = self.expr_ty(discrim);
+            discrim_ty = self.check_expr_with_lvalue_pref(discrim, LvaluePreference::from_mutbl(m));
         } else {
             // ...but otherwise we want to use any supertype of the
             // discriminant. This is sort of a workaround, see note (*) in
@@ -425,12 +419,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
             _ => result_ty
         };
+
         for (i, arm) in arms.iter().enumerate() {
             if let Some(ref e) = arm.guard {
                 self.check_expr_has_type(e, tcx.types.bool);
             }
-            self.check_expr_with_expectation(&arm.body, expected);
-            let arm_ty = self.expr_ty(&arm.body);
+            let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
 
             if result_ty.references_error() || arm_ty.references_error() {
                 result_ty = tcx.types.err;
@@ -460,10 +454,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     })
             } else if i == 0 {
                 // Special-case the first arm, as it has no "previous expressions".
-                self.try_coerce(&arm.body, coerce_first)
+                self.try_coerce(&arm.body, arm_ty, coerce_first)
             } else {
                 let prev_arms = || arms[..i].iter().map(|arm| &*arm.body);
-                self.try_find_coercion_lub(origin, prev_arms, result_ty, &arm.body)
+                self.try_find_coercion_lub(origin, prev_arms, result_ty, &arm.body, arm_ty)
             };
 
             result_ty = match result {
@@ -480,7 +474,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             };
         }
 
-        self.write_ty(expr.id, result_ty);
+        result_ty
     }
 }
 
@@ -490,18 +484,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         path: &hir::Path,
                         fields: &'gcx [Spanned<hir::FieldPat>],
                         etc: bool,
-                        expected: Ty<'tcx>)
+                        expected: Ty<'tcx>) -> Ty<'tcx>
     {
         // Resolve the path and check the definition for errors.
         let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(path, pat.id,
                                                                                  pat.span) {
             variant_ty
         } else {
-            self.write_error(pat.id);
             for field in fields {
                 self.check_pat(&field.node.pat, self.tcx.types.err);
             }
-            return;
+            return self.tcx.types.err;
         };
 
         // Type check the path.
@@ -509,20 +502,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         // Type check subpatterns.
         self.check_struct_pat_fields(pat_ty, pat.span, variant, fields, etc);
+        pat_ty
     }
 
     fn check_pat_path(&self,
                       pat: &hir::Pat,
                       opt_self_ty: Option<Ty<'tcx>>,
                       path: &hir::Path,
-                      expected: Ty<'tcx>)
+                      expected: Ty<'tcx>) -> Ty<'tcx>
     {
         let tcx = self.tcx;
         let report_unexpected_def = || {
             span_err!(tcx.sess, pat.span, E0533,
                       "`{}` does not name a unit variant, unit struct or a constant",
                       pprust::path_to_string(path));
-            self.write_error(pat.id);
         };
 
         // Resolve the path and check the definition for errors.
@@ -531,18 +524,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         match def {
             Def::Err => {
                 self.set_tainted_by_errors();
-                self.write_error(pat.id);
-                return;
+                return tcx.types.err;
             }
             Def::Method(..) => {
                 report_unexpected_def();
-                return;
+                return tcx.types.err;
             }
             Def::Variant(..) | Def::Struct(..) => {
                 let variant = tcx.expect_variant_def(def);
                 if variant.kind != VariantKind::Unit {
                     report_unexpected_def();
-                    return;
+                    return tcx.types.err;
                 }
             }
             Def::Const(..) | Def::AssociatedConst(..) => {} // OK
@@ -552,6 +544,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // Type check the path.
         let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id);
         self.demand_suptype(pat.span, expected, pat_ty);
+        pat_ty
     }
 
     fn check_pat_tuple_struct(&self,
@@ -559,11 +552,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                               path: &hir::Path,
                               subpats: &'gcx [P<hir::Pat>],
                               ddpos: Option<usize>,
-                              expected: Ty<'tcx>)
+                              expected: Ty<'tcx>) -> Ty<'tcx>
     {
         let tcx = self.tcx;
         let on_error = || {
-            self.write_error(pat.id);
             for pat in subpats {
                 self.check_pat(&pat, tcx.types.err);
             }
@@ -587,11 +579,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             Def::Err => {
                 self.set_tainted_by_errors();
                 on_error();
-                return;
+                return tcx.types.err;
             }
             Def::Const(..) | Def::AssociatedConst(..) | Def::Method(..) => {
                 report_unexpected_def(false);
-                return;
+                return tcx.types.err;
             }
             Def::Variant(..) | Def::Struct(..) => {
                 tcx.expect_variant_def(def)
@@ -604,12 +596,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             report_unexpected_def(true);
         } else if variant.kind != VariantKind::Tuple {
             report_unexpected_def(false);
-            return;
+            return tcx.types.err;
         }
 
         // Type check the path.
         let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id);
-
         let pat_ty = if pat_ty.is_fn() {
             // Replace constructor type with constructed type for tuple struct patterns.
             tcx.no_late_bound_regions(&pat_ty.fn_ret()).unwrap()
@@ -617,7 +608,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             // Leave the type as is for unit structs (backward compatibility).
             pat_ty
         };
-        self.write_ty(pat.id, pat_ty);
         self.demand_eqtype(pat.span, expected, pat_ty);
 
         // Type check subpatterns.
@@ -650,7 +640,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                variant.fields.len(), fields_ending, subpats.len()))
                 .emit();
             on_error();
+            return tcx.types.err;
         }
+        pat_ty
     }
 
     fn check_struct_pat_fields(&self,
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 49db56d2dab..5bd4f13a111 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -15,7 +15,7 @@ use CrateCtxt;
 use middle::cstore::LOCAL_CRATE;
 use hir::def::Def;
 use hir::def_id::DefId;
-use rustc::infer;
+use rustc::{infer, traits};
 use rustc::ty::{self, LvaluePreference, Ty};
 use syntax::parse::token;
 use syntax::ptr::P;
@@ -45,10 +45,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                       call_expr: &'gcx hir::Expr,
                       callee_expr: &'gcx hir::Expr,
                       arg_exprs: &'gcx [P<hir::Expr>],
-                      expected: Expectation<'tcx>)
+                      expected: Expectation<'tcx>) -> Ty<'tcx>
     {
-        self.check_expr(callee_expr);
-        let original_callee_ty = self.expr_ty(callee_expr);
+        let original_callee_ty = self.check_expr(callee_expr);
 
         let mut autoderef = self.autoderef(callee_expr.span, original_callee_ty);
         let result = autoderef.by_ref().flat_map(|(adj_ty, idx)| {
@@ -57,25 +56,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let callee_ty = autoderef.unambiguous_final_ty();
         autoderef.finalize(LvaluePreference::NoPreference, Some(callee_expr));
 
-        match result {
+        let output = match result {
             None => {
                 // this will report an error since original_callee_ty is not a fn
-                self.confirm_builtin_call(call_expr, original_callee_ty, arg_exprs, expected);
+                self.confirm_builtin_call(call_expr, original_callee_ty, arg_exprs, expected)
             }
 
             Some(CallStep::Builtin) => {
-                self.confirm_builtin_call(call_expr, callee_ty, arg_exprs, expected);
+                self.confirm_builtin_call(call_expr, callee_ty, arg_exprs, expected)
             }
 
             Some(CallStep::DeferredClosure(fn_sig)) => {
-                self.confirm_deferred_closure_call(call_expr, arg_exprs, expected, fn_sig);
+                self.confirm_deferred_closure_call(call_expr, arg_exprs, expected, fn_sig)
             }
 
             Some(CallStep::Overloaded(method_callee)) => {
                 self.confirm_overloaded_call(call_expr, callee_expr,
-                                             arg_exprs, expected, method_callee);
+                                             arg_exprs, expected, method_callee)
             }
-        }
+        };
+
+        // we must check that return type of called functions is WF:
+        self.register_wf_obligation(output, call_expr.span, traits::MiscObligation);
+
+        output
     }
 
     fn try_overloaded_call_step(&self,
@@ -181,7 +185,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             call_expr: &hir::Expr,
                             callee_ty: Ty<'tcx>,
                             arg_exprs: &'gcx [P<hir::Expr>],
-                            expected: Expectation<'tcx>)
+                            expected: Expectation<'tcx>) -> Ty<'tcx>
     {
         let error_fn_sig;
 
@@ -245,14 +249,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                   fn_sig.variadic,
                                   TupleArgumentsFlag::DontTupleArguments);
 
-        self.write_call(call_expr, fn_sig.output);
+        fn_sig.output
     }
 
     fn confirm_deferred_closure_call(&self,
                                      call_expr: &hir::Expr,
                                      arg_exprs: &'gcx [P<hir::Expr>],
                                      expected: Expectation<'tcx>,
-                                     fn_sig: ty::FnSig<'tcx>)
+                                     fn_sig: ty::FnSig<'tcx>) -> Ty<'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
@@ -272,7 +276,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                   fn_sig.variadic,
                                   TupleArgumentsFlag::TupleArguments);
 
-        self.write_call(call_expr, fn_sig.output);
+        fn_sig.output
     }
 
     fn confirm_overloaded_call(&self,
@@ -280,7 +284,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                callee_expr: &'gcx hir::Expr,
                                arg_exprs: &'gcx [P<hir::Expr>],
                                expected: Expectation<'tcx>,
-                               method_callee: ty::MethodCallee<'tcx>)
+                               method_callee: ty::MethodCallee<'tcx>) -> Ty<'tcx>
     {
         let output_type =
             self.check_method_argument_types(call_expr.span,
@@ -289,9 +293,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                              arg_exprs,
                                              TupleArgumentsFlag::TupleArguments,
                                              expected);
-        self.write_call(call_expr, output_type);
 
         self.write_overloaded_call_method_map(call_expr, method_callee);
+        output_type
     }
 
     fn write_overloaded_call_method_map(&self,
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 1fda38d8a33..0c9da86563a 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -321,7 +321,7 @@ impl<'a, 'gcx, '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 = fcx.try_coerce(self.expr, fcx.tcx.mk_fn_ptr(f));
+                    let res = fcx.try_coerce(self.expr, self.expr_ty, fcx.tcx.mk_fn_ptr(f));
                     if !res.is_ok() {
                         return Err(CastError::NonScalar);
                     }
@@ -471,7 +471,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
     }
 
     fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> bool {
-        fcx.try_coerce(self.expr, self.cast_ty).is_ok()
+        fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty).is_ok()
     }
 
 }
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 8980cb90760..9e41d1b5676 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -24,7 +24,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                               _capture: hir::CaptureClause,
                               decl: &'gcx hir::FnDecl,
                               body: &'gcx hir::Block,
-                              expected: Expectation<'tcx>) {
+                              expected: Expectation<'tcx>) -> Ty<'tcx> {
         debug!("check_expr_closure(expr={:?},expected={:?})",
                expr,
                expected);
@@ -44,7 +44,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                      opt_kind: Option<ty::ClosureKind>,
                      decl: &'gcx hir::FnDecl,
                      body: &'gcx hir::Block,
-                     expected_sig: Option<ty::FnSig<'tcx>>) {
+                     expected_sig: Option<ty::FnSig<'tcx>>) -> Ty<'tcx> {
         let expr_def_id = self.tcx.map.local_def_id(expr.id);
 
         debug!("check_closure opt_kind={:?} expected_sig={:?}",
@@ -70,8 +70,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.parameter_environment.free_substs,
             upvar_tys);
 
-        self.write_ty(expr.id, closure_type);
-
         let fn_sig = self.tcx.liberate_late_bound_regions(
             self.tcx.region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig);
         let fn_sig =
@@ -93,6 +91,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             Some(kind) => { self.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); }
             None => { }
         }
+
+        closure_type
     }
 
     fn deduce_expectations_from_expected_type(&self, expected_ty: Ty<'tcx>)
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 60ca9309eea..98a05989b14 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -630,9 +630,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     /// The expressions *must not* have any pre-existing adjustments.
     pub fn try_coerce(&self,
                       expr: &hir::Expr,
+                      expr_ty: Ty<'tcx>,
                       target: Ty<'tcx>)
                       -> RelateResult<'tcx, Ty<'tcx>> {
-        let source = self.resolve_type_vars_with_obligations(self.expr_ty(expr));
+        let source = self.resolve_type_vars_with_obligations(expr_ty);
         debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
 
         let mut coerce = Coerce::new(self, TypeOrigin::ExprAssignable(expr.span));
@@ -658,14 +659,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                            origin: TypeOrigin,
                                            exprs: E,
                                            prev_ty: Ty<'tcx>,
-                                           new: &'b hir::Expr)
+                                           new: &'b hir::Expr,
+                                           new_ty: Ty<'tcx>)
                                            -> 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 = self.resolve_type_vars_with_obligations(prev_ty);
-        let new_ty = self.resolve_type_vars_with_obligations(self.expr_ty(new));
+        let new_ty = self.resolve_type_vars_with_obligations(new_ty);
         debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty);
 
         let trace = TypeTrace::types(origin, true, prev_ty, new_ty);
@@ -741,7 +743,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     autoderefs: 1,
                     autoref: Some(AutoPtr(_, mutbl_adj)),
                     unsize: None
-                })) => match self.expr_ty(expr).sty {
+                })) => match self.node_ty(expr.id).sty {
                     ty::TyRef(_, mt_orig) => {
                         // Reborrow that we can safely ignore.
                         mutbl_adj == mt_orig.mutbl
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 1f3a83ebc1d..d622bc7f751 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -53,11 +53,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     // Checks that the type of `expr` can be coerced to `expected`.
-    pub fn demand_coerce(&self, expr: &hir::Expr, expected: Ty<'tcx>) {
+    pub fn demand_coerce(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, expected: Ty<'tcx>) {
         let expected = self.resolve_type_vars_with_obligations(expected);
-        if let Err(e) = self.try_coerce(expr, expected) {
+        if let Err(e) = self.try_coerce(expr, checked_ty, expected) {
             let origin = TypeOrigin::Misc(expr.span);
-            let expr_ty = self.resolve_type_vars_with_obligations(self.expr_ty(expr));
+            let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
             self.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 dbf74e371df..ab59fafb652 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -472,7 +472,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                    i, expr, autoderef_count);
 
             if autoderef_count > 0 {
-                let mut autoderef = self.autoderef(expr.span, self.expr_ty(expr));
+                let mut autoderef = self.autoderef(expr.span, self.node_ty(expr.id));
                 autoderef.nth(autoderef_count).unwrap_or_else(|| {
                     span_bug!(expr.span, "expr was deref-able {} times but now isn't?",
                               autoderef_count);
@@ -532,7 +532,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                                 unsize: None
                             }))), false)
                     };
-                    let index_expr_ty = self.expr_ty(&index_expr);
+                    let index_expr_ty = self.node_ty(index_expr.id);
 
                     let result = self.try_index_step(
                         ty::MethodCall::expr(expr.id),
@@ -547,7 +547,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                     if let Some((input_ty, return_ty)) = result {
                         self.demand_suptype(index_expr.span, input_ty, index_expr_ty);
 
-                        let expr_ty = self.expr_ty(&expr);
+                        let expr_ty = self.node_ty(expr.id);
                         self.demand_suptype(expr.span, expr_ty, return_ty);
                     }
                 }
@@ -558,7 +558,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                     if self.tables.borrow().method_map.contains_key(&method_call) {
                         let method = self.try_overloaded_deref(expr.span,
                             Some(&base_expr),
-                            self.expr_ty(&base_expr),
+                            self.node_ty(base_expr.id),
                             PreferMutLvalue);
                         let method = method.expect("re-trying deref failed");
                         self.tables.borrow_mut().method_map.insert(method_call, method);
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 0aa523e9d5e..00fdcd59f7c 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1534,14 +1534,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         debug!("write_ty({}, {:?}) in fcx {}",
                node_id, ty, self.tag());
         self.tables.borrow_mut().node_types.insert(node_id, ty);
-
-        // Add adjustments to !-expressions
-        if ty.is_never() {
-            if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(node_id) {
-                let adj = adjustment::AdjustNeverToAny(self.next_diverging_ty_var());
-                self.write_adjustment(node_id, adj);
-            }
-        }
     }
 
     pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) {
@@ -1708,7 +1700,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.add_obligations_for_parameters(cause, &bounds);
 
         let ty_substituted = self.instantiate_type_scheme(path.span, substs, &ty);
-        self.write_ty(node_id, ty_substituted);
         self.write_substs(node_id, ty::ItemSubsts {
             substs: substs
         });
@@ -1747,13 +1738,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.require_type_meets(ty, span, code, ty::BoundSized);
     }
 
-    pub fn require_expr_have_sized_type(&self,
-                                        expr: &hir::Expr,
-                                        code: traits::ObligationCauseCode<'tcx>)
-    {
-        self.require_type_is_sized(self.expr_ty(expr), expr.span, code);
-    }
-
     pub fn register_builtin_bound(&self,
                                   ty: Ty<'tcx>,
                                   builtin_bound: ty::BuiltinBound,
@@ -1779,26 +1763,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         t
     }
 
-    pub fn expr_ty(&self, ex: &hir::Expr) -> Ty<'tcx> {
-        if let Some(&adjustment::AdjustNeverToAny(ref t))
-                = self.tables.borrow().adjustments.get(&ex.id) {
-            return t;
-        }
-        match self.tables.borrow().node_types.get(&ex.id) {
-            Some(&t) => t,
-            None => {
-                bug!("no type for expr in fcx {}", self.tag());
-            }
-        }
-    }
-
     /// Apply `adjustment` to the type of `expr`
     pub fn adjust_expr_ty(&self,
                           expr: &hir::Expr,
                           adjustment: Option<&adjustment::AutoAdjustment<'tcx>>)
                           -> Ty<'tcx>
     {
-        let raw_ty = self.expr_ty(expr);
+        let raw_ty = self.node_ty(expr.id);
         let raw_ty = self.shallow_resolve(raw_ty);
         let resolve_ty = |ty: Ty<'tcx>| self.resolve_type_vars_if_possible(&ty);
         raw_ty.adjust(self.tcx, expr.span, expr.id, adjustment, |method_call| {
@@ -2583,13 +2554,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         Expectation::rvalue_hint(self, ty)
                     });
 
-                    self.check_expr_with_expectation(&arg,
-                        expected.unwrap_or(ExpectHasType(formal_ty)));
+                    let checked_ty = 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(self));
-                    self.demand_coerce(&arg, coerce_ty.unwrap_or(formal_ty));
+                    self.demand_coerce(&arg, checked_ty, coerce_ty.unwrap_or(formal_ty));
 
                     // 3. Relate the expected type and the formal one,
                     //    if the expected type was used for the coercion.
@@ -2620,12 +2591,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // arguments which we skipped above.
         if variadic {
             for arg in args.iter().skip(expected_arg_count) {
-                self.check_expr(&arg);
+                let arg_ty = 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 = self.structurally_resolved_type(arg.span,
-                                                             self.expr_ty(&arg));
+                                                             arg_ty);
                 match arg_ty.sty {
                     ty::TyFloat(ast::FloatTy::F32) => {
                         self.type_error_message(arg.span, |t| {
@@ -2666,12 +2637,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         (0..len).map(|_| self.tcx.types.err).collect()
     }
 
-    fn write_call(&self,
-                  call_expr: &hir::Expr,
-                  output: Ty<'tcx>) {
-        self.write_ty(call_expr.id, output);
-    }
-
     // AST fragment checking
     fn check_lit(&self,
                  lit: &ast::Lit,
@@ -2721,41 +2686,43 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     fn check_expr_eq_type(&self,
                           expr: &'gcx hir::Expr,
                           expected: Ty<'tcx>) {
-        self.check_expr_with_hint(expr, expected);
-        self.demand_eqtype(expr.span, expected, self.expr_ty(expr));
+        let ty = self.check_expr_with_hint(expr, expected);
+        self.demand_eqtype(expr.span, expected, ty);
     }
 
     pub fn check_expr_has_type(&self,
                                expr: &'gcx hir::Expr,
-                               expected: Ty<'tcx>) {
-        self.check_expr_with_hint(expr, expected);
-        self.demand_suptype(expr.span, expected, self.expr_ty(expr));
+                               expected: Ty<'tcx>) -> Ty<'tcx> {
+        let ty = self.check_expr_with_hint(expr, expected);
+        self.demand_suptype(expr.span, expected, ty);
+        ty
     }
 
     fn check_expr_coercable_to_type(&self,
                                     expr: &'gcx hir::Expr,
-                                    expected: Ty<'tcx>) {
-        self.check_expr_with_hint(expr, expected);
-        self.demand_coerce(expr, expected);
+                                    expected: Ty<'tcx>) -> Ty<'tcx> {
+        let ty = self.check_expr_with_hint(expr, expected);
+        self.demand_coerce(expr, ty, expected);
+        ty
     }
 
     fn check_expr_with_hint(&self, expr: &'gcx hir::Expr,
-                            expected: Ty<'tcx>) {
+                            expected: Ty<'tcx>) -> Ty<'tcx> {
         self.check_expr_with_expectation(expr, ExpectHasType(expected))
     }
 
     fn check_expr_with_expectation(&self,
                                    expr: &'gcx hir::Expr,
-                                   expected: Expectation<'tcx>) {
+                                   expected: Expectation<'tcx>) -> Ty<'tcx> {
         self.check_expr_with_expectation_and_lvalue_pref(expr, expected, NoPreference)
     }
 
-    fn check_expr(&self, expr: &'gcx hir::Expr)  {
+    fn check_expr(&self, expr: &'gcx hir::Expr) -> Ty<'tcx> {
         self.check_expr_with_expectation(expr, NoExpectation)
     }
 
     fn check_expr_with_lvalue_pref(&self, expr: &'gcx hir::Expr,
-                                   lvalue_pref: LvaluePreference)  {
+                                   lvalue_pref: LvaluePreference) -> Ty<'tcx> {
         self.check_expr_with_expectation_and_lvalue_pref(expr, NoExpectation, lvalue_pref)
     }
 
@@ -2820,12 +2787,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                          args: &'gcx [P<hir::Expr>],
                          tps: &[P<hir::Ty>],
                          expected: Expectation<'tcx>,
-                         lvalue_pref: LvaluePreference) {
+                         lvalue_pref: LvaluePreference) -> Ty<'tcx> {
         let rcvr = &args[0];
-        self.check_expr_with_lvalue_pref(&rcvr, lvalue_pref);
+        let rcvr_t = self.check_expr_with_lvalue_pref(&rcvr, lvalue_pref);
 
         // no need to check for bot/err -- callee does that
-        let expr_t = self.structurally_resolved_type(expr.span, self.expr_ty(&rcvr));
+        let expr_t = self.structurally_resolved_type(expr.span, rcvr_t);
 
         let tps = tps.iter().map(|ast_ty| self.to_ty(&ast_ty)).collect::<Vec<_>>();
         let fn_ty = match self.lookup_method(method_name.span,
@@ -2856,7 +2823,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                       DontTupleArguments,
                                                       expected);
 
-        self.write_call(expr, ret_ty);
+        ret_ty
     }
 
     // A generic function for checking the then and else in an if
@@ -2865,27 +2832,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                        cond_expr: &'gcx hir::Expr,
                        then_blk: &'gcx hir::Block,
                        opt_else_expr: Option<&'gcx hir::Expr>,
-                       id: ast::NodeId,
                        sp: Span,
-                       expected: Expectation<'tcx>) {
-        self.check_expr_has_type(cond_expr, self.tcx.types.bool);
+                       expected: Expectation<'tcx>) -> Ty<'tcx> {
+        let cond_ty = 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 then_ty = self.check_block_with_expected(then_blk, expected);
 
         let unit = self.tcx.mk_nil();
         let (origin, expected, found, result) =
         if let Some(else_expr) = opt_else_expr {
-            self.check_expr_with_expectation(else_expr, expected);
-            let else_ty = self.expr_ty(else_expr);
+            let else_ty = self.check_expr_with_expectation(else_expr, expected);
             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 = self.try_find_coercion_lub(origin, || Some(&**then),
-                                                     then_ty, else_expr);
+                                                     then_ty, else_expr, else_ty);
 
                 // In case we did perform an adjustment, we have to update
                 // the type of the block, because old trans still uses it.
@@ -2918,9 +2882,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                  }))
         };
 
-        let if_ty = match result {
+        match result {
             Ok(ty) => {
-                if self.expr_ty(cond_expr).references_error() {
+                if cond_ty.references_error() {
                     self.tcx.types.err
                 } else {
                     ty
@@ -2930,9 +2894,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 self.report_mismatched_types(origin, expected, found, e);
                 self.tcx.types.err
             }
-        };
-
-        self.write_ty(id, if_ty);
+        }
     }
 
     // Check field access expressions
@@ -2940,10 +2902,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                    expr: &'gcx hir::Expr,
                    lvalue_pref: LvaluePreference,
                    base: &'gcx hir::Expr,
-                   field: &Spanned<ast::Name>) {
-        self.check_expr_with_lvalue_pref(base, lvalue_pref);
+                   field: &Spanned<ast::Name>) -> Ty<'tcx> {
+        let expr_t = self.check_expr_with_lvalue_pref(base, lvalue_pref);
         let expr_t = self.structurally_resolved_type(expr.span,
-                                                     self.expr_ty(base));
+                                                     expr_t);
         let mut private_candidate = None;
         let mut autoderef = self.autoderef(expr.span, expr_t);
         while let Some((base_t, autoderefs)) = autoderef.next() {
@@ -2954,9 +2916,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         let field_ty = self.field_ty(expr.span, field, substs);
                         if field.vis.is_accessible_from(self.body_id, &self.tcx().map) {
                             autoderef.finalize(lvalue_pref, Some(base));
-                            self.write_ty(expr.id, field_ty);
                             self.write_autoderef_adjustment(base.id, autoderefs);
-                            return;
+                            return field_ty;
                         }
                         private_candidate = Some((base_def.did, field_ty));
                     }
@@ -2968,7 +2929,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         if let Some((did, field_ty)) = private_candidate {
             let struct_path = self.tcx().item_path_str(did);
-            self.write_ty(expr.id, field_ty);
             let msg = format!("field `{}` of struct `{}` is private", field.node, struct_path);
             let mut err = self.tcx().sess.struct_span_err(expr.span, &msg);
             // Also check if an accessible method exists, which is often what is meant.
@@ -2977,8 +2937,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                   field.node));
             }
             err.emit();
+            field_ty
         } else if field.node == keywords::Invalid.name() {
-            self.write_error(expr.id);
+            self.tcx().types.err
         } else if self.method_exists(field.span, field.node, expr_t, expr.id, true) {
             self.type_error_struct(field.span, |actual| {
                 format!("attempted to take value of method `{}` on type \
@@ -2987,7 +2948,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 .help("maybe a `()` to call it is missing? \
                        If not, try an anonymous function")
                 .emit();
-            self.write_error(expr.id);
+            self.tcx().types.err
         } else {
             let mut err = self.type_error_struct(expr.span, |actual| {
                 format!("attempted access of field `{}` on type `{}`, \
@@ -3005,7 +2966,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 _ => {}
             }
             err.emit();
-            self.write_error(expr.id);
+            self.tcx().types.err
         }
     }
 
@@ -3037,10 +2998,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                        expr: &'gcx hir::Expr,
                        lvalue_pref: LvaluePreference,
                        base: &'gcx hir::Expr,
-                       idx: codemap::Spanned<usize>) {
-        self.check_expr_with_lvalue_pref(base, lvalue_pref);
+                       idx: codemap::Spanned<usize>) -> Ty<'tcx> {
+        let expr_t = self.check_expr_with_lvalue_pref(base, lvalue_pref);
         let expr_t = self.structurally_resolved_type(expr.span,
-                                                     self.expr_ty(base));
+                                                     expr_t);
         let mut private_candidate = None;
         let mut tuple_like = false;
         let mut autoderef = self.autoderef(expr.span, expr_t);
@@ -3070,9 +3031,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
             if let Some(field_ty) = field {
                 autoderef.finalize(lvalue_pref, Some(base));
-                self.write_ty(expr.id, field_ty);
                 self.write_autoderef_adjustment(base.id, autoderefs);
-                return;
+                return field_ty;
             }
         }
         autoderef.unambiguous_final_ty();
@@ -3081,8 +3041,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             let struct_path = self.tcx().item_path_str(did);
             let msg = format!("field `{}` of struct `{}` is private", idx.node, struct_path);
             self.tcx().sess.span_err(expr.span, &msg);
-            self.write_ty(expr.id, field_ty);
-            return;
+            return field_ty;
         }
 
         self.type_error_message(
@@ -3102,7 +3061,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             },
             expr_t);
 
-        self.write_error(expr.id);
+        self.tcx().types.err
     }
 
     fn report_unknown_field(&self,
@@ -3205,17 +3164,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     fn check_struct_fields_on_error(&self,
-                                    id: ast::NodeId,
                                     fields: &'gcx [hir::Field],
                                     base_expr: &'gcx Option<P<hir::Expr>>) {
-        // Make sure to still write the types
-        // otherwise we might ICE
-        self.write_error(id);
         for field in fields {
             self.check_expr(&field.expr);
         }
         match *base_expr {
-            Some(ref base) => self.check_expr(&base),
+            Some(ref base) => {
+                self.check_expr(&base);
+            },
             None => {}
         }
     }
@@ -3267,22 +3224,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                          expr: &hir::Expr,
                          path: &hir::Path,
                          fields: &'gcx [hir::Field],
-                         base_expr: &'gcx Option<P<hir::Expr>>)
+                         base_expr: &'gcx Option<P<hir::Expr>>) -> Ty<'tcx>
     {
         // Find the relevant variant
-        let (variant, expr_ty) = if let Some(variant_ty) = self.check_struct_path(path, expr.id,
-                                                                                  expr.span) {
+        let (variant, struct_ty) = if let Some(variant_ty) = self.check_struct_path(path, expr.id,
+                                                                                    expr.span) {
             variant_ty
         } else {
-            self.check_struct_fields_on_error(expr.id, fields, base_expr);
-            return;
+            self.check_struct_fields_on_error(fields, base_expr);
+            return self.tcx().types.err;
         };
 
-        self.check_expr_struct_fields(expr_ty, path.span, variant, fields,
+        self.check_expr_struct_fields(struct_ty, path.span, variant, fields,
                                       base_expr.is_none());
         if let &Some(ref base_expr) = base_expr {
-            self.check_expr_has_type(base_expr, expr_ty);
-            match expr_ty.sty {
+            self.check_expr_has_type(base_expr, struct_ty);
+            match struct_ty.sty {
                 ty::TyStruct(adt, substs) => {
                     self.tables.borrow_mut().fru_field_types.insert(
                         expr.id,
@@ -3299,6 +3256,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             }
         }
+        self.require_type_is_sized(struct_ty, expr.span, traits::StructInitializerSized);
+        struct_ty
     }
 
 
@@ -3315,10 +3274,35 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     fn check_expr_with_expectation_and_lvalue_pref(&self,
                                                    expr: &'gcx hir::Expr,
                                                    expected: Expectation<'tcx>,
-                                                   lvalue_pref: LvaluePreference) {
+                                                   lvalue_pref: LvaluePreference) -> Ty<'tcx> {
         debug!(">> typechecking: expr={:?} expected={:?}",
                expr, expected);
+        let ty = self.check_expr_kind(expr, expected, lvalue_pref);
+
+        self.write_ty(expr.id, ty);
+
+        debug!("type of expr({}) {} is...", expr.id,
+               pprust::expr_to_string(expr));
+        debug!("... {:?}, expected is {:?}",
+               ty,
+               expected);
 
+        // Add adjustments to !-expressions
+        if ty.is_never() {
+            if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(expr.id) {
+                let adj_ty = self.next_diverging_ty_var();
+                let adj = adjustment::AdjustNeverToAny(adj_ty);
+                self.write_adjustment(expr.id, adj);
+                return adj_ty;
+            }
+        }
+        ty
+    }
+
+    fn check_expr_kind(&self,
+                       expr: &'gcx hir::Expr,
+                       expected: Expectation<'tcx>,
+                       lvalue_pref: LvaluePreference) -> Ty<'tcx> {
         let tcx = self.tcx;
         let id = expr.id;
         match expr.node {
@@ -3329,20 +3313,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     _ => NoExpectation
                 }
             });
-            self.check_expr_with_expectation(subexpr, expected_inner);
-            let referent_ty = self.expr_ty(&subexpr);
-            self.write_ty(id, tcx.mk_box(referent_ty));
+            let referent_ty = self.check_expr_with_expectation(subexpr, expected_inner);
+            tcx.mk_box(referent_ty)
           }
 
           hir::ExprLit(ref lit) => {
-            let typ = self.check_lit(&lit, expected);
-            self.write_ty(id, typ);
+            self.check_lit(&lit, expected)
           }
           hir::ExprBinary(op, ref lhs, ref rhs) => {
-            self.check_binop(expr, op, lhs, rhs);
+            self.check_binop(expr, op, lhs, rhs)
           }
           hir::ExprAssignOp(op, ref lhs, ref rhs) => {
-            self.check_binop_assign(expr, op, lhs, rhs);
+            self.check_binop_assign(expr, op, lhs, rhs)
           }
           hir::ExprUnary(unop, ref oprnd) => {
             let expected_inner = match unop {
@@ -3357,10 +3339,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 hir::UnDeref => lvalue_pref,
                 _ => NoPreference
             };
-            self.check_expr_with_expectation_and_lvalue_pref(&oprnd,
-                                                             expected_inner,
-                                                             lvalue_pref);
-            let mut oprnd_t = self.expr_ty(&oprnd);
+            let mut oprnd_t = self.check_expr_with_expectation_and_lvalue_pref(&oprnd,
+                                                                               expected_inner,
+                                                                               lvalue_pref);
 
             if !oprnd_t.references_error() {
                 match unop {
@@ -3402,7 +3383,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
             }
-            self.write_ty(id, oprnd_t);
+            oprnd_t
           }
           hir::ExprAddrOf(mutbl, ref oprnd) => {
             let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| {
@@ -3421,10 +3402,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             });
             let lvalue_pref = LvaluePreference::from_mutbl(mutbl);
-            self.check_expr_with_expectation_and_lvalue_pref(&oprnd, hint, lvalue_pref);
+            let ty = self.check_expr_with_expectation_and_lvalue_pref(&oprnd, hint, lvalue_pref);
 
-            let tm = ty::TypeAndMut { ty: self.expr_ty(&oprnd), mutbl: mutbl };
-            let oprnd_t = if tm.ty.references_error() {
+            let tm = ty::TypeAndMut { ty: ty, mutbl: mutbl };
+            if tm.ty.references_error() {
                 tcx.types.err
             } else {
                 // Note: at this point, we cannot say what the best lifetime
@@ -3442,25 +3423,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // as long as it needs to live.
                 let region = self.next_region_var(infer::AddrOfRegion(expr.span));
                 tcx.mk_ref(region, tm)
-            };
-            self.write_ty(id, oprnd_t);
+            }
           }
           hir::ExprPath(ref opt_qself, ref path) => {
               let opt_self_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty));
               let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(opt_self_ty, path,
                                                                          expr.id, expr.span);
-              if def != Def::Err {
-                  self.instantiate_value_path(segments, opt_ty, def, expr.span, id);
+              let ty = if def != Def::Err {
+                  self.instantiate_value_path(segments, opt_ty, def, expr.span, id)
               } else {
                   self.set_tainted_by_errors();
-                  self.write_error(id);
-              }
+                  tcx.types.err
+              };
 
               // We always require that the type provided as the value for
               // a type parameter outlives the moment of instantiation.
               self.opt_node_ty_substs(expr.id, |item_substs| {
                   self.add_wf_bounds(&item_substs.substs, expr);
               });
+
+              ty
           }
           hir::ExprInlineAsm(_, ref outputs, ref inputs) => {
               for output in outputs {
@@ -3469,10 +3451,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
               for input in inputs {
                   self.check_expr(input);
               }
-              self.write_nil(id);
+              tcx.mk_nil()
           }
-          hir::ExprBreak(_) => { self.write_never(id); }
-          hir::ExprAgain(_) => { self.write_never(id); }
+          hir::ExprBreak(_) => { tcx.types.never }
+          hir::ExprAgain(_) => { tcx.types.never }
           hir::ExprRet(ref expr_opt) => {
             if let Some(ref e) = *expr_opt {
                 self.check_expr_coercable_to_type(&e, self.ret_ty);
@@ -3490,10 +3472,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         .emit();
                 }
             }
-            self.write_never(id);
+            tcx.types.never
           }
           hir::ExprAssign(ref lhs, ref rhs) => {
-            self.check_expr_with_lvalue_pref(&lhs, PreferMutLvalue);
+            let lhs_ty = self.check_expr_with_lvalue_pref(&lhs, PreferMutLvalue);
 
             let tcx = self.tcx;
             if !tcx.expr_is_lval(&lhs) {
@@ -3506,66 +3488,53 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 .emit();
             }
 
-            let lhs_ty = self.expr_ty(&lhs);
-            self.check_expr_coercable_to_type(&rhs, lhs_ty);
-            let rhs_ty = self.expr_ty(&rhs);
+            let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty);
 
-            self.require_expr_have_sized_type(&lhs, traits::AssignmentLhsSized);
+            self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized);
 
             if lhs_ty.references_error() || rhs_ty.references_error() {
-                self.write_error(id);
+                tcx.types.err
             } else {
-                self.write_nil(id);
+                tcx.mk_nil()
             }
           }
           hir::ExprIf(ref cond, ref then_blk, ref opt_else_expr) => {
             self.check_then_else(&cond, &then_blk, opt_else_expr.as_ref().map(|e| &**e),
-                                 id, expr.span, expected);
+                                 expr.span, expected)
           }
           hir::ExprWhile(ref cond, ref body, _) => {
-            self.check_expr_has_type(&cond, tcx.types.bool);
+            let cond_ty = 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() {
-                self.write_error(id);
+                tcx.types.err
             }
             else {
-                self.write_nil(id);
+                tcx.mk_nil()
             }
           }
           hir::ExprLoop(ref body, _) => {
             self.check_block_no_value(&body);
             if !may_break(tcx, expr.id, &body) {
-                self.write_never(id);
+                tcx.types.never
             } else {
-                self.write_nil(id);
+                tcx.mk_nil()
             }
           }
           hir::ExprMatch(ref discrim, ref arms, match_src) => {
-            self.check_match(expr, &discrim, arms, expected, match_src);
+            self.check_match(expr, &discrim, arms, expected, match_src)
           }
           hir::ExprClosure(capture, ref decl, ref body, _) => {
-              self.check_expr_closure(expr, capture, &decl, &body, expected);
+              self.check_expr_closure(expr, capture, &decl, &body, expected)
           }
           hir::ExprBlock(ref b) => {
-            self.check_block_with_expected(&b, expected);
-            self.write_ty(id, self.node_ty(b.id));
+            self.check_block_with_expected(&b, expected)
           }
           hir::ExprCall(ref callee, ref args) => {
-              self.check_call(expr, &callee, &args[..], expected);
-
-              // we must check that return type of called functions is WF:
-              let ret_ty = self.expr_ty(expr);
-              self.register_wf_obligation(ret_ty, expr.span, traits::MiscObligation);
+              self.check_call(expr, &callee, &args[..], expected)
           }
           hir::ExprMethodCall(name, ref tps, ref args) => {
-              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 {
-                  self.write_error(id);
-              }
+              self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref)
           }
           hir::ExprCast(ref e, ref t) => {
             if let hir::TyFixedLengthVec(_, ref count_expr) = t.node {
@@ -3576,26 +3545,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             // if appropriate.
             let t_cast = self.to_ty(t);
             let t_cast = self.resolve_type_vars_if_possible(&t_cast);
-            self.check_expr_with_expectation(e, ExpectCastableToType(t_cast));
-            let t_expr = self.expr_ty(e);
+            let t_expr = self.check_expr_with_expectation(e, ExpectCastableToType(t_cast));
             let t_cast = self.resolve_type_vars_if_possible(&t_cast);
 
             // Eagerly check for some obvious errors.
             if t_expr.references_error() || t_cast.references_error() {
-                self.write_error(id);
+                tcx.types.err
             } else {
-                // Write a type for the whole expression, assuming everything is going
-                // to work out Ok.
-                self.write_ty(id, t_cast);
-
                 // Defer other checks until we're done type checking.
                 let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
                 match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) {
                     Ok(cast_check) => {
                         deferred_cast_checks.push(cast_check);
+                        t_cast
                     }
                     Err(ErrorReported) => {
-                        self.write_error(id);
+                        tcx.types.err
                     }
                 }
             }
@@ -3603,7 +3568,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
           hir::ExprType(ref e, ref t) => {
             let typ = self.to_ty(&t);
             self.check_expr_eq_type(&e, typ);
-            self.write_ty(id, typ);
+            typ
           }
           hir::ExprVec(ref args) => {
             let uty = expected.to_option(self).and_then(|uty| {
@@ -3617,16 +3582,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             let coerce_to = uty.unwrap_or(unified);
 
             for (i, e) in args.iter().enumerate() {
-                self.check_expr_with_hint(e, coerce_to);
-                let e_ty = self.expr_ty(e);
+                let e_ty = self.check_expr_with_hint(e, coerce_to);
                 let origin = TypeOrigin::Misc(e.span);
 
                 // Special-case the first element, as it has no "previous expressions".
                 let result = if i == 0 {
-                    self.try_coerce(e, coerce_to)
+                    self.try_coerce(e, e_ty, coerce_to)
                 } else {
                     let prev_elems = || args[..i].iter().map(|e| &**e);
-                    self.try_find_coercion_lub(origin, prev_elems, unified, e)
+                    self.try_find_coercion_lub(origin, prev_elems, unified, e, e_ty)
                 };
 
                 match result {
@@ -3636,7 +3600,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
             }
-            self.write_ty(id, tcx.mk_array(unified, args.len()));
+            tcx.mk_array(unified, args.len())
           }
           hir::ExprRepeat(ref element, ref count_expr) => {
             self.check_expr_has_type(&count_expr, tcx.types.usize);
@@ -3660,8 +3624,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
                 None => {
                     let t: Ty = self.next_ty_var();
-                    self.check_expr_has_type(&element, t);
-                    (self.expr_ty(&element), t)
+                    let element_ty = self.check_expr_has_type(&element, t);
+                    (element_ty, t)
                 }
             };
 
@@ -3672,10 +3636,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
 
             if element_ty.references_error() {
-                self.write_error(id);
+                tcx.types.err
             } else {
-                let t = tcx.mk_array(t, count);
-                self.write_ty(id, t);
+                tcx.mk_array(t, count)
             }
           }
           hir::ExprTup(ref elts) => {
@@ -3695,49 +3658,41 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         ety
                     }
                     _ => {
-                        self.check_expr_with_expectation(&e, NoExpectation);
-                        self.expr_ty(&e)
+                        self.check_expr_with_expectation(&e, NoExpectation)
                     }
                 };
                 err_field = err_field || t.references_error();
                 t
             }).collect();
             if err_field {
-                self.write_error(id);
+                tcx.types.err
             } else {
-                let typ = tcx.mk_tup(elt_ts);
-                self.write_ty(id, typ);
+                tcx.mk_tup(elt_ts)
             }
           }
           hir::ExprStruct(ref path, ref fields, ref base_expr) => {
-            self.check_expr_struct(expr, path, fields, base_expr);
-
-            self.require_expr_have_sized_type(expr, traits::StructInitializerSized);
+            self.check_expr_struct(expr, path, fields, base_expr)
           }
           hir::ExprField(ref base, ref field) => {
-            self.check_field(expr, lvalue_pref, &base, field);
+            self.check_field(expr, lvalue_pref, &base, field)
           }
           hir::ExprTupField(ref base, idx) => {
-            self.check_tup_field(expr, lvalue_pref, &base, idx);
+            self.check_tup_field(expr, lvalue_pref, &base, idx)
           }
           hir::ExprIndex(ref base, ref idx) => {
-              self.check_expr_with_lvalue_pref(&base, lvalue_pref);
-              self.check_expr(&idx);
-
-              let base_t = self.expr_ty(&base);
-              let idx_t = self.expr_ty(&idx);
+              let base_t = self.check_expr_with_lvalue_pref(&base, lvalue_pref);
+              let idx_t = self.check_expr(&idx);
 
               if base_t.references_error() {
-                  self.write_ty(id, base_t);
+                  base_t
               } else if idx_t.references_error() {
-                  self.write_ty(id, idx_t);
+                  idx_t
               } else {
                   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 = self.expr_ty(idx);
-                          self.demand_eqtype(expr.span, index_ty, idx_expr_ty);
-                          self.write_ty(id, element_ty);
+                          self.demand_eqtype(expr.span, index_ty, idx_t);
+                          element_ty
                       }
                       None => {
                           self.check_expr_has_type(&idx, self.tcx.types.err);
@@ -3773,18 +3728,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                               }
                           }
                           err.emit();
-                          self.write_ty(id, self.tcx().types.err);
+                          self.tcx().types.err
                       }
                   }
               }
            }
         }
-
-        debug!("type of expr({}) {} is...", expr.id,
-               pprust::expr_to_string(expr));
-        debug!("... {:?}, expected is {:?}",
-               self.expr_ty(expr),
-               expected);
     }
 
     // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary.
@@ -3864,7 +3813,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
     pub fn check_decl_initializer(&self,
                                   local: &'gcx hir::Local,
-                                  init: &'gcx hir::Expr)
+                                  init: &'gcx hir::Expr) -> Ty<'tcx>
     {
         let ref_bindings = self.tcx.pat_contains_ref_binding(&local.pat);
 
@@ -3878,12 +3827,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             // referent for the reference that results is *equal to* the
             // type of the lvalue it is referencing, and not some
             // supertype thereof.
-            self.check_expr_with_lvalue_pref(init, LvaluePreference::from_mutbl(m));
-            let init_ty = self.expr_ty(init);
+            let init_ty = self.check_expr_with_lvalue_pref(init, LvaluePreference::from_mutbl(m));
             self.demand_eqtype(init.span, init_ty, local_ty);
+            init_ty
         } else {
             self.check_expr_coercable_to_type(init, local_ty)
-        };
+        }
     }
 
     pub fn check_decl_local(&self, local: &'gcx hir::Local)  {
@@ -3891,8 +3840,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.write_ty(local.id, t);
 
         if let Some(ref init) = local.init {
-            self.check_decl_initializer(local, &init);
-            let init_ty = self.expr_ty(&init);
+            let init_ty = self.check_decl_initializer(local, &init);
             if init_ty.references_error() {
                 self.write_ty(local.id, init_ty);
             }
@@ -3905,7 +3853,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn check_stmt(&self, stmt: &'gcx hir::Stmt)  {
+    pub fn check_stmt(&self, stmt: &'gcx hir::Stmt) {
         let node_id;
         let mut saw_bot = false;
         let mut saw_err = false;
@@ -3925,17 +3873,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
           hir::StmtExpr(ref expr, id) => {
             node_id = id;
             // Check with expected type of ()
-            self.check_expr_has_type(&expr, self.tcx.mk_nil());
-            let expr_ty = self.expr_ty(&expr);
-            saw_bot = saw_bot || self.type_var_diverges(expr_ty);
-            saw_err = saw_err || expr_ty.references_error();
+            let ty = self.check_expr_has_type(&expr, self.tcx.mk_nil());
+            saw_bot = saw_bot || self.type_var_diverges(ty);
+            saw_err = saw_err || ty.references_error();
           }
           hir::StmtSemi(ref expr, id) => {
             node_id = id;
-            self.check_expr(&expr);
-            let expr_ty = self.expr_ty(&expr);
-            saw_bot |= self.type_var_diverges(expr_ty);
-            saw_err |= expr_ty.references_error();
+            let ty = self.check_expr(&expr);
+            saw_bot |= self.type_var_diverges(ty);
+            saw_err |= ty.references_error();
           }
         }
         if saw_bot {
@@ -3945,13 +3891,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.write_error(node_id);
         }
         else {
-            self.write_nil(node_id)
+            self.write_nil(node_id);
         }
     }
 
     pub fn check_block_no_value(&self, blk: &'gcx hir::Block)  {
-        self.check_block_with_expected(blk, ExpectHasType(self.tcx.mk_nil()));
-        let blkty = self.node_ty(blk.id);
+        let blkty = self.check_block_with_expected(blk, ExpectHasType(self.tcx.mk_nil()));
         if blkty.references_error() {
             self.write_error(blk.id);
         } else {
@@ -3962,7 +3907,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
     fn check_block_with_expected(&self,
                                  blk: &'gcx hir::Block,
-                                 expected: Expectation<'tcx>) {
+                                 expected: Expectation<'tcx>) -> Ty<'tcx> {
         let prev = {
             let mut fcx_ps = self.ps.borrow_mut();
             let unsafety_state = fcx_ps.recurse(blk);
@@ -3999,13 +3944,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                            s_ty.is_never();
             any_err = any_err || s_ty.references_error();
         }
-        match blk.expr {
+        let ty = match blk.expr {
             None => if any_err {
-                self.write_error(blk.id);
+                self.tcx.types.err
             } else if any_diverges {
-                self.write_ty(blk.id, self.next_diverging_ty_var());
+                self.next_diverging_ty_var()
             } else {
-                self.write_nil(blk.id);
+                self.tcx.mk_nil()
             },
             Some(ref e) => {
                 if any_diverges && !warned {
@@ -4022,22 +3967,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         ety
                     }
                     _ => {
-                        self.check_expr_with_expectation(&e, expected);
-                        self.expr_ty(&e)
+                        self.check_expr_with_expectation(&e, expected)
                     }
                 };
 
                 if any_err {
-                    self.write_error(blk.id);
+                    self.tcx.types.err
                 } else if any_diverges {
-                    self.write_ty(blk.id, self.next_diverging_ty_var());
+                    self.next_diverging_ty_var()
                 } else {
-                    self.write_ty(blk.id, ety);
+                    ety
                 }
             }
         };
+        self.write_ty(blk.id, ty);
 
         *self.ps.borrow_mut() = prev;
+        ty
     }
 
     // Instantiates the given path, which must refer to an item with the given
@@ -4348,7 +4294,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         debug!("instantiate_value_path: type of {:?} is {:?}",
                node_id,
                ty_substituted);
-        self.write_ty(node_id, ty_substituted);
         self.write_substs(node_id, ty::ItemSubsts {
             substs: substs
         });
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index a8b1683f6d3..411bd7e7b5c 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -23,21 +23,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                               expr: &'gcx hir::Expr,
                               op: hir::BinOp,
                               lhs_expr: &'gcx hir::Expr,
-                              rhs_expr: &'gcx hir::Expr)
+                              rhs_expr: &'gcx hir::Expr) -> Ty<'tcx>
     {
-        self.check_expr_with_lvalue_pref(lhs_expr, PreferMutLvalue);
+        let lhs_ty = self.check_expr_with_lvalue_pref(lhs_expr, PreferMutLvalue);
 
-        let lhs_ty = self.resolve_type_vars_with_obligations(self.expr_ty(lhs_expr));
+        let lhs_ty = self.resolve_type_vars_with_obligations(lhs_ty);
         let (rhs_ty, return_ty) =
             self.check_overloaded_binop(expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::Yes);
         let rhs_ty = self.resolve_type_vars_with_obligations(rhs_ty);
 
-        if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) {
+        let ty = if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var()
+                    && is_builtin_binop(lhs_ty, rhs_ty, op) {
             self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op);
-            self.write_nil(expr.id);
+            self.tcx.mk_nil()
         } else {
-            self.write_ty(expr.id, return_ty);
-        }
+            return_ty
+        };
 
         let tcx = self.tcx;
         if !tcx.expr_is_lval(lhs_expr) {
@@ -49,6 +50,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 &format!("invalid expression for left-hand side"))
             .emit();
         }
+        ty
     }
 
     /// Check a potentially overloaded binary operator.
@@ -56,7 +58,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                        expr: &'gcx hir::Expr,
                        op: hir::BinOp,
                        lhs_expr: &'gcx hir::Expr,
-                       rhs_expr: &'gcx hir::Expr)
+                       rhs_expr: &'gcx hir::Expr) -> Ty<'tcx>
     {
         let tcx = self.tcx;
 
@@ -67,15 +69,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                lhs_expr,
                rhs_expr);
 
-        self.check_expr(lhs_expr);
-        let lhs_ty = self.resolve_type_vars_with_obligations(self.expr_ty(lhs_expr));
+        let lhs_ty = self.check_expr(lhs_expr);
+        let lhs_ty = self.resolve_type_vars_with_obligations(lhs_ty);
 
         match BinOpCategory::from(op) {
             BinOpCategory::Shortcircuit => {
                 // && and || are a simple case.
                 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());
+                tcx.mk_bool()
             }
             _ => {
                 // Otherwise, we always treat operators as if they are
@@ -107,7 +109,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     self.demand_suptype(expr.span, builtin_return_ty, return_ty);
                 }
 
-                self.write_ty(expr.id, return_ty);
+                return_ty
             }
         }
     }