From b2422ab806b9a6c2c52e0bd690486df1950f7339 Mon Sep 17 00:00:00 2001
From: Ariel Ben-Yehuda <ariel.byd@gmail.com>
Date: Fri, 8 Jul 2016 22:51:29 +0300
Subject: [PATCH 01/14] remove never-called type-error reporting functions

---
 src/librustc/infer/mod.rs | 88 +++++++++------------------------------
 1 file changed, 19 insertions(+), 69 deletions(-)

diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 2ea2978b294..fc5625036ae 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -1468,75 +1468,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     // error type, meaning that an error occurred when typechecking this expression),
     // this is a derived error. The error cascaded from another error (that was already
     // reported), so it's not useful to display it to the user.
-    // The following four methods -- type_error_message_str, type_error_message_str_with_expected,
-    // type_error_message, and report_mismatched_types -- implement this logic.
+    // The following methods implement this logic.
     // They check if either the actual or expected type is TyError, and don't print the error
     // in this case. The typechecker should only ever report type errors involving mismatched
-    // types using one of these four methods, and should not call span_err directly for such
+    // types using one of these methods, and should not call span_err directly for such
     // errors.
-    pub fn type_error_message_str<M>(&self,
-                                     sp: Span,
-                                     mk_msg: M,
-                                     actual_ty: String,
-                                     err: Option<&TypeError<'tcx>>)
-        where M: FnOnce(Option<String>, String) -> String,
-    {
-        self.type_error_message_str_with_expected(sp, mk_msg, None, actual_ty, err)
-    }
-
-    pub fn type_error_struct_str<M>(&self,
-                                    sp: Span,
-                                    mk_msg: M,
-                                    actual_ty: String,
-                                    err: Option<&TypeError<'tcx>>)
-                                    -> DiagnosticBuilder<'tcx>
-        where M: FnOnce(Option<String>, String) -> String,
-    {
-        self.type_error_struct_str_with_expected(sp, mk_msg, None, actual_ty, err)
-    }
-
-    pub fn type_error_message_str_with_expected<M>(&self,
-                                                   sp: Span,
-                                                   mk_msg: M,
-                                                   expected_ty: Option<Ty<'tcx>>,
-                                                   actual_ty: String,
-                                                   err: Option<&TypeError<'tcx>>)
-        where M: FnOnce(Option<String>, String) -> String,
-    {
-        self.type_error_struct_str_with_expected(sp, mk_msg, expected_ty, actual_ty, err)
-            .emit();
-    }
-
-    pub fn type_error_struct_str_with_expected<M>(&self,
-                                                  sp: Span,
-                                                  mk_msg: M,
-                                                  expected_ty: Option<Ty<'tcx>>,
-                                                  actual_ty: String,
-                                                  err: Option<&TypeError<'tcx>>)
-                                                  -> DiagnosticBuilder<'tcx>
-        where M: FnOnce(Option<String>, String) -> String,
-    {
-        debug!("hi! expected_ty = {:?}, actual_ty = {}", expected_ty, actual_ty);
-
-        let resolved_expected = expected_ty.map(|e_ty| self.resolve_type_vars_if_possible(&e_ty));
-
-        if !resolved_expected.references_error() {
-            let error_str = err.map_or("".to_string(), |t_err| {
-                format!(" ({})", t_err)
-            });
-
-            let mut db = self.tcx.sess.struct_span_err(sp, &format!("{}{}",
-                mk_msg(resolved_expected.map(|t| self.ty_to_string(t)), actual_ty),
-                error_str));
-
-            if let Some(err) = err {
-                self.tcx.note_and_explain_type_err(&mut db, err, sp);
-            }
-            db
-        } else {
-            self.tcx.sess.diagnostic().struct_dummy()
-        }
-    }
 
     pub fn type_error_message<M>(&self,
                                  sp: Span,
@@ -1556,6 +1492,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                 -> DiagnosticBuilder<'tcx>
         where M: FnOnce(String) -> String,
     {
+        debug!("type_error_struct({:?}, {:?}, {:?})", sp, actual_ty, err);
+
         let actual_ty = self.resolve_type_vars_if_possible(&actual_ty);
 
         // Don't report an error if actual type is TyError.
@@ -1563,9 +1501,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             return self.tcx.sess.diagnostic().struct_dummy();
         }
 
-        self.type_error_struct_str(sp,
-            move |_e, a| { mk_msg(a) },
-            self.ty_to_string(actual_ty), err)
+        let error_str = err.map_or("".to_string(), |t_err| {
+            format!(" ({})", t_err)
+        });
+
+        let msg = mk_msg(self.ty_to_string(actual_ty));
+
+        // FIXME: use an error code.
+        let mut db = self.tcx.sess.struct_span_err(
+            sp, &format!("{} {}", msg, error_str));
+
+        if let Some(err) = err {
+            self.tcx.note_and_explain_type_err(&mut db, err, sp);
+        }
+
+        db
     }
 
     pub fn report_mismatched_types(&self,

From 8eb12d91aaf95432ca73bda429af04e0710c984d Mon Sep 17 00:00:00 2001
From: Ariel Ben-Yehuda <ariel.byd@gmail.com>
Date: Sat, 16 Jul 2016 19:38:17 +0300
Subject: [PATCH 02/14] remove rustc_typeck::same_type_err

---
 src/librustc/infer/error_reporting.rs         | 10 +++
 src/librustc/infer/mod.rs                     | 64 ++++++++++++++++++-
 src/librustc/ty/structural_impls.rs           | 13 ++++
 src/librustc_typeck/check/_match.rs           | 10 +--
 src/librustc_typeck/check/demand.rs           | 12 ----
 src/librustc_typeck/check/intrinsic.rs        |  6 +-
 src/librustc_typeck/check/wfcheck.rs          |  3 +-
 src/librustc_typeck/diagnostics.rs            |  2 +
 src/librustc_typeck/lib.rs                    | 36 ++++-------
 src/test/compile-fail/issue-26194.rs          |  2 +-
 src/test/compile-fail/match-range-fail.rs     |  5 +-
 .../compile-fail/ufcs-explicit-self-bad.rs    |  6 +-
 12 files changed, 114 insertions(+), 55 deletions(-)

diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index 96ecad629f5..a0fa188c4f8 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -554,6 +554,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                          trace: TypeTrace<'tcx>,
                                          terr: &TypeError<'tcx>)
                                          -> DiagnosticBuilder<'tcx> {
+        let trace = self.resolve_type_vars_if_possible(&trace);
         let span = trace.origin.span();
         let mut err = self.report_type_error(trace, terr);
         self.tcx.note_and_explain_type_err(&mut err, terr, span);
@@ -1643,6 +1644,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                     TypeOrigin::EquatePredicate(_) => {
                         "equality where clause is satisfied"
                     }
+                    TypeOrigin::MainFunctionType(_) => {
+                        "the `main` function has the correct type"
+                    }
+                    TypeOrigin::StartFunctionType(_) => {
+                        "the `start` function has the correct type"
+                    }
+                    TypeOrigin::IntrinsicType(_) => {
+                        "the intrinsic has the correct type"
+                    }
                 };
 
                 match self.values_str(&trace.values) {
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index fc5625036ae..dc262e61dd0 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -32,7 +32,7 @@ use ty::adjustment;
 use ty::{TyVid, IntVid, FloatVid};
 use ty::{self, Ty, TyCtxt};
 use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
-use ty::fold::TypeFoldable;
+use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use ty::relate::{Relate, RelateResult, TypeRelation};
 use traits::{self, PredicateObligations, ProjectionMode};
 use rustc_data_structures::unify::{self, UnificationTable};
@@ -219,6 +219,15 @@ pub enum TypeOrigin {
 
     // `where a == b`
     EquatePredicate(Span),
+
+    // `main` has wrong type
+    MainFunctionType(Span),
+
+    // `start` has wrong type
+    StartFunctionType(Span),
+
+    // intrinsic has wrong type
+    IntrinsicType(Span),
 }
 
 impl TypeOrigin {
@@ -238,6 +247,9 @@ impl TypeOrigin {
             &TypeOrigin::IfExpressionWithNoElse(_) => "if may be missing an else clause",
             &TypeOrigin::RangeExpression(_) => "start and end of range have incompatible types",
             &TypeOrigin::EquatePredicate(_) => "equality predicate not satisfied",
+            &TypeOrigin::MainFunctionType(_) => "main function has wrong type",
+            &TypeOrigin::StartFunctionType(_) => "start function has wrong type",
+            &TypeOrigin::IntrinsicType(_) => "intrinsic has wrong type",
         }
     }
 }
@@ -1791,6 +1803,9 @@ impl TypeOrigin {
             TypeOrigin::IfExpressionWithNoElse(span) => span,
             TypeOrigin::RangeExpression(span) => span,
             TypeOrigin::EquatePredicate(span) => span,
+            TypeOrigin::MainFunctionType(span) => span,
+            TypeOrigin::StartFunctionType(span) => span,
+            TypeOrigin::IntrinsicType(span) => span,
         }
     }
 }
@@ -1841,3 +1856,50 @@ impl RegionVariableOrigin {
         }
     }
 }
+
+impl<'tcx> TypeFoldable<'tcx> for TypeOrigin {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self {
+        self.clone()
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool {
+        false
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ValuePairs<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        match *self {
+            ValuePairs::Types(ref ef) => {
+                ValuePairs::Types(ef.fold_with(folder))
+            }
+            ValuePairs::TraitRefs(ref ef) => {
+                ValuePairs::TraitRefs(ef.fold_with(folder))
+            }
+            ValuePairs::PolyTraitRefs(ref ef) => {
+                ValuePairs::PolyTraitRefs(ef.fold_with(folder))
+            }
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        match *self {
+            ValuePairs::Types(ref ef) => ef.visit_with(visitor),
+            ValuePairs::TraitRefs(ref ef) => ef.visit_with(visitor),
+            ValuePairs::PolyTraitRefs(ref ef) => ef.visit_with(visitor),
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for TypeTrace<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        TypeTrace {
+            origin: self.origin.fold_with(folder),
+            values: self.values.fold_with(folder)
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.origin.visit_with(visitor) || self.values.visit_with(visitor)
+    }
+}
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 1e2920ca87e..16a54c20925 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -1018,3 +1018,16 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeScheme<'tcx>  {
         self.generics.visit_with(visitor) || self.ty.visit_with(visitor)
     }
 }
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::error::ExpectedFound<T> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        ty::error::ExpectedFound {
+            expected: self.expected.fold_with(folder),
+            found: self.found.fold_with(folder),
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.expected.visit_with(visitor) || self.found.visit_with(visitor)
+    }
+}
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index e90b32cd5df..aae6e3ad36d 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -103,15 +103,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     return;
                 }
 
-                // Check that the types of the end-points can be unified.
-                let types_unify = self.require_same_types(pat.span, rhs_ty, lhs_ty,
-                                                          "mismatched types in range");
-
-                // It's ok to return without a message as `require_same_types` prints an error.
-                if !types_unify {
-                    return;
-                }
-
                 // Now that we know the types can be unified we find the unified type and use
                 // it to type the entire expression.
                 let common_type = self.resolve_type_vars_if_possible(&lhs_ty);
@@ -120,6 +111,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
                 // 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);
             }
             PatKind::Binding(bm, _, ref sub) => {
                 let typ = self.local_ty(pat.span, pat.id);
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index eeebd6a7f62..c1f415b3c02 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -54,16 +54,4 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.report_mismatched_types(origin, expected, expr_ty, e);
         }
     }
-
-    pub fn require_same_types(&self, span: Span, t1: Ty<'tcx>, t2: Ty<'tcx>, msg: &str)
-                              -> bool {
-        if let Err(err) = self.eq_types(false, TypeOrigin::Misc(span), t1, t2) {
-            let found_ty = self.resolve_type_vars_if_possible(&t1);
-            let expected_ty = self.resolve_type_vars_if_possible(&t2);
-            ::emit_type_err(self.tcx, span, found_ty, expected_ty, &err, msg);
-            false
-        } else {
-            true
-        }
-    }
 }
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 5a3268e9e44..8a53c59b4c7 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -12,6 +12,7 @@
 //! intrinsics that the compiler exposes.
 
 use intrinsics;
+use rustc::infer::TypeOrigin;
 use rustc::ty::subst::{self, Substs};
 use rustc::ty::FnSig;
 use rustc::ty::{self, Ty};
@@ -56,10 +57,9 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
              i_n_tps, n_tps);
     } else {
         require_same_types(ccx,
-                           it.span,
+                           TypeOrigin::IntrinsicType(it.span),
                            i_ty.ty,
-                           fty,
-                           "intrinsic has wrong type");
+                           fty);
     }
 }
 
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index d101381e256..2d44a85f9af 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -437,8 +437,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
 
         debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty);
 
-        fcx.require_same_types(span, sig.inputs[0], rcvr_ty,
-                               "mismatched method receiver");
+        fcx.demand_eqtype(span, rcvr_ty, sig.inputs[0]);
     }
 
     fn check_variances_for_type_defn(&self,
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 8769bc1a32b..683328f4eb4 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -2660,6 +2660,7 @@ For information on the design of the orphan rules, see [RFC 1023].
 [RFC 1023]: https://github.com/rust-lang/rfcs/pull/1023
 "##,
 
+/*
 E0211: r##"
 You used a function or type which doesn't fit the requirements for where it was
 used. Erroneous code examples:
@@ -2739,6 +2740,7 @@ impl Foo {
 }
 ```
 "##,
+     */
 
 E0214: r##"
 A generic type was described using parentheses rather than angle brackets. For
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 84452589dfd..3b2d02dc861 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -186,28 +186,14 @@ fn require_c_abi_if_variadic(tcx: TyCtxt,
     }
 }
 
-pub fn emit_type_err<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                     span: Span,
-                                     found_ty: Ty<'tcx>,
-                                     expected_ty: Ty<'tcx>,
-                                     terr: &ty::error::TypeError<'tcx>,
-                                     msg: &str) {
-    let mut err = struct_span_err!(tcx.sess, span, E0211, "{}", msg);
-    err.span_label(span, &terr);
-    err.note_expected_found(&"type", &expected_ty, &found_ty);
-    tcx.note_and_explain_type_err(&mut err, terr, span);
-    err.emit();
-}
-
 fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                span: Span,
+                                origin: TypeOrigin,
                                 t1: Ty<'tcx>,
-                                t2: Ty<'tcx>,
-                                msg: &str)
+                                t2: Ty<'tcx>)
                                 -> bool {
     ccx.tcx.infer_ctxt(None, None, ProjectionMode::AnyFinal).enter(|infcx| {
-        if let Err(err) = infcx.eq_types(false, TypeOrigin::Misc(span), t1, t2) {
-            emit_type_err(infcx.tcx, span, t1, t2, &err, msg);
+        if let Err(err) = infcx.eq_types(false, origin.clone(), t1, t2) {
+            infcx.report_mismatched_types(origin, t1, t2, err);
             false
         } else {
             true
@@ -249,8 +235,11 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
                 })
             }));
 
-            require_same_types(ccx, main_span, main_t, se_ty,
-                               "main function has wrong type");
+            require_same_types(
+                ccx,
+                TypeOrigin::MainFunctionType(main_span),
+                main_t,
+                se_ty);
         }
         _ => {
             span_bug!(main_span,
@@ -298,8 +287,11 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
                 }),
             }));
 
-            require_same_types(ccx, start_span, start_t, se_ty,
-                               "start function has wrong type");
+            require_same_types(
+                ccx,
+                TypeOrigin::StartFunctionType(start_span),
+                start_t,
+                se_ty);
         }
         _ => {
             span_bug!(start_span,
diff --git a/src/test/compile-fail/issue-26194.rs b/src/test/compile-fail/issue-26194.rs
index ef91188c5d1..1bc0a4f9652 100644
--- a/src/test/compile-fail/issue-26194.rs
+++ b/src/test/compile-fail/issue-26194.rs
@@ -12,7 +12,7 @@ struct S(String);
 
 impl S {
     fn f(self: *mut S) -> String { self.0 }
-    //~^ ERROR mismatched method receiver
+    //~^ ERROR mismatched types
 }
 
 fn main() { S("".to_owned()).f(); }
diff --git a/src/test/compile-fail/match-range-fail.rs b/src/test/compile-fail/match-range-fail.rs
index 526aa83dec7..2c4c2563021 100644
--- a/src/test/compile-fail/match-range-fail.rs
+++ b/src/test/compile-fail/match-range-fail.rs
@@ -27,6 +27,7 @@ fn main() {
         'c' ... 100 => { }
         _ => { }
     };
-    //~^^^ ERROR mismatched types in range
-    //~| expected char, found integral variable
+    //~^^^ ERROR mismatched types
+    //~| expected type `_`
+    //~| found type `char`
 }
diff --git a/src/test/compile-fail/ufcs-explicit-self-bad.rs b/src/test/compile-fail/ufcs-explicit-self-bad.rs
index f14a3505cde..e997cf47c73 100644
--- a/src/test/compile-fail/ufcs-explicit-self-bad.rs
+++ b/src/test/compile-fail/ufcs-explicit-self-bad.rs
@@ -15,7 +15,7 @@ struct Foo {
 }
 
 impl Foo {
-    fn foo(self: isize, x: isize) -> isize {  //~ ERROR mismatched method receiver
+    fn foo(self: isize, x: isize) -> isize {  //~ ERROR mismatched types
         self.f + x
     }
 }
@@ -25,10 +25,10 @@ struct Bar<T> {
 }
 
 impl<T> Bar<T> {
-    fn foo(self: Bar<isize>, x: isize) -> isize { //~ ERROR mismatched method receiver
+    fn foo(self: Bar<isize>, x: isize) -> isize { //~ ERROR mismatched types
         x
     }
-    fn bar(self: &Bar<usize>, x: isize) -> isize {   //~ ERROR mismatched method receiver
+    fn bar(self: &Bar<usize>, x: isize) -> isize {   //~ ERROR mismatched types
         x
     }
 }

From cea88ebb39402ceee9ec5f7cd61c877ae4cd16dc Mon Sep 17 00:00:00 2001
From: Ariel Ben-Yehuda <ariel.byd@gmail.com>
Date: Sat, 16 Jul 2016 23:18:20 +0300
Subject: [PATCH 03/14] refactor type error reporting

---
 src/librustc/infer/error_reporting.rs       | 233 +++++++-------------
 src/librustc/infer/mod.rs                   |  48 ++--
 src/librustc/macros.rs                      |  12 +
 src/librustc_typeck/check/callee.rs         |   2 +-
 src/librustc_typeck/check/cast.rs           |  15 +-
 src/librustc_typeck/check/method/suggest.rs |   3 +-
 src/librustc_typeck/check/mod.rs            |  27 +--
 src/librustc_typeck/check/op.rs             |   2 +-
 8 files changed, 140 insertions(+), 202 deletions(-)

diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index a0fa188c4f8..be73818c8a4 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -83,7 +83,7 @@ use hir::def_id::DefId;
 use infer::{self, TypeOrigin};
 use middle::region;
 use ty::subst;
-use ty::{self, Ty, TyCtxt, TypeFoldable};
+use ty::{self, TyCtxt, TypeFoldable};
 use ty::{Region, ReFree};
 use ty::error::TypeError;
 
@@ -462,52 +462,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    fn report_type_error(&self,
-                         trace: TypeTrace<'tcx>,
-                         terr: &TypeError<'tcx>)
-                         -> DiagnosticBuilder<'tcx> {
-        let (expected, found) = match self.values_str(&trace.values) {
-            Some(v) => v,
-            None => {
-                return self.tcx.sess.diagnostic().struct_dummy(); /* derived error */
-            }
-        };
-
-        let is_simple_error = if let &TypeError::Sorts(ref values) = terr {
-            values.expected.is_primitive() && values.found.is_primitive()
-        } else {
-            false
-        };
-
-        let mut err = struct_span_err!(self.tcx.sess,
-                                       trace.origin.span(),
-                                       E0308,
-                                       "{}",
-                                       trace.origin);
-
-        if !is_simple_error || check_old_school() {
-            err.note_expected_found(&"type", &expected, &found);
-        }
-
-        err.span_label(trace.origin.span(), &terr);
-
-        self.check_and_note_conflicting_crates(&mut err, terr, trace.origin.span());
-
-        match trace.origin {
-            TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source {
-                hir::MatchSource::IfLetDesugar{..} => {
-                    err.span_note(arm_span, "`if let` arm with an incompatible type");
-                }
-                _ => {
-                    err.span_note(arm_span, "match arm with an incompatible type");
-                }
-            },
-            _ => ()
-        }
-
-        err
-    }
-
     /// Adds a note if the types come from similarly named crates
     fn check_and_note_conflicting_crates(&self,
                                          err: &mut DiagnosticBuilder,
@@ -550,43 +504,91 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn report_and_explain_type_error(&self,
-                                         trace: TypeTrace<'tcx>,
-                                         terr: &TypeError<'tcx>)
-                                         -> DiagnosticBuilder<'tcx> {
-        let trace = self.resolve_type_vars_if_possible(&trace);
+    fn note_error_origin(&self,
+                         err: &mut DiagnosticBuilder<'tcx>,
+                         origin: &TypeOrigin)
+    {
+        match origin {
+            &TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source {
+                hir::MatchSource::IfLetDesugar {..} => {
+                    err.span_note(arm_span, "`if let` arm with an incompatible type");
+                }
+                _ => {
+                    err.span_note(arm_span, "match arm with an incompatible type");
+                }
+            },
+            _ => ()
+        }
+    }
+
+    pub fn report_and_explain_type_error_with_code(&self,
+                                                   trace: TypeTrace<'tcx>,
+                                                   terr: &TypeError<'tcx>,
+                                                   message: &str,
+                                                   code: &str)
+                                                   -> DiagnosticBuilder<'tcx>
+    {
+        let (expected, found) = match self.values_str(&trace.values) {
+            Some((expected, found)) => (expected, found),
+            None => return self.tcx.sess.diagnostic().struct_dummy() /* derived error */
+        };
+
         let span = trace.origin.span();
-        let mut err = self.report_type_error(trace, terr);
+
+        let is_simple_error = if let &TypeError::Sorts(ref values) = terr {
+            values.expected.is_primitive() && values.found.is_primitive()
+        } else {
+            false
+        };
+
+        let mut err = self.tcx.sess.struct_span_err_with_code(
+            trace.origin.span(),
+            message,
+            code);
+
+        if !is_simple_error || check_old_school() {
+            err.note_expected_found(&"type", &expected, &found);
+        }
+
+        err.span_label(span, &terr);
+
+        self.note_error_origin(&mut err, &trace.origin);
+        self.check_and_note_conflicting_crates(&mut err, terr, span);
         self.tcx.note_and_explain_type_err(&mut err, terr, span);
+
         err
     }
 
-    /// Returns a string of the form "expected `{}`, found `{}`", or None if this is a derived
-    /// error.
+    pub fn report_and_explain_type_error(&self,
+                                         trace: TypeTrace<'tcx>,
+                                         terr: &TypeError<'tcx>)
+                                         -> DiagnosticBuilder<'tcx>
+    {
+        // FIXME: do we want to use a different error code for each origin?
+        let failure_str = trace.origin.as_failure_str();
+        type_err!(self, trace, terr, E0308, "{}", failure_str)
+    }
+
+    /// Returns a string of the form "expected `{}`, found `{}`".
     fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<(String, String)> {
         match *values {
             infer::Types(ref exp_found) => self.expected_found_str(exp_found),
             infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found),
-            infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found)
+            infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found),
         }
     }
 
-    fn expected_found_str<T: fmt::Display + Resolvable<'tcx> + TypeFoldable<'tcx>>(
+    fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>(
         &self,
         exp_found: &ty::error::ExpectedFound<T>)
         -> Option<(String, String)>
     {
-        let expected = exp_found.expected.resolve(self);
-        if expected.references_error() {
+        let exp_found = self.resolve_type_vars_if_possible(exp_found);
+        if exp_found.references_error() {
             return None;
         }
 
-        let found = exp_found.found.resolve(self);
-        if found.references_error() {
-            return None;
-        }
-
-        Some((format!("{}", expected), format!("{}", found)))
+        Some((format!("{}", exp_found.expected), format!("{}", exp_found.found)))
     }
 
     fn report_generic_bound_failure(&self,
@@ -1609,68 +1611,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     fn note_region_origin(&self, err: &mut DiagnosticBuilder, origin: &SubregionOrigin<'tcx>) {
         match *origin {
             infer::Subtype(ref trace) => {
-                let desc = match trace.origin {
-                    TypeOrigin::Misc(_) => {
-                        "types are compatible"
-                    }
-                    TypeOrigin::MethodCompatCheck(_) => {
-                        "method type is compatible with trait"
-                    }
-                    TypeOrigin::ExprAssignable(_) => {
-                        "expression is assignable"
-                    }
-                    TypeOrigin::RelateTraitRefs(_) => {
-                        "traits are compatible"
-                    }
-                    TypeOrigin::RelateSelfType(_) => {
-                        "self type matches impl self type"
-                    }
-                    TypeOrigin::RelateOutputImplTypes(_) => {
-                        "trait type parameters matches those \
-                                 specified on the impl"
-                    }
-                    TypeOrigin::MatchExpressionArm(_, _, _) => {
-                        "match arms have compatible types"
-                    }
-                    TypeOrigin::IfExpression(_) => {
-                        "if and else have compatible types"
-                    }
-                    TypeOrigin::IfExpressionWithNoElse(_) => {
-                        "if may be missing an else clause"
-                    }
-                    TypeOrigin::RangeExpression(_) => {
-                        "start and end of range have compatible types"
-                    }
-                    TypeOrigin::EquatePredicate(_) => {
-                        "equality where clause is satisfied"
-                    }
-                    TypeOrigin::MainFunctionType(_) => {
-                        "the `main` function has the correct type"
-                    }
-                    TypeOrigin::StartFunctionType(_) => {
-                        "the `start` function has the correct type"
-                    }
-                    TypeOrigin::IntrinsicType(_) => {
-                        "the intrinsic has the correct type"
-                    }
-                };
+                if let Some((expected, found)) = self.values_str(&trace.values) {
+                    // FIXME: do we want a "the" here?
+                    err.span_note(
+                        trace.origin.span(),
+                        &format!("...so that {} (expected {}, found {})",
+                                 trace.origin.as_requirement_str(), expected, found));
+                } else {
+                    // FIXME: this really should be handled at some earlier stage. Our
+                    // handling of region checking when type errors are present is
+                    // *terrible*.
 
-                match self.values_str(&trace.values) {
-                    Some((expected, found)) => {
-                        err.span_note(
-                            trace.origin.span(),
-                            &format!("...so that {} (expected {}, found {})",
-                                    desc, expected, found));
-                    }
-                    None => {
-                        // Really should avoid printing this error at
-                        // all, since it is derived, but that would
-                        // require more refactoring than I feel like
-                        // doing right now. - nmatsakis
-                        err.span_note(
-                            trace.origin.span(),
-                            &format!("...so that {}", desc));
-                    }
+                    err.span_note(
+                        trace.origin.span(),
+                        &format!("...so that {}",
+                                 trace.origin.as_requirement_str()));
                 }
             }
             infer::Reborrow(span) => {
@@ -1813,32 +1768,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 }
 
-pub trait Resolvable<'tcx> {
-    fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Self;
-}
-
-impl<'tcx> Resolvable<'tcx> for Ty<'tcx> {
-    fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
-        infcx.resolve_type_vars_if_possible(self)
-    }
-}
-
-impl<'tcx> Resolvable<'tcx> for ty::TraitRef<'tcx> {
-    fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>)
-                         -> ty::TraitRef<'tcx> {
-        infcx.resolve_type_vars_if_possible(self)
-    }
-}
-
-impl<'tcx> Resolvable<'tcx> for ty::PolyTraitRef<'tcx> {
-    fn resolve<'a, 'gcx>(&self,
-                         infcx: &InferCtxt<'a, 'gcx, 'tcx>)
-                         -> ty::PolyTraitRef<'tcx>
-    {
-        infcx.resolve_type_vars_if_possible(self)
-    }
-}
-
 fn lifetimes_in_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                                       scope_id: ast::NodeId)
                                       -> Vec<hir::LifetimeDef> {
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index dc262e61dd0..fd65e06ea97 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -231,7 +231,7 @@ pub enum TypeOrigin {
 }
 
 impl TypeOrigin {
-    fn as_str(&self) -> &'static str {
+    fn as_failure_str(&self) -> &'static str {
         match self {
             &TypeOrigin::Misc(_) |
             &TypeOrigin::RelateSelfType(_) |
@@ -252,11 +252,26 @@ impl TypeOrigin {
             &TypeOrigin::IntrinsicType(_) => "intrinsic has wrong type",
         }
     }
-}
 
-impl fmt::Display for TypeOrigin {
-    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(),fmt::Error> {
-        fmt::Display::fmt(self.as_str(), f)
+    fn as_requirement_str(&self) -> &'static str {
+        match self {
+            &TypeOrigin::Misc(_) => "types are compatible",
+            &TypeOrigin::MethodCompatCheck(_) => "method type is compatible with trait",
+            &TypeOrigin::ExprAssignable(_) => "expression is assignable",
+            &TypeOrigin::RelateTraitRefs(_) => "traits are compatible",
+            &TypeOrigin::RelateSelfType(_) => "self type matches impl self type",
+            &TypeOrigin::RelateOutputImplTypes(_) => {
+                "trait type parameters matches those specified on the impl"
+            }
+            &TypeOrigin::MatchExpressionArm(_, _, _) => "match arms have compatible types",
+            &TypeOrigin::IfExpression(_) => "if and else have compatible types",
+            &TypeOrigin::IfExpressionWithNoElse(_) => "if missing an else returns ()",
+            &TypeOrigin::RangeExpression(_) => "start and end of range have compatible types",
+            &TypeOrigin::EquatePredicate(_) => "equality where clause is satisfied",
+            &TypeOrigin::MainFunctionType(_) => "`main` function has the correct type",
+            &TypeOrigin::StartFunctionType(_) => "`start` function has the correct type",
+            &TypeOrigin::IntrinsicType(_) => "intrinsic has the correct type",
+        }
     }
 }
 
@@ -1489,22 +1504,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     pub fn type_error_message<M>(&self,
                                  sp: Span,
                                  mk_msg: M,
-                                 actual_ty: Ty<'tcx>,
-                                 err: Option<&TypeError<'tcx>>)
+                                 actual_ty: Ty<'tcx>)
         where M: FnOnce(String) -> String,
     {
-        self.type_error_struct(sp, mk_msg, actual_ty, err).emit();
+        self.type_error_struct(sp, mk_msg, actual_ty).emit();
     }
 
     pub fn type_error_struct<M>(&self,
                                 sp: Span,
                                 mk_msg: M,
-                                actual_ty: Ty<'tcx>,
-                                err: Option<&TypeError<'tcx>>)
+                                actual_ty: Ty<'tcx>)
                                 -> DiagnosticBuilder<'tcx>
         where M: FnOnce(String) -> String,
     {
-        debug!("type_error_struct({:?}, {:?}, {:?})", sp, actual_ty, err);
+        debug!("type_error_struct({:?}, {:?})", sp, actual_ty);
 
         let actual_ty = self.resolve_type_vars_if_possible(&actual_ty);
 
@@ -1513,21 +1526,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             return self.tcx.sess.diagnostic().struct_dummy();
         }
 
-        let error_str = err.map_or("".to_string(), |t_err| {
-            format!(" ({})", t_err)
-        });
-
         let msg = mk_msg(self.ty_to_string(actual_ty));
 
         // FIXME: use an error code.
-        let mut db = self.tcx.sess.struct_span_err(
-            sp, &format!("{} {}", msg, error_str));
-
-        if let Some(err) = err {
-            self.tcx.note_and_explain_type_err(&mut db, err, sp);
-        }
-
-        db
+        self.tcx.sess.struct_span_err(sp, &msg)
     }
 
     pub fn report_mismatched_types(&self,
diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs
index 76dca1bb5b6..52420475db1 100644
--- a/src/librustc/macros.rs
+++ b/src/librustc/macros.rs
@@ -59,3 +59,15 @@ macro_rules! span_bug {
         $crate::session::span_bug_fmt(file!(), line!(), $span, format_args!($($message)*))
     })
 }
+
+#[macro_export]
+macro_rules! type_err {
+    ($infcx:expr, $trace: expr, $terr: expr, $code:ident, $($message:tt)*) => ({
+        __diagnostic_used!($code);
+        $infcx.report_and_explain_type_error_with_code(
+            $trace,
+            $terr,
+            &format!($($message)*),
+            stringify!($code))
+    })
+}
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 2c7e7d284fa..9c6727ebbfc 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -216,7 +216,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             _ => {
                 let mut err = self.type_error_struct(call_expr.span, |actual| {
                     format!("expected function, found `{}`", actual)
-                }, callee_ty, None);
+                }, callee_ty);
 
                 if let hir::ExprCall(ref expr, _) = call_expr.node {
                     let tcx = self.tcx;
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 22ac8bc5690..7a4cc09a7d5 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -149,7 +149,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
                     format!("casting `{}` as `{}` is invalid",
                             actual,
                             fcx.ty_to_string(self.cast_ty))
-                }, self.expr_ty, None)
+                }, self.expr_ty)
                     .help(&format!("cast through {} first", match e {
                             CastError::NeedViaPtr => "a raw pointer",
                             CastError::NeedViaThinPtr => "a thin pointer",
@@ -167,35 +167,35 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
             CastError::CastToChar => {
                 fcx.type_error_message(self.span, |actual| {
                     format!("only `u8` can be cast as `char`, not `{}`", actual)
-                }, self.expr_ty, None);
+                }, self.expr_ty);
             }
             CastError::NonScalar => {
                 fcx.type_error_message(self.span, |actual| {
                     format!("non-scalar cast: `{}` as `{}`",
                             actual,
                             fcx.ty_to_string(self.cast_ty))
-                }, self.expr_ty, None);
+                }, self.expr_ty);
             }
             CastError::IllegalCast => {
                 fcx.type_error_message(self.span, |actual| {
                     format!("casting `{}` as `{}` is invalid",
                             actual,
                             fcx.ty_to_string(self.cast_ty))
-                }, self.expr_ty, None);
+                }, self.expr_ty);
             }
             CastError::SizedUnsizedCast => {
                 fcx.type_error_message(self.span, |actual| {
                     format!("cannot cast thin pointer `{}` to fat pointer `{}`",
                             actual,
                             fcx.ty_to_string(self.cast_ty))
-                }, self.expr_ty, None)
+                }, self.expr_ty)
             }
             CastError::DifferingKinds => {
                 fcx.type_error_struct(self.span, |actual| {
                     format!("casting `{}` as `{}` is invalid",
                             actual,
                             fcx.ty_to_string(self.cast_ty))
-                }, self.expr_ty, None)
+                }, self.expr_ty)
                     .note("vtable kinds may not match")
                     .emit();
             }
@@ -213,7 +213,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
         let tstr = fcx.ty_to_string(self.cast_ty);
         let mut err = fcx.type_error_struct(self.span, |actual| {
             format!("cast to unsized type: `{}` as `{}`", actual, tstr)
-        }, self.expr_ty, None);
+        }, self.expr_ty);
         match self.expr_ty.sty {
             ty::TyRef(_, ty::TypeAndMut { mutbl: mt, .. }) => {
                 let mtstr = match mt {
@@ -484,4 +484,3 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundSized, span)
     }
 }
-
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index f20dcdc35ae..346449d0a51 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -160,8 +160,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                 item_name,
                                 actual)
                     },
-                    rcvr_ty,
-                    None);
+                    rcvr_ty);
 
                 // 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) {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index fc1d2236f3f..7076b6a2a90 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2541,21 +2541,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         self.type_error_message(arg.span, |t| {
                             format!("can't pass an `{}` to variadic \
                                      function, cast to `c_double`", t)
-                        }, arg_ty, None);
+                        }, arg_ty);
                     }
                     ty::TyInt(ast::IntTy::I8) | ty::TyInt(ast::IntTy::I16) | ty::TyBool => {
                         self.type_error_message(arg.span, |t| {
                             format!("can't pass `{}` to variadic \
                                      function, cast to `c_int`",
                                            t)
-                        }, arg_ty, None);
+                        }, arg_ty);
                     }
                     ty::TyUint(ast::UintTy::U8) | ty::TyUint(ast::UintTy::U16) => {
                         self.type_error_message(arg.span, |t| {
                             format!("can't pass `{}` to variadic \
                                      function, cast to `c_uint`",
                                            t)
-                        }, arg_ty, None);
+                        }, arg_ty);
                     }
                     ty::TyFnDef(_, _, f) => {
                         let ptr_ty = self.tcx.mk_fn_ptr(f);
@@ -2564,7 +2564,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                 |t| {
                             format!("can't pass `{}` to variadic \
                                      function, cast to `{}`", t, ptr_ty)
-                        }, arg_ty, None);
+                        }, arg_ty);
                     }
                     _ => {}
                 }
@@ -2908,9 +2908,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             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? \
+            }, expr_t)
+                .help("maybe a `()` to call it is missing? \
                        If not, try an anonymous function")
                 .emit();
             self.write_error(expr.id);
@@ -2919,7 +2918,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 format!("attempted access of field `{}` on type `{}`, \
                          but no field with that name was found",
                         field.node, actual)
-            }, expr_t, None);
+            }, expr_t);
             if let ty::TyStruct(def, _) = expr_t.sty {
                 Self::suggest_field_names(&mut err, def.struct_variant(), field, vec![]);
             }
@@ -3019,7 +3018,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                     actual)
                 }
             },
-            expr_t, None);
+            expr_t);
 
         self.write_error(expr.id);
     }
@@ -3038,8 +3037,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 format!("structure `{}` has no field named `{}`",
                         actual, field.name.node)
             },
-            ty,
-            None);
+            ty);
         // prevent all specified fields from being suggested
         let skip_fields = skip_fields.iter().map(|ref x| x.name.node.as_str());
         Self::suggest_field_names(&mut err, variant, &field.name, skip_fields.collect());
@@ -3272,7 +3270,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             self.type_error_message(expr.span, |actual| {
                                 format!("type `{}` cannot be \
                                         dereferenced", actual)
-                            }, oprnd_t, None);
+                            }, oprnd_t);
                             oprnd_t = tcx.types.err;
                         }
                     }
@@ -3647,8 +3645,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                   format!("cannot index a value of type `{}`",
                                           actual)
                               },
-                              base_t,
-                              None);
+                              base_t);
                           // Try to give some advice about indexing tuples.
                           if let ty::TyTuple(_) = base_t.sty {
                               let mut needs_note = true;
@@ -4523,7 +4520,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 if !self.is_tainted_by_errors() {
                     self.type_error_message(sp, |_actual| {
                         "the type of this value must be known in this context".to_string()
-                    }, ty, None);
+                    }, ty);
                 }
                 self.demand_suptype(sp, self.tcx.types.err, ty);
                 ty = self.tcx.types.err;
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index 8604dadf46d..d02f87d0b9c 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -239,7 +239,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 self.type_error_message(ex.span, |actual| {
                     format!("cannot apply unary operator `{}` to type `{}`",
                             op_str, actual)
-                }, operand_ty, None);
+                }, operand_ty);
                 self.tcx.types.err
             }
         }

From b7b2db4da7dc6762d53659b32e5fb4ba8e5c5988 Mon Sep 17 00:00:00 2001
From: Ariel Ben-Yehuda <ariel.byd@gmail.com>
Date: Mon, 18 Jul 2016 23:13:34 +0300
Subject: [PATCH 04/14] switch compare_method to new-style trait error
 reporting

---
 src/librustc_typeck/check/compare_method.rs   | 21 ++++++++++---------
 .../associated-const-impl-wrong-type.rs       |  5 ++---
 src/test/compile-fail/issue-13033.rs          |  4 +++-
 src/test/compile-fail/issue-15094.rs          |  4 ++--
 src/test/compile-fail/issue-21332.rs          |  3 +--
 src/test/compile-fail/issue-24356.rs          |  3 ---
 .../trait-impl-method-mismatch.rs             |  4 ++--
 src/test/compile-fail/unsafe-trait-impl.rs    |  4 ++--
 8 files changed, 23 insertions(+), 25 deletions(-)

diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 35a5bc9c609..847dcc90ad3 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -324,10 +324,10 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             debug!("sub_types failed: impl ty {:?}, trait ty {:?}",
                    impl_fty,
                    trait_fty);
-            span_err!(tcx.sess, impl_m_span, E0053,
-                      "method `{}` has an incompatible type for trait: {}",
-                      trait_m.name,
-                      terr);
+            let trace = infer::TypeTrace::types(origin, false, impl_fty, trait_fty);
+            type_err!(infcx, trace, &terr, E0053,
+                      "method `{}` has an incompatible type for trait",
+                      trait_m.name).emit();
             return
         }
 
@@ -437,10 +437,9 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         // Compute skolemized form of impl and trait const tys.
         let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs);
         let trait_ty = trait_c.ty.subst(tcx, &trait_to_skol_substs);
+        let origin = TypeOrigin::Misc(impl_c_span);
 
         let err = infcx.commit_if_ok(|_| {
-            let origin = TypeOrigin::Misc(impl_c_span);
-
             // There is no "body" here, so just pass dummy id.
             let impl_ty =
                 assoc::normalize_associated_types_in(&infcx,
@@ -473,11 +472,13 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             debug!("checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
                    impl_ty,
                    trait_ty);
-            span_err!(tcx.sess, impl_c_span, E0326,
+            let values = Some(infer::ValuePairs::Types(ExpectedFound {
+                expected: trait_ty,
+                found: impl_ty
+            }));
+            type_err!(infcx, origin, values, terr, E0326,
                       "implemented const `{}` has an incompatible type for \
-                      trait: {}",
-                      trait_c.name,
-                      terr);
+                      trait", trait_c.name).emit();
         }
     });
 }
diff --git a/src/test/compile-fail/associated-const-impl-wrong-type.rs b/src/test/compile-fail/associated-const-impl-wrong-type.rs
index 4658d0f057d..95508a31044 100644
--- a/src/test/compile-fail/associated-const-impl-wrong-type.rs
+++ b/src/test/compile-fail/associated-const-impl-wrong-type.rs
@@ -18,9 +18,8 @@ struct SignedBar;
 
 impl Foo for SignedBar {
     const BAR: i32 = -1;
-    //~^ ERROR implemented const `BAR` has an incompatible type for trait
-    //~| expected u32,
-    //~| found i32 [E0326]
+    //~^ ERROR implemented const `BAR` has an incompatible type for trait [E0326]
+    //~| expected u32, found i32
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-13033.rs b/src/test/compile-fail/issue-13033.rs
index 43cf70e5bc3..3d9d81471cb 100644
--- a/src/test/compile-fail/issue-13033.rs
+++ b/src/test/compile-fail/issue-13033.rs
@@ -16,7 +16,9 @@ struct Baz;
 
 impl Foo for Baz {
     fn bar(&mut self, other: &Foo) {}
-    //~^ ERROR method `bar` has an incompatible type for trait: values differ in mutability [E0053]
+    //~^ ERROR method `bar` has an incompatible type for trait
+    //~| expected type `fn(&mut Baz, &mut Foo)`
+    //~| found type `fn(&mut Baz, &Foo)`
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-15094.rs b/src/test/compile-fail/issue-15094.rs
index 42e3456b309..da48bbb3ecd 100644
--- a/src/test/compile-fail/issue-15094.rs
+++ b/src/test/compile-fail/issue-15094.rs
@@ -20,8 +20,8 @@ impl<T: fmt::Debug> ops::FnOnce<(),> for Debuger<T> {
     type Output = ();
     fn call_once(self, _args: ()) {
     //~^ ERROR `call_once` has an incompatible type for trait
-    //~| expected "rust-call" fn,
-    //~| found "Rust" fn
+    //~| expected type `extern "rust-call" fn
+    //~| found type `fn
         println!("{:?}", self.x);
     }
 }
diff --git a/src/test/compile-fail/issue-21332.rs b/src/test/compile-fail/issue-21332.rs
index b36918149fa..db3334834d4 100644
--- a/src/test/compile-fail/issue-21332.rs
+++ b/src/test/compile-fail/issue-21332.rs
@@ -14,8 +14,7 @@ impl Iterator for S {
     type Item = i32;
     fn next(&mut self) -> Result<i32, i32> { Ok(7) }
     //~^ ERROR method `next` has an incompatible type for trait
-    //~| expected enum `std::option::Option`
-    //~|    found enum `std::result::Result` [E0053]
+    //~| expected enum `std::option::Option`, found enum `std::result::Result`
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-24356.rs b/src/test/compile-fail/issue-24356.rs
index 27d46be40fb..ede81bea32a 100644
--- a/src/test/compile-fail/issue-24356.rs
+++ b/src/test/compile-fail/issue-24356.rs
@@ -30,9 +30,6 @@ fn main() {
         impl Deref for Thing {
             //~^ ERROR not all trait items implemented, missing: `Target` [E0046]
             fn deref(&self) -> i8 { self.0 }
-            //~^ ERROR method `deref` has an incompatible type for trait
-            //~| expected &-ptr
-            //~| found i8 [E0053]
         }
 
         let thing = Thing(72);
diff --git a/src/test/compile-fail/trait-impl-method-mismatch.rs b/src/test/compile-fail/trait-impl-method-mismatch.rs
index f86d9b7648b..a05e007d6b7 100644
--- a/src/test/compile-fail/trait-impl-method-mismatch.rs
+++ b/src/test/compile-fail/trait-impl-method-mismatch.rs
@@ -17,8 +17,8 @@ impl Mumbo for usize {
     // Cannot have a larger effect than the trait:
     unsafe fn jumbo(&self, x: &usize) { *self + *x; }
     //~^ ERROR method `jumbo` has an incompatible type for trait
-    //~| expected normal fn,
-    //~| found unsafe fn
+    //~| expected type `fn
+    //~| found type `unsafe fn
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/unsafe-trait-impl.rs b/src/test/compile-fail/unsafe-trait-impl.rs
index 51f876661f6..fb4652affd0 100644
--- a/src/test/compile-fail/unsafe-trait-impl.rs
+++ b/src/test/compile-fail/unsafe-trait-impl.rs
@@ -17,8 +17,8 @@ trait Foo {
 impl Foo for u32 {
     fn len(&self) -> u32 { *self }
     //~^ ERROR method `len` has an incompatible type for trait
-    //~| expected unsafe fn,
-    //~| found normal fn
+    //~| expected type `unsafe fn(&u32) -> u32`
+    //~| found type `fn(&u32) -> u32`
 }
 
 fn main() { }

From fa4eda8935cc902b0757815e774f11ee791af156 Mon Sep 17 00:00:00 2001
From: Ariel Ben-Yehuda <ariel.byd@gmail.com>
Date: Tue, 19 Jul 2016 01:02:47 +0300
Subject: [PATCH 05/14] switch projection errors to use the new type error
 messages

Unfortunately, projection errors do not come with a nice set of
mismatched types. This is because the type equality check occurs
within a higher-ranked context. Therefore, only the type error
is reported. This is ugly but was always the situation.

I will introduce better errors for the lower-ranked case in
another commit.

Fixes the last known occurence of #31173
---
 src/librustc/infer/error_reporting.rs         | 49 +++++++++++--------
 src/librustc/macros.rs                        |  7 +--
 src/librustc/traits/error_reporting.rs        | 14 ++++--
 src/librustc_typeck/check/compare_method.rs   |  8 ++-
 .../compile-fail/associated-types-eq-3.rs     |  6 +--
 src/test/compile-fail/issue-31173.rs          | 26 ++++++++++
 6 files changed, 76 insertions(+), 34 deletions(-)
 create mode 100644 src/test/compile-fail/issue-31173.rs

diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index be73818c8a4..0726d8560ba 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -522,37 +522,46 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn report_and_explain_type_error_with_code(&self,
-                                                   trace: TypeTrace<'tcx>,
+                                                   origin: TypeOrigin,
+                                                   values: Option<ValuePairs<'tcx>>,
                                                    terr: &TypeError<'tcx>,
                                                    message: &str,
                                                    code: &str)
                                                    -> DiagnosticBuilder<'tcx>
     {
-        let (expected, found) = match self.values_str(&trace.values) {
-            Some((expected, found)) => (expected, found),
-            None => return self.tcx.sess.diagnostic().struct_dummy() /* derived error */
-        };
-
-        let span = trace.origin.span();
-
-        let is_simple_error = if let &TypeError::Sorts(ref values) = terr {
-            values.expected.is_primitive() && values.found.is_primitive()
-        } else {
-            false
+        let expected_found = match values {
+            None => None,
+            Some(values) => match self.values_str(&values) {
+                Some((expected, found)) => Some((expected, found)),
+                None => return self.tcx.sess.diagnostic().struct_dummy() /* derived error */
+            }
         };
 
+        let span = origin.span();
         let mut err = self.tcx.sess.struct_span_err_with_code(
-            trace.origin.span(),
-            message,
-            code);
+            span, message, code);
 
-        if !is_simple_error || check_old_school() {
-            err.note_expected_found(&"type", &expected, &found);
+        let mut is_simple_error = false;
+
+        if let Some((expected, found)) = expected_found {
+            is_simple_error = if let &TypeError::Sorts(ref values) = terr {
+                values.expected.is_primitive() && values.found.is_primitive()
+            } else {
+                false
+            };
+
+            if !is_simple_error || check_old_school() {
+                err.note_expected_found(&"type", &expected, &found);
+            }
         }
 
-        err.span_label(span, &terr);
+        if !is_simple_error && check_old_school() {
+            err.span_note(span, &format!("{}", terr));
+        } else {
+            err.span_label(span, &terr);
+        }
 
-        self.note_error_origin(&mut err, &trace.origin);
+        self.note_error_origin(&mut err, &origin);
         self.check_and_note_conflicting_crates(&mut err, terr, span);
         self.tcx.note_and_explain_type_err(&mut err, terr, span);
 
@@ -566,7 +575,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     {
         // FIXME: do we want to use a different error code for each origin?
         let failure_str = trace.origin.as_failure_str();
-        type_err!(self, trace, terr, E0308, "{}", failure_str)
+        type_err!(self, trace.origin, Some(trace.values), terr, E0308, "{}", failure_str)
     }
 
     /// Returns a string of the form "expected `{}`, found `{}`".
diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs
index 52420475db1..190c9b665e0 100644
--- a/src/librustc/macros.rs
+++ b/src/librustc/macros.rs
@@ -62,11 +62,12 @@ macro_rules! span_bug {
 
 #[macro_export]
 macro_rules! type_err {
-    ($infcx:expr, $trace: expr, $terr: expr, $code:ident, $($message:tt)*) => ({
+    ($infcx:expr, $origin: expr, $values: expr, $terr: expr, $code:ident, $($message:tt)*) => ({
         __diagnostic_used!($code);
         $infcx.report_and_explain_type_error_with_code(
-            $trace,
-            $terr,
+            $origin,
+            $values,
+            &$terr,
             &format!($($message)*),
             stringify!($code))
     })
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 3b9ecb88258..afbe34f89bb 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -26,7 +26,7 @@ use super::{
 
 use fmt_macros::{Parser, Piece, Position};
 use hir::def_id::DefId;
-use infer::{InferCtxt};
+use infer::{InferCtxt, TypeOrigin};
 use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
 use ty::fast_reject;
 use ty::fold::TypeFolder;
@@ -117,10 +117,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                             predicate,
                             error.err));
             } else {
-                let mut err = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271,
-                                               "type mismatch resolving `{}`: {}",
-                                               predicate,
-                                               error.err);
+                let mut err = type_err!(
+                    self,
+                    TypeOrigin::Misc(obligation.cause.span),
+                    None, // FIXME: be smarter
+                    error.err,
+                    E0271,
+                    "type mismatch resolving `{}`",
+                    predicate);
                 self.note_obligation_cause(&mut err, obligation);
                 err.emit();
             }
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 847dcc90ad3..2c4c6279076 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -12,6 +12,7 @@ use middle::free_region::FreeRegionMap;
 use rustc::infer::{self, InferOk, TypeOrigin};
 use rustc::ty;
 use rustc::traits::{self, ProjectionMode};
+use rustc::ty::error::ExpectedFound;
 use rustc::ty::subst::{self, Subst, Substs, VecPerParamSpace};
 
 use syntax::ast;
@@ -324,8 +325,11 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             debug!("sub_types failed: impl ty {:?}, trait ty {:?}",
                    impl_fty,
                    trait_fty);
-            let trace = infer::TypeTrace::types(origin, false, impl_fty, trait_fty);
-            type_err!(infcx, trace, &terr, E0053,
+            let values = Some(infer::ValuePairs::Types(ExpectedFound {
+                expected: trait_fty,
+                found: impl_fty
+            }));
+            type_err!(infcx, origin, values, terr, E0053,
                       "method `{}` has an incompatible type for trait",
                       trait_m.name).emit();
             return
diff --git a/src/test/compile-fail/associated-types-eq-3.rs b/src/test/compile-fail/associated-types-eq-3.rs
index 8c66160e8a3..cb952f6534f 100644
--- a/src/test/compile-fail/associated-types-eq-3.rs
+++ b/src/test/compile-fail/associated-types-eq-3.rs
@@ -47,10 +47,8 @@ pub fn main() {
     let a = 42;
     foo1(a);
     //~^ ERROR type mismatch resolving
-    //~| expected usize
-    //~| found struct `Bar`
+    //~| expected usize, found struct `Bar`
     baz(&a);
     //~^ ERROR type mismatch resolving
-    //~| expected usize
-    //~| found struct `Bar`
+    //~| expected usize, found struct `Bar`
 }
diff --git a/src/test/compile-fail/issue-31173.rs b/src/test/compile-fail/issue-31173.rs
new file mode 100644
index 00000000000..62d23a99cba
--- /dev/null
+++ b/src/test/compile-fail/issue-31173.rs
@@ -0,0 +1,26 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::vec::IntoIter;
+
+pub fn get_tok(it: &mut IntoIter<u8>) {
+    let mut found_e = false;
+
+    let temp: Vec<u8> = it.take_while(|&x| {
+        found_e = true;
+        false
+    })
+        .cloned()
+        //~^ ERROR type mismatch resolving
+        //~| expected u8, found &-ptr
+        .collect(); //~ ERROR no method named `collect`
+}
+
+fn main() {}

From 37c569627cd285788509f654a6a2658126ba72e4 Mon Sep 17 00:00:00 2001
From: Ariel Ben-Yehuda <ariel.byd@gmail.com>
Date: Wed, 20 Jul 2016 00:02:56 +0300
Subject: [PATCH 06/14] refactor constant evaluation error reporting

Refactor constant evaluation to use a single error reporting function
that reports a type-error-like message.

Also, unify all error codes with the "constant evaluation error" message
to just E0080, and similarly for a few other duplicate codes. The old
situation was a total mess, and now that we have *something* we can
further iterate on the UX.
---
 src/librustc_const_eval/Cargo.toml            |   1 +
 src/librustc_const_eval/check_match.rs        |  55 ++--
 src/librustc_const_eval/diagnostics.rs        |  44 +--
 src/librustc_const_eval/eval.rs               | 256 +++++++++++++-----
 src/librustc_const_eval/lib.rs                |   1 +
 src/librustc_passes/consts.rs                 |  28 +-
 src/librustc_passes/diagnostics.rs            |   4 +-
 src/librustc_trans/_match.rs                  |  16 +-
 src/librustc_trans/consts.rs                  |  21 +-
 src/librustc_trans/intrinsic.rs               |   6 +-
 src/librustc_trans/mir/constant.rs            |   2 +-
 src/librustc_trans/trans_item.rs              |   7 +-
 src/librustc_trans/tvec.rs                    |   6 +-
 src/librustc_typeck/astconv.rs                |  37 +--
 src/librustc_typeck/check/mod.rs              |   5 +-
 src/librustc_typeck/collect.rs                |  12 +-
 src/librustc_typeck/diagnostics.rs            |  52 +---
 src/rustc/Cargo.lock                          |   1 +
 src/test/compile-fail/array_const_index-0.rs  |   3 +-
 src/test/compile-fail/array_const_index-1.rs  |   3 +-
 .../associated-const-array-len.rs             |   2 +-
 ...ssociated-const-type-parameter-arrays-2.rs |   3 +-
 src/test/compile-fail/const-array-oob.rs      |   3 +-
 src/test/compile-fail/const-call.rs           |   3 +-
 src/test/compile-fail/const-err.rs            |  24 +-
 .../compile-fail/const-eval-overflow-2.rs     |  11 +-
 .../compile-fail/const-eval-overflow-3.rs     |   2 +-
 .../compile-fail/const-eval-overflow-4b.rs    |  10 +-
 src/test/compile-fail/const-eval-overflow.rs  |  84 ++++--
 src/test/compile-fail/const-eval-span.rs      |   3 +-
 src/test/compile-fail/const-fn-error.rs       |   5 +-
 .../compile-fail/const-index-feature-gate.rs  |   3 +-
 .../compile-fail/const-integer-bool-ops.rs    |  24 +-
 .../const-len-underflow-separate-spans.rs     |   3 +-
 .../const-len-underflow-subspans.rs           |   3 +-
 .../const-pattern-not-const-evaluable.rs      |  16 +-
 src/test/compile-fail/const-slice-oob.rs      |   3 +-
 src/test/compile-fail/const-tup-index-span.rs |   3 +-
 src/test/compile-fail/discrim-ill-typed.rs    |  24 +-
 .../compile-fail/enum-discrim-too-small.rs    |  12 +-
 src/test/compile-fail/eval-enum.rs            |   6 +-
 .../feature-gate-negate-unsigned0.rs          |   9 +-
 .../compile-fail/invalid-path-in-const.rs     |   3 +-
 src/test/compile-fail/issue-22933-2.rs        |   6 +-
 src/test/compile-fail/issue-23217.rs          |   3 +-
 src/test/compile-fail/issue-25145.rs          |   3 +-
 src/test/compile-fail/issue-27008.rs          |   2 +-
 src/test/compile-fail/issue-27895.rs          |   3 +-
 src/test/compile-fail/issue-28586.rs          |   2 +-
 src/test/compile-fail/issue-3521.rs           |   3 +-
 src/test/compile-fail/issue-8761.rs           |  12 +-
 .../non-constant-enum-for-vec-repeat.rs       |   3 +-
 .../non-constant-expr-for-vec-repeat.rs       |   4 +-
 .../non-constant-in-const-path.rs             |   3 +-
 src/test/compile-fail/repeat_count.rs         |  19 +-
 55 files changed, 506 insertions(+), 376 deletions(-)

diff --git a/src/librustc_const_eval/Cargo.toml b/src/librustc_const_eval/Cargo.toml
index 01872bbe3c0..8967672548b 100644
--- a/src/librustc_const_eval/Cargo.toml
+++ b/src/librustc_const_eval/Cargo.toml
@@ -14,6 +14,7 @@ serialize = { path = "../libserialize" }
 rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
 rustc_const_math = { path = "../librustc_const_math" }
+rustc_errors = { path = "../librustc_errors" }
 syntax = { path = "../libsyntax" }
 graphviz = { path = "../libgraphviz" }
 syntax_pos = { path = "../libsyntax_pos" }
\ No newline at end of file
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index 0de00d9d7f6..915a0cf0bdc 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -17,6 +17,7 @@ use rustc::middle::const_val::ConstVal;
 use ::{eval_const_expr, eval_const_expr_partial, compare_const_vals};
 use ::{const_expr_to_pat, lookup_const_by_id};
 use ::EvalHint::ExprTypeChecked;
+use eval::report_const_eval_err;
 use rustc::hir::def::*;
 use rustc::hir::def_id::{DefId};
 use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
@@ -42,6 +43,7 @@ use syntax_pos::{Span, DUMMY_SP};
 use rustc::hir::fold::{Folder, noop_fold_pat};
 use rustc::hir::print::pat_to_string;
 use syntax::ptr::P;
+use rustc::util::common::ErrorReported;
 use rustc::util::nodemap::FnvHashMap;
 
 pub const DUMMY_WILD_PAT: &'static Pat = &Pat {
@@ -279,13 +281,7 @@ fn check_for_static_nan(cx: &MatchCheckCtxt, pat: &Pat) {
                 Ok(_) => {}
 
                 Err(err) => {
-                    let mut diag = struct_span_err!(cx.tcx.sess, err.span, E0471,
-                                                    "constant evaluation error: {}",
-                                                    err.description());
-                    if !p.span.contains(err.span) {
-                        diag.span_note(p.span, "in pattern here");
-                    }
-                    diag.emit();
+                    report_const_eval_err(cx.tcx, &err, p.span, "pattern").emit();
                 }
             }
         }
@@ -838,22 +834,19 @@ pub fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> us
     }
 }
 
-fn range_covered_by_constructor(ctor: &Constructor,
-                                from: &ConstVal, to: &ConstVal) -> Option<bool> {
+fn range_covered_by_constructor(tcx: TyCtxt, span: Span,
+                                ctor: &Constructor,
+                                from: &ConstVal, to: &ConstVal)
+                                -> Result<bool, ErrorReported> {
     let (c_from, c_to) = match *ctor {
         ConstantValue(ref value)        => (value, value),
         ConstantRange(ref from, ref to) => (from, to),
-        Single                          => return Some(true),
+        Single                          => return Ok(true),
         _                               => bug!()
     };
-    let cmp_from = compare_const_vals(c_from, from);
-    let cmp_to = compare_const_vals(c_to, to);
-    match (cmp_from, cmp_to) {
-        (Some(cmp_from), Some(cmp_to)) => {
-            Some(cmp_from != Ordering::Less && cmp_to != Ordering::Greater)
-        }
-        _ => None
-    }
+    let cmp_from = compare_const_vals(tcx, span, c_from, from)?;
+    let cmp_to = compare_const_vals(tcx, span, c_to, to)?;
+    Ok(cmp_from != Ordering::Less && cmp_to != Ordering::Greater)
 }
 
 fn wrap_pat<'a, 'b, 'tcx>(cx: &MatchCheckCtxt<'b, 'tcx>,
@@ -965,13 +958,12 @@ pub fn specialize<'a, 'b, 'tcx>(
                 Some(vec![(pat, Some(mt.ty))])
             } else {
                 let expr_value = eval_const_expr(cx.tcx, &expr);
-                match range_covered_by_constructor(constructor, &expr_value, &expr_value) {
-                    Some(true) => Some(vec![]),
-                    Some(false) => None,
-                    None => {
-                        span_err!(cx.tcx.sess, pat_span, E0298, "mismatched types between arms");
-                        None
-                    }
+                match range_covered_by_constructor(
+                    cx.tcx, expr.span, constructor, &expr_value, &expr_value
+                ) {
+                    Ok(true) => Some(vec![]),
+                    Ok(false) => None,
+                    Err(ErrorReported) => None,
                 }
             }
         }
@@ -979,13 +971,12 @@ pub fn specialize<'a, 'b, 'tcx>(
         PatKind::Range(ref from, ref to) => {
             let from_value = eval_const_expr(cx.tcx, &from);
             let to_value = eval_const_expr(cx.tcx, &to);
-            match range_covered_by_constructor(constructor, &from_value, &to_value) {
-                Some(true) => Some(vec![]),
-                Some(false) => None,
-                None => {
-                    span_err!(cx.tcx.sess, pat_span, E0299, "mismatched types between arms");
-                    None
-                }
+            match range_covered_by_constructor(
+                cx.tcx, pat_span, constructor, &from_value, &to_value
+            ) {
+                Ok(true) => Some(vec![]),
+                Ok(false) => None,
+                Err(ErrorReported) => None,
             }
         }
 
diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs
index f2abdf831a3..45414c33c07 100644
--- a/src/librustc_const_eval/diagnostics.rs
+++ b/src/librustc_const_eval/diagnostics.rs
@@ -551,6 +551,26 @@ The `op_string_ref` binding has type `&Option<&String>` in both cases.
 See also https://github.com/rust-lang/rust/issues/14587
 "##,
 
+E0080: r##"
+This error indicates that the compiler was unable to sensibly evaluate an
+constant expression that had to be evaluated. Attempting to divide by 0
+or causing integer overflow are two ways to induce this error. For example:
+
+```compile_fail
+enum Enum {
+    X = (1 << 500),
+    Y = (1 / 0)
+}
+```
+
+Ensure that the expressions given can be evaluated as the desired integer type.
+See the FFI section of the Reference for more information about using a custom
+integer type:
+
+https://doc.rust-lang.org/reference.html#ffi-attributes
+"##,
+
+
 E0306: r##"
 In an array literal `[x; N]`, `N` is the number of elements in the array. This
 must be an unsigned integer. Erroneous code example:
@@ -566,29 +586,11 @@ Working example:
 let x = [0i32; 2];
 ```
 "##,
-
-E0307: r##"
-The length of an array is part of its type. For this reason, this length must
-be a compile-time constant. Erroneous code example:
-
-```compile_fail
-    let len = 10;
-    let x = [0i32; len]; // error: expected constant integer for repeat count,
-                         //        found variable
-```
-
-Working example:
-
-```
-let x = [0i32; 10];
-```
-"##,
-
 }
 
 
 register_diagnostics! {
-E0298, // mismatched types between arms
-E0299, // mismatched types between arms
-E0471, // constant evaluation error: ..
+    E0298, // cannot compare constants
+//  E0299, // mismatched types between arms
+//  E0471, // constant evaluation error (in pattern)
 }
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index a3c707e82a0..03d2f596e21 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -25,6 +25,7 @@ use rustc::hir::pat_util::def_to_path;
 use rustc::ty::{self, Ty, TyCtxt, subst};
 use rustc::ty::util::IntTypeExt;
 use rustc::traits::ProjectionMode;
+use rustc::util::common::ErrorReported;
 use rustc::util::nodemap::NodeMap;
 use rustc::lint;
 
@@ -43,6 +44,7 @@ use std::cmp::Ordering;
 use std::collections::hash_map::Entry::Vacant;
 
 use rustc_const_math::*;
+use rustc_errors::{DiagnosticBuilder, check_old_school};
 
 macro_rules! math {
     ($e:expr, $op:expr) => {
@@ -338,20 +340,80 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     Ok(P(hir::Pat { id: expr.id, node: pat, span: span }))
 }
 
+pub fn report_const_eval_err<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    err: &ConstEvalErr,
+    primary_span: Span,
+    primary_kind: &str)
+    -> DiagnosticBuilder<'tcx>
+{
+    let mut err = err;
+    while let &ConstEvalErr { kind: ErroneousReferencedConstant(box ref i_err), .. } = err {
+        err = i_err;
+    }
+
+    let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error");
+    note_const_eval_err(tcx, err, primary_span, primary_kind, &mut diag);
+    diag
+}
+
+pub fn fatal_const_eval_err<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    err: &ConstEvalErr,
+    primary_span: Span,
+    primary_kind: &str)
+    -> !
+{
+    report_const_eval_err(tcx, err, primary_span, primary_kind).emit();
+    tcx.sess.abort_if_errors();
+    unreachable!()
+}
+
+pub fn note_const_eval_err<'a, 'tcx>(
+    _tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    err: &ConstEvalErr,
+    primary_span: Span,
+    primary_kind: &str,
+    diag: &mut DiagnosticBuilder)
+{
+    match err.description() {
+        ConstEvalErrDescription::Simple(message) => {
+            if check_old_school() {
+                diag.note(&message);
+            } else {
+                diag.span_label(err.span, &message);
+            }
+        }
+        ConstEvalErrDescription::ExpectedFound { error, expected, found } => {
+            if check_old_school() {
+                diag.note(&error);
+            } else {
+                diag.span_label(err.span, &error);
+            }
+            diag.note(&format!("expected `{}`", expected));
+            diag.note(&format!("found `{}`", found));
+        }
+    }
+
+    if !primary_span.contains(err.span) {
+        diag.span_note(primary_span,
+                       &format!("for {} here", primary_kind));
+    }
+}
+
 pub fn eval_const_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                  e: &Expr) -> ConstVal {
     match eval_const_expr_partial(tcx, e, ExprTypeChecked, None) {
         Ok(r) => r,
         // non-const path still needs to be a fatal error, because enums are funky
         Err(s) => {
+            report_const_eval_err(tcx, &s, e.span, "expression").emit();
             match s.kind {
                 NonConstPath |
-                UnimplementedConstVal(_) => tcx.sess.span_fatal(s.span, &s.description()),
-                _ => {
-                    tcx.sess.span_err(s.span, &s.description());
-                    Dummy
-                }
+                UnimplementedConstVal(_) => tcx.sess.abort_if_errors(),
+                _ => {}
             }
+            Dummy
         },
     }
 }
@@ -400,6 +462,7 @@ pub enum ErrKind {
     IntermediateUnsignedNegative,
     /// Expected, Got
     TypeMismatch(String, ConstInt),
+
     BadType(ConstVal),
     ErroneousReferencedConstant(Box<ConstEvalErr>),
     CharCast(ConstInt),
@@ -411,57 +474,96 @@ impl From<ConstMathErr> for ErrKind {
     }
 }
 
+#[derive(Clone, Debug)]
+pub enum ConstEvalErrDescription<'a> {
+    Simple(Cow<'a, str>),
+    ExpectedFound {
+        error: Cow<'a, str>,
+        expected: Cow<'a, str>,
+        found: Cow<'a, str>
+    }
+}
+
+impl<'a> ConstEvalErrDescription<'a> {
+    /// Return a one-line description of the error, for lints and such
+    pub fn into_oneline(self) -> Cow<'a, str> {
+        match self {
+            ConstEvalErrDescription::Simple(simple) => simple,
+            ConstEvalErrDescription::ExpectedFound {
+                error,
+                expected,
+                found
+            } => {
+                format!("{}: expected `{}`, found `{}`", error, expected, found)
+                    .into_cow()
+            }
+        }
+    }
+}
+
 impl ConstEvalErr {
-    pub fn description(&self) -> Cow<str> {
+    pub fn description(&self) -> ConstEvalErrDescription {
         use self::ErrKind::*;
+        use self::ConstEvalErrDescription::*;
+
+        macro_rules! simple {
+            ($msg:expr) => ({ Simple($msg.into_cow()) });
+            ($fmt:expr, $($arg:tt)+) => ({
+                Simple(format!($fmt, $($arg)+).into_cow())
+            })
+        }
 
         match self.kind {
-            CannotCast => "can't cast this type".into_cow(),
-            CannotCastTo(s) => format!("can't cast this type to {}", s).into_cow(),
-            InvalidOpForInts(_) =>  "can't do this op on integrals".into_cow(),
-            InvalidOpForBools(_) =>  "can't do this op on bools".into_cow(),
-            InvalidOpForFloats(_) => "can't do this op on floats".into_cow(),
-            InvalidOpForIntUint(..) => "can't do this op on an isize and usize".into_cow(),
-            InvalidOpForUintInt(..) => "can't do this op on a usize and isize".into_cow(),
-            NegateOn(ref const_val) => format!("negate on {}", const_val.description()).into_cow(),
-            NotOn(ref const_val) => format!("not on {}", const_val.description()).into_cow(),
-            CallOn(ref const_val) => format!("call on {}", const_val.description()).into_cow(),
+            CannotCast => simple!("can't cast this type"),
+            CannotCastTo(s) => simple!("can't cast this type to {}", s),
+            InvalidOpForInts(_) =>  simple!("can't do this op on integrals"),
+            InvalidOpForBools(_) =>  simple!("can't do this op on bools"),
+            InvalidOpForFloats(_) => simple!("can't do this op on floats"),
+            InvalidOpForIntUint(..) => simple!("can't do this op on an isize and usize"),
+            InvalidOpForUintInt(..) => simple!("can't do this op on a usize and isize"),
+            NegateOn(ref const_val) => simple!("negate on {}", const_val.description()),
+            NotOn(ref const_val) => simple!("not on {}", const_val.description()),
+            CallOn(ref const_val) => simple!("call on {}", const_val.description()),
 
-            MissingStructField  => "nonexistent struct field".into_cow(),
-            NonConstPath        => "non-constant path in constant expression".into_cow(),
+            MissingStructField  => simple!("nonexistent struct field"),
+            NonConstPath        => simple!("non-constant path in constant expression"),
             UnimplementedConstVal(what) =>
-                format!("unimplemented constant expression: {}", what).into_cow(),
-            UnresolvedPath => "unresolved path in constant expression".into_cow(),
-            ExpectedConstTuple => "expected constant tuple".into_cow(),
-            ExpectedConstStruct => "expected constant struct".into_cow(),
-            TupleIndexOutOfBounds => "tuple index out of bounds".into_cow(),
-            IndexedNonVec => "indexing is only supported for arrays".into_cow(),
-            IndexNegative => "indices must be non-negative integers".into_cow(),
-            IndexNotInt => "indices must be integers".into_cow(),
+                simple!("unimplemented constant expression: {}", what),
+            UnresolvedPath => simple!("unresolved path in constant expression"),
+            ExpectedConstTuple => simple!("expected constant tuple"),
+            ExpectedConstStruct => simple!("expected constant struct"),
+            TupleIndexOutOfBounds => simple!("tuple index out of bounds"),
+            IndexedNonVec => simple!("indexing is only supported for arrays"),
+            IndexNegative => simple!("indices must be non-negative integers"),
+            IndexNotInt => simple!("indices must be integers"),
             IndexOutOfBounds { len, index } => {
-                format!("index out of bounds: the len is {} but the index is {}",
-                        len, index).into_cow()
+                simple!("index out of bounds: the len is {} but the index is {}",
+                        len, index)
             }
-            RepeatCountNotNatural => "repeat count must be a natural number".into_cow(),
-            RepeatCountNotInt => "repeat count must be integers".into_cow(),
+            RepeatCountNotNatural => simple!("repeat count must be a natural number"),
+            RepeatCountNotInt => simple!("repeat count must be integers"),
 
-            MiscBinaryOp => "bad operands for binary".into_cow(),
-            MiscCatchAll => "unsupported constant expr".into_cow(),
-            IndexOpFeatureGated => "the index operation on const values is unstable".into_cow(),
-            Math(ref err) => err.description().into_cow(),
+            MiscBinaryOp => simple!("bad operands for binary"),
+            MiscCatchAll => simple!("unsupported constant expr"),
+            IndexOpFeatureGated => simple!("the index operation on const values is unstable"),
+            Math(ref err) => Simple(err.description().into_cow()),
 
-            IntermediateUnsignedNegative => "during the computation of an unsigned a negative \
-                                             number was encountered. This is most likely a bug in\
-                                             the constant evaluator".into_cow(),
+            IntermediateUnsignedNegative => simple!(
+                "during the computation of an unsigned a negative \
+                 number was encountered. This is most likely a bug in\
+                 the constant evaluator"),
 
             TypeMismatch(ref expected, ref got) => {
-                format!("mismatched types: expected `{}`, found `{}`",
-                        expected, got.description()).into_cow()
+                ExpectedFound {
+                    error: "mismatched types".into_cow(),
+                    expected: <&str>::into_cow(expected),
+                    found: got.description().into_cow()
+                }
             },
-            BadType(ref i) => format!("value of wrong type: {:?}", i).into_cow(),
-            ErroneousReferencedConstant(_) => "could not evaluate referenced constant".into_cow(),
+            BadType(ref i) => simple!("value of wrong type: {:?}", i),
+            ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"),
             CharCast(ref got) => {
-                format!("only `u8` can be cast as `char`, not `{}`", got.description()).into_cow()
+                simple!("only `u8` can be cast as `char`, not `{}`", got.description())
             },
         }
     }
@@ -1185,8 +1287,10 @@ fn parse_float(num: &str, fty_hint: Option<ast::FloatTy>, span: Span) -> ConstFl
     })
 }
 
-pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
-    match (a, b) {
+pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal)
+                          -> Result<Ordering, ErrorReported>
+{
+    let result = match (a, b) {
         (&Integral(a), &Integral(b)) => a.try_cmp(b).ok(),
         (&Float(a), &Float(b)) => a.try_cmp(b).ok(),
         (&Str(ref a), &Str(ref b)) => Some(a.cmp(b)),
@@ -1194,62 +1298,82 @@ pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
         (&ByteStr(ref a), &ByteStr(ref b)) => Some(a.cmp(b)),
         (&Char(a), &Char(ref b)) => Some(a.cmp(b)),
         _ => None,
+    };
+
+    match result {
+        Some(result) => Ok(result),
+        None => {
+            // FIXME: can this ever be reached?
+            span_err!(tcx.sess, span, E0298,
+                      "type mismatch comparing {} and {}",
+                      a.description(),
+                      b.description());
+            Err(ErrorReported)
+        }
     }
 }
 
 pub fn compare_lit_exprs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                   span: Span,
                                    a: &Expr,
-                                   b: &Expr) -> Option<Ordering> {
+                                   b: &Expr) -> Result<Ordering, ErrorReported> {
     let a = match eval_const_expr_partial(tcx, a, ExprTypeChecked, None) {
         Ok(a) => a,
         Err(e) => {
-            tcx.sess.span_err(a.span, &e.description());
-            return None;
+            report_const_eval_err(tcx, &e, a.span, "expression").emit();
+            return Err(ErrorReported);
         }
     };
     let b = match eval_const_expr_partial(tcx, b, ExprTypeChecked, None) {
         Ok(b) => b,
         Err(e) => {
-            tcx.sess.span_err(b.span, &e.description());
-            return None;
+            report_const_eval_err(tcx, &e, b.span, "expression").emit();
+            return Err(ErrorReported);
         }
     };
-    compare_const_vals(&a, &b)
+    compare_const_vals(tcx, span, &a, &b)
 }
 
 
-/// Returns the repeat count for a repeating vector expression.
-pub fn eval_repeat_count<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                   count_expr: &hir::Expr) -> usize {
+/// Returns the value of the length-valued expression
+pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                             count_expr: &hir::Expr,
+                             reason: &str)
+                             -> Result<usize, ErrorReported>
+{
     let hint = UncheckedExprHint(tcx.types.usize);
     match eval_const_expr_partial(tcx, count_expr, hint, None) {
         Ok(Integral(Usize(count))) => {
             let val = count.as_u64(tcx.sess.target.uint_type);
             assert_eq!(val as usize as u64, val);
-            val as usize
+            Ok(val as usize)
         },
         Ok(const_val) => {
             span_err!(tcx.sess, count_expr.span, E0306,
-                      "expected positive integer for repeat count, found {}",
+                      "expected usize for {}, found {}",
+                      reason,
                       const_val.description());
-            0
+            Err(ErrorReported)
         }
         Err(err) => {
-            let err_msg = match count_expr.node {
+            let mut diag = report_const_eval_err(
+                tcx, &err, count_expr.span, reason);
+
+            match count_expr.node {
                 hir::ExprPath(None, hir::Path {
                     global: false,
                     ref segments,
                     ..
-                }) if segments.len() == 1 =>
-                    format!("found variable"),
-                _ => match err.kind {
-                    MiscCatchAll => format!("but found {}", err.description()),
-                    _ => format!("but {}", err.description())
+                }) if segments.len() == 1 => {
+                    if let Some(Def::Local(..)) = tcx.expect_def_or_none(count_expr.id) {
+                        diag.note(&format!("`{}` is a variable", segments[0].name));
+                    }
                 }
-            };
-            span_err!(tcx.sess, count_expr.span, E0307,
-                "expected constant integer for repeat count, {}", err_msg);
-            0
+                _ => {}
+            }
+
+            diag.emit();
+            Err(ErrorReported)
         }
     }
 }
diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs
index 726ba4fc192..a6714c178e7 100644
--- a/src/librustc_const_eval/lib.rs
+++ b/src/librustc_const_eval/lib.rs
@@ -36,6 +36,7 @@
 #[macro_use] extern crate rustc;
 extern crate rustc_back;
 extern crate rustc_const_math;
+extern crate rustc_errors;
 extern crate graphviz;
 extern crate syntax_pos;
 extern crate serialize as rustc_serialize; // used by deriving
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 27ce03b2d93..b0ba38f1db6 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -40,6 +40,7 @@ use rustc::middle::mem_categorization as mc;
 use rustc::middle::mem_categorization::Categorization;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::traits::ProjectionMode;
+use rustc::util::common::ErrorReported;
 use rustc::util::nodemap::NodeMap;
 use rustc::middle::const_qualif::ConstQualif;
 use rustc::lint::builtin::CONST_ERR;
@@ -116,7 +117,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
                 _ => self.tcx.sess.add_lint(CONST_ERR, expr.id, expr.span,
                                          format!("constant evaluation error: {}. This will \
                                                  become a HARD ERROR in the future",
-                                                 err.description())),
+                                                 err.description().into_oneline())),
             }
         }
         self.with_mode(mode, |this| {
@@ -211,15 +212,6 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
             }
         }
     }
-
-    fn msg(&self) -> &'static str {
-        match self.mode {
-            Mode::Const => "constant",
-            Mode::ConstFn => "constant function",
-            Mode::StaticMut | Mode::Static => "static",
-            Mode::Var => bug!(),
-        }
-    }
 }
 
 impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
@@ -289,18 +281,14 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
                 self.global_expr(Mode::Const, &start);
                 self.global_expr(Mode::Const, &end);
 
-                match compare_lit_exprs(self.tcx, start, end) {
-                    Some(Ordering::Less) |
-                    Some(Ordering::Equal) => {}
-                    Some(Ordering::Greater) => {
+                match compare_lit_exprs(self.tcx, p.span, start, end) {
+                    Ok(Ordering::Less) |
+                    Ok(Ordering::Equal) => {}
+                    Ok(Ordering::Greater) => {
                         span_err!(self.tcx.sess, start.span, E0030,
                             "lower range bound must be less than or equal to upper");
                     }
-                    None => {
-                        span_err!(self.tcx.sess, p.span, E0014,
-                                  "paths in {}s may only refer to constants",
-                                  self.msg());
-                    }
+                    Err(ErrorReported) => {}
                 }
             }
             _ => intravisit::walk_pat(self, p)
@@ -429,7 +417,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
                 Err(msg) => {
                     self.tcx.sess.add_lint(CONST_ERR, ex.id,
                                            msg.span,
-                                           msg.description().into_owned())
+                                           msg.description().into_oneline().into_owned())
                 }
             }
         }
diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs
index 918e17d21ea..a616b95ef72 100644
--- a/src/librustc_passes/diagnostics.rs
+++ b/src/librustc_passes/diagnostics.rs
@@ -11,7 +11,7 @@
 #![allow(non_snake_case)]
 
 register_long_diagnostics! {
-
+/*
 E0014: r##"
 Constants can only be initialized by a constant value or, in a future
 version of Rust, a call to a const function. This error indicates the use
@@ -30,7 +30,7 @@ const FOO: i32 = { const X : i32 = 0; X };
 const FOO2: i32 = { 0 }; // but brackets are useless here
 ```
 "##,
-
+*/
 E0030: r##"
 When matching against a range, the compiler verifies that the range is
 non-empty.  Range patterns include both end-points, so this is equivalent to
diff --git a/src/librustc_trans/_match.rs b/src/librustc_trans/_match.rs
index 08e894ffbcf..f7fd970f37f 100644
--- a/src/librustc_trans/_match.rs
+++ b/src/librustc_trans/_match.rs
@@ -190,7 +190,7 @@ use self::FailureHandler::*;
 
 use llvm::{ValueRef, BasicBlockRef};
 use rustc_const_eval::check_match::{self, Constructor, StaticInliner};
-use rustc_const_eval::{compare_lit_exprs, eval_const_expr};
+use rustc_const_eval::{compare_lit_exprs, eval_const_expr, fatal_const_eval_err};
 use rustc::hir::def::{Def, DefMap};
 use rustc::hir::def_id::DefId;
 use middle::expr_use_visitor as euv;
@@ -239,9 +239,9 @@ struct ConstantExpr<'a>(&'a hir::Expr);
 
 impl<'a> ConstantExpr<'a> {
     fn eq<'b, 'tcx>(self, other: ConstantExpr<'a>, tcx: TyCtxt<'b, 'tcx, 'tcx>) -> bool {
-        match compare_lit_exprs(tcx, self.0, other.0) {
-            Some(result) => result == Ordering::Equal,
-            None => bug!("compare_list_exprs: type mismatch"),
+        match compare_lit_exprs(tcx, self.0.span, self.0, other.0) {
+            Ok(result) => result == Ordering::Equal,
+            Err(_) => bug!("compare_list_exprs: type mismatch"),
         }
     }
 }
@@ -288,7 +288,9 @@ impl<'a, 'b, 'tcx> Opt<'a, 'tcx> {
                 let expr = consts::const_expr(ccx, &lit_expr, bcx.fcx.param_substs, None, Yes);
                 let llval = match expr {
                     Ok((llval, _)) => llval,
-                    Err(err) => bcx.ccx().sess().span_fatal(lit_expr.span, &err.description()),
+                    Err(err) => {
+                        fatal_const_eval_err(bcx.tcx(), err.as_inner(), lit_expr.span, "pattern");
+                    }
                 };
                 let lit_datum = immediate_rvalue(llval, lit_ty);
                 let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx));
@@ -297,11 +299,11 @@ impl<'a, 'b, 'tcx> Opt<'a, 'tcx> {
             ConstantRange(ConstantExpr(ref l1), ConstantExpr(ref l2), _) => {
                 let l1 = match consts::const_expr(ccx, &l1, bcx.fcx.param_substs, None, Yes) {
                     Ok((l1, _)) => l1,
-                    Err(err) => bcx.ccx().sess().span_fatal(l1.span, &err.description()),
+                    Err(err) => fatal_const_eval_err(bcx.tcx(), err.as_inner(), l1.span, "pattern"),
                 };
                 let l2 = match consts::const_expr(ccx, &l2, bcx.fcx.param_substs, None, Yes) {
                     Ok((l2, _)) => l2,
-                    Err(err) => bcx.ccx().sess().span_fatal(l2.span, &err.description()),
+                    Err(err) => fatal_const_eval_err(bcx.tcx(), err.as_inner(), l2.span, "pattern"),
                 };
                 RangeResult(Result::new(bcx, l1), Result::new(bcx, l2))
             }
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index 00feb2cd1de..f662ba75cc6 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -14,7 +14,7 @@ use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr};
 use llvm::{InternalLinkage, ValueRef, Bool, True};
 use middle::const_qualif::ConstQualif;
 use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, lookup_const_by_id, ErrKind};
-use rustc_const_eval::eval_repeat_count;
+use rustc_const_eval::{eval_length, report_const_eval_err, note_const_eval_err};
 use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
 use rustc::hir::map as hir_map;
@@ -44,7 +44,6 @@ use rustc_const_math::{ConstInt, ConstUsize, ConstIsize};
 use rustc::hir;
 
 use std::ffi::{CStr, CString};
-use std::borrow::Cow;
 use libc::c_uint;
 use syntax::ast::{self, LitKind};
 use syntax::attr::{self, AttrMetaMethods};
@@ -250,10 +249,11 @@ impl ConstEvalFailure {
             Compiletime(e) => e,
         }
     }
-    pub fn description(&self) -> Cow<str> {
+
+    pub fn as_inner(&self) -> &ConstEvalErr {
         match self {
-            &Runtime(ref e) => e.description(),
-            &Compiletime(ref e) => e.description(),
+            &Runtime(ref e) => e,
+            &Compiletime(ref e) => e,
         }
     }
 }
@@ -274,7 +274,7 @@ fn get_const_val<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let empty_substs = ccx.tcx().mk_substs(Substs::empty());
     match get_const_expr_as_global(ccx, expr, ConstQualif::empty(), empty_substs, TrueConst::Yes) {
         Err(Runtime(err)) => {
-            ccx.tcx().sess.span_err(expr.span, &err.description());
+            report_const_eval_err(ccx.tcx(), &err, expr.span, "expression").emit();
             Err(Compiletime(err))
         },
         other => other,
@@ -526,12 +526,15 @@ pub fn const_err<T>(cx: &CrateContext,
         (Ok(x), _) => Ok(x),
         (Err(err), TrueConst::Yes) => {
             let err = ConstEvalErr{ span: span, kind: err };
-            cx.tcx().sess.span_err(span, &err.description());
+            report_const_eval_err(cx.tcx(), &err, span, "expression").emit();
             Err(Compiletime(err))
         },
         (Err(err), TrueConst::No) => {
             let err = ConstEvalErr{ span: span, kind: err };
-            cx.tcx().sess.span_warn(span, &err.description());
+            let mut diag = cx.tcx().sess.struct_span_warn(
+                span, "this expression will panic at run-time");
+            note_const_eval_err(cx.tcx(), &err, span, "expression", &mut diag);
+            diag.emit();
             Err(Runtime(err))
         },
     }
@@ -875,7 +878,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         hir::ExprRepeat(ref elem, ref count) => {
             let unit_ty = ety.sequence_element_type(cx.tcx());
             let llunitty = type_of::type_of(cx, unit_ty);
-            let n = eval_repeat_count(cx.tcx(), count);
+            let n = eval_length(cx.tcx(), count, "repeat count").unwrap();
             let unit_val = const_expr(cx, &elem, param_substs, fn_args, trueconst)?.0;
             let vs = vec![unit_val; n];
             if val_ty(unit_val) != llunitty {
diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs
index a721361fce0..bc5f3a0f22e 100644
--- a/src/librustc_trans/intrinsic.rs
+++ b/src/librustc_trans/intrinsic.rs
@@ -44,6 +44,7 @@ use syntax::ptr::P;
 use syntax::parse::token;
 
 use rustc::session::Session;
+use rustc_const_eval::fatal_const_eval_err;
 use syntax_pos::{Span, DUMMY_SP};
 
 use std::cmp::Ordering;
@@ -1408,7 +1409,10 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a>
                                          // this should probably help simd error reporting
                                          consts::TrueConst::Yes) {
                     Ok((vector, _)) => vector,
-                    Err(err) => bcx.sess().span_fatal(span, &err.description()),
+                    Err(err) => {
+                        fatal_const_eval_err(bcx.tcx(), err.as_inner(), span,
+                                             "shuffle indices");
+                    }
                 }
             }
             None => llargs[2]
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index da72793abf6..1f3b1320316 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -925,7 +925,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
             }
             Err(ConstEvalFailure::Runtime(err)) => {
                 span_bug!(constant.span,
-                          "MIR constant {:?} results in runtime panic: {}",
+                          "MIR constant {:?} results in runtime panic: {:?}",
                           constant, err.description())
             }
         }
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index 8b8e658533e..fc95d208f32 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -29,6 +29,7 @@ use rustc::hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::ty::subst;
 use rustc::dep_graph::DepNode;
+use rustc_const_eval::fatal_const_eval_err;
 use std::hash::{Hash, Hasher};
 use syntax::ast::{self, NodeId};
 use syntax::{attr,errors};
@@ -81,7 +82,11 @@ impl<'a, 'tcx> TransItem<'tcx> {
                 if let hir::ItemStatic(_, m, ref expr) = item.node {
                     match consts::trans_static(&ccx, m, expr, item.id, &item.attrs) {
                         Ok(_) => { /* Cool, everything's alright. */ },
-                        Err(err) => ccx.tcx().sess.span_fatal(expr.span, &err.description()),
+                        Err(err) => {
+                            // FIXME: shouldn't this be a `span_err`?
+                            fatal_const_eval_err(
+                                ccx.tcx(), &err, expr.span, "static");
+                        }
                     };
                 } else {
                     span_bug!(item.span, "Mismatch between hir::Item type and TransItem type")
diff --git a/src/librustc_trans/tvec.rs b/src/librustc_trans/tvec.rs
index f5b9bef5313..92a2d3787bf 100644
--- a/src/librustc_trans/tvec.rs
+++ b/src/librustc_trans/tvec.rs
@@ -30,7 +30,7 @@ use value::Value;
 use rustc::ty::{self, Ty};
 
 use rustc::hir;
-use rustc_const_eval::eval_repeat_count;
+use rustc_const_eval::eval_length;
 
 use syntax::ast;
 use syntax::parse::token::InternedString;
@@ -218,7 +218,7 @@ fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                     return expr::trans_into(bcx, &element, Ignore);
                 }
                 SaveIn(lldest) => {
-                    match eval_repeat_count(bcx.tcx(), &count_expr) {
+                    match eval_length(bcx.tcx(), &count_expr, "repeat count").unwrap() {
                         0 => expr::trans_into(bcx, &element, Ignore),
                         1 => expr::trans_into(bcx, &element, SaveIn(lldest)),
                         count => {
@@ -268,7 +268,7 @@ fn elements_required(bcx: Block, content_expr: &hir::Expr) -> usize {
         },
         hir::ExprVec(ref es) => es.len(),
         hir::ExprRepeat(_, ref count_expr) => {
-            eval_repeat_count(bcx.tcx(), &count_expr)
+            eval_length(bcx.tcx(), &count_expr, "repeat count").unwrap()
         }
         _ => span_bug!(content_expr.span, "unexpected vec content")
     }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 9ff30f9ede2..b642a712219 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -48,10 +48,7 @@
 //! case but `&a` in the second.  Basically, defaults that appear inside
 //! an rptr (`&r.T`) use the region `r` that appears in the rptr.
 
-use middle::const_val::ConstVal;
-use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr};
-use rustc_const_eval::EvalHint::UncheckedExprHint;
-use rustc_const_eval::ErrKind::ErroneousReferencedConstant;
+use rustc_const_eval::eval_length;
 use hir::{self, SelfKind};
 use hir::def::{Def, PathResolution};
 use hir::def_id::DefId;
@@ -70,7 +67,6 @@ use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
 use util::common::{ErrorReported, FN_OUTPUT_NAME};
 use util::nodemap::{NodeMap, FnvHashSet};
 
-use rustc_const_math::ConstInt;
 use std::cell::RefCell;
 use syntax::{abi, ast};
 use syntax::feature_gate::{GateIssue, emit_feature_err};
@@ -1741,33 +1737,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 ty
             }
             hir::TyFixedLengthVec(ref ty, ref e) => {
-                let hint = UncheckedExprHint(tcx.types.usize);
-                match eval_const_expr_partial(tcx.global_tcx(), &e, hint, None) {
-                    Ok(ConstVal::Integral(ConstInt::Usize(i))) => {
-                        let i = i.as_u64(tcx.sess.target.uint_type);
-                        assert_eq!(i as usize as u64, i);
-                        tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), i as usize)
-                    },
-                    Ok(val) => {
-                        span_err!(tcx.sess, ast_ty.span, E0249,
-                                  "expected usize value for array length, got {}",
-                                  val.description());
-                        self.tcx().types.err
-                    },
-                    // array length errors happen before the global constant check
-                    // so we need to report the real error
-                    Err(ConstEvalErr { kind: ErroneousReferencedConstant(box r), ..}) |
-                    Err(r) => {
-                        let mut err = struct_span_err!(tcx.sess, r.span, E0250,
-                                                       "array length constant \
-                                                        evaluation error: {}",
-                                                       r.description());
-                        if !ast_ty.span.contains(r.span) {
-                            span_note!(&mut err, ast_ty.span, "for array length here")
-                        }
-                        err.emit();
-                        self.tcx().types.err
-                    }
+                if let Ok(length) = eval_length(tcx.global_tcx(), &e, "array length") {
+                    tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), length)
+                } else {
+                    self.tcx().types.err
                 }
             }
             hir::TyTypeof(ref _e) => {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 7076b6a2a90..c01edc568af 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -126,7 +126,7 @@ use rustc::hir::intravisit::{self, Visitor};
 use rustc::hir::{self, PatKind};
 use rustc::hir::print as pprust;
 use rustc_back::slice;
-use rustc_const_eval::eval_repeat_count;
+use rustc_const_eval::eval_length;
 
 mod assoc;
 mod autoderef;
@@ -3539,7 +3539,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
           }
           hir::ExprRepeat(ref element, ref count_expr) => {
             self.check_expr_has_type(&count_expr, tcx.types.usize);
-            let count = eval_repeat_count(self.tcx.global_tcx(), &count_expr);
+            let count = eval_length(self.tcx.global_tcx(), &count_expr, "repeat count")
+                  .unwrap_or(0);
 
             let uty = match expected {
                 ExpectHasType(uty) => {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 41e7a467fa3..57602b55cc9 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -66,8 +66,7 @@ use constrained_type_params as ctp;
 use middle::lang_items::SizedTraitLangItem;
 use middle::const_val::ConstVal;
 use rustc_const_eval::EvalHint::UncheckedExprHint;
-use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr};
-use rustc_const_eval::ErrKind::ErroneousReferencedConstant;
+use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err};
 use rustc::ty::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace};
 use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer};
 use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeScheme};
@@ -1091,14 +1090,9 @@ fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             },
             // enum variant evaluation happens before the global constant check
             // so we need to report the real error
-            Err(ConstEvalErr { kind: ErroneousReferencedConstant(box err), ..}) |
             Err(err) => {
-                let mut diag = struct_span_err!(ccx.tcx.sess, err.span, E0080,
-                                                "constant evaluation error: {}",
-                                                err.description());
-                if !e.span.contains(err.span) {
-                    diag.span_note(e.span, "for enum discriminant here");
-                }
+                let mut diag = report_const_eval_err(
+                    ccx.tcx, &err, e.span, "enum discriminant");
                 diag.emit();
                 None
             }
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 683328f4eb4..38bf869119c 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -1079,25 +1079,6 @@ impl Foo {
 ```
 "##,
 
-E0080: r##"
-This error indicates that the compiler was unable to sensibly evaluate an
-integer expression provided as an enum discriminant. Attempting to divide by 0
-or causing integer overflow are two ways to induce this error. For example:
-
-```compile_fail
-enum Enum {
-    X = (1 << 500),
-    Y = (1 / 0)
-}
-```
-
-Ensure that the expressions given can be evaluated as the desired integer type.
-See the FFI section of the Reference for more information about using a custom
-integer type:
-
-https://doc.rust-lang.org/reference.html#ffi-attributes
-"##,
-
 E0081: r##"
 Enum discriminants are used to differentiate enum variants stored in memory.
 This error indicates that the same value was used for two or more variants,
@@ -2970,38 +2951,6 @@ not a distinct static type. Likewise, it's not legal to attempt to
 behavior for specific enum variants.
 "##,
 
-E0249: r##"
-This error indicates a constant expression for the array length was found, but
-it was not an integer (signed or unsigned) expression.
-
-Some examples of code that produces this error are:
-
-```compile_fail
-const A: [u32; "hello"] = []; // error
-const B: [u32; true] = []; // error
-const C: [u32; 0.0] = []; // error
-"##,
-
-E0250: r##"
-There was an error while evaluating the expression for the length of a fixed-
-size array type.
-
-Some examples of this error are:
-
-```compile_fail
-// divide by zero in the length expression
-const A: [u32; 1/0] = [];
-
-// Rust currently will not evaluate the function `foo` at compile time
-fn foo() -> usize { 12 }
-const B: [u32; foo()] = [];
-
-// it is an error to try to add `u8` and `f64`
-use std::{f64, u8};
-const C: [u32; u8::MAX + f64::EPSILON] = [];
-```
-"##,
-
 E0318: r##"
 Default impls for a trait must be located in the same crate where the trait was
 defined. For more information see the [opt-in builtin traits RFC](https://github
@@ -4088,6 +4037,7 @@ register_diagnostics! {
     E0245, // not a trait
 //  E0246, // invalid recursive type
 //  E0247,
+//  E0249,
 //  E0319, // trait impls for defaulted traits allowed just for structs/enums
     E0320, // recursive overflow during dropck
     E0328, // cannot implement Unsize explicitly
diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock
index 4def60e485f..0b2287cf233 100644
--- a/src/rustc/Cargo.lock
+++ b/src/rustc/Cargo.lock
@@ -105,6 +105,7 @@ dependencies = [
  "rustc 0.0.0",
  "rustc_back 0.0.0",
  "rustc_const_math 0.0.0",
+ "rustc_errors 0.0.0",
  "serialize 0.0.0",
  "syntax 0.0.0",
  "syntax_pos 0.0.0",
diff --git a/src/test/compile-fail/array_const_index-0.rs b/src/test/compile-fail/array_const_index-0.rs
index e65230389f9..501c66e75cd 100644
--- a/src/test/compile-fail/array_const_index-0.rs
+++ b/src/test/compile-fail/array_const_index-0.rs
@@ -10,7 +10,8 @@
 
 const A: &'static [i32] = &[];
 const B: i32 = (&A)[1];
-//~^ ERROR index out of bounds: the len is 0 but the index is 1
+//~^ ERROR constant evaluation error
+//~| index out of bounds: the len is 0 but the index is 1
 
 fn main() {
     let _ = B;
diff --git a/src/test/compile-fail/array_const_index-1.rs b/src/test/compile-fail/array_const_index-1.rs
index 69d84e24c49..d3b43e83bfe 100644
--- a/src/test/compile-fail/array_const_index-1.rs
+++ b/src/test/compile-fail/array_const_index-1.rs
@@ -10,7 +10,8 @@
 
 const A: [i32; 0] = [];
 const B: i32 = A[1];
-//~^ ERROR index out of bounds: the len is 0 but the index is 1
+//~^ ERROR constant evaluation error
+//~| index out of bounds: the len is 0 but the index is 1
 
 fn main() {
     let _ = B;
diff --git a/src/test/compile-fail/associated-const-array-len.rs b/src/test/compile-fail/associated-const-array-len.rs
index 5d8007defc9..0239986f5ad 100644
--- a/src/test/compile-fail/associated-const-array-len.rs
+++ b/src/test/compile-fail/associated-const-array-len.rs
@@ -14,7 +14,7 @@ trait Foo {
     const ID: usize;
 }
 
-const X: [i32; <i32 as Foo>::ID] = [0, 1, 2]; //~ ERROR E0250
+const X: [i32; <i32 as Foo>::ID] = [0, 1, 2]; //~ ERROR E0080
 
 fn main() {
     assert_eq!(1, X);
diff --git a/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs b/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs
index 2f687350f34..c3fa39659b9 100644
--- a/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs
+++ b/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs
@@ -25,7 +25,8 @@ impl Foo for Def {
 }
 
 pub fn test<A: Foo, B: Foo>() {
-    let _array = [4; <A as Foo>::Y]; //~ error: expected constant integer
+    let _array = [4; <A as Foo>::Y]; //~ ERROR E0080
+                                     //~| non-constant path in constant
 }
 
 fn main() {
diff --git a/src/test/compile-fail/const-array-oob.rs b/src/test/compile-fail/const-array-oob.rs
index faabed4fd5e..b980bc02c85 100644
--- a/src/test/compile-fail/const-array-oob.rs
+++ b/src/test/compile-fail/const-array-oob.rs
@@ -16,7 +16,8 @@ const FOO: [u32; 3] = [1, 2, 3];
 const BAR: u32 = FOO[5]; // no error, because the error below occurs before regular const eval
 
 const BLUB: [u32; FOO[4]] = [5, 6];
-//~^ ERROR array length constant evaluation error: index out of bounds: the len is 3 but the index is 4 [E0250]
+//~^ ERROR constant evaluation error [E0080]
+//~| index out of bounds: the len is 3 but the index is 4
 
 fn main() {
     let _ = BAR;
diff --git a/src/test/compile-fail/const-call.rs b/src/test/compile-fail/const-call.rs
index 1143d3bd5cd..7e2eabf412d 100644
--- a/src/test/compile-fail/const-call.rs
+++ b/src/test/compile-fail/const-call.rs
@@ -15,5 +15,6 @@ fn f(x: usize) -> usize {
 }
 
 fn main() {
-    let _ = [0; f(2)]; //~ ERROR: non-constant path in constant expression [E0307]
+    let _ = [0; f(2)]; //~ ERROR constant evaluation error [E0080]
+                       //~| non-constant path in constant expression
 }
diff --git a/src/test/compile-fail/const-err.rs b/src/test/compile-fail/const-err.rs
index a1d3888e78e..f2079800cad 100644
--- a/src/test/compile-fail/const-err.rs
+++ b/src/test/compile-fail/const-err.rs
@@ -22,21 +22,29 @@ fn black_box<T>(_: T) {
 
 // Make sure that the two uses get two errors.
 const FOO: u8 = [5u8][1];
-//~^ ERROR index out of bounds: the len is 1 but the index is 1
-//~^^ ERROR index out of bounds: the len is 1 but the index is 1
+//~^ ERROR constant evaluation error
+//~| index out of bounds: the len is 1 but the index is 1
+//~^^^ ERROR constant evaluation error
+//~| index out of bounds: the len is 1 but the index is 1
 
 fn main() {
     let a = -std::i8::MIN;
-    //~^ WARN attempted to negate with overflow
+    //~^ WARN this expression will panic at run-time
+    //~| attempted to negate with overflow
     let b = 200u8 + 200u8 + 200u8;
-    //~^ WARN attempted to add with overflow
-    //~| WARN attempted to add with overflow
+    //~^ WARN this expression will panic at run-time
+    //~| attempted to add with overflow
+    //~^^^ WARN this expression will panic at run-time
+    //~| attempted to add with overflow
     let c = 200u8 * 4;
-    //~^ WARN attempted to multiply with overflow
+    //~^ WARN this expression will panic at run-time
+    //~| attempted to multiply with overflow
     let d = 42u8 - (42u8 + 1);
-    //~^ WARN attempted to subtract with overflow
+    //~^ WARN this expression will panic at run-time
+    //~| attempted to subtract with overflow
     let _e = [5u8][1];
-    //~^ WARN index out of bounds: the len is 1 but the index is 1
+    //~^ WARN this expression will panic at run-time
+    //~| index out of bounds: the len is 1 but the index is 1
     black_box(a);
     black_box(b);
     black_box(c);
diff --git a/src/test/compile-fail/const-eval-overflow-2.rs b/src/test/compile-fail/const-eval-overflow-2.rs
index 07e27a7dc9a..4749457da88 100644
--- a/src/test/compile-fail/const-eval-overflow-2.rs
+++ b/src/test/compile-fail/const-eval-overflow-2.rs
@@ -19,13 +19,16 @@ use std::{u8, u16, u32, u64, usize};
 
 const NEG_128: i8 = -128;
 const NEG_NEG_128: i8 = -NEG_128;
-//~^ ERROR constant evaluation error: attempted to negate with overflow
-//~| ERROR attempted to negate with overflow
-//~| ERROR attempted to negate with overflow
+//~^ ERROR constant evaluation error
+//~| attempted to negate with overflow
+//~| ERROR constant evaluation error
+//~| attempted to negate with overflow
+//~| ERROR constant evaluation error
+//~| attempted to negate with overflow
 
 fn main() {
     match -128i8 {
-        NEG_NEG_128 => println!("A"), //~ NOTE in pattern here
+        NEG_NEG_128 => println!("A"), //~ NOTE for pattern here
         _ => println!("B"),
     }
 }
diff --git a/src/test/compile-fail/const-eval-overflow-3.rs b/src/test/compile-fail/const-eval-overflow-3.rs
index c90ae045f96..c78c74e9e23 100644
--- a/src/test/compile-fail/const-eval-overflow-3.rs
+++ b/src/test/compile-fail/const-eval-overflow-3.rs
@@ -17,7 +17,7 @@
 // self-hosted and a cross-compiled setup; therefore resorting to
 // error-pattern for now.
 
-// error-pattern: expected constant integer for repeat count, but attempted to add with overflow
+// error-pattern: attempted to add with overflow
 
 #![allow(unused_imports)]
 
diff --git a/src/test/compile-fail/const-eval-overflow-4b.rs b/src/test/compile-fail/const-eval-overflow-4b.rs
index 31e1a72967f..e7639a4ff70 100644
--- a/src/test/compile-fail/const-eval-overflow-4b.rs
+++ b/src/test/compile-fail/const-eval-overflow-4b.rs
@@ -20,9 +20,10 @@ use std::{u8, u16, u32, u64, usize};
 
 const A_I8_T
     : [u32; (i8::MAX as i8 + 1u8) as usize]
-    //~^ ERROR mismatched types:
-    //~| expected `i8`,
-    //~| found `u8` [E0250]
+    //~^ ERROR constant evaluation error [E0080]
+    //~| mismatched types
+    //~| expected `i8`
+    //~| found `u8`
     = [0; (i8::MAX as usize) + 1];
 
 
@@ -33,7 +34,8 @@ const A_CHAR_USIZE
 
 const A_BAD_CHAR_USIZE
     : [u32; 5i8 as char as usize]
-    //~^ ERROR only `u8` can be cast as `char`, not `i8`
+    //~^ ERROR constant evaluation error
+    //~| only `u8` can be cast as `char`, not `i8`
     = [0; 5];
 
 fn main() {}
diff --git a/src/test/compile-fail/const-eval-overflow.rs b/src/test/compile-fail/const-eval-overflow.rs
index 3dfcb5bb29a..c1c693544fa 100644
--- a/src/test/compile-fail/const-eval-overflow.rs
+++ b/src/test/compile-fail/const-eval-overflow.rs
@@ -21,86 +21,114 @@ use std::{u8, u16, u32, u64, usize};
 
 const VALS_I8: (i8, i8, i8, i8) =
     (-i8::MIN,
-     //~^ ERROR attempted to negate with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to negate with overflow
      i8::MIN - 1,
-     //~^ ERROR attempted to subtract with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to subtract with overflow
      i8::MAX + 1,
-     //~^ ERROR attempted to add with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to add with overflow
      i8::MIN * 2,
-     //~^ ERROR attempted to multiply with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to multiply with overflow
      );
 
 const VALS_I16: (i16, i16, i16, i16) =
     (-i16::MIN,
-     //~^ ERROR attempted to negate with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to negate with overflow
      i16::MIN - 1,
-     //~^ ERROR attempted to subtract with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to subtract with overflow
      i16::MAX + 1,
-     //~^ ERROR attempted to add with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to add with overflow
      i16::MIN * 2,
-     //~^ ERROR attempted to multiply with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to multiply with overflow
      );
 
 const VALS_I32: (i32, i32, i32, i32) =
     (-i32::MIN,
-     //~^ ERROR attempted to negate with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to negate with overflow
      i32::MIN - 1,
-     //~^ ERROR attempted to subtract with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to subtract with overflow
      i32::MAX + 1,
-     //~^ ERROR attempted to add with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to add with overflow
      i32::MIN * 2,
-     //~^ ERROR attempted to multiply with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to multiply with overflow
      );
 
 const VALS_I64: (i64, i64, i64, i64) =
     (-i64::MIN,
-     //~^ ERROR attempted to negate with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to negate with overflow
      i64::MIN - 1,
-     //~^ ERROR attempted to subtract with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to subtract with overflow
      i64::MAX + 1,
-     //~^ ERROR attempted to add with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to add with overflow
      i64::MAX * 2,
-     //~^ ERROR attempted to multiply with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to multiply with overflow
      );
 
 const VALS_U8: (u8, u8, u8, u8) =
     (-(u8::MIN as i8) as u8,
      u8::MIN - 1,
-     //~^ ERROR attempted to subtract with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to subtract with overflow
      u8::MAX + 1,
-     //~^ ERROR attempted to add with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to add with overflow
      u8::MAX * 2,
-     //~^ ERROR attempted to multiply with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to multiply with overflow
      );
 
 const VALS_U16: (u16, u16, u16, u16) =
     (-(u16::MIN as i16) as u16,
      u16::MIN - 1,
-     //~^ ERROR attempted to subtract with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to subtract with overflow
      u16::MAX + 1,
-     //~^ ERROR attempted to add with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to add with overflow
      u16::MAX * 2,
-     //~^ ERROR attempted to multiply with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to multiply with overflow
      );
 
 const VALS_U32: (u32, u32, u32, u32) =
     (-(u32::MIN as i32) as u32,
      u32::MIN - 1,
-     //~^ ERROR attempted to subtract with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to subtract with overflow
      u32::MAX + 1,
-     //~^ ERROR attempted to add with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to add with overflow
      u32::MAX * 2,
-     //~^ ERROR attempted to multiply with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to multiply with overflow
      );
 
 const VALS_U64: (u64, u64, u64, u64) =
     (-(u64::MIN as i64) as u64,
      u64::MIN - 1,
-     //~^ ERROR attempted to subtract with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to subtract with overflow
      u64::MAX + 1,
-     //~^ ERROR attempted to add with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to add with overflow
      u64::MAX * 2,
-     //~^ ERROR attempted to multiply with overflow
+     //~^ ERROR constant evaluation error
+     //~| attempted to multiply with overflow
      );
 
 fn main() {
diff --git a/src/test/compile-fail/const-eval-span.rs b/src/test/compile-fail/const-eval-span.rs
index 9fdd24c42fd..73351429b50 100644
--- a/src/test/compile-fail/const-eval-span.rs
+++ b/src/test/compile-fail/const-eval-span.rs
@@ -14,7 +14,8 @@
 struct S(i32);
 
 const CONSTANT: S = S(0);
-//~^ ERROR: unimplemented constant expression: tuple struct constructors [E0080]
+//~^ ERROR E0080
+//~| unimplemented constant expression: tuple struct constructors
 
 enum E {
     V = CONSTANT,
diff --git a/src/test/compile-fail/const-fn-error.rs b/src/test/compile-fail/const-fn-error.rs
index 45a00de48e7..dd0f058f2c9 100644
--- a/src/test/compile-fail/const-fn-error.rs
+++ b/src/test/compile-fail/const-fn-error.rs
@@ -17,10 +17,11 @@ const fn f(x: usize) -> usize {
     for i in 0..x {
         sum += i;
     }
-    sum //~ ERROR: E0250
+    sum //~ ERROR E0080
+        //~| non-constant path in constant
 }
 
 #[allow(unused_variables)]
 fn main() {
-    let a : [i32; f(X)];
+    let a : [i32; f(X)]; //~ NOTE for array length here
 }
diff --git a/src/test/compile-fail/const-index-feature-gate.rs b/src/test/compile-fail/const-index-feature-gate.rs
index 09822e46cc1..4f92770df28 100644
--- a/src/test/compile-fail/const-index-feature-gate.rs
+++ b/src/test/compile-fail/const-index-feature-gate.rs
@@ -9,7 +9,8 @@
 // except according to those terms.
 
 const ARR: [usize; 1] = [2];
-const ARR2: [i32; ARR[0]] = [5, 6]; //~ ERROR unstable
+const ARR2: [i32; ARR[0]] = [5, 6]; //~ ERROR E0080
+                                    //~| unstable
 
 fn main() {
 }
diff --git a/src/test/compile-fail/const-integer-bool-ops.rs b/src/test/compile-fail/const-integer-bool-ops.rs
index 0d6cf3bab45..5dadd892f83 100644
--- a/src/test/compile-fail/const-integer-bool-ops.rs
+++ b/src/test/compile-fail/const-integer-bool-ops.rs
@@ -8,30 +8,34 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-const X: usize = 42 && 39; //~ ERROR: can't do this op on integrals
+const X: usize = 42 && 39; //~ ERROR E0080
+                           //~| can't do this op on integrals
 const ARR: [i32; X] = [99; 34]; //~ NOTE: for array length here
 
-const X1: usize = 42 || 39; //~ ERROR: can't do this op on integrals
+const X1: usize = 42 || 39; //~ ERROR E0080
+                            //~| can't do this op on integrals
 const ARR1: [i32; X1] = [99; 47]; //~ NOTE: for array length here
 
-const X2: usize = -42 || -39; //~ ERROR: unary negation of unsigned integer
+const X2: usize = -42 || -39; //~ ERROR E0080
+                              //~| unary negation of unsigned integer
 const ARR2: [i32; X2] = [99; 18446744073709551607]; //~ NOTE: for array length here
 
-const X3: usize = -42 && -39; //~ ERROR: unary negation of unsigned integer
+const X3: usize = -42 && -39; //~ ERROR E0080
+                              //~| unary negation of unsigned integer
 const ARR3: [i32; X3] = [99; 6]; //~ NOTE: for array length here
 
 const Y: usize = 42.0 == 42.0;
-const ARRR: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length
+const ARRR: [i32; Y] = [99; 1]; //~ ERROR: expected usize for array length
 const Y1: usize = 42.0 >= 42.0;
-const ARRR1: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length
+const ARRR1: [i32; Y] = [99; 1]; //~ ERROR: expected usize for array length
 const Y2: usize = 42.0 <= 42.0;
-const ARRR2: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length
+const ARRR2: [i32; Y] = [99; 1]; //~ ERROR: expected usize for array length
 const Y3: usize = 42.0 > 42.0;
-const ARRR3: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length
+const ARRR3: [i32; Y] = [99; 0]; //~ ERROR: expected usize for array length
 const Y4: usize = 42.0 < 42.0;
-const ARRR4: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length
+const ARRR4: [i32; Y] = [99; 0]; //~ ERROR: expected usize for array length
 const Y5: usize = 42.0 != 42.0;
-const ARRR5: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length
+const ARRR5: [i32; Y] = [99; 0]; //~ ERROR: expected usize for array length
 
 fn main() {
     let _ = ARR;
diff --git a/src/test/compile-fail/const-len-underflow-separate-spans.rs b/src/test/compile-fail/const-len-underflow-separate-spans.rs
index 9c6b774b990..43375ee3d18 100644
--- a/src/test/compile-fail/const-len-underflow-separate-spans.rs
+++ b/src/test/compile-fail/const-len-underflow-separate-spans.rs
@@ -15,7 +15,8 @@
 const ONE: usize = 1;
 const TWO: usize = 2;
 const LEN: usize = ONE - TWO;
-//~^ ERROR array length constant evaluation error: attempted to subtract with overflow [E0250]
+//~^ ERROR E0080
+//~| attempted to subtract with overflow
 
 fn main() {
     let a: [i8; LEN] = unimplemented!();
diff --git a/src/test/compile-fail/const-len-underflow-subspans.rs b/src/test/compile-fail/const-len-underflow-subspans.rs
index d51f31087d0..e338f206553 100644
--- a/src/test/compile-fail/const-len-underflow-subspans.rs
+++ b/src/test/compile-fail/const-len-underflow-subspans.rs
@@ -16,5 +16,6 @@ const TWO: usize = 2;
 
 fn main() {
     let a: [i8; ONE - TWO] = unimplemented!();
-    //~^ ERROR array length constant evaluation error: attempted to subtract with overflow [E0250]
+    //~^ ERROR constant evaluation error [E0080]
+    //~| attempted to subtract with overflow
 }
diff --git a/src/test/compile-fail/const-pattern-not-const-evaluable.rs b/src/test/compile-fail/const-pattern-not-const-evaluable.rs
index 4567cd4a74b..d68d63683a7 100644
--- a/src/test/compile-fail/const-pattern-not-const-evaluable.rs
+++ b/src/test/compile-fail/const-pattern-not-const-evaluable.rs
@@ -17,22 +17,26 @@ enum Cake {
 use Cake::*;
 
 const BOO: (Cake, Cake) = (Marmor, BlackForest);
-//~^ ERROR: constant evaluation error: unimplemented constant expression: enum variants [E0471]
+//~^ ERROR: constant evaluation error [E0080]
+//~| unimplemented constant expression: enum variants
 const FOO: Cake = BOO.1;
 
 const fn foo() -> Cake {
-    Marmor //~ ERROR: constant evaluation error: unimplemented constant expression: enum variants
-    //~^ ERROR: unimplemented constant expression: enum variants
+    Marmor
+        //~^ ERROR: constant evaluation error [E0080]
+        //~| unimplemented constant expression: enum variants
+        //~^^^ ERROR: constant evaluation error [E0080]
+        //~| unimplemented constant expression: enum variants
 }
 
 const WORKS: Cake = Marmor;
 
-const GOO: Cake = foo();
+const GOO: Cake = foo(); //~ NOTE for expression here
 
 fn main() {
     match BlackForest {
-        FOO => println!("hi"), //~ NOTE: in pattern here
-        GOO => println!("meh"), //~ NOTE: in pattern here
+        FOO => println!("hi"), //~ NOTE: for pattern here
+        GOO => println!("meh"), //~ NOTE: for pattern here
         WORKS => println!("möp"),
         _ => println!("bye"),
     }
diff --git a/src/test/compile-fail/const-slice-oob.rs b/src/test/compile-fail/const-slice-oob.rs
index d63b0097e5a..b1b4bfe2d1c 100644
--- a/src/test/compile-fail/const-slice-oob.rs
+++ b/src/test/compile-fail/const-slice-oob.rs
@@ -10,7 +10,8 @@
 
 const FOO: &'static[u32] = &[1, 2, 3];
 const BAR: u32 = FOO[5];
-//~^ ERROR index out of bounds: the len is 3 but the index is 5
+//~^ ERROR constant evaluation error [E0080]
+//~| index out of bounds: the len is 3 but the index is 5
 
 fn main() {
     let _ = BAR;
diff --git a/src/test/compile-fail/const-tup-index-span.rs b/src/test/compile-fail/const-tup-index-span.rs
index 9d3c432d148..6f095b3041f 100644
--- a/src/test/compile-fail/const-tup-index-span.rs
+++ b/src/test/compile-fail/const-tup-index-span.rs
@@ -11,7 +11,8 @@
 // Test spans of errors
 
 const TUP: (usize,) = 5 << 64;
-//~^ ERROR: attempted to shift left with overflow [E0250]
+//~^ ERROR E0080
+//~| attempted to shift left with overflow
 const ARR: [i32; TUP.0] = [];
 
 fn main() {
diff --git a/src/test/compile-fail/discrim-ill-typed.rs b/src/test/compile-fail/discrim-ill-typed.rs
index 23106c99594..5af889cb239 100644
--- a/src/test/compile-fail/discrim-ill-typed.rs
+++ b/src/test/compile-fail/discrim-ill-typed.rs
@@ -25,7 +25,8 @@ fn f_i8() {
         Ok = i8::MAX - 1,
         Ok2,
         OhNo = 0_u8,
-        //~^ ERROR mismatched types
+        //~^ ERROR E0080
+        //~| mismatched types
     }
 
     let x = A::Ok;
@@ -37,7 +38,8 @@ fn f_u8() {
         Ok = u8::MAX - 1,
         Ok2,
         OhNo = 0_i8,
-        //~^  ERROR mismatched types
+        //~^ ERROR E0080
+        //~| mismatched types
     }
 
     let x = A::Ok;
@@ -49,7 +51,8 @@ fn f_i16() {
         Ok = i16::MAX - 1,
         Ok2,
         OhNo = 0_u16,
-        //~^ ERROR mismatched types
+        //~^ ERROR E0080
+        //~| mismatched types
     }
 
     let x = A::Ok;
@@ -61,7 +64,8 @@ fn f_u16() {
         Ok = u16::MAX - 1,
         Ok2,
         OhNo = 0_i16,
-        //~^ ERROR mismatched types
+        //~^ ERROR E0080
+        //~| mismatched types
     }
 
     let x = A::Ok;
@@ -73,7 +77,8 @@ fn f_i32() {
         Ok = i32::MAX - 1,
         Ok2,
         OhNo = 0_u32,
-        //~^ ERROR mismatched types
+        //~^ ERROR E0080
+        //~| mismatched types
     }
 
     let x = A::Ok;
@@ -85,7 +90,8 @@ fn f_u32() {
         Ok = u32::MAX - 1,
         Ok2,
         OhNo = 0_i32,
-        //~^ ERROR mismatched types
+        //~^ ERROR E0080
+        //~| mismatched types
     }
 
     let x = A::Ok;
@@ -97,7 +103,8 @@ fn f_i64() {
         Ok = i64::MAX - 1,
         Ok2,
         OhNo = 0_u64,
-        //~^ ERROR mismatched types
+        //~^ ERROR E0080
+        //~| mismatched types
     }
 
     let x = A::Ok;
@@ -109,7 +116,8 @@ fn f_u64() {
         Ok = u64::MAX - 1,
         Ok2,
         OhNo = 0_i64,
-        //~^ ERROR mismatched types
+        //~^ ERROR E0080
+        //~| mismatched types
     }
 
     let x = A::Ok;
diff --git a/src/test/compile-fail/enum-discrim-too-small.rs b/src/test/compile-fail/enum-discrim-too-small.rs
index d6ba09bb4c5..bbdb3891d99 100644
--- a/src/test/compile-fail/enum-discrim-too-small.rs
+++ b/src/test/compile-fail/enum-discrim-too-small.rs
@@ -13,28 +13,32 @@
 enum Eu8 {
     Au8 = 23,
     Bu8 = 223,
-    Cu8 = -23, //~ ERROR unary negation of unsigned integer
+    Cu8 = -23, //~ ERROR E0080
+               //~| unary negation of unsigned integer
 }
 
 #[repr(u16)]
 enum Eu16 {
     Au16 = 23,
     Bu16 = 55555,
-    Cu16 = -22333, //~ ERROR unary negation of unsigned integer
+    Cu16 = -22333, //~ ERROR E0080
+                   //~| unary negation of unsigned integer
 }
 
 #[repr(u32)]
 enum Eu32 {
     Au32 = 23,
     Bu32 = 3_000_000_000,
-    Cu32 = -2_000_000_000, //~ ERROR unary negation of unsigned integer
+    Cu32 = -2_000_000_000, //~ ERROR E0080
+                           //~| unary negation of unsigned integer
 }
 
 #[repr(u64)]
 enum Eu64 {
     Au32 = 23,
     Bu32 = 3_000_000_000,
-    Cu32 = -2_000_000_000, //~ ERROR unary negation of unsigned integer
+    Cu32 = -2_000_000_000, //~ ERROR E0080
+                           //~| unary negation of unsigned integer
 }
 
 // u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`.  This is a
diff --git a/src/test/compile-fail/eval-enum.rs b/src/test/compile-fail/eval-enum.rs
index 7ca274b81e5..57db583aefe 100644
--- a/src/test/compile-fail/eval-enum.rs
+++ b/src/test/compile-fail/eval-enum.rs
@@ -9,9 +9,11 @@
 // except according to those terms.
 
 enum test {
-    div_zero = 1/0, //~ERROR constant evaluation error: attempted to divide by zero
+    div_zero = 1/0, //~ ERROR E0080
+                    //~| attempted to divide by zero
     rem_zero = 1%0,
-//~^ ERROR constant evaluation error: attempted to calculate the remainder with a divisor of zero
+    //~^ ERROR E0080
+    //~| attempted to calculate the remainder with a divisor of zero
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/feature-gate-negate-unsigned0.rs b/src/test/compile-fail/feature-gate-negate-unsigned0.rs
index 05b194345d4..89ae1a09bd3 100644
--- a/src/test/compile-fail/feature-gate-negate-unsigned0.rs
+++ b/src/test/compile-fail/feature-gate-negate-unsigned0.rs
@@ -18,14 +18,17 @@ impl std::ops::Neg for S {
 
 fn main() {
     let a = -1;
-    //~^ ERROR unary negation of unsigned integer
+    //~^ ERROR E0080
+    //~| unary negation of unsigned integer
     let _b : u8 = a; // for infering variable a to u8.
 
     let _d = -1u8;
-    //~^ ERROR unary negation of unsigned integer
+    //~^ ERROR E0080
+    //~| unary negation of unsigned integer
 
     for _ in -10..10u8 {}
-    //~^ ERROR unary negation of unsigned integer
+    //~^ ERROR E0080
+    //~| unary negation of unsigned integer
 
     -S; // should not trigger the gate; issue 26840
 }
diff --git a/src/test/compile-fail/invalid-path-in-const.rs b/src/test/compile-fail/invalid-path-in-const.rs
index 3c4ad5a56ec..9a9358b787f 100644
--- a/src/test/compile-fail/invalid-path-in-const.rs
+++ b/src/test/compile-fail/invalid-path-in-const.rs
@@ -10,5 +10,6 @@
 
 fn main() {
     fn f(a: [u8; u32::DOESNOTEXIST]) {}
-    //~^ ERROR unresolved path in constant expression
+    //~^ ERROR constant evaluation error
+    //~| unresolved path in constant expression
 }
diff --git a/src/test/compile-fail/issue-22933-2.rs b/src/test/compile-fail/issue-22933-2.rs
index 7d619c270d3..54a24089354 100644
--- a/src/test/compile-fail/issue-22933-2.rs
+++ b/src/test/compile-fail/issue-22933-2.rs
@@ -12,10 +12,12 @@ enum Delicious {
     Pie      = 0x1,
     Apple    = 0x2,
     ApplePie = Delicious::Apple as isize | Delicious::PIE as isize,
-    //~^ ERROR constant evaluation error: unresolved path in constant expression
+    //~^ ERROR constant evaluation error
+    //~| unresolved path in constant expression
 }
 
 const FOO: [u32; u8::MIN as usize] = [];
-//~^ ERROR array length constant evaluation error: unresolved path in constant expression
+//~^ ERROR constant evaluation error
+//~| unresolved path in constant expression
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-23217.rs b/src/test/compile-fail/issue-23217.rs
index 32cdd6b5ed9..c2bcbb9d54a 100644
--- a/src/test/compile-fail/issue-23217.rs
+++ b/src/test/compile-fail/issue-23217.rs
@@ -10,7 +10,8 @@
 
 pub enum SomeEnum {
     B = SomeEnum::A,
-    //~^ ERROR constant evaluation error: unresolved path in constant expression
+    //~^ ERROR constant evaluation error
+    //~| unresolved path in constant expression
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-25145.rs b/src/test/compile-fail/issue-25145.rs
index e8a9c8d2ea3..93f75e9bfed 100644
--- a/src/test/compile-fail/issue-25145.rs
+++ b/src/test/compile-fail/issue-25145.rs
@@ -17,6 +17,7 @@ impl S {
 }
 
 static STUFF: [u8; S::N] = [0; S::N];
-//~^ ERROR array length constant evaluation error: unresolved path in constant expression
+//~^ ERROR constant evaluation error
+//~| unresolved path in constant expression
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-27008.rs b/src/test/compile-fail/issue-27008.rs
index bdcbaf09177..ee6ec527612 100644
--- a/src/test/compile-fail/issue-27008.rs
+++ b/src/test/compile-fail/issue-27008.rs
@@ -16,5 +16,5 @@ fn main() {
     //~| expected type `usize`
     //~| found type `S`
     //~| expected usize, found struct `S`
-    //~| ERROR expected positive integer for repeat count, found struct
+    //~| ERROR expected usize for repeat count, found struct
 }
diff --git a/src/test/compile-fail/issue-27895.rs b/src/test/compile-fail/issue-27895.rs
index 3b3abc94a49..ca8d5a1f704 100644
--- a/src/test/compile-fail/issue-27895.rs
+++ b/src/test/compile-fail/issue-27895.rs
@@ -14,7 +14,8 @@ fn main() {
 
     match i {
         0...index => println!("winner"),
-        //~^ ERROR non-constant path in constant expression
+        //~^ ERROR constant evaluation error
+        //~| non-constant path in constant expression
         _ => println!("hello"),
     }
 }
diff --git a/src/test/compile-fail/issue-28586.rs b/src/test/compile-fail/issue-28586.rs
index c8a1e424da2..1dfd146985f 100644
--- a/src/test/compile-fail/issue-28586.rs
+++ b/src/test/compile-fail/issue-28586.rs
@@ -11,6 +11,6 @@
 // Regression test for issue #28586
 
 pub trait Foo {}
-impl Foo for [u8; usize::BYTES] {} //~ ERROR E0250
+impl Foo for [u8; usize::BYTES] {} //~ ERROR E0080
 
 fn main() { }
diff --git a/src/test/compile-fail/issue-3521.rs b/src/test/compile-fail/issue-3521.rs
index 52375ef281a..1b6e4b1d289 100644
--- a/src/test/compile-fail/issue-3521.rs
+++ b/src/test/compile-fail/issue-3521.rs
@@ -15,7 +15,8 @@ fn main() {
     enum Stuff {
         Bar = foo
         //~^ ERROR attempt to use a non-constant value in a constant
-        //~^^ ERROR constant evaluation error: non-constant path in constant expression
+        //~^^ ERROR constant evaluation error
+        //~| non-constant path in constant expression
     }
 
     println!("{}", Stuff::Bar);
diff --git a/src/test/compile-fail/issue-8761.rs b/src/test/compile-fail/issue-8761.rs
index 1c98abce030..6352f4f6a04 100644
--- a/src/test/compile-fail/issue-8761.rs
+++ b/src/test/compile-fail/issue-8761.rs
@@ -10,13 +10,13 @@
 
 enum Foo {
     A = 1i64,
-    //~^ ERROR mismatched types:
-    //~| expected `isize`,
-    //~| found `i64` [E0080]
+    //~^ ERROR constant evaluation error
+    //~| expected `isize`
+    //~| found `i64`
     B = 2u8
-    //~^ ERROR mismatched types:
-    //~| expected `isize`,
-    //~| found `u8` [E0080]
+    //~^ ERROR constant evaluation error
+    //~| expected `isize`
+    //~| found `u8`
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs b/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs
index 9564a080b8e..cadfec5a38d 100644
--- a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs
+++ b/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs
@@ -15,5 +15,6 @@ enum State { ST_NULL, ST_WHITESPACE }
 
 fn main() {
     [State::ST_NULL; (State::ST_WHITESPACE as usize)];
-    //~^ ERROR expected constant integer for repeat count, but unimplemented constant expression
+    //~^ ERROR constant evaluation error
+    //~| unimplemented constant expression: enum variants
 }
diff --git a/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs b/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs
index 3ce206ff7fb..a6f88a57b91 100644
--- a/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs
+++ b/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs
@@ -13,6 +13,8 @@
 fn main() {
     fn bar(n: usize) {
         let _x = [0; n];
-        //~^ ERROR expected constant integer for repeat count, found variable
+        //~^ ERROR constant evaluation error
+        //~| non-constant path in constant expression
+        //~| NOTE `n` is a variable
     }
 }
diff --git a/src/test/compile-fail/non-constant-in-const-path.rs b/src/test/compile-fail/non-constant-in-const-path.rs
index ee88168515d..737f80372de 100644
--- a/src/test/compile-fail/non-constant-in-const-path.rs
+++ b/src/test/compile-fail/non-constant-in-const-path.rs
@@ -12,6 +12,7 @@ fn main() {
     let x = 0;
     match 1 {
         0 ... x => {}
-        //~^ ERROR non-constant path in constant expression
+        //~^ ERROR constant evaluation error
+        //~| non-constant path in constant expression
     };
 }
diff --git a/src/test/compile-fail/repeat_count.rs b/src/test/compile-fail/repeat_count.rs
index ab5af64d95c..d68df973641 100644
--- a/src/test/compile-fail/repeat_count.rs
+++ b/src/test/compile-fail/repeat_count.rs
@@ -13,37 +13,38 @@
 fn main() {
     let n = 1;
     let a = [0; n];
-    //~^ ERROR expected constant integer for repeat count, found variable [E0307]
+    //~^ ERROR constant evaluation error
+    //~| non-constant path in constant expression
     let b = [0; ()];
     //~^ ERROR mismatched types
     //~| expected type `usize`
     //~| found type `()`
     //~| expected usize, found ()
-    //~| ERROR expected positive integer for repeat count, found tuple [E0306]
+    //~| ERROR expected usize for repeat count, found tuple [E0306]
     let c = [0; true];
     //~^ ERROR mismatched types
     //~| expected usize, found bool
-    //~| ERROR expected positive integer for repeat count, found boolean [E0306]
+    //~| ERROR expected usize for repeat count, found boolean [E0306]
     let d = [0; 0.5];
     //~^ ERROR mismatched types
     //~| expected type `usize`
     //~| found type `_`
     //~| expected usize, found floating-point variable
-    //~| ERROR expected positive integer for repeat count, found float [E0306]
+    //~| ERROR expected usize for repeat count, found float [E0306]
     let e = [0; "foo"];
     //~^ ERROR mismatched types
     //~| expected type `usize`
     //~| found type `&'static str`
     //~| expected usize, found &-ptr
-    //~| ERROR expected positive integer for repeat count, found string literal [E0306]
+    //~| ERROR expected usize for repeat count, found string literal [E0306]
     let f = [0; -4_isize];
-    //~^ ERROR mismatched types
+    //~^ ERROR constant evaluation error
     //~| expected `usize`
     //~| found `isize`
-    //~| ERROR mismatched types:
+    //~| ERROR mismatched types
     //~| expected usize, found isize
     let f = [0_usize; -1_isize];
-    //~^ ERROR mismatched types
+    //~^ ERROR constant evaluation error
     //~| expected `usize`
     //~| found `isize`
     //~| ERROR mismatched types
@@ -56,5 +57,5 @@ fn main() {
     //~| expected type `usize`
     //~| found type `main::G`
     //~| expected usize, found struct `main::G`
-    //~| ERROR expected positive integer for repeat count, found struct [E0306]
+    //~| ERROR expected usize for repeat count, found struct [E0306]
 }

From 712c5cadbbb460a0b313a2fbcdaa9d6e10a25b6b Mon Sep 17 00:00:00 2001
From: Ariel Ben-Yehuda <ariel.byd@gmail.com>
Date: Tue, 19 Jul 2016 01:10:19 +0300
Subject: [PATCH 07/14] remove the now-unused multiline error code

---
 src/librustc/session/mod.rs | 81 ++-----------------------------------
 1 file changed, 4 insertions(+), 77 deletions(-)

diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index fa9bc7c8368..5901c42b525 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -126,20 +126,14 @@ impl Session {
                                                    sp: S,
                                                    msg: &str)
                                                    -> DiagnosticBuilder<'a>  {
-        match split_msg_into_multilines(msg) {
-            Some(ref msg) => self.diagnostic().struct_span_err(sp, msg),
-            None => self.diagnostic().struct_span_err(sp, msg),
-        }
+        self.diagnostic().struct_span_err(sp, msg)
     }
     pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
                                                              sp: S,
                                                              msg: &str,
                                                              code: &str)
                                                              -> DiagnosticBuilder<'a>  {
-        match split_msg_into_multilines(msg) {
-            Some(ref msg) => self.diagnostic().struct_span_err_with_code(sp, msg, code),
-            None => self.diagnostic().struct_span_err_with_code(sp, msg, code),
-        }
+        self.diagnostic().struct_span_err_with_code(sp, msg, code)
     }
     pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a>  {
         self.diagnostic().struct_err(msg)
@@ -178,16 +172,10 @@ impl Session {
         }
     }
     pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
-        match split_msg_into_multilines(msg) {
-            Some(msg) => self.diagnostic().span_err(sp, &msg),
-            None => self.diagnostic().span_err(sp, msg)
-        }
+        self.diagnostic().span_err(sp, msg)
     }
     pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
-        match split_msg_into_multilines(msg) {
-            Some(msg) => self.diagnostic().span_err_with_code(sp, &msg, code),
-            None => self.diagnostic().span_err_with_code(sp, msg, code)
-        }
+        self.diagnostic().span_err_with_code(sp, &msg, code)
     }
     pub fn err(&self, msg: &str) {
         self.diagnostic().err(msg)
@@ -343,67 +331,6 @@ impl Session {
     }
 }
 
-fn split_msg_into_multilines(msg: &str) -> Option<String> {
-    // Conditions for enabling multi-line errors:
-    if !msg.contains("mismatched types") &&
-        !msg.contains("type mismatch resolving") &&
-        !msg.contains("if and else have incompatible types") &&
-        !msg.contains("if may be missing an else clause") &&
-        !msg.contains("match arms have incompatible types") &&
-        !msg.contains("structure constructor specifies a structure of type") &&
-        !msg.contains("has an incompatible type for trait") {
-            return None
-    }
-    let first = msg.match_indices("expected").filter(|s| {
-        let last = msg[..s.0].chars().rev().next();
-        last == Some(' ') || last == Some('(')
-    }).map(|(a, b)| (a - 1, a + b.len()));
-    let second = msg.match_indices("found").filter(|s| {
-        msg[..s.0].chars().rev().next() == Some(' ')
-    }).map(|(a, b)| (a - 1, a + b.len()));
-
-    let mut new_msg = String::new();
-    let mut head = 0;
-
-    // Insert `\n` before expected and found.
-    for (pos1, pos2) in first.zip(second) {
-        new_msg = new_msg +
-        // A `(` may be preceded by a space and it should be trimmed
-                  msg[head..pos1.0].trim_right() + // prefix
-                  "\n" +                           // insert before first
-                  &msg[pos1.0..pos1.1] +           // insert what first matched
-                  &msg[pos1.1..pos2.0] +           // between matches
-                  "\n   " +                        // insert before second
-        //           123
-        // `expected` is 3 char longer than `found`. To align the types,
-        // `found` gets 3 spaces prepended.
-                  &msg[pos2.0..pos2.1];            // insert what second matched
-
-        head = pos2.1;
-    }
-
-    let mut tail = &msg[head..];
-    let third = tail.find("(values differ")
-                   .or(tail.find("(lifetime"))
-                   .or(tail.find("(cyclic type of infinite size"));
-    // Insert `\n` before any remaining messages which match.
-    if let Some(pos) = third {
-        // The end of the message may just be wrapped in `()` without
-        // `expected`/`found`.  Push this also to a new line and add the
-        // final tail after.
-        new_msg = new_msg +
-        // `(` is usually preceded by a space and should be trimmed.
-                  tail[..pos].trim_right() + // prefix
-                  "\n" +                     // insert before paren
-                  &tail[pos..];              // append the tail
-
-        tail = "";
-    }
-
-    new_msg.push_str(tail);
-    return Some(new_msg);
-}
-
 pub fn build_session(sopts: config::Options,
                      dep_graph: &DepGraph,
                      local_crate_source_file: Option<PathBuf>,

From f3ee99bd4d9d282c33127449073c521f29b07c21 Mon Sep 17 00:00:00 2001
From: Ariel Ben-Yehuda <ariel.byd@gmail.com>
Date: Thu, 21 Jul 2016 02:13:14 +0300
Subject: [PATCH 08/14] try to recover the non-matching types in projection
 errors

The type equation in projection takes place under a binder and a snapshot, which
we can't easily take types out of. Instead, when encountering a projection error,
try to re-do the projection and find the type error then.

This fails to produce a sane type error when the failure was a "leak_check" failure.
I can't think of a sane way to show *these*, so I just left them use the old crappy
representation, and added a test to make sure we don't break them.
---
 src/librustc/traits/error_reporting.rs        | 83 ++++++++++++++-----
 .../higher-ranked-projection.rs               | 38 +++++++++
 src/test/compile-fail/issue-31173.rs          |  3 +-
 3 files changed, 101 insertions(+), 23 deletions(-)
 create mode 100644 src/test/compile-fail/associated-types/higher-ranked-projection.rs

diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index afbe34f89bb..33ca1d05cad 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -26,8 +26,9 @@ use super::{
 
 use fmt_macros::{Parser, Piece, Position};
 use hir::def_id::DefId;
-use infer::{InferCtxt, TypeOrigin};
+use infer::{self, InferCtxt, TypeOrigin};
 use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
+use ty::error::ExpectedFound;
 use ty::fast_reject;
 use ty::fold::TypeFolder;
 use ty::subst::{self, Subst, TypeSpace};
@@ -107,28 +108,66 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         let predicate =
             self.resolve_type_vars_if_possible(&obligation.predicate);
 
-        if !predicate.references_error() {
-            if let Some(warning_node_id) = warning_node_id {
-                self.tcx.sess.add_lint(
-                    ::lint::builtin::UNSIZED_IN_TUPLE,
-                    warning_node_id,
-                    obligation.cause.span,
-                    format!("type mismatch resolving `{}`: {}",
-                            predicate,
-                            error.err));
-            } else {
-                let mut err = type_err!(
-                    self,
-                    TypeOrigin::Misc(obligation.cause.span),
-                    None, // FIXME: be smarter
-                    error.err,
-                    E0271,
-                    "type mismatch resolving `{}`",
-                    predicate);
-                self.note_obligation_cause(&mut err, obligation);
-                err.emit();
-            }
+        if predicate.references_error() {
+            return
         }
+        if let Some(warning_node_id) = warning_node_id {
+            self.tcx.sess.add_lint(
+                ::lint::builtin::UNSIZED_IN_TUPLE,
+                warning_node_id,
+                obligation.cause.span,
+                format!("type mismatch resolving `{}`: {}",
+                        predicate,
+                        error.err));
+            return
+        }
+        self.probe(|_| {
+            let origin = TypeOrigin::Misc(obligation.cause.span);
+            let err_buf;
+            let mut err = &error.err;
+            let mut values = None;
+
+            // try to find the mismatched types to report the error with.
+            //
+            // this can fail if the problem was higher-ranked, in which
+            // cause I have no idea for a good error message.
+            if let ty::Predicate::Projection(ref data) = predicate {
+                let mut selcx = SelectionContext::new(self);
+                let (data, _) = self.replace_late_bound_regions_with_fresh_var(
+                    obligation.cause.span,
+                    infer::LateBoundRegionConversionTime::HigherRankedType,
+                    data);
+                let normalized = super::normalize_projection_type(
+                    &mut selcx,
+                    data.projection_ty,
+                    obligation.cause.clone(),
+                    0
+                );
+                let origin = TypeOrigin::Misc(obligation.cause.span);
+                if let Err(error) = self.eq_types(
+                    false, origin,
+                    data.ty, normalized.value
+                ) {
+                    values = Some(infer::ValuePairs::Types(ExpectedFound {
+                        expected: normalized.value,
+                        found: data.ty,
+                    }));
+                    err_buf = error;
+                    err = &err_buf;
+                }
+            }
+
+            let mut diag = type_err!(
+                self,
+                origin,
+                values,
+                err,
+                E0271,
+                "type mismatch resolving `{}`",
+                predicate);
+            self.note_obligation_cause(&mut diag, obligation);
+            diag.emit();
+        });
     }
 
     fn impl_substs(&self,
diff --git a/src/test/compile-fail/associated-types/higher-ranked-projection.rs b/src/test/compile-fail/associated-types/higher-ranked-projection.rs
new file mode 100644
index 00000000000..12341fa8db3
--- /dev/null
+++ b/src/test/compile-fail/associated-types/higher-ranked-projection.rs
@@ -0,0 +1,38 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(rustc_attrs)]
+
+// revisions: good bad
+
+trait Mirror {
+    type Image;
+}
+
+impl<T> Mirror for T {
+    type Image = T;
+}
+
+#[cfg(bad)]
+fn foo<U, T>(_t: T)
+    where for<'a> &'a T: Mirror<Image=U>
+{}
+
+#[cfg(good)]
+fn foo<U, T>(_t: T)
+    where for<'a> &'a T: Mirror<Image=&'a U>
+{}
+
+#[rustc_error]
+fn main() { //[good]~ ERROR compilation successful
+    foo(());
+    //[bad]~^ ERROR type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _`
+    //[bad]~| expected bound lifetime parameter 'a, found concrete lifetime
+}
diff --git a/src/test/compile-fail/issue-31173.rs b/src/test/compile-fail/issue-31173.rs
index 62d23a99cba..fb1e3cc87e8 100644
--- a/src/test/compile-fail/issue-31173.rs
+++ b/src/test/compile-fail/issue-31173.rs
@@ -19,7 +19,8 @@ pub fn get_tok(it: &mut IntoIter<u8>) {
     })
         .cloned()
         //~^ ERROR type mismatch resolving
-        //~| expected u8, found &-ptr
+        //~| expected type `u8`
+        //~| found type `&_`
         .collect(); //~ ERROR no method named `collect`
 }
 

From 1e4f6d56836e9f9867bb8b05efc2fffceab6b423 Mon Sep 17 00:00:00 2001
From: Ariel Ben-Yehuda <arielb1@mail.tau.ac.il>
Date: Thu, 21 Jul 2016 20:12:04 +0300
Subject: [PATCH 09/14] rustc_errors: fix a few bugs

---
 src/librustc_errors/lib.rs | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs
index 6a48f65714c..610e5647d6d 100644
--- a/src/librustc_errors/lib.rs
+++ b/src/librustc_errors/lib.rs
@@ -531,10 +531,12 @@ impl Handler {
         DiagnosticBuilder::new(self, Level::Fatal, msg)
     }
 
-    pub fn cancel(&mut self, err: &mut DiagnosticBuilder) {
+    pub fn cancel(&self, err: &mut DiagnosticBuilder) {
         if err.level == Level::Error || err.level == Level::Fatal {
-            assert!(self.has_errors());
-            self.err_count.set(self.err_count.get() + 1);
+            self.err_count.set(
+                self.err_count.get().checked_sub(1)
+                    .expect("cancelled an error but err_count is 0")
+            );
         }
         err.cancel();
     }

From 93a96835b09fda7aefb886c9c1c9daa5831bdac6 Mon Sep 17 00:00:00 2001
From: Ariel Ben-Yehuda <arielb1@mail.tau.ac.il>
Date: Thu, 21 Jul 2016 20:12:30 +0300
Subject: [PATCH 10/14] use diagnostic-mutating style for `note_type_err` too

that is much cleaner than the `type_err!` style I used earlier.
---
 src/librustc/infer/error_reporting.rs       | 42 +++++++++++----------
 src/librustc/macros.rs                      | 13 -------
 src/librustc/traits/error_reporting.rs      | 13 +++----
 src/librustc_typeck/check/compare_method.rs | 40 +++++++++++++-------
 4 files changed, 53 insertions(+), 55 deletions(-)

diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index 0726d8560ba..511cc32d2e1 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -521,25 +521,25 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn report_and_explain_type_error_with_code(&self,
-                                                   origin: TypeOrigin,
-                                                   values: Option<ValuePairs<'tcx>>,
-                                                   terr: &TypeError<'tcx>,
-                                                   message: &str,
-                                                   code: &str)
-                                                   -> DiagnosticBuilder<'tcx>
+    pub fn note_type_err(&self,
+                         diag: &mut DiagnosticBuilder<'tcx>,
+                         origin: TypeOrigin,
+                         values: Option<ValuePairs<'tcx>>,
+                         terr: &TypeError<'tcx>)
     {
         let expected_found = match values {
             None => None,
             Some(values) => match self.values_str(&values) {
                 Some((expected, found)) => Some((expected, found)),
-                None => return self.tcx.sess.diagnostic().struct_dummy() /* derived error */
+                None => {
+                    // Derived error. Cancel the emitter.
+                    self.tcx.sess.diagnostic().cancel(diag);
+                    return
+                }
             }
         };
 
         let span = origin.span();
-        let mut err = self.tcx.sess.struct_span_err_with_code(
-            span, message, code);
 
         let mut is_simple_error = false;
 
@@ -551,21 +551,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             };
 
             if !is_simple_error || check_old_school() {
-                err.note_expected_found(&"type", &expected, &found);
+                diag.note_expected_found(&"type", &expected, &found);
             }
         }
 
         if !is_simple_error && check_old_school() {
-            err.span_note(span, &format!("{}", terr));
+            diag.span_note(span, &format!("{}", terr));
         } else {
-            err.span_label(span, &terr);
+            diag.span_label(span, &terr);
         }
 
-        self.note_error_origin(&mut err, &origin);
-        self.check_and_note_conflicting_crates(&mut err, terr, span);
-        self.tcx.note_and_explain_type_err(&mut err, terr, span);
-
-        err
+        self.note_error_origin(diag, &origin);
+        self.check_and_note_conflicting_crates(diag, terr, span);
+        self.tcx.note_and_explain_type_err(diag, terr, span);
     }
 
     pub fn report_and_explain_type_error(&self,
@@ -574,8 +572,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                          -> DiagnosticBuilder<'tcx>
     {
         // FIXME: do we want to use a different error code for each origin?
-        let failure_str = trace.origin.as_failure_str();
-        type_err!(self, trace.origin, Some(trace.values), terr, E0308, "{}", failure_str)
+        let mut diag = struct_span_err!(
+            self.tcx.sess, trace.origin.span(), E0308,
+            "{}", trace.origin.as_failure_str()
+        );
+        self.note_type_err(&mut diag, trace.origin, Some(trace.values), terr);
+        diag
     }
 
     /// Returns a string of the form "expected `{}`, found `{}`".
diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs
index 190c9b665e0..76dca1bb5b6 100644
--- a/src/librustc/macros.rs
+++ b/src/librustc/macros.rs
@@ -59,16 +59,3 @@ macro_rules! span_bug {
         $crate::session::span_bug_fmt(file!(), line!(), $span, format_args!($($message)*))
     })
 }
-
-#[macro_export]
-macro_rules! type_err {
-    ($infcx:expr, $origin: expr, $values: expr, $terr: expr, $code:ident, $($message:tt)*) => ({
-        __diagnostic_used!($code);
-        $infcx.report_and_explain_type_error_with_code(
-            $origin,
-            $values,
-            &$terr,
-            &format!($($message)*),
-            stringify!($code))
-    })
-}
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 33ca1d05cad..67ad887530e 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -157,14 +157,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 }
             }
 
-            let mut diag = type_err!(
-                self,
-                origin,
-                values,
-                err,
-                E0271,
-                "type mismatch resolving `{}`",
-                predicate);
+            let mut diag = struct_span_err!(
+                self.tcx.sess, origin.span(), E0271,
+                "type mismatch resolving `{}`", predicate
+            );
+            self.note_type_err(&mut diag, origin, values, err);
             self.note_obligation_cause(&mut diag, obligation);
             diag.emit();
         });
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 2c4c6279076..9844377d0bd 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -325,13 +325,19 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             debug!("sub_types failed: impl ty {:?}, trait ty {:?}",
                    impl_fty,
                    trait_fty);
-            let values = Some(infer::ValuePairs::Types(ExpectedFound {
-                expected: trait_fty,
-                found: impl_fty
-            }));
-            type_err!(infcx, origin, values, terr, E0053,
-                      "method `{}` has an incompatible type for trait",
-                      trait_m.name).emit();
+
+            let mut diag = struct_span_err!(
+                tcx.sess, origin.span(), E0053,
+                "method `{}` has an incompatible type for trait", trait_m.name
+            );
+            infcx.note_type_err(
+                &mut diag, origin,
+                Some(infer::ValuePairs::Types(ExpectedFound {
+                    expected: trait_fty,
+                    found: impl_fty
+                })), &terr
+            );
+            diag.emit();
             return
         }
 
@@ -476,13 +482,19 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             debug!("checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
                    impl_ty,
                    trait_ty);
-            let values = Some(infer::ValuePairs::Types(ExpectedFound {
-                expected: trait_ty,
-                found: impl_ty
-            }));
-            type_err!(infcx, origin, values, terr, E0326,
-                      "implemented const `{}` has an incompatible type for \
-                      trait", trait_c.name).emit();
+            let mut diag = struct_span_err!(
+                tcx.sess, origin.span(), E0326,
+                "implemented const `{}` has an incompatible type for trait",
+                trait_c.name
+            );
+            infcx.note_type_err(
+                &mut diag, origin,
+                Some(infer::ValuePairs::Types(ExpectedFound {
+                    expected: trait_ty,
+                    found: impl_ty
+                })), &terr
+            );
+            diag.emit();
         }
     });
 }

From e76a46a10d9bc0e5a2765addf24c3069555bdc83 Mon Sep 17 00:00:00 2001
From: ggomez <guillaume1.gomez@gmail.com>
Date: Thu, 21 Jul 2016 16:07:08 +0200
Subject: [PATCH 11/14] Add new error codes in librustc_typeck

---
 src/librustc/infer/mod.rs          | 19 ++++++++++++++-----
 src/librustc_typeck/check/mod.rs   | 12 +++++++-----
 src/librustc_typeck/diagnostics.rs |  2 ++
 3 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index fd65e06ea97..1df06e8a007 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -1510,6 +1510,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         self.type_error_struct(sp, mk_msg, actual_ty).emit();
     }
 
+    // FIXME: this results in errors without an error code. Deprecate?
     pub fn type_error_struct<M>(&self,
                                 sp: Span,
                                 mk_msg: M,
@@ -1517,19 +1518,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                 -> DiagnosticBuilder<'tcx>
         where M: FnOnce(String) -> String,
     {
-        debug!("type_error_struct({:?}, {:?})", sp, actual_ty);
+        self.type_error_struct_with_diag(sp, |actual_ty| {
+            self.tcx.sess.struct_span_err(sp, &mk_msg(actual_ty))
+        }, actual_ty)
+    }
 
+    pub fn type_error_struct_with_diag<M>(&self,
+                                          sp: Span,
+                                          mk_diag: M,
+                                          actual_ty: Ty<'tcx>)
+                                          -> DiagnosticBuilder<'tcx>
+        where M: FnOnce(String) -> DiagnosticBuilder<'tcx>,
+    {
         let actual_ty = self.resolve_type_vars_if_possible(&actual_ty);
+        debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty);
 
         // Don't report an error if actual type is TyError.
         if actual_ty.references_error() {
             return self.tcx.sess.diagnostic().struct_dummy();
         }
 
-        let msg = mk_msg(self.ty_to_string(actual_ty));
-
-        // FIXME: use an error code.
-        self.tcx.sess.struct_span_err(sp, &msg)
+        mk_diag(self.ty_to_string(actual_ty))
     }
 
     pub fn report_mismatched_types(&self,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index c01edc568af..6062bd048b3 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3028,14 +3028,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             variant: ty::VariantDef<'tcx>,
                             field: &hir::Field,
                             skip_fields: &[hir::Field]) {
-        let mut err = self.type_error_struct(
+        let mut err = self.type_error_struct_with_diag(
             field.name.span,
             |actual| if let ty::TyEnum(..) = ty.sty {
-                format!("struct variant `{}::{}` has no field named `{}`",
-                        actual, variant.name.as_str(), field.name.node)
+                struct_span_err!(self.tcx.sess, field.name.span, E0559,
+                                 "struct variant `{}::{}` has no field named `{}`",
+                                 actual, variant.name.as_str(), field.name.node)
             } else {
-                format!("structure `{}` has no field named `{}`",
-                        actual, field.name.node)
+                struct_span_err!(self.tcx.sess, field.name.span, E0560,
+                                 "structure `{}` has no field named `{}`",
+                                 actual, field.name.node)
             },
             ty);
         // prevent all specified fields from being suggested
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 38bf869119c..6000ea71bff 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -4053,4 +4053,6 @@ register_diagnostics! {
     E0528, // expected at least {} elements, found {}
     E0529, // slice pattern expects array or slice, not `{}`
     E0533, // `{}` does not name a unit variant, unit struct or a constant
+    E0559,
+    E0560,
 }

From 0304850942d40c798750c4a1ba194c3992dbde1a Mon Sep 17 00:00:00 2001
From: ggomez <guillaume1.gomez@gmail.com>
Date: Thu, 21 Jul 2016 16:18:12 +0200
Subject: [PATCH 12/14] Add E0560 error explanation

---
 src/librustc_typeck/diagnostics.rs | 27 ++++++++++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 6000ea71bff..e7efed905ad 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -3980,6 +3980,32 @@ impl SpaceLlama for i32 {
 ```
 "##,
 
+E0560: r##"
+An unknown field was specified into a structure.
+
+Erroneous code example:
+
+```compile_fail,E0560
+struct Simba {
+    mother: u32,
+}
+
+let s = Simba { mother: 1, father: 0 };
+// error: structure `Simba` has no field named `father`
+```
+
+Verify you didn't misspell the field's name or that the field exists. Example:
+
+```
+struct Simba {
+    mother: u32,
+    father: u32,
+}
+
+let s = Simba { mother: 1, father: 0 }; // ok!
+```
+"##,
+
 }
 
 register_diagnostics! {
@@ -4054,5 +4080,4 @@ register_diagnostics! {
     E0529, // slice pattern expects array or slice, not `{}`
     E0533, // `{}` does not name a unit variant, unit struct or a constant
     E0559,
-    E0560,
 }

From 23bb1df1e52dd17062cd135b5be70ba55d5af147 Mon Sep 17 00:00:00 2001
From: ggomez <guillaume1.gomez@gmail.com>
Date: Thu, 21 Jul 2016 16:47:05 +0200
Subject: [PATCH 13/14] Add E0559 error explanation

---
 src/librustc_typeck/diagnostics.rs | 26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index e7efed905ad..500f624ea3f 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -3980,6 +3980,31 @@ impl SpaceLlama for i32 {
 ```
 "##,
 
+E0559: r##"
+An unknown field was specified into an enum's structure variant.
+
+Erroneous code example:
+
+```compile_fail,E0559
+enum Field {
+    Fool { x: u32 },
+}
+
+let s = Field::Fool { joke: 0 };
+// error: struct variant `Field::Fool` has no field named `joke`
+```
+
+Verify you didn't misspell the field's name or that the field exists. Example:
+
+```
+enum Field {
+    Fool { joke: u32 },
+}
+
+let s = Field::Fool { joke: 0 }; // ok!
+```
+"##,
+
 E0560: r##"
 An unknown field was specified into a structure.
 
@@ -4079,5 +4104,4 @@ register_diagnostics! {
     E0528, // expected at least {} elements, found {}
     E0529, // slice pattern expects array or slice, not `{}`
     E0533, // `{}` does not name a unit variant, unit struct or a constant
-    E0559,
 }

From 717e39294f635d90f8ba9e0968494f741878f37b Mon Sep 17 00:00:00 2001
From: Ariel Ben-Yehuda <ariel.byd@gmail.com>
Date: Fri, 22 Jul 2016 23:52:53 +0300
Subject: [PATCH 14/14] address review comments

I split the RFC1592 commit out
---
 src/librustc/infer/mod.rs                     | 18 +++-----
 src/librustc_const_eval/eval.rs               | 28 +-----------
 src/librustc_typeck/check/demand.rs           |  9 +++-
 src/librustc_typeck/check/wfcheck.rs          | 44 +++++++++++++------
 .../compile-fail/const-eval-overflow-4b.rs    |  4 +-
 src/test/compile-fail/discrim-ill-typed.rs    | 16 +++----
 .../explicit-self-lifetime-mismatch.rs        |  8 ++--
 src/test/compile-fail/issue-17740.rs          |  4 +-
 src/test/compile-fail/issue-26194.rs          |  2 +-
 src/test/compile-fail/issue-8761.rs           |  6 +--
 src/test/compile-fail/repeat_count.rs         |  6 +--
 .../compile-fail/ufcs-explicit-self-bad.rs    | 14 +++---
 12 files changed, 74 insertions(+), 85 deletions(-)

diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 1df06e8a007..87882c5528e 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -196,12 +196,6 @@ pub enum TypeOrigin {
     // FIXME(eddyb) #11161 is the original Expr required?
     ExprAssignable(Span),
 
-    // Relating trait refs when resolving vtables
-    RelateTraitRefs(Span),
-
-    // Relating self types when resolving vtables
-    RelateSelfType(Span),
-
     // Relating trait type parameters to those found in impl etc
     RelateOutputImplTypes(Span),
 
@@ -228,16 +222,17 @@ pub enum TypeOrigin {
 
     // intrinsic has wrong type
     IntrinsicType(Span),
+
+    // method receiver
+    MethodReceiver(Span),
 }
 
 impl TypeOrigin {
     fn as_failure_str(&self) -> &'static str {
         match self {
             &TypeOrigin::Misc(_) |
-            &TypeOrigin::RelateSelfType(_) |
             &TypeOrigin::RelateOutputImplTypes(_) |
             &TypeOrigin::ExprAssignable(_) => "mismatched types",
-            &TypeOrigin::RelateTraitRefs(_) => "mismatched traits",
             &TypeOrigin::MethodCompatCheck(_) => "method not compatible with trait",
             &TypeOrigin::MatchExpressionArm(_, _, source) => match source {
                 hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types",
@@ -250,6 +245,7 @@ impl TypeOrigin {
             &TypeOrigin::MainFunctionType(_) => "main function has wrong type",
             &TypeOrigin::StartFunctionType(_) => "start function has wrong type",
             &TypeOrigin::IntrinsicType(_) => "intrinsic has wrong type",
+            &TypeOrigin::MethodReceiver(_) => "mismatched method receiver",
         }
     }
 
@@ -258,8 +254,6 @@ impl TypeOrigin {
             &TypeOrigin::Misc(_) => "types are compatible",
             &TypeOrigin::MethodCompatCheck(_) => "method type is compatible with trait",
             &TypeOrigin::ExprAssignable(_) => "expression is assignable",
-            &TypeOrigin::RelateTraitRefs(_) => "traits are compatible",
-            &TypeOrigin::RelateSelfType(_) => "self type matches impl self type",
             &TypeOrigin::RelateOutputImplTypes(_) => {
                 "trait type parameters matches those specified on the impl"
             }
@@ -271,6 +265,7 @@ impl TypeOrigin {
             &TypeOrigin::MainFunctionType(_) => "`main` function has the correct type",
             &TypeOrigin::StartFunctionType(_) => "`start` function has the correct type",
             &TypeOrigin::IntrinsicType(_) => "intrinsic has the correct type",
+            &TypeOrigin::MethodReceiver(_) => "method receiver has the correct type",
         }
     }
 }
@@ -1806,8 +1801,6 @@ impl TypeOrigin {
             TypeOrigin::MethodCompatCheck(span) => span,
             TypeOrigin::ExprAssignable(span) => span,
             TypeOrigin::Misc(span) => span,
-            TypeOrigin::RelateTraitRefs(span) => span,
-            TypeOrigin::RelateSelfType(span) => span,
             TypeOrigin::RelateOutputImplTypes(span) => span,
             TypeOrigin::MatchExpressionArm(match_span, _, _) => match_span,
             TypeOrigin::IfExpression(span) => span,
@@ -1817,6 +1810,7 @@ impl TypeOrigin {
             TypeOrigin::MainFunctionType(span) => span,
             TypeOrigin::StartFunctionType(span) => span,
             TypeOrigin::IntrinsicType(span) => span,
+            TypeOrigin::MethodReceiver(span) => span,
         }
     }
 }
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 03d2f596e21..2eb08cab1aa 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -384,15 +384,6 @@ pub fn note_const_eval_err<'a, 'tcx>(
                 diag.span_label(err.span, &message);
             }
         }
-        ConstEvalErrDescription::ExpectedFound { error, expected, found } => {
-            if check_old_school() {
-                diag.note(&error);
-            } else {
-                diag.span_label(err.span, &error);
-            }
-            diag.note(&format!("expected `{}`", expected));
-            diag.note(&format!("found `{}`", found));
-        }
     }
 
     if !primary_span.contains(err.span) {
@@ -477,11 +468,6 @@ impl From<ConstMathErr> for ErrKind {
 #[derive(Clone, Debug)]
 pub enum ConstEvalErrDescription<'a> {
     Simple(Cow<'a, str>),
-    ExpectedFound {
-        error: Cow<'a, str>,
-        expected: Cow<'a, str>,
-        found: Cow<'a, str>
-    }
 }
 
 impl<'a> ConstEvalErrDescription<'a> {
@@ -489,14 +475,6 @@ impl<'a> ConstEvalErrDescription<'a> {
     pub fn into_oneline(self) -> Cow<'a, str> {
         match self {
             ConstEvalErrDescription::Simple(simple) => simple,
-            ConstEvalErrDescription::ExpectedFound {
-                error,
-                expected,
-                found
-            } => {
-                format!("{}: expected `{}`, found `{}`", error, expected, found)
-                    .into_cow()
-            }
         }
     }
 }
@@ -554,11 +532,7 @@ impl ConstEvalErr {
                  the constant evaluator"),
 
             TypeMismatch(ref expected, ref got) => {
-                ExpectedFound {
-                    error: "mismatched types".into_cow(),
-                    expected: <&str>::into_cow(expected),
-                    found: got.description().into_cow()
-                }
+                simple!("expected {}, found {}", expected, got.description())
             },
             BadType(ref i) => simple!("value of wrong type: {:?}", i),
             ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"),
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index c1f415b3c02..1f3a83ebc1d 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -33,7 +33,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
-        let origin = TypeOrigin::Misc(sp);
+        self.demand_eqtype_with_origin(TypeOrigin::Misc(sp), expected, actual);
+    }
+
+    pub fn demand_eqtype_with_origin(&self,
+                                     origin: TypeOrigin,
+                                     expected: Ty<'tcx>,
+                                     actual: Ty<'tcx>)
+    {
         match self.eq_types(false, origin, actual, expected) {
             Ok(InferOk { obligations, .. }) => {
                 // FIXME(#32730) propagate obligations
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 2d44a85f9af..907cb734c2f 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -13,6 +13,7 @@ use constrained_type_params::{identify_constrained_type_params, Parameter};
 use CrateCtxt;
 use hir::def_id::DefId;
 use middle::region::{CodeExtent};
+use rustc::infer::TypeOrigin;
 use rustc::ty::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace};
 use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt};
@@ -157,7 +158,10 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
         }
     }
 
-    fn check_trait_or_impl_item(&mut self, item_id: ast::NodeId, span: Span) {
+    fn check_trait_or_impl_item(&mut self,
+                                item_id: ast::NodeId,
+                                span: Span,
+                                sig_if_method: Option<&hir::MethodSig>) {
         let code = self.code.clone();
         self.for_id(item_id, span).with_fcx(|fcx, this| {
             let free_substs = &fcx.parameter_environment.free_substs;
@@ -182,7 +186,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
                     let predicates = fcx.instantiate_bounds(span, free_substs, &method.predicates);
                     this.check_fn_or_method(fcx, span, &method_ty, &predicates,
                                             free_id_outlive, &mut implied_bounds);
-                    this.check_method_receiver(fcx, span, &method,
+                    let sig_if_method = sig_if_method.expect("bad signature for method");
+                    this.check_method_receiver(fcx, sig_if_method, &method,
                                                free_id_outlive, self_ty);
                 }
                 ty::TypeTraitItem(assoc_type) => {
@@ -405,20 +410,15 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
 
     fn check_method_receiver<'fcx, 'tcx>(&mut self,
                                          fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
-                                         span: Span,
+                                         method_sig: &hir::MethodSig,
                                          method: &ty::Method<'tcx>,
                                          free_id_outlive: CodeExtent,
                                          self_ty: ty::Ty<'tcx>)
     {
         // check that the type of the method's receiver matches the
         // method's first parameter.
-
-        let free_substs = &fcx.parameter_environment.free_substs;
-        let fty = fcx.instantiate_type_scheme(span, free_substs, &method.fty);
-        let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.sig);
-
-        debug!("check_method_receiver({:?},cat={:?},self_ty={:?},sig={:?})",
-               method.name, method.explicit_self, self_ty, sig);
+        debug!("check_method_receiver({:?},cat={:?},self_ty={:?})",
+               method.name, method.explicit_self, self_ty);
 
         let rcvr_ty = match method.explicit_self {
             ty::ExplicitSelfCategory::Static => return,
@@ -431,13 +431,23 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
             }
             ty::ExplicitSelfCategory::ByBox => fcx.tcx.mk_box(self_ty)
         };
+
+        let span = method_sig.decl.inputs[0].pat.span;
+
+        let free_substs = &fcx.parameter_environment.free_substs;
+        let fty = fcx.instantiate_type_scheme(span, free_substs, &method.fty);
+        let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.sig);
+
+        debug!("check_method_receiver: sig={:?}", sig);
+
         let rcvr_ty = fcx.instantiate_type_scheme(span, free_substs, &rcvr_ty);
         let rcvr_ty = fcx.tcx.liberate_late_bound_regions(free_id_outlive,
                                                           &ty::Binder(rcvr_ty));
 
         debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty);
 
-        fcx.demand_eqtype(span, rcvr_ty, sig.inputs[0]);
+        let origin = TypeOrigin::MethodReceiver(span);
+        fcx.demand_eqtype_with_origin(origin, rcvr_ty, sig.inputs[0]);
     }
 
     fn check_variances_for_type_defn(&self,
@@ -552,13 +562,21 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> {
 
     fn visit_trait_item(&mut self, trait_item: &'v hir::TraitItem) {
         debug!("visit_trait_item: {:?}", trait_item);
-        self.check_trait_or_impl_item(trait_item.id, trait_item.span);
+        let method_sig = match trait_item.node {
+            hir::TraitItem_::MethodTraitItem(ref sig, _) => Some(sig),
+            _ => None
+        };
+        self.check_trait_or_impl_item(trait_item.id, trait_item.span, method_sig);
         intravisit::walk_trait_item(self, trait_item)
     }
 
     fn visit_impl_item(&mut self, impl_item: &'v hir::ImplItem) {
         debug!("visit_impl_item: {:?}", impl_item);
-        self.check_trait_or_impl_item(impl_item.id, impl_item.span);
+        let method_sig = match impl_item.node {
+            hir::ImplItemKind::Method(ref sig, _) => Some(sig),
+            _ => None
+        };
+        self.check_trait_or_impl_item(impl_item.id, impl_item.span, method_sig);
         intravisit::walk_impl_item(self, impl_item)
     }
 }
diff --git a/src/test/compile-fail/const-eval-overflow-4b.rs b/src/test/compile-fail/const-eval-overflow-4b.rs
index e7639a4ff70..9e7a5ecae10 100644
--- a/src/test/compile-fail/const-eval-overflow-4b.rs
+++ b/src/test/compile-fail/const-eval-overflow-4b.rs
@@ -21,9 +21,7 @@ use std::{u8, u16, u32, u64, usize};
 const A_I8_T
     : [u32; (i8::MAX as i8 + 1u8) as usize]
     //~^ ERROR constant evaluation error [E0080]
-    //~| mismatched types
-    //~| expected `i8`
-    //~| found `u8`
+    //~| expected i8, found u8
     = [0; (i8::MAX as usize) + 1];
 
 
diff --git a/src/test/compile-fail/discrim-ill-typed.rs b/src/test/compile-fail/discrim-ill-typed.rs
index 5af889cb239..c73b7e831b3 100644
--- a/src/test/compile-fail/discrim-ill-typed.rs
+++ b/src/test/compile-fail/discrim-ill-typed.rs
@@ -26,7 +26,7 @@ fn f_i8() {
         Ok2,
         OhNo = 0_u8,
         //~^ ERROR E0080
-        //~| mismatched types
+        //~| expected i8, found u8
     }
 
     let x = A::Ok;
@@ -39,7 +39,7 @@ fn f_u8() {
         Ok2,
         OhNo = 0_i8,
         //~^ ERROR E0080
-        //~| mismatched types
+        //~| expected u8, found i8
     }
 
     let x = A::Ok;
@@ -52,7 +52,7 @@ fn f_i16() {
         Ok2,
         OhNo = 0_u16,
         //~^ ERROR E0080
-        //~| mismatched types
+        //~| expected i16, found u16
     }
 
     let x = A::Ok;
@@ -65,7 +65,7 @@ fn f_u16() {
         Ok2,
         OhNo = 0_i16,
         //~^ ERROR E0080
-        //~| mismatched types
+        //~| expected u16, found i16
     }
 
     let x = A::Ok;
@@ -78,7 +78,7 @@ fn f_i32() {
         Ok2,
         OhNo = 0_u32,
         //~^ ERROR E0080
-        //~| mismatched types
+        //~| expected i32, found u32
     }
 
     let x = A::Ok;
@@ -91,7 +91,7 @@ fn f_u32() {
         Ok2,
         OhNo = 0_i32,
         //~^ ERROR E0080
-        //~| mismatched types
+        //~| expected u32, found i32
     }
 
     let x = A::Ok;
@@ -104,7 +104,7 @@ fn f_i64() {
         Ok2,
         OhNo = 0_u64,
         //~^ ERROR E0080
-        //~| mismatched types
+        //~| expected i64, found u64
     }
 
     let x = A::Ok;
@@ -117,7 +117,7 @@ fn f_u64() {
         Ok2,
         OhNo = 0_i64,
         //~^ ERROR E0080
-        //~| mismatched types
+        //~| expected u64, found i64
     }
 
     let x = A::Ok;
diff --git a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs
index b5432fafb1b..f8aa1ea95f0 100644
--- a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs
+++ b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs
@@ -14,15 +14,17 @@ struct Foo<'a,'b> {
 }
 
 impl<'a,'b> Foo<'a,'b> {
-    fn bar(self: Foo<'b,'a>) {}
-    //~^ ERROR mismatched types
+    fn bar(
+        self
+    //~^ ERROR mismatched method receiver
     //~| expected type `Foo<'a, 'b>`
     //~| found type `Foo<'b, 'a>`
     //~| lifetime mismatch
-    //~| ERROR mismatched types
+    //~| ERROR mismatched method receiver
     //~| expected type `Foo<'a, 'b>`
     //~| found type `Foo<'b, 'a>`
     //~| lifetime mismatch
+            : Foo<'b,'a>) {}
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-17740.rs b/src/test/compile-fail/issue-17740.rs
index 6b9294b2038..664d62e87ae 100644
--- a/src/test/compile-fail/issue-17740.rs
+++ b/src/test/compile-fail/issue-17740.rs
@@ -14,11 +14,11 @@ struct Foo<'a> {
 
 impl <'a> Foo<'a>{
     fn bar(self: &mut Foo) {
-    //~^ mismatched types
+    //~^ mismatched method receiver
     //~| expected type `&mut Foo<'a>`
     //~| found type `&mut Foo<'_>`
     //~| lifetime mismatch
-    //~| mismatched types
+    //~| mismatched method receiver
     //~| expected type `&mut Foo<'a>`
     //~| found type `&mut Foo<'_>`
     //~| lifetime mismatch
diff --git a/src/test/compile-fail/issue-26194.rs b/src/test/compile-fail/issue-26194.rs
index 1bc0a4f9652..ef91188c5d1 100644
--- a/src/test/compile-fail/issue-26194.rs
+++ b/src/test/compile-fail/issue-26194.rs
@@ -12,7 +12,7 @@ struct S(String);
 
 impl S {
     fn f(self: *mut S) -> String { self.0 }
-    //~^ ERROR mismatched types
+    //~^ ERROR mismatched method receiver
 }
 
 fn main() { S("".to_owned()).f(); }
diff --git a/src/test/compile-fail/issue-8761.rs b/src/test/compile-fail/issue-8761.rs
index 6352f4f6a04..91a07dd9ba6 100644
--- a/src/test/compile-fail/issue-8761.rs
+++ b/src/test/compile-fail/issue-8761.rs
@@ -11,12 +11,10 @@
 enum Foo {
     A = 1i64,
     //~^ ERROR constant evaluation error
-    //~| expected `isize`
-    //~| found `i64`
+    //~| expected isize, found i64
     B = 2u8
     //~^ ERROR constant evaluation error
-    //~| expected `isize`
-    //~| found `u8`
+    //~| expected isize, found u8
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/repeat_count.rs b/src/test/compile-fail/repeat_count.rs
index d68df973641..3a7e9cc4191 100644
--- a/src/test/compile-fail/repeat_count.rs
+++ b/src/test/compile-fail/repeat_count.rs
@@ -39,14 +39,12 @@ fn main() {
     //~| ERROR expected usize for repeat count, found string literal [E0306]
     let f = [0; -4_isize];
     //~^ ERROR constant evaluation error
-    //~| expected `usize`
-    //~| found `isize`
+    //~| expected usize, found isize
     //~| ERROR mismatched types
     //~| expected usize, found isize
     let f = [0_usize; -1_isize];
     //~^ ERROR constant evaluation error
-    //~| expected `usize`
-    //~| found `isize`
+    //~| expected usize, found isize
     //~| ERROR mismatched types
     //~| expected usize, found isize
     struct G {
diff --git a/src/test/compile-fail/ufcs-explicit-self-bad.rs b/src/test/compile-fail/ufcs-explicit-self-bad.rs
index e997cf47c73..a98b7cd4309 100644
--- a/src/test/compile-fail/ufcs-explicit-self-bad.rs
+++ b/src/test/compile-fail/ufcs-explicit-self-bad.rs
@@ -15,7 +15,7 @@ struct Foo {
 }
 
 impl Foo {
-    fn foo(self: isize, x: isize) -> isize {  //~ ERROR mismatched types
+    fn foo(self: isize, x: isize) -> isize {  //~ ERROR mismatched method receiver
         self.f + x
     }
 }
@@ -25,10 +25,10 @@ struct Bar<T> {
 }
 
 impl<T> Bar<T> {
-    fn foo(self: Bar<isize>, x: isize) -> isize { //~ ERROR mismatched types
+    fn foo(self: Bar<isize>, x: isize) -> isize { //~ ERROR mismatched method receiver
         x
     }
-    fn bar(self: &Bar<usize>, x: isize) -> isize {   //~ ERROR mismatched types
+    fn bar(self: &Bar<usize>, x: isize) -> isize {   //~ ERROR mismatched method receiver
         x
     }
 }
@@ -41,14 +41,14 @@ trait SomeTrait {
 
 impl<'a, T> SomeTrait for &'a Bar<T> {
     fn dummy1(self: &&'a Bar<T>) { }
-    fn dummy2(self: &Bar<T>) {} //~ ERROR mismatched types
-    //~^ ERROR mismatched types
+    fn dummy2(self: &Bar<T>) {} //~ ERROR mismatched method receiver
+    //~^ ERROR mismatched method receiver
     fn dummy3(self: &&Bar<T>) {}
-    //~^ ERROR mismatched types
+    //~^ ERROR mismatched method receiver
     //~| expected type `&&'a Bar<T>`
     //~| found type `&&Bar<T>`
     //~| lifetime mismatch
-    //~| ERROR mismatched types
+    //~| ERROR mismatched method receiver
     //~| expected type `&&'a Bar<T>`
     //~| found type `&&Bar<T>`
     //~| lifetime mismatch