about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduard-Mihai Burtescu <edy.burt@gmail.com>2017-02-15 15:00:20 +0200
committerEduard-Mihai Burtescu <edy.burt@gmail.com>2017-02-25 18:35:26 +0200
commite7a48821c0d30ccd6b7ea88be24eed1bcba5f48a (patch)
tree82387e47712464862cadd6749f6c8556d59df63b
parentc832e6f3272fd01e22a6370e7745e305fe13a4c9 (diff)
downloadrust-e7a48821c0d30ccd6b7ea88be24eed1bcba5f48a.tar.gz
rust-e7a48821c0d30ccd6b7ea88be24eed1bcba5f48a.zip
rustc_const_eval: always demand typeck_tables for evaluating constants.
-rw-r--r--src/librustc/diagnostics.rs73
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/middle/astconv_util.rs83
-rw-r--r--src/librustc/middle/const_val.rs21
-rw-r--r--src/librustc/mir/mod.rs6
-rw-r--r--src/librustc/ty/context.rs5
-rw-r--r--src/librustc/ty/layout.rs7
-rw-r--r--src/librustc/ty/maps.rs2
-rw-r--r--src/librustc/ty/util.rs56
-rw-r--r--src/librustc_const_eval/_match.rs25
-rw-r--r--src/librustc_const_eval/check_match.rs2
-rw-r--r--src/librustc_const_eval/diagnostics.rs16
-rw-r--r--src/librustc_const_eval/eval.rs693
-rw-r--r--src/librustc_const_eval/lib.rs1
-rw-r--r--src/librustc_const_eval/pattern.rs24
-rw-r--r--src/librustc_const_math/float.rs47
-rw-r--r--src/librustc_const_math/int.rs240
-rw-r--r--src/librustc_const_math/lib.rs2
-rw-r--r--src/librustc_lint/types.rs3
-rw-r--r--src/librustc_metadata/schema.rs10
-rw-r--r--src/librustc_mir/build/matches/mod.rs6
-rw-r--r--src/librustc_mir/build/matches/test.rs4
-rw-r--r--src/librustc_mir/build/mod.rs11
-rw-r--r--src/librustc_mir/hair/cx/expr.rs4
-rw-r--r--src/librustc_mir/hair/cx/mod.rs4
-rw-r--r--src/librustc_mir/mir_map.rs4
-rw-r--r--src/librustc_passes/consts.rs14
-rw-r--r--src/librustc_trans/consts.rs10
-rw-r--r--src/librustc_trans/mir/block.rs2
-rw-r--r--src/librustc_trans/mir/constant.rs23
-rw-r--r--src/librustc_typeck/astconv.rs60
-rw-r--r--src/librustc_typeck/check/mod.rs8
-rw-r--r--src/librustc_typeck/check/writeback.rs52
-rw-r--r--src/librustc_typeck/collect.rs70
-rw-r--r--src/librustc_typeck/diagnostics.rs112
-rw-r--r--src/test/compile-fail/E0306.rs24
-rw-r--r--src/test/compile-fail/associated-const-array-len.rs3
-rw-r--r--src/test/compile-fail/associated-const-type-parameter-arrays-2.rs2
-rw-r--r--src/test/compile-fail/associated-const-type-parameter-arrays.rs2
-rw-r--r--src/test/compile-fail/const-array-oob.rs4
-rw-r--r--src/test/compile-fail/const-eval-overflow-4b.rs6
-rw-r--r--src/test/compile-fail/const-eval-span.rs7
-rw-r--r--src/test/compile-fail/const-integer-bool-ops.rs79
-rw-r--r--src/test/compile-fail/const-tup-index-span.rs4
-rw-r--r--src/test/compile-fail/discrim-ill-typed.rs16
-rw-r--r--src/test/compile-fail/enum-discrim-too-small.rs16
-rw-r--r--src/test/compile-fail/invalid-path-in-const.rs3
-rw-r--r--src/test/compile-fail/issue-22933-2.rs6
-rw-r--r--src/test/compile-fail/issue-23217.rs3
-rw-r--r--src/test/compile-fail/issue-28586.rs3
-rw-r--r--src/test/compile-fail/issue-31910.rs4
-rw-r--r--src/test/compile-fail/issue-3521.rs4
-rw-r--r--src/test/compile-fail/issue-39559.rs8
-rw-r--r--src/test/compile-fail/issue-8761.rs4
-rw-r--r--src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs1
-rw-r--r--src/test/compile-fail/non-constant-expr-for-vec-repeat.rs2
-rw-r--r--src/test/mir-opt/simplify_if.rs2
-rw-r--r--src/test/run-pass/issue-25145.rs (renamed from src/test/compile-fail/issue-25145.rs)6
-rw-r--r--src/test/run-pass/issue-39548.rs (renamed from src/test/compile-fail/E0079.rs)8
-rw-r--r--src/test/ui/resolve/levenshtein.stderr8
60 files changed, 705 insertions, 1221 deletions
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index 458a774c956..b1b1b849437 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -390,44 +390,6 @@ RFC. It is, however, [currently unimplemented][iss15872].
 [iss15872]: https://github.com/rust-lang/rust/issues/15872
 "##,
 
-E0109: r##"
-You tried to give a type parameter to a type which doesn't need it. Erroneous
-code example:
-
-```compile_fail,E0109
-type X = u32<i32>; // error: type parameters are not allowed on this type
-```
-
-Please check that you used the correct type and recheck its definition. Perhaps
-it doesn't need the type parameter.
-
-Example:
-
-```
-type X = u32; // this compiles
-```
-
-Note that type parameters for enum-variant constructors go after the variant,
-not after the enum (Option::None::<u32>, not Option::<u32>::None).
-"##,
-
-E0110: r##"
-You tried to give a lifetime parameter to a type which doesn't need it.
-Erroneous code example:
-
-```compile_fail,E0110
-type X = u32<'static>; // error: lifetime parameters are not allowed on
-                       //        this type
-```
-
-Please check that the correct type was used and recheck its definition; perhaps
-it doesn't need the lifetime parameter. Example:
-
-```
-type X = u32; // ok!
-```
-"##,
-
 E0133: r##"
 Unsafe code was used outside of an unsafe function or block.
 
@@ -627,41 +589,6 @@ attributes:
 See also https://doc.rust-lang.org/book/no-stdlib.html
 "##,
 
-E0229: r##"
-An associated type binding was done outside of the type parameter declaration
-and `where` clause. Erroneous code example:
-
-```compile_fail,E0229
-pub trait Foo {
-    type A;
-    fn boo(&self) -> <Self as Foo>::A;
-}
-
-struct Bar;
-
-impl Foo for isize {
-    type A = usize;
-    fn boo(&self) -> usize { 42 }
-}
-
-fn baz<I>(x: &<I as Foo<A=Bar>>::A) {}
-// error: associated type bindings are not allowed here
-```
-
-To solve this error, please move the type bindings in the type parameter
-declaration:
-
-```ignore
-fn baz<I: Foo<A=Bar>>(x: &<I as Foo>::A) {} // ok!
-```
-
-Or in the `where` clause:
-
-```ignore
-fn baz<I>(x: &<I as Foo>::A) where I: Foo<A=Bar> {}
-```
-"##,
-
 E0261: r##"
 When using a lifetime like `'a` in a type, it must be declared before being
 used.
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 60d03ccfe24..c4fccdcb9eb 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -76,7 +76,6 @@ pub mod infer;
 pub mod lint;
 
 pub mod middle {
-    pub mod astconv_util;
     pub mod expr_use_visitor;
     pub mod const_val;
     pub mod cstore;
diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs
deleted file mode 100644
index 3418034b069..00000000000
--- a/src/librustc/middle/astconv_util.rs
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2012-2014 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.
-
-/*!
- * This module contains a simple utility routine
- * used by both `typeck` and `const_eval`.
- * Almost certainly this could (and should) be refactored out of existence.
- */
-
-use hir;
-use hir::def::Def;
-use ty::{Ty, TyCtxt};
-
-use syntax_pos::Span;
-
-impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
-    pub fn prohibit_type_params(self, segments: &[hir::PathSegment]) {
-        for segment in segments {
-            for typ in segment.parameters.types() {
-                struct_span_err!(self.sess, typ.span, E0109,
-                                 "type parameters are not allowed on this type")
-                    .span_label(typ.span, &format!("type parameter not allowed"))
-                    .emit();
-                break;
-            }
-            for lifetime in segment.parameters.lifetimes() {
-                struct_span_err!(self.sess, lifetime.span, E0110,
-                                 "lifetime parameters are not allowed on this type")
-                    .span_label(lifetime.span,
-                                &format!("lifetime parameter not allowed on this type"))
-                    .emit();
-                break;
-            }
-            for binding in segment.parameters.bindings() {
-                self.prohibit_projection(binding.span);
-                break;
-            }
-        }
-    }
-
-    pub fn prohibit_projection(self, span: Span)
-    {
-        let mut err = struct_span_err!(self.sess, span, E0229,
-                                       "associated type bindings are not allowed here");
-        err.span_label(span, &format!("associate type not allowed here")).emit();
-    }
-
-    pub fn prim_ty_to_ty(self,
-                         segments: &[hir::PathSegment],
-                         nty: hir::PrimTy)
-                         -> Ty<'tcx> {
-        self.prohibit_type_params(segments);
-        match nty {
-            hir::TyBool => self.types.bool,
-            hir::TyChar => self.types.char,
-            hir::TyInt(it) => self.mk_mach_int(it),
-            hir::TyUint(uit) => self.mk_mach_uint(uit),
-            hir::TyFloat(ft) => self.mk_mach_float(ft),
-            hir::TyStr => self.mk_str()
-        }
-    }
-
-    /// If a type in the AST is a primitive type, return the ty::Ty corresponding
-    /// to it.
-    pub fn ast_ty_to_prim_ty(self, ast_ty: &hir::Ty) -> Option<Ty<'tcx>> {
-        if let hir::TyPath(hir::QPath::Resolved(None, ref path)) = ast_ty.node {
-            if let Def::PrimTy(nty) = path.def {
-                Some(self.prim_ty_to_ty(&path.segments, nty))
-            } else {
-                None
-            }
-        } else {
-            None
-        }
-    }
-}
diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs
index 11919db479c..d81f89827d9 100644
--- a/src/librustc/middle/const_val.rs
+++ b/src/librustc/middle/const_val.rs
@@ -12,28 +12,30 @@ use syntax::symbol::InternedString;
 use syntax::ast;
 use std::rc::Rc;
 use hir::def_id::DefId;
+use ty::subst::Substs;
 use rustc_const_math::*;
+
 use self::ConstVal::*;
 pub use rustc_const_math::ConstInt;
 
 use std::collections::BTreeMap;
 
 #[derive(Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
-pub enum ConstVal {
+pub enum ConstVal<'tcx> {
     Float(ConstFloat),
     Integral(ConstInt),
     Str(InternedString),
     ByteStr(Rc<Vec<u8>>),
     Bool(bool),
-    Function(DefId),
-    Struct(BTreeMap<ast::Name, ConstVal>),
-    Tuple(Vec<ConstVal>),
-    Array(Vec<ConstVal>),
-    Repeat(Box<ConstVal>, u64),
+    Function(DefId, &'tcx Substs<'tcx>),
+    Struct(BTreeMap<ast::Name, ConstVal<'tcx>>),
+    Tuple(Vec<ConstVal<'tcx>>),
+    Array(Vec<ConstVal<'tcx>>),
+    Repeat(Box<ConstVal<'tcx>>, u64),
     Char(char),
 }
 
-impl ConstVal {
+impl<'tcx> ConstVal<'tcx> {
     pub fn description(&self) -> &'static str {
         match *self {
             Float(f) => f.description(),
@@ -43,7 +45,7 @@ impl ConstVal {
             Bool(_) => "boolean",
             Struct(_) => "struct",
             Tuple(_) => "tuple",
-            Function(_) => "function definition",
+            Function(..) => "function definition",
             Array(..) => "array",
             Repeat(..) => "repeat",
             Char(..) => "char",
@@ -53,8 +55,7 @@ impl ConstVal {
     pub fn to_const_int(&self) -> Option<ConstInt> {
         match *self {
             ConstVal::Integral(i) => Some(i),
-            ConstVal::Bool(true) => Some(ConstInt::Infer(1)),
-            ConstVal::Bool(false) => Some(ConstInt::Infer(0)),
+            ConstVal::Bool(b) => Some(ConstInt::U8(b as u8)),
             ConstVal::Char(ch) => Some(ConstInt::U32(ch as u32)),
             _ => None
         }
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index d2a657e35b5..40ebc97a78a 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -542,7 +542,7 @@ impl<'tcx> Terminator<'tcx> {
 impl<'tcx> TerminatorKind<'tcx> {
     pub fn if_<'a, 'gcx>(tcx: ty::TyCtxt<'a, 'gcx, 'tcx>, cond: Operand<'tcx>,
                          t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> {
-        static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::Infer(0)];
+        static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::U8(0)];
         TerminatorKind::SwitchInt {
             discr: cond,
             switch_ty: tcx.types.bool,
@@ -1224,7 +1224,7 @@ pub enum Literal<'tcx> {
         substs: &'tcx Substs<'tcx>,
     },
     Value {
-        value: ConstVal,
+        value: ConstVal<'tcx>,
     },
     Promoted {
         // Index into the `promoted` vector of `Mir`.
@@ -1271,7 +1271,7 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
             write!(fmt, "b\"{}\"", escaped)
         }
         Bool(b) => write!(fmt, "{:?}", b),
-        Function(def_id) => write!(fmt, "{}", item_path_str(def_id)),
+        Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)),
         Struct(_) | Tuple(_) | Array(_) | Repeat(..) =>
             bug!("ConstVal `{:?}` should not be in MIR", const_val),
         Char(c) => write!(fmt, "{:?}", c),
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 318c866a59f..6961e0da362 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -244,6 +244,10 @@ pub struct TypeckTables<'tcx> {
     /// Set of trait imports actually used in the method resolution.
     /// This is used for warning unused imports.
     pub used_trait_imports: DefIdSet,
+
+    /// If any errors occurred while type-checking this body,
+    /// this field will be set to `true`.
+    pub tainted_by_errors: bool,
 }
 
 impl<'tcx> TypeckTables<'tcx> {
@@ -262,6 +266,7 @@ impl<'tcx> TypeckTables<'tcx> {
             cast_kinds: NodeMap(),
             lints: lint::LintTable::new(),
             used_trait_imports: DefIdSet(),
+            tainted_by_errors: false,
         }
     }
 
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 3773796e47d..e7895ca7990 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -20,7 +20,6 @@ use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions};
 use syntax::ast::{FloatTy, IntTy, UintTy};
 use syntax::attr;
 use syntax_pos::DUMMY_SP;
-use rustc_const_math::ConstInt;
 
 use std::cmp;
 use std::fmt;
@@ -1183,11 +1182,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                                                             i64::min_value(),
                                                             true);
                     for discr in def.discriminants(tcx) {
-                        let x = match discr.erase_type() {
-                            ConstInt::InferSigned(i) => i as i64,
-                            ConstInt::Infer(i) => i as u64 as i64,
-                            _ => bug!()
-                        };
+                        let x = discr.to_u128_unchecked() as i64;
                         if x == 0 { non_zero = false; }
                         if x < min { min = x; }
                         if x > max { max = x; }
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index 358d69ff8db..b79ab2a26fd 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -381,7 +381,7 @@ define_maps! { <'tcx>
 
     /// Results of evaluating monomorphic constants embedded in
     /// other items, such as enum variant explicit discriminants.
-    pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result<ConstVal, ()>
+    pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result<ConstVal<'tcx>, ()>
 }
 
 fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> {
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 64480e51022..49c25d25c60 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -47,6 +47,35 @@ type Disr = ConstInt;
  }
 
 
+macro_rules! typed_literal {
+    ($tcx:expr, $ty:expr, $lit:expr) => {
+        match $ty {
+            SignedInt(ast::IntTy::I8)    => ConstInt::I8($lit),
+            SignedInt(ast::IntTy::I16)   => ConstInt::I16($lit),
+            SignedInt(ast::IntTy::I32)   => ConstInt::I32($lit),
+            SignedInt(ast::IntTy::I64)   => ConstInt::I64($lit),
+            SignedInt(ast::IntTy::I128)   => ConstInt::I128($lit),
+            SignedInt(ast::IntTy::Is) => match $tcx.sess.target.int_type {
+                ast::IntTy::I16 => ConstInt::Isize(ConstIsize::Is16($lit)),
+                ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32($lit)),
+                ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64($lit)),
+                _ => bug!(),
+            },
+            UnsignedInt(ast::UintTy::U8)  => ConstInt::U8($lit),
+            UnsignedInt(ast::UintTy::U16) => ConstInt::U16($lit),
+            UnsignedInt(ast::UintTy::U32) => ConstInt::U32($lit),
+            UnsignedInt(ast::UintTy::U64) => ConstInt::U64($lit),
+            UnsignedInt(ast::UintTy::U128) => ConstInt::U128($lit),
+            UnsignedInt(ast::UintTy::Us) => match $tcx.sess.target.uint_type {
+                ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16($lit)),
+                ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32($lit)),
+                ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64($lit)),
+                _ => bug!(),
+            },
+        }
+    }
+}
+
 impl IntTypeExt for attr::IntType {
     fn to_ty<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
         match *self {
@@ -66,30 +95,7 @@ impl IntTypeExt for attr::IntType {
     }
 
     fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr {
-        match *self {
-            SignedInt(ast::IntTy::I8)    => ConstInt::I8(0),
-            SignedInt(ast::IntTy::I16)   => ConstInt::I16(0),
-            SignedInt(ast::IntTy::I32)   => ConstInt::I32(0),
-            SignedInt(ast::IntTy::I64)   => ConstInt::I64(0),
-            SignedInt(ast::IntTy::I128)   => ConstInt::I128(0),
-            SignedInt(ast::IntTy::Is) => match tcx.sess.target.int_type {
-                ast::IntTy::I16 => ConstInt::Isize(ConstIsize::Is16(0)),
-                ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32(0)),
-                ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64(0)),
-                _ => bug!(),
-            },
-            UnsignedInt(ast::UintTy::U8)  => ConstInt::U8(0),
-            UnsignedInt(ast::UintTy::U16) => ConstInt::U16(0),
-            UnsignedInt(ast::UintTy::U32) => ConstInt::U32(0),
-            UnsignedInt(ast::UintTy::U64) => ConstInt::U64(0),
-            UnsignedInt(ast::UintTy::U128) => ConstInt::U128(0),
-            UnsignedInt(ast::UintTy::Us) => match tcx.sess.target.uint_type {
-                ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16(0)),
-                ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32(0)),
-                ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64(0)),
-                _ => bug!(),
-            },
-        }
+        typed_literal!(tcx, *self, 0)
     }
 
     fn assert_ty_matches(&self, val: Disr) {
@@ -114,7 +120,7 @@ impl IntTypeExt for attr::IntType {
                            -> Option<Disr> {
         if let Some(val) = val {
             self.assert_ty_matches(val);
-            (val + ConstInt::Infer(1)).ok()
+            (val + typed_literal!(tcx, *self, 1)).ok()
         } else {
             Some(self.initial_discriminant(tcx))
         }
diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs
index 5a9f885719c..53a7e872928 100644
--- a/src/librustc_const_eval/_match.rs
+++ b/src/librustc_const_eval/_match.rs
@@ -221,21 +221,21 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
 }
 
 #[derive(Clone, Debug, PartialEq)]
-pub enum Constructor {
+pub enum Constructor<'tcx> {
     /// The constructor of all patterns that don't vary by constructor,
     /// e.g. struct patterns and fixed-length arrays.
     Single,
     /// Enum variants.
     Variant(DefId),
     /// Literal values.
-    ConstantValue(ConstVal),
+    ConstantValue(ConstVal<'tcx>),
     /// Ranges of literal values (`2...5` and `2..5`).
-    ConstantRange(ConstVal, ConstVal, RangeEnd),
+    ConstantRange(ConstVal<'tcx>, ConstVal<'tcx>, RangeEnd),
     /// Array patterns of length n.
     Slice(usize),
 }
 
-impl<'tcx> Constructor {
+impl<'tcx> Constructor<'tcx> {
     fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> usize {
         match self {
             &Variant(vid) => adt.variant_index_with_id(vid),
@@ -289,7 +289,7 @@ impl<'tcx> Witness<'tcx> {
     fn push_wild_constructor<'a>(
         mut self,
         cx: &MatchCheckCtxt<'a, 'tcx>,
-        ctor: &Constructor,
+        ctor: &Constructor<'tcx>,
         ty: Ty<'tcx>)
         -> Self
     {
@@ -321,7 +321,7 @@ impl<'tcx> Witness<'tcx> {
     fn apply_constructor<'a>(
         mut self,
         cx: &MatchCheckCtxt<'a,'tcx>,
-        ctor: &Constructor,
+        ctor: &Constructor<'tcx>,
         ty: Ty<'tcx>)
         -> Self
     {
@@ -399,7 +399,8 @@ impl<'tcx> Witness<'tcx> {
 /// We make sure to omit constructors that are statically impossible. eg for
 /// Option<!> we do not include Some(_) in the returned list of constructors.
 fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
-                                  pcx: PatternContext<'tcx>) -> Vec<Constructor>
+                                  pcx: PatternContext<'tcx>)
+                                  -> Vec<Constructor<'tcx>>
 {
     debug!("all_constructors({:?})", pcx.ty);
     match pcx.ty.sty {
@@ -664,7 +665,7 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>(
     cx: &mut MatchCheckCtxt<'a, 'tcx>,
     &Matrix(ref m): &Matrix<'p, 'tcx>,
     v: &[&'p Pattern<'tcx>],
-    ctor: Constructor,
+    ctor: Constructor<'tcx>,
     lty: Ty<'tcx>,
     witness: WitnessPreference) -> Usefulness<'tcx>
 {
@@ -702,10 +703,10 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>(
 /// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on.
 ///
 /// Returns None in case of a catch-all, which can't be specialized.
-fn pat_constructors(_cx: &mut MatchCheckCtxt,
-                    pat: &Pattern,
-                    pcx: PatternContext)
-                    -> Option<Vec<Constructor>>
+fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
+                          pat: &Pattern<'tcx>,
+                          pcx: PatternContext)
+                          -> Option<Vec<Constructor<'tcx>>>
 {
     match *pat.kind {
         PatternKind::Binding { .. } | PatternKind::Wild =>
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index db5df72267d..e2b9f174ff0 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -124,7 +124,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
                               "statics cannot be referenced in patterns");
                 }
                 PatternError::ConstEval(err) => {
-                    report_const_eval_err(self.tcx, &err, pat_span, "pattern").emit();
+                    report_const_eval_err(self.tcx, &err, pat_span, "pattern");
                 }
             }
         }
diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs
index 8c8b2b5da36..9937cbbf8e1 100644
--- a/src/librustc_const_eval/diagnostics.rs
+++ b/src/librustc_const_eval/diagnostics.rs
@@ -576,22 +576,6 @@ integer type:
 https://doc.rust-lang.org/reference.html#ffi-attributes
 "##,
 
-
-E0306: r##"
-In an array type `[T; N]`, `N` is the number of elements in the array. This
-must be an unsigned integer. Erroneous code example:
-
-```compile_fail,E0306
-const X: [i32; true] = [0]; // error: expected `usize` for array length,
-                            //        found boolean
-```
-
-Working example:
-
-```
-const X: [i32; 1] = [0];
-```
-"##,
 }
 
 
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 0ab2255aab0..284991a11b1 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -11,7 +11,6 @@
 use rustc::middle::const_val::ConstVal::*;
 use rustc::middle::const_val::ConstVal;
 use self::ErrKind::*;
-use self::EvalHint::*;
 
 use rustc::hir::map as hir_map;
 use rustc::hir::map::blocks::FnLikeNode;
@@ -20,7 +19,7 @@ use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::util::IntTypeExt;
-use rustc::ty::subst::Substs;
+use rustc::ty::subst::{Substs, Subst};
 use rustc::traits::Reveal;
 use rustc::util::common::ErrorReported;
 use rustc::util::nodemap::DefIdMap;
@@ -28,7 +27,6 @@ use rustc::util::nodemap::DefIdMap;
 use graphviz::IntoCow;
 use syntax::ast;
 use rustc::hir::{self, Expr};
-use syntax::attr::IntType;
 use syntax_pos::Span;
 
 use std::borrow::Cow;
@@ -37,18 +35,24 @@ use std::cmp::Ordering;
 use rustc_const_math::*;
 use rustc_errors::DiagnosticBuilder;
 
+macro_rules! signal {
+    ($e:expr, $exn:expr) => {
+        return Err(ConstEvalErr { span: $e.span, kind: $exn })
+    }
+}
+
 macro_rules! math {
     ($e:expr, $op:expr) => {
         match $op {
             Ok(val) => val,
-            Err(e) => signal!($e, Math(e)),
+            Err(e) => signal!($e, ErrKind::from(e)),
         }
     }
 }
 
 fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                   variant_def: DefId)
-                                  -> Option<(&'tcx Expr, Option<&'a ty::TypeckTables<'tcx>>)> {
+                                  -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)> {
     if let Some(variant_node_id) = tcx.hir.as_local_node_id(variant_def) {
         let enum_node_id = tcx.hir.get_parent(variant_node_id);
         if let Some(hir_map::NodeItem(it)) = tcx.hir.find(enum_node_id) {
@@ -58,7 +62,7 @@ fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         return variant.node.disr_expr.map(|e| {
                             let def_id = tcx.hir.body_owner_def_id(e);
                             (&tcx.hir.body(e).value,
-                             tcx.maps.typeck_tables.borrow().get(&def_id).cloned())
+                             tcx.item_tables(def_id))
                         });
                     }
                 }
@@ -75,55 +79,41 @@ fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 /// This generally happens in late/trans const evaluation.
 pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                         def_id: DefId,
-                                        substs: Option<&'tcx Substs<'tcx>>)
+                                        substs: &'tcx Substs<'tcx>)
                                         -> Option<(&'tcx Expr,
-                                                   Option<&'a ty::TypeckTables<'tcx>>,
-                                                   Option<ty::Ty<'tcx>>)> {
+                                                   &'a ty::TypeckTables<'tcx>)> {
     if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
         match tcx.hir.find(node_id) {
             None => None,
             Some(hir_map::NodeItem(&hir::Item {
-                node: hir::ItemConst(ref ty, body), ..
+                node: hir::ItemConst(_, body), ..
             })) |
             Some(hir_map::NodeImplItem(&hir::ImplItem {
-                node: hir::ImplItemKind::Const(ref ty, body), ..
+                node: hir::ImplItemKind::Const(_, body), ..
             })) => {
                 Some((&tcx.hir.body(body).value,
-                      tcx.maps.typeck_tables.borrow().get(&def_id).cloned(),
-                      tcx.ast_ty_to_prim_ty(ty)))
+                      tcx.item_tables(def_id)))
             }
             Some(hir_map::NodeTraitItem(ti)) => match ti.node {
-                hir::TraitItemKind::Const(ref ty, default) => {
-                    if let Some(substs) = substs {
-                        // If we have a trait item and the substitutions for it,
-                        // `resolve_trait_associated_const` will select an impl
-                        // or the default.
-                        let trait_id = tcx.hir.get_parent(node_id);
-                        let trait_id = tcx.hir.local_def_id(trait_id);
-                        let default_value = default.map(|body| {
-                            (&tcx.hir.body(body).value,
-                             tcx.maps.typeck_tables.borrow().get(&def_id).cloned(),
-                             tcx.ast_ty_to_prim_ty(ty))
-                        });
-                        resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs)
-                    } else {
-                        // Technically, without knowing anything about the
-                        // expression that generates the obligation, we could
-                        // still return the default if there is one. However,
-                        // it's safer to return `None` than to return some value
-                        // that may differ from what you would get from
-                        // correctly selecting an impl.
-                        None
-                    }
+                hir::TraitItemKind::Const(_, default) => {
+                    // If we have a trait item and the substitutions for it,
+                    // `resolve_trait_associated_const` will select an impl
+                    // or the default.
+                    let trait_id = tcx.hir.get_parent(node_id);
+                    let trait_id = tcx.hir.local_def_id(trait_id);
+                    let default_value = default.map(|body| {
+                        (&tcx.hir.body(body).value,
+                            tcx.item_tables(def_id))
+                    });
+                    resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs)
                 }
                 _ => None
             },
             Some(_) => None
         }
     } else {
-        let expr_tables_ty = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
-            (&body.value, Some(tcx.item_tables(def_id)),
-             Some(tcx.item_type(def_id)))
+        let expr_and_tables = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
+            (&body.value, tcx.item_tables(def_id))
         });
         match tcx.sess.cstore.describe_def(def_id) {
             Some(Def::AssociatedConst(_)) => {
@@ -133,30 +123,26 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 // trait-associated const if the caller gives us the
                 // substitutions for the reference to it.
                 if let Some(trait_id) = trait_id {
-                    if let Some(substs) = substs {
-                        resolve_trait_associated_const(tcx, def_id, expr_tables_ty,
-                                                       trait_id, substs)
-                    } else {
-                        None
-                    }
+                    resolve_trait_associated_const(tcx, def_id, expr_and_tables,
+                                                   trait_id, substs)
                 } else {
-                    expr_tables_ty
+                    expr_and_tables
                 }
             },
-            Some(Def::Const(..)) => expr_tables_ty,
+            Some(Def::Const(..)) => expr_and_tables,
             _ => None
         }
     }
 }
 
 fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-                                   -> Option<(&'tcx hir::Body, Option<&'a ty::TypeckTables<'tcx>>)>
+                                   -> Option<(&'tcx hir::Body, &'a ty::TypeckTables<'tcx>)>
 {
     if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
         FnLikeNode::from_node(tcx.hir.get(node_id)).and_then(|fn_like| {
             if fn_like.constness() == hir::Constness::Const {
                 Some((tcx.hir.body(fn_like.body()),
-                      tcx.maps.typeck_tables.borrow().get(&def_id).cloned()))
+                      tcx.item_tables(def_id)))
             } else {
                 None
             }
@@ -164,7 +150,7 @@ fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
     } else {
         if tcx.sess.cstore.is_const_fn(def_id) {
             tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
-                (body, Some(tcx.item_tables(def_id)))
+                (body, tcx.item_tables(def_id))
             })
         } else {
             None
@@ -172,7 +158,7 @@ fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
     }
 }
 
-pub fn report_const_eval_err<'a, 'tcx>(
+fn build_const_eval_err<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     err: &ConstEvalErr,
     primary_span: Span,
@@ -189,6 +175,18 @@ pub fn report_const_eval_err<'a, 'tcx>(
     diag
 }
 
+pub fn report_const_eval_err<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    err: &ConstEvalErr,
+    primary_span: Span,
+    primary_kind: &str)
+{
+    if let TypeckError = err.kind {
+        return;
+    }
+    build_const_eval_err(tcx, err, primary_span, primary_kind).emit();
+}
+
 pub fn fatal_const_eval_err<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     err: &ConstEvalErr,
@@ -196,7 +194,7 @@ pub fn fatal_const_eval_err<'a, 'tcx>(
     primary_kind: &str)
     -> !
 {
-    report_const_eval_err(tcx, err, primary_span, primary_kind).emit();
+    report_const_eval_err(tcx, err, primary_span, primary_kind);
     tcx.sess.abort_if_errors();
     unreachable!()
 }
@@ -222,69 +220,57 @@ pub fn note_const_eval_err<'a, 'tcx>(
 
 pub struct ConstContext<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    tables: Option<&'a ty::TypeckTables<'tcx>>,
-    fn_args: Option<DefIdMap<ConstVal>>
+    tables: &'a ty::TypeckTables<'tcx>,
+    substs: &'tcx Substs<'tcx>,
+    fn_args: Option<DefIdMap<ConstVal<'tcx>>>
 }
 
 impl<'a, 'tcx> ConstContext<'a, 'tcx> {
     pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, body: hir::BodyId) -> Self {
         let def_id = tcx.hir.body_owner_def_id(body);
-        ConstContext {
-            tcx: tcx,
-            tables: tcx.maps.typeck_tables.borrow().get(&def_id).cloned(),
-            fn_args: None
-        }
+        ConstContext::with_tables(tcx, tcx.item_tables(def_id))
     }
 
     pub fn with_tables(tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>) -> Self {
         ConstContext {
             tcx: tcx,
-            tables: Some(tables),
+            tables: tables,
+            substs: tcx.intern_substs(&[]),
             fn_args: None
         }
     }
 
     /// Evaluate a constant expression in a context where the expression isn't
-    /// guaranteed to be evaluatable. `ty_hint` is usually ExprTypeChecked,
-    /// but a few places need to evaluate constants during type-checking, like
-    /// computing the length of an array. (See also the FIXME above EvalHint.)
-    pub fn eval(&self, e: &Expr, ty_hint: EvalHint<'tcx>) -> EvalResult {
-        eval_const_expr_partial(self, e, ty_hint)
+    /// guaranteed to be evaluatable.
+    pub fn eval(&self, e: &Expr) -> EvalResult<'tcx> {
+        if self.tables.tainted_by_errors {
+            signal!(e, TypeckError);
+        }
+        eval_const_expr_partial(self, e)
     }
 }
 
 #[derive(Clone, Debug)]
-pub struct ConstEvalErr {
+pub struct ConstEvalErr<'tcx> {
     pub span: Span,
-    pub kind: ErrKind,
+    pub kind: ErrKind<'tcx>,
 }
 
 #[derive(Clone, Debug)]
-pub enum ErrKind {
+pub enum ErrKind<'tcx> {
     CannotCast,
-    CannotCastTo(&'static str),
-    InvalidOpForInts(hir::BinOp_),
-    InvalidOpForBools(hir::BinOp_),
-    InvalidOpForFloats(hir::BinOp_),
-    InvalidOpForIntUint(hir::BinOp_),
-    InvalidOpForUintInt(hir::BinOp_),
-    NegateOn(ConstVal),
-    NotOn(ConstVal),
-    CallOn(ConstVal),
-
     MissingStructField,
+    NegateOn(ConstVal<'tcx>),
+    NotOn(ConstVal<'tcx>),
+    CallOn(ConstVal<'tcx>),
+
     NonConstPath,
     UnimplementedConstVal(&'static str),
-    UnresolvedPath,
     ExpectedConstTuple,
     ExpectedConstStruct,
-    TupleIndexOutOfBounds,
     IndexedNonVec,
-    IndexNegative,
-    IndexNotInt,
+    IndexNotUsize,
     IndexOutOfBounds { len: u64, index: u64 },
-    RepeatCountNotNatural,
-    RepeatCountNotInt,
 
     MiscBinaryOp,
     MiscCatchAll,
@@ -292,18 +278,17 @@ pub enum ErrKind {
     IndexOpFeatureGated,
     Math(ConstMathErr),
 
-    IntermediateUnsignedNegative,
-    /// Expected, Got
-    TypeMismatch(String, ConstInt),
+    ErroneousReferencedConstant(Box<ConstEvalErr<'tcx>>),
 
-    BadType(ConstVal),
-    ErroneousReferencedConstant(Box<ConstEvalErr>),
-    CharCast(ConstInt),
+    TypeckError
 }
 
-impl From<ConstMathErr> for ErrKind {
-    fn from(err: ConstMathErr) -> ErrKind {
-        Math(err)
+impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> {
+    fn from(err: ConstMathErr) -> ErrKind<'tcx> {
+        match err {
+            ConstMathErr::UnsignedNegation => TypeckError,
+            _ => Math(err)
+        }
     }
 }
 
@@ -321,7 +306,7 @@ impl<'a> ConstEvalErrDescription<'a> {
     }
 }
 
-impl ConstEvalErr {
+impl<'tcx> ConstEvalErr<'tcx> {
     pub fn description(&self) -> ConstEvalErrDescription {
         use self::ErrKind::*;
         use self::ConstEvalErrDescription::*;
@@ -335,12 +320,6 @@ impl ConstEvalErr {
 
         match self.kind {
             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()),
@@ -349,111 +328,42 @@ impl ConstEvalErr {
             NonConstPath        => simple!("non-constant path in constant expression"),
             UnimplementedConstVal(what) =>
                 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"),
+            IndexNotUsize => simple!("indices must be of type `usize`"),
             IndexOutOfBounds { len, index } => {
                 simple!("index out of bounds: the len is {} but the index is {}",
                         len, index)
             }
-            RepeatCountNotNatural => simple!("repeat count must be a natural number"),
-            RepeatCountNotInt => simple!("repeat count must be integers"),
 
             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 => 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) => {
-                simple!("expected {}, found {}", expected, got.description())
-            },
-            BadType(ref i) => simple!("value of wrong type: {:?}", i),
             ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"),
-            CharCast(ref got) => {
-                simple!("only `u8` can be cast as `char`, not `{}`", got.description())
-            },
-        }
-    }
-}
-
-pub type EvalResult = Result<ConstVal, ConstEvalErr>;
-pub type CastResult = Result<ConstVal, ErrKind>;
-
-// FIXME: Long-term, this enum should go away: trying to evaluate
-// an expression which hasn't been type-checked is a recipe for
-// disaster.  That said, it's not clear how to fix ast_ty_to_ty
-// to avoid the ordering issue.
-
-/// Hint to determine how to evaluate constant expressions which
-/// might not be type-checked.
-#[derive(Copy, Clone, Debug)]
-pub enum EvalHint<'tcx> {
-    /// We have a type-checked expression.
-    ExprTypeChecked,
-    /// We have an expression which hasn't been type-checked, but we have
-    /// an idea of what the type will be because of the context. For example,
-    /// the length of an array is always `usize`. (This is referred to as
-    /// a hint because it isn't guaranteed to be consistent with what
-    /// type-checking would compute.)
-    UncheckedExprHint(Ty<'tcx>),
-    /// We have an expression which has not yet been type-checked, and
-    /// and we have no clue what the type will be.
-    UncheckedExprNoHint,
-}
 
-impl<'tcx> EvalHint<'tcx> {
-    fn erase_hint(&self) -> EvalHint<'tcx> {
-        match *self {
-            ExprTypeChecked => ExprTypeChecked,
-            UncheckedExprHint(_) | UncheckedExprNoHint => UncheckedExprNoHint,
-        }
-    }
-    fn checked_or(&self, ty: Ty<'tcx>) -> EvalHint<'tcx> {
-        match *self {
-            ExprTypeChecked => ExprTypeChecked,
-            _ => UncheckedExprHint(ty),
+            TypeckError => simple!("type-checking failed"),
         }
     }
 }
 
-macro_rules! signal {
-    ($e:expr, $exn:expr) => {
-        return Err(ConstEvalErr { span: $e.span, kind: $exn })
-    }
-}
+pub type EvalResult<'tcx> = Result<ConstVal<'tcx>, ConstEvalErr<'tcx>>;
+pub type CastResult<'tcx> = Result<ConstVal<'tcx>, ErrKind<'tcx>>;
 
 fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
-                                     e: &Expr,
-                                     ty_hint: EvalHint<'tcx>) -> EvalResult {
+                                     e: &Expr) -> EvalResult<'tcx> {
     let tcx = cx.tcx;
-    // Try to compute the type of the expression based on the EvalHint.
-    // (See also the definition of EvalHint, and the FIXME above EvalHint.)
-    let ety = match ty_hint {
-        ExprTypeChecked => {
-            // After type-checking, expr_ty is guaranteed to succeed.
-            cx.tables.map(|tables| tables.expr_ty(e))
-        }
-        UncheckedExprHint(ty) => {
-            // Use the type hint; it's not guaranteed to be right, but it's
-            // usually good enough.
-            Some(ty)
-        }
-        UncheckedExprNoHint => {
-            // This expression might not be type-checked, and we have no hint.
-            // Try to query the context for a type anyway; we might get lucky
-            // (for example, if the expression was imported from another crate).
-            cx.tables.and_then(|tables| tables.expr_ty_opt(e))
-        }
+    let ety = cx.tables.expr_ty(e);
+
+    // Avoid applying substitutions if they're empty, that'd ICE.
+    let ety = if cx.substs.is_empty() {
+        ety
+    } else {
+        ety.subst(tcx, cx.substs)
     };
+
     let result = match e.node {
       hir::ExprUnary(hir::UnNeg, ref inner) => {
         // unary neg literals already got their sign during creation
@@ -465,28 +375,28 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
             const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128;
             const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128;
             const I128_OVERFLOW: u128 = i128::min_value() as u128;
-            match (&lit.node, ety.map(|t| &t.sty)) {
-                (&LitKind::Int(I8_OVERFLOW, _), Some(&ty::TyInt(IntTy::I8))) |
+            match (&lit.node, &ety.sty) {
+                (&LitKind::Int(I8_OVERFLOW, _), &ty::TyInt(IntTy::I8)) |
                 (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
                     return Ok(Integral(I8(i8::min_value())))
                 },
-                (&LitKind::Int(I16_OVERFLOW, _), Some(&ty::TyInt(IntTy::I16))) |
+                (&LitKind::Int(I16_OVERFLOW, _), &ty::TyInt(IntTy::I16)) |
                 (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
                     return Ok(Integral(I16(i16::min_value())))
                 },
-                (&LitKind::Int(I32_OVERFLOW, _), Some(&ty::TyInt(IntTy::I32))) |
+                (&LitKind::Int(I32_OVERFLOW, _), &ty::TyInt(IntTy::I32)) |
                 (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
                     return Ok(Integral(I32(i32::min_value())))
                 },
-                (&LitKind::Int(I64_OVERFLOW, _), Some(&ty::TyInt(IntTy::I64))) |
+                (&LitKind::Int(I64_OVERFLOW, _), &ty::TyInt(IntTy::I64)) |
                 (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
                     return Ok(Integral(I64(i64::min_value())))
                 },
-                (&LitKind::Int(I128_OVERFLOW, _), Some(&ty::TyInt(IntTy::I128))) |
+                (&LitKind::Int(I128_OVERFLOW, _), &ty::TyInt(IntTy::I128)) |
                 (&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => {
                     return Ok(Integral(I128(i128::min_value())))
                 },
-                (&LitKind::Int(n, _), Some(&ty::TyInt(IntTy::Is))) |
+                (&LitKind::Int(n, _), &ty::TyInt(IntTy::Is)) |
                 (&LitKind::Int(n, Signed(IntTy::Is)), _) => {
                     match tcx.sess.target.int_type {
                         IntTy::I16 => if n == I16_OVERFLOW {
@@ -498,20 +408,20 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
                         IntTy::I64 => if n == I64_OVERFLOW {
                             return Ok(Integral(Isize(Is64(i64::min_value()))));
                         },
-                        _ => bug!(),
+                        _ => span_bug!(e.span, "typeck error")
                     }
                 },
                 _ => {},
             }
         }
-        match cx.eval(inner, ty_hint)? {
+        match cx.eval(inner)? {
           Float(f) => Float(-f),
           Integral(i) => Integral(math!(e, -i)),
           const_val => signal!(e, NegateOn(const_val)),
         }
       }
       hir::ExprUnary(hir::UnNot, ref inner) => {
-        match cx.eval(inner, ty_hint)? {
+        match cx.eval(inner)? {
           Integral(i) => Integral(math!(e, !i)),
           Bool(b) => Bool(!b),
           const_val => signal!(e, NotOn(const_val)),
@@ -519,16 +429,11 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
       }
       hir::ExprUnary(hir::UnDeref, _) => signal!(e, UnimplementedConstVal("deref operation")),
       hir::ExprBinary(op, ref a, ref b) => {
-        let b_ty = match op.node {
-            hir::BiShl | hir::BiShr => ty_hint.erase_hint(),
-            _ => ty_hint
-        };
         // technically, if we don't have type hints, but integral eval
         // gives us a type through a type-suffix, cast or const def type
         // we need to re-eval the other value of the BinOp if it was
         // not inferred
-        match (cx.eval(a, ty_hint)?,
-               cx.eval(b, b_ty)?) {
+        match (cx.eval(a)?, cx.eval(b)?) {
           (Float(a), Float(b)) => {
             use std::cmp::Ordering::*;
             match op.node {
@@ -543,7 +448,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
               hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
               hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
               hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
-              _ => signal!(e, InvalidOpForFloats(op.node)),
+              _ => span_bug!(e.span, "typeck error"),
             }
           }
           (Integral(a), Integral(b)) => {
@@ -565,7 +470,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
               hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
               hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
               hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
-              _ => signal!(e, InvalidOpForInts(op.node)),
+              _ => span_bug!(e.span, "typeck error"),
             }
           }
           (Bool(a), Bool(b)) => {
@@ -581,90 +486,57 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
               hir::BiLe => a <= b,
               hir::BiGe => a >= b,
               hir::BiGt => a > b,
-              _ => signal!(e, InvalidOpForBools(op.node)),
+              _ => span_bug!(e.span, "typeck error"),
              })
           }
 
           _ => signal!(e, MiscBinaryOp),
         }
       }
-      hir::ExprCast(ref base, ref target_ty) => {
-        let ety = tcx.ast_ty_to_prim_ty(&target_ty).or(ety)
-                .unwrap_or_else(|| {
-                    tcx.sess.span_fatal(target_ty.span,
-                                        "target type not found for const cast")
-                });
-
-        let base_hint = if let ExprTypeChecked = ty_hint {
-            ExprTypeChecked
-        } else {
-            match cx.tables.and_then(|tables| tables.expr_ty_opt(&base)) {
-                Some(t) => UncheckedExprHint(t),
-                None => ty_hint
-            }
-        };
-
-        let val = match cx.eval(base, base_hint) {
-            Ok(val) => val,
-            Err(ConstEvalErr { kind: ErroneousReferencedConstant(
-                box ConstEvalErr { kind: TypeMismatch(_, val), .. }), .. }) |
-            Err(ConstEvalErr { kind: TypeMismatch(_, val), .. }) => {
-                // Something like `5i8 as usize` doesn't need a type hint for the base
-                // instead take the type hint from the inner value
-                let hint = match val.int_type() {
-                    Some(IntType::UnsignedInt(ty)) => ty_hint.checked_or(tcx.mk_mach_uint(ty)),
-                    Some(IntType::SignedInt(ty)) => ty_hint.checked_or(tcx.mk_mach_int(ty)),
-                    // we had a type hint, so we can't have an unknown type
-                    None => bug!(),
-                };
-                cx.eval(base, hint)?
-            },
-            Err(e) => return Err(e),
-        };
-        match cast_const(tcx, val, ety) {
+      hir::ExprCast(ref base, _) => {
+        match cast_const(tcx, cx.eval(base)?, ety) {
             Ok(val) => val,
             Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
         }
       }
       hir::ExprPath(ref qpath) => {
-          let def = cx.tables.map(|tables| tables.qpath_def(qpath, e.id)).unwrap_or_else(|| {
-            // There are no tables so we can only handle already-resolved HIR.
-            match *qpath {
-                hir::QPath::Resolved(_, ref path) => path.def,
-                hir::QPath::TypeRelative(..) => Def::Err
-            }
-          });
-          match def {
+        let substs = cx.tables.node_id_item_substs(e.id)
+            .unwrap_or_else(|| tcx.intern_substs(&[]));
+
+        // Avoid applying substitutions if they're empty, that'd ICE.
+        let substs = if cx.substs.is_empty() {
+            substs
+        } else {
+            substs.subst(tcx, cx.substs)
+        };
+
+          match cx.tables.qpath_def(qpath, e.id) {
               Def::Const(def_id) |
               Def::AssociatedConst(def_id) => {
-                  let substs = if let ExprTypeChecked = ty_hint {
-                      Some(cx.tables.and_then(|tables| tables.node_id_item_substs(e.id))
-                        .unwrap_or_else(|| tcx.intern_substs(&[])))
-                  } else {
-                      None
-                  };
-                  if let Some((expr, tables, ty)) = lookup_const_by_id(tcx, def_id, substs) {
-                      let item_hint = match ty {
-                          Some(ty) => ty_hint.checked_or(ty),
-                          None => ty_hint,
-                      };
-                      let cx = ConstContext { tcx: tcx, tables: tables, fn_args: None };
-                      match cx.eval(expr, item_hint) {
+                  if let Some((expr, tables)) = lookup_const_by_id(tcx, def_id, substs) {
+                      let cx = ConstContext::with_tables(tcx, tables);
+                      match cx.eval(expr) {
                           Ok(val) => val,
+                          Err(ConstEvalErr { kind: TypeckError, .. }) => {
+                              signal!(e, TypeckError);
+                          }
                           Err(err) => {
                               debug!("bad reference: {:?}, {:?}", err.description(), err.span);
                               signal!(e, ErroneousReferencedConstant(box err))
                           },
                       }
                   } else {
-                      signal!(e, NonConstPath);
+                      signal!(e, TypeckError);
                   }
               },
               Def::VariantCtor(variant_def, ..) => {
                   if let Some((expr, tables)) = lookup_variant_by_id(tcx, variant_def) {
-                      let cx = ConstContext { tcx: tcx, tables: tables, fn_args: None };
-                      match cx.eval(expr, ty_hint) {
+                      let cx = ConstContext::with_tables(tcx, tables);
+                      match cx.eval(expr) {
                           Ok(val) => val,
+                          Err(ConstEvalErr { kind: TypeckError, .. }) => {
+                              signal!(e, TypeckError);
+                          }
                           Err(err) => {
                               debug!("bad reference: {:?}, {:?}", err.description(), err.span);
                               signal!(e, ErroneousReferencedConstant(box err))
@@ -685,16 +557,14 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
                       signal!(e, NonConstPath);
                   }
               },
-              Def::Method(id) | Def::Fn(id) => Function(id),
-              Def::Err => signal!(e, UnresolvedPath),
+              Def::Method(id) | Def::Fn(id) => Function(id, substs),
+              Def::Err => span_bug!(e.span, "typeck error"),
               _ => signal!(e, NonConstPath),
           }
       }
       hir::ExprCall(ref callee, ref args) => {
-          let sub_ty_hint = ty_hint.erase_hint();
-          let callee_val = cx.eval(callee, sub_ty_hint)?;
-          let did = match callee_val {
-              Function(did) => did,
+          let (did, substs) = match cx.eval(callee)? {
+              Function(did, substs) => (did, substs),
               Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")),
               callee => signal!(e, CallOn(callee)),
           };
@@ -711,8 +581,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
 
           let mut call_args = DefIdMap();
           for (arg, arg_expr) in arg_defs.into_iter().zip(args.iter()) {
-              let arg_hint = ty_hint.erase_hint();
-              let arg_val = cx.eval(arg_expr, arg_hint)?;
+              let arg_val = cx.eval(arg_expr)?;
               debug!("const call arg: {:?}", arg);
               if let Some(def_id) = arg {
                 assert!(call_args.insert(def_id, arg_val).is_none());
@@ -722,9 +591,10 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
           let callee_cx = ConstContext {
             tcx: tcx,
             tables: tables,
+            substs: substs,
             fn_args: Some(call_args)
           };
-          callee_cx.eval(&body.value, ty_hint)?
+          callee_cx.eval(&body.value)?
       },
       hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) {
           Ok(val) => val,
@@ -732,32 +602,27 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
       },
       hir::ExprBlock(ref block) => {
         match block.expr {
-            Some(ref expr) => cx.eval(expr, ty_hint)?,
-            None => signal!(e, UnimplementedConstVal("empty block")),
+            Some(ref expr) => cx.eval(expr)?,
+            None => Tuple(vec![]),
         }
       }
-      hir::ExprType(ref e, _) => cx.eval(e, ty_hint)?,
+      hir::ExprType(ref e, _) => cx.eval(e)?,
       hir::ExprTup(ref fields) => {
-        let field_hint = ty_hint.erase_hint();
-        Tuple(fields.iter().map(|e| cx.eval(e, field_hint)).collect::<Result<_, _>>()?)
+        Tuple(fields.iter().map(|e| cx.eval(e)).collect::<Result<_, _>>()?)
       }
       hir::ExprStruct(_, ref fields, _) => {
-        let field_hint = ty_hint.erase_hint();
         Struct(fields.iter().map(|f| {
-            cx.eval(&f.expr, field_hint).map(|v| (f.name.node, v))
+            cx.eval(&f.expr).map(|v| (f.name.node, v))
         }).collect::<Result<_, _>>()?)
       }
       hir::ExprIndex(ref arr, ref idx) => {
         if !tcx.sess.features.borrow().const_indexing {
             signal!(e, IndexOpFeatureGated);
         }
-        let arr_hint = ty_hint.erase_hint();
-        let arr = cx.eval(arr, arr_hint)?;
-        let idx_hint = ty_hint.checked_or(tcx.types.usize);
-        let idx = match cx.eval(idx, idx_hint)? {
+        let arr = cx.eval(arr)?;
+        let idx = match cx.eval(idx)? {
             Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
-            Integral(_) => bug!(),
-            _ => signal!(idx, IndexNotInt),
+            _ => signal!(idx, IndexNotUsize),
         };
         assert_eq!(idx as usize as u64, idx);
         match arr {
@@ -787,45 +652,25 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
         }
       }
       hir::ExprArray(ref v) => {
-        let elem_hint = ty_hint.erase_hint();
-        Array(v.iter().map(|e| cx.eval(e, elem_hint)).collect::<Result<_, _>>()?)
+        Array(v.iter().map(|e| cx.eval(e)).collect::<Result<_, _>>()?)
       }
-      hir::ExprRepeat(ref elem, count) => {
-          let elem_hint = ty_hint.erase_hint();
-          let len_hint = ty_hint.checked_or(tcx.types.usize);
-          let n = if let Some(ty) = ety {
-            // For cross-crate constants, we have the type already,
-            // but not the body for `count`, so use the type.
-            match ty.sty {
-                ty::TyArray(_, n) => n as u64,
-                _ => bug!()
-            }
-          } else {
-            let n = &tcx.hir.body(count).value;
-            match ConstContext::new(tcx, count).eval(n, len_hint)? {
-                Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
-                Integral(_) => signal!(e, RepeatCountNotNatural),
-                _ => signal!(e, RepeatCountNotInt),
-            }
+      hir::ExprRepeat(ref elem, _) => {
+          let n = match ety.sty {
+            ty::TyArray(_, n) => n as u64,
+            _ => span_bug!(e.span, "typeck error")
           };
-          Repeat(Box::new(cx.eval(elem, elem_hint)?), n)
+          Repeat(Box::new(cx.eval(elem)?), n)
       },
       hir::ExprTupField(ref base, index) => {
-        let base_hint = ty_hint.erase_hint();
-        let c = cx.eval(base, base_hint)?;
+        let c = cx.eval(base)?;
         if let Tuple(ref fields) = c {
-            if let Some(elem) = fields.get(index.node) {
-                elem.clone()
-            } else {
-                signal!(e, TupleIndexOutOfBounds);
-            }
+            fields[index.node].clone()
         } else {
             signal!(base, ExpectedConstTuple);
         }
       }
       hir::ExprField(ref base, field_name) => {
-        let base_hint = ty_hint.erase_hint();
-        let c = cx.eval(base, base_hint)?;
+        let c = cx.eval(base)?;
         if let Struct(ref fields) = c {
             if let Some(f) = fields.get(&field_name.node) {
                 f.clone()
@@ -840,82 +685,16 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
       _ => signal!(e, MiscCatchAll)
     };
 
-    match (ety.map(|t| &t.sty), result) {
-        (Some(ref ty_hint), Integral(i)) => match infer(i, tcx, ty_hint) {
-            Ok(inferred) => Ok(Integral(inferred)),
-            Err(err) => signal!(e, err),
-        },
-        (_, result) => Ok(result),
-    }
-}
-
-fn infer<'a, 'tcx>(i: ConstInt,
-                   tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                   ty_hint: &ty::TypeVariants<'tcx>)
-                   -> Result<ConstInt, ErrKind> {
-    use syntax::ast::*;
-
-    match (ty_hint, i) {
-        (&ty::TyInt(IntTy::I8), result @ I8(_)) => Ok(result),
-        (&ty::TyInt(IntTy::I16), result @ I16(_)) => Ok(result),
-        (&ty::TyInt(IntTy::I32), result @ I32(_)) => Ok(result),
-        (&ty::TyInt(IntTy::I64), result @ I64(_)) => Ok(result),
-        (&ty::TyInt(IntTy::I128), result @ I128(_)) => Ok(result),
-        (&ty::TyInt(IntTy::Is), result @ Isize(_)) => Ok(result),
-
-        (&ty::TyUint(UintTy::U8), result @ U8(_)) => Ok(result),
-        (&ty::TyUint(UintTy::U16), result @ U16(_)) => Ok(result),
-        (&ty::TyUint(UintTy::U32), result @ U32(_)) => Ok(result),
-        (&ty::TyUint(UintTy::U64), result @ U64(_)) => Ok(result),
-        (&ty::TyUint(UintTy::U128), result @ U128(_)) => Ok(result),
-        (&ty::TyUint(UintTy::Us), result @ Usize(_)) => Ok(result),
-
-        (&ty::TyInt(IntTy::I8), Infer(i)) => Ok(I8(i as i128 as i8)),
-        (&ty::TyInt(IntTy::I16), Infer(i)) => Ok(I16(i as i128 as i16)),
-        (&ty::TyInt(IntTy::I32), Infer(i)) => Ok(I32(i as i128 as i32)),
-        (&ty::TyInt(IntTy::I64), Infer(i)) => Ok(I64(i as i128 as i64)),
-        (&ty::TyInt(IntTy::I128), Infer(i)) => Ok(I128(i as i128)),
-        (&ty::TyInt(IntTy::Is), Infer(i)) => {
-            Ok(Isize(ConstIsize::new_truncating(i as i128, tcx.sess.target.int_type)))
-        },
-
-        (&ty::TyInt(IntTy::I8), InferSigned(i)) => Ok(I8(i as i8)),
-        (&ty::TyInt(IntTy::I16), InferSigned(i)) => Ok(I16(i as i16)),
-        (&ty::TyInt(IntTy::I32), InferSigned(i)) => Ok(I32(i as i32)),
-        (&ty::TyInt(IntTy::I64), InferSigned(i)) => Ok(I64(i as i64)),
-        (&ty::TyInt(IntTy::I128), InferSigned(i)) => Ok(I128(i)),
-        (&ty::TyInt(IntTy::Is), InferSigned(i)) => {
-            Ok(Isize(ConstIsize::new_truncating(i, tcx.sess.target.int_type)))
-        },
-
-        (&ty::TyUint(UintTy::U8), Infer(i)) => Ok(U8(i as u8)),
-        (&ty::TyUint(UintTy::U16), Infer(i)) => Ok(U16(i as u16)),
-        (&ty::TyUint(UintTy::U32), Infer(i)) => Ok(U32(i as u32)),
-        (&ty::TyUint(UintTy::U64), Infer(i)) => Ok(U64(i as u64)),
-        (&ty::TyUint(UintTy::U128), Infer(i)) => Ok(U128(i)),
-        (&ty::TyUint(UintTy::Us), Infer(i)) => {
-            Ok(Usize(ConstUsize::new_truncating(i, tcx.sess.target.uint_type)))
-        },
-        (&ty::TyUint(_), InferSigned(_)) => Err(IntermediateUnsignedNegative),
-
-        (&ty::TyInt(ity), i) => Err(TypeMismatch(ity.to_string(), i)),
-        (&ty::TyUint(ity), i) => Err(TypeMismatch(ity.to_string(), i)),
-
-        (&ty::TyAdt(adt, _), i) if adt.is_enum() => {
-            let int_ty = adt.repr.discr_type();
-            infer(i, tcx, &int_ty.to_ty(tcx).sty)
-        },
-        (_, i) => Err(BadType(ConstVal::Integral(i))),
-    }
+    Ok(result)
 }
 
 fn resolve_trait_associated_const<'a, 'tcx: 'a>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     trait_item_id: DefId,
-    default_value: Option<(&'tcx Expr, Option<&'a ty::TypeckTables<'tcx>>, Option<ty::Ty<'tcx>>)>,
+    default_value: Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>,
     trait_id: DefId,
     rcvr_substs: &'tcx Substs<'tcx>
-) -> Option<(&'tcx Expr, Option<&'a ty::TypeckTables<'tcx>>, Option<ty::Ty<'tcx>>)>
+) -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>
 {
     let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs));
     debug!("resolve_trait_associated_const: trait_ref={:?}",
@@ -950,7 +729,7 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(
                 let ac = tcx.associated_items(impl_data.impl_def_id)
                     .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
                 match ac {
-                    Some(ic) => lookup_const_by_id(tcx, ic.def_id, None),
+                    Some(ic) => lookup_const_by_id(tcx, ic.def_id, Substs::empty()),
                     None => default_value,
                 }
             }
@@ -961,7 +740,10 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(
     })
 }
 
-fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstInt, ty: ty::Ty) -> CastResult {
+fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                            val: ConstInt,
+                            ty: Ty<'tcx>)
+                            -> CastResult<'tcx> {
     let v = val.to_u128_unchecked();
     match ty.sty {
         ty::TyBool if v == 0 => Ok(Bool(false)),
@@ -982,42 +764,31 @@ fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstInt, ty: ty::
         ty::TyUint(ast::UintTy::Us) => {
             Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.uint_type))))
         },
-        ty::TyFloat(ast::FloatTy::F64) => match val.erase_type() {
-            Infer(u) => Ok(Float(F64(u as f64))),
-            InferSigned(i) => Ok(Float(F64(i as f64))),
-            _ => bug!("ConstInt::erase_type returned something other than Infer/InferSigned"),
-        },
-        ty::TyFloat(ast::FloatTy::F32) => match val.erase_type() {
-            Infer(u) => Ok(Float(F32(u as f32))),
-            InferSigned(i) => Ok(Float(F32(i as f32))),
-            _ => bug!("ConstInt::erase_type returned something other than Infer/InferSigned"),
-        },
+        ty::TyFloat(ast::FloatTy::F64) => Ok(Float(F64(val.to_f64()))),
+        ty::TyFloat(ast::FloatTy::F32) => Ok(Float(F32(val.to_f32()))),
         ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")),
-        ty::TyChar => match infer(val, tcx, &ty::TyUint(ast::UintTy::U8)) {
-            Ok(U8(u)) => Ok(Char(u as char)),
-            // can only occur before typeck, typeck blocks `T as char` for `T` != `u8`
-            _ => Err(CharCast(val)),
+        ty::TyChar => match val {
+            U8(u) => Ok(Char(u as char)),
+            _ => bug!(),
         },
-        _ => Err(CannotCast),
+        _ => bug!(),
     }
 }
 
 fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                               val: ConstFloat,
-                              ty: ty::Ty) -> CastResult {
+                              ty: Ty<'tcx>) -> CastResult<'tcx> {
     match ty.sty {
         ty::TyInt(_) | ty::TyUint(_) => {
             let i = match val {
-                F32(f) if f >= 0.0 => Infer(f as u128),
-                FInfer { f64: f, .. } |
-                F64(f) if f >= 0.0 => Infer(f as u128),
+                F32(f) if f >= 0.0 => U128(f as u128),
+                F64(f) if f >= 0.0 => U128(f as u128),
 
-                F32(f) => InferSigned(f as i128),
-                FInfer { f64: f, .. } |
-                F64(f) => InferSigned(f as i128)
+                F32(f) => I128(f as i128),
+                F64(f) => I128(f as i128)
             };
 
-            if let (InferSigned(_), &ty::TyUint(_)) = (i, &ty.sty) {
+            if let (I128(_), &ty::TyUint(_)) = (i, &ty.sty) {
                 return Err(CannotCast);
             }
 
@@ -1025,23 +796,26 @@ fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
         ty::TyFloat(ast::FloatTy::F64) => Ok(Float(F64(match val {
             F32(f) => f as f64,
-            FInfer { f64: f, .. } | F64(f) => f
+            F64(f) => f
         }))),
         ty::TyFloat(ast::FloatTy::F32) => Ok(Float(F32(match val {
             F64(f) => f as f32,
-            FInfer { f32: f, .. } | F32(f) => f
+            F32(f) => f
         }))),
         _ => Err(CannotCast),
     }
 }
 
-fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstVal, ty: ty::Ty) -> CastResult {
+fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                        val: ConstVal<'tcx>,
+                        ty: Ty<'tcx>)
+                        -> CastResult<'tcx> {
     match val {
         Integral(i) => cast_const_int(tcx, i, ty),
-        Bool(b) => cast_const_int(tcx, Infer(b as u128), ty),
+        Bool(b) => cast_const_int(tcx, U8(b as u8), ty),
         Float(f) => cast_const_float(tcx, f, ty),
-        Char(c) => cast_const_int(tcx, Infer(c as u128), ty),
-        Function(_) => Err(UnimplementedConstVal("casting fn pointers")),
+        Char(c) => cast_const_int(tcx, U32(c as u32), ty),
+        Function(..) => Err(UnimplementedConstVal("casting fn pointers")),
         ByteStr(b) => match ty.sty {
             ty::TyRawPtr(_) => {
                 Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr"))
@@ -1069,66 +843,56 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstVal, ty: ty::Ty)
 
 fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind,
                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                          ty_hint: Option<Ty<'tcx>>)
-                          -> Result<ConstVal, ErrKind> {
+                          mut ty: Ty<'tcx>)
+                          -> Result<ConstVal<'tcx>, ErrKind<'tcx>> {
     use syntax::ast::*;
     use syntax::ast::LitIntType::*;
+
+    if let ty::TyAdt(adt, _) = ty.sty {
+        if adt.is_enum() {
+            ty = adt.repr.discr_type().to_ty(tcx)
+        }
+    }
+
     match *lit {
         LitKind::Str(ref s, _) => Ok(Str(s.as_str())),
         LitKind::ByteStr(ref data) => Ok(ByteStr(data.clone())),
         LitKind::Byte(n) => Ok(Integral(U8(n))),
-        LitKind::Int(n, Signed(ity)) => {
-            infer(InferSigned(n as i128), tcx, &ty::TyInt(ity)).map(Integral)
-        },
-
-        // FIXME: this should become u128.
-        LitKind::Int(n, Unsuffixed) => {
-            match ty_hint.map(|t| &t.sty) {
-                Some(&ty::TyInt(ity)) => {
-                    infer(InferSigned(n as i128), tcx, &ty::TyInt(ity)).map(Integral)
-                },
-                Some(&ty::TyUint(uty)) => {
-                    infer(Infer(n as u128), tcx, &ty::TyUint(uty)).map(Integral)
-                },
-                None => Ok(Integral(Infer(n as u128))),
-                Some(&ty::TyAdt(adt, _)) => {
-                    let int_ty = adt.repr.discr_type();
-                    infer(Infer(n as u128), tcx, &int_ty.to_ty(tcx).sty).map(Integral)
-                },
-                Some(ty_hint) => bug!("bad ty_hint: {:?}, {:?}", ty_hint, lit),
+        LitKind::Int(n, hint) => {
+            match (&ty.sty, hint) {
+                (&ty::TyInt(ity), _) |
+                (_, Signed(ity)) => {
+                    Ok(Integral(ConstInt::new_signed_truncating(n as i128,
+                        ity, tcx.sess.target.int_type)))
+                }
+                (&ty::TyUint(uty), _) |
+                (_, Unsigned(uty)) => {
+                    Ok(Integral(ConstInt::new_unsigned_truncating(n as u128,
+                        uty, tcx.sess.target.uint_type)))
+                }
+                _ => bug!()
             }
-        },
-        LitKind::Int(n, Unsigned(ity)) => {
-            infer(Infer(n as u128), tcx, &ty::TyUint(ity)).map(Integral)
-        },
-
+        }
         LitKind::Float(n, fty) => {
-            parse_float(&n.as_str(), Some(fty)).map(Float)
+            parse_float(&n.as_str(), fty).map(Float)
         }
         LitKind::FloatUnsuffixed(n) => {
-            let fty_hint = match ty_hint.map(|t| &t.sty) {
-                Some(&ty::TyFloat(fty)) => Some(fty),
-                _ => None
+            let fty = match ty.sty {
+                ty::TyFloat(fty) => fty,
+                _ => bug!()
             };
-            parse_float(&n.as_str(), fty_hint).map(Float)
+            parse_float(&n.as_str(), fty).map(Float)
         }
         LitKind::Bool(b) => Ok(Bool(b)),
         LitKind::Char(c) => Ok(Char(c)),
     }
 }
 
-fn parse_float(num: &str, fty_hint: Option<ast::FloatTy>)
-               -> Result<ConstFloat, ErrKind> {
-    let val = match fty_hint {
-        Some(ast::FloatTy::F32) => num.parse::<f32>().map(F32),
-        Some(ast::FloatTy::F64) => num.parse::<f64>().map(F64),
-        None => {
-            num.parse::<f32>().and_then(|f32| {
-                num.parse::<f64>().map(|f64| {
-                    FInfer { f32: f32, f64: f64 }
-                })
-            })
-        }
+fn parse_float<'tcx>(num: &str, fty: ast::FloatTy)
+                     -> Result<ConstFloat, ErrKind<'tcx>> {
+    let val = match fty {
+        ast::FloatTy::F32 => num.parse::<f32>().map(F32),
+        ast::FloatTy::F64 => num.parse::<f64>().map(F64)
     };
     val.map_err(|_| {
         // FIXME(#31407) this is only necessary because float parsing is buggy
@@ -1168,17 +932,17 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> {
                              a: &Expr,
                              b: &Expr) -> Result<Ordering, ErrorReported> {
         let tcx = self.tcx;
-        let a = match self.eval(a, ExprTypeChecked) {
+        let a = match self.eval(a) {
             Ok(a) => a,
             Err(e) => {
-                report_const_eval_err(tcx, &e, a.span, "expression").emit();
+                report_const_eval_err(tcx, &e, a.span, "expression");
                 return Err(ErrorReported);
             }
         };
-        let b = match self.eval(b, ExprTypeChecked) {
+        let b = match self.eval(b) {
             Ok(b) => b,
             Err(e) => {
-                report_const_eval_err(tcx, &e, b.span, "expression").emit();
+                report_const_eval_err(tcx, &e, b.span, "expression");
                 return Err(ErrorReported);
             }
         };
@@ -1193,26 +957,17 @@ pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              reason: &str)
                              -> Result<usize, ErrorReported>
 {
-    let hint = UncheckedExprHint(tcx.types.usize);
     let count_expr = &tcx.hir.body(count).value;
-    match ConstContext::new(tcx, count).eval(count_expr, hint) {
+    match ConstContext::new(tcx, count).eval(count_expr) {
         Ok(Integral(Usize(count))) => {
             let val = count.as_u64(tcx.sess.target.uint_type);
             assert_eq!(val as usize as u64, val);
             Ok(val as usize)
         },
-        Ok(const_val) => {
-            struct_span_err!(tcx.sess, count_expr.span, E0306,
-                             "expected `usize` for {}, found {}",
-                             reason,
-                             const_val.description())
-                .span_label(count_expr.span, &format!("expected `usize`"))
-                .emit();
-
-            Err(ErrorReported)
-        }
+        Ok(_) |
+        Err(ConstEvalErr { kind: TypeckError, .. }) => Err(ErrorReported),
         Err(err) => {
-            let mut diag = report_const_eval_err(
+            let mut diag = build_const_eval_err(
                 tcx, &err, count_expr.span, reason);
 
             if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node {
diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs
index 198e49daabc..4434a901f94 100644
--- a/src/librustc_const_eval/lib.rs
+++ b/src/librustc_const_eval/lib.rs
@@ -21,6 +21,7 @@
 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![deny(warnings)]
 
 #![feature(rustc_private)]
 #![feature(staged_api)]
diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs
index 609fb3e39d6..72a47c00281 100644
--- a/src/librustc_const_eval/pattern.rs
+++ b/src/librustc_const_eval/pattern.rs
@@ -27,9 +27,9 @@ use syntax::ptr::P;
 use syntax_pos::Span;
 
 #[derive(Clone, Debug)]
-pub enum PatternError {
+pub enum PatternError<'tcx> {
     StaticInPattern(Span),
-    ConstEval(eval::ConstEvalErr),
+    ConstEval(eval::ConstEvalErr<'tcx>),
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -84,12 +84,12 @@ pub enum PatternKind<'tcx> {
     },
 
     Constant {
-        value: ConstVal,
+        value: ConstVal<'tcx>,
     },
 
     Range {
-        lo: ConstVal,
-        hi: ConstVal,
+        lo: ConstVal<'tcx>,
+        hi: ConstVal<'tcx>,
         end: RangeEnd,
     },
 
@@ -118,7 +118,7 @@ fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result {
         ConstVal::Char(c) => write!(f, "{:?}", c),
         ConstVal::Struct(_) |
         ConstVal::Tuple(_) |
-        ConstVal::Function(_) |
+        ConstVal::Function(..) |
         ConstVal::Array(..) |
         ConstVal::Repeat(..) => bug!("{:?} not printable in a pattern", value)
     }
@@ -265,7 +265,7 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
 pub struct PatternContext<'a, 'gcx: 'tcx, 'tcx: 'a> {
     pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
     pub tables: &'a ty::TypeckTables<'gcx>,
-    pub errors: Vec<PatternError>,
+    pub errors: Vec<PatternError<'tcx>>,
 }
 
 impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
@@ -582,11 +582,11 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
                 let tcx = self.tcx.global_tcx();
                 let substs = self.tables.node_id_item_substs(id)
                     .unwrap_or_else(|| tcx.intern_substs(&[]));
-                match eval::lookup_const_by_id(tcx, def_id, Some(substs)) {
-                    Some((const_expr, const_tables, _const_ty)) => {
+                match eval::lookup_const_by_id(tcx, def_id, substs) {
+                    Some((const_expr, const_tables)) => {
                         // Enter the inlined constant's tables temporarily.
                         let old_tables = self.tables;
-                        self.tables = const_tables.expect("missing tables after typeck");
+                        self.tables = const_tables;
                         let pat = self.lower_const_expr(const_expr, pat_id, span);
                         self.tables = old_tables;
                         return pat;
@@ -609,7 +609,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
 
     fn lower_lit(&mut self, expr: &hir::Expr) -> PatternKind<'tcx> {
         let const_cx = eval::ConstContext::with_tables(self.tcx.global_tcx(), self.tables);
-        match const_cx.eval(expr, eval::EvalHint::ExprTypeChecked) {
+        match const_cx.eval(expr) {
             Ok(value) => {
                 PatternKind::Constant { value: value }
             }
@@ -796,7 +796,7 @@ macro_rules! CloneImpls {
 }
 
 CloneImpls!{ <'tcx>
-    Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal, Region,
+    Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal<'tcx>, Region,
     Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
     &'tcx Substs<'tcx>, &'tcx Kind<'tcx>
 }
diff --git a/src/librustc_const_math/float.rs b/src/librustc_const_math/float.rs
index 4610c183e1b..f557edffbda 100644
--- a/src/librustc_const_math/float.rs
+++ b/src/librustc_const_math/float.rs
@@ -17,13 +17,7 @@ use super::err::*;
 #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
 pub enum ConstFloat {
     F32(f32),
-    F64(f64),
-
-    // When the type isn't known, we have to operate on both possibilities.
-    FInfer {
-        f32: f32,
-        f64: f64
-    }
+    F64(f64)
 }
 pub use self::ConstFloat::*;
 
@@ -31,7 +25,6 @@ impl ConstFloat {
     /// Description of the type, not the value
     pub fn description(&self) -> &'static str {
         match *self {
-            FInfer {..} => "float",
             F32(_) => "f32",
             F64(_) => "f64",
         }
@@ -41,17 +34,13 @@ impl ConstFloat {
         match *self {
             F32(f) => f.is_nan(),
             F64(f) => f.is_nan(),
-            FInfer { f32, f64 } => f32.is_nan() || f64.is_nan()
         }
     }
 
     /// Compares the values if they are of the same type
     pub fn try_cmp(self, rhs: Self) -> Result<Ordering, ConstMathErr> {
         match (self, rhs) {
-            (F64(a), F64(b)) |
-            (F64(a), FInfer { f64: b, .. }) |
-            (FInfer { f64: a, .. }, F64(b)) |
-            (FInfer { f64: a, .. }, FInfer { f64: b, .. })  => {
+            (F64(a), F64(b))  => {
                 // This is pretty bad but it is the existing behavior.
                 Ok(if a == b {
                     Ordering::Equal
@@ -62,9 +51,7 @@ impl ConstFloat {
                 })
             }
 
-            (F32(a), F32(b)) |
-            (F32(a), FInfer { f32: b, .. }) |
-            (FInfer { f32: a, .. }, F32(b)) => {
+            (F32(a), F32(b)) => {
                 Ok(if a == b {
                     Ordering::Equal
                 } else if a < b {
@@ -86,10 +73,7 @@ impl ConstFloat {
 impl PartialEq for ConstFloat {
     fn eq(&self, other: &Self) -> bool {
         match (*self, *other) {
-            (F64(a), F64(b)) |
-            (F64(a), FInfer { f64: b, .. }) |
-            (FInfer { f64: a, .. }, F64(b)) |
-            (FInfer { f64: a, .. }, FInfer { f64: b, .. }) => {
+            (F64(a), F64(b)) => {
                 unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)}
             }
             (F32(a), F32(b)) => {
@@ -105,7 +89,7 @@ impl Eq for ConstFloat {}
 impl hash::Hash for ConstFloat {
     fn hash<H: hash::Hasher>(&self, state: &mut H) {
         match *self {
-            F64(a) | FInfer { f64: a, .. } => {
+            F64(a) => {
                 unsafe { transmute::<_,u64>(a) }.hash(state)
             }
             F32(a) => {
@@ -118,7 +102,6 @@ impl hash::Hash for ConstFloat {
 impl ::std::fmt::Display for ConstFloat {
     fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
         match *self {
-            FInfer { f64, .. } => write!(fmt, "{}", f64),
             F32(f) => write!(fmt, "{}f32", f),
             F64(f) => write!(fmt, "{}f64", f),
         }
@@ -131,20 +114,8 @@ macro_rules! derive_binop {
             type Output = Result<Self, ConstMathErr>;
             fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
                 match (self, rhs) {
-                    (F32(a), F32(b)) |
-                    (F32(a), FInfer { f32: b, .. }) |
-                    (FInfer { f32: a, .. }, F32(b)) => Ok(F32(a.$func(b))),
-
-                    (F64(a), F64(b)) |
-                    (FInfer { f64: a, .. }, F64(b)) |
-                    (F64(a), FInfer { f64: b, .. }) => Ok(F64(a.$func(b))),
-
-                    (FInfer { f32: a32, f64: a64 },
-                     FInfer { f32: b32, f64: b64 }) => Ok(FInfer {
-                        f32: a32.$func(b32),
-                        f64: a64.$func(b64)
-                    }),
-
+                    (F32(a), F32(b)) => Ok(F32(a.$func(b))),
+                    (F64(a), F64(b)) => Ok(F64(a.$func(b))),
                     _ => Err(UnequalTypes(Op::$op)),
                 }
             }
@@ -164,10 +135,6 @@ impl ::std::ops::Neg for ConstFloat {
         match self {
             F32(f) => F32(-f),
             F64(f) => F64(-f),
-            FInfer { f32, f64 } => FInfer {
-                f32: -f32,
-                f64: -f64
-            }
         }
     }
 }
diff --git a/src/librustc_const_math/int.rs b/src/librustc_const_math/int.rs
index 17714f2fb2d..d97276da9bf 100644
--- a/src/librustc_const_math/int.rs
+++ b/src/librustc_const_math/int.rs
@@ -30,8 +30,6 @@ pub enum ConstInt {
     U64(u64),
     U128(u128),
     Usize(ConstUsize),
-    Infer(u128),
-    InferSigned(i128),
 }
 pub use self::ConstInt::*;
 
@@ -92,7 +90,7 @@ impl ConstInt {
         }
     }
 
-    /// Creates a new unsigned ConstInt with matching type while also checking that overflow does
+    /// Creates a new signed ConstInt with matching type while also checking that overflow does
     /// not happen.
     pub fn new_signed(val: i128, ty: IntTy, isize_ty: IntTy) -> Option<ConstInt> {
         match ty {
@@ -107,103 +105,33 @@ impl ConstInt {
         }
     }
 
-    /// If either value is `Infer` or `InferSigned`, try to turn the value into the type of
-    /// the other value. If both values have no type, don't do anything
-    pub fn infer(self, other: Self) -> Result<(Self, Self), ConstMathErr> {
-        let inferred = match (self, other) {
-            (InferSigned(_), InferSigned(_))
-            | (Infer(_), Infer(_)) => self, // no inference possible
-            // kindof wrong, you could have had values > I64MAX during computation of a
-            (Infer(a @ 0...ubounds::I64MAX), InferSigned(_)) => InferSigned(a as i128),
-            (Infer(_), InferSigned(_)) => return Err(ConstMathErr::NotInRange),
-            (_, InferSigned(_))
-            | (_, Infer(_)) => return other.infer(self).map(|(b, a)| (a, b)),
-
-            (Infer(a @ 0...ubounds::I8MAX), I8(_)) => I8(a as i64 as i8),
-            (Infer(a @ 0...ubounds::I16MAX), I16(_)) => I16(a as i64 as i16),
-            (Infer(a @ 0...ubounds::I32MAX), I32(_)) => I32(a as i64 as i32),
-            (Infer(a @ 0...ubounds::I64MAX), I64(_)) => I64(a as i64),
-            (Infer(a @ 0...ubounds::I128MAX), I128(_)) => I128(a as i128),
-            (Infer(a @ 0...ubounds::I16MAX), Isize(Is16(_))) => Isize(Is16(a as i64 as i16)),
-            (Infer(a @ 0...ubounds::I32MAX), Isize(Is32(_))) => Isize(Is32(a as i64 as i32)),
-            (Infer(a @ 0...ubounds::I64MAX), Isize(Is64(_))) => Isize(Is64(a as i64)),
-            (Infer(a @ 0...ubounds::U8MAX), U8(_)) => U8(a as u8),
-            (Infer(a @ 0...ubounds::U16MAX), U16(_)) => U16(a as u16),
-            (Infer(a @ 0...ubounds::U32MAX), U32(_)) => U32(a as u32),
-            (Infer(a @ 0...ubounds::U64MAX), U64(_)) => U64(a as u64),
-            (Infer(a @ 0...ubounds::U128MAX), U128(_)) => U128(a as u128),
-            (Infer(a @ 0...ubounds::U16MAX), Usize(Us16(_))) => Usize(Us16(a as u16)),
-            (Infer(a @ 0...ubounds::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)),
-            (Infer(a @ 0...ubounds::U64MAX), Usize(Us64(_))) => Usize(Us64(a as u64)),
-
-            (Infer(_), _) => return Err(ConstMathErr::NotInRange),
-
-            (InferSigned(a @ ibounds::I8MIN...ibounds::I8MAX), I8(_)) => I8(a as i8),
-            (InferSigned(a @ ibounds::I16MIN...ibounds::I16MAX), I16(_)) => I16(a as i16),
-            (InferSigned(a @ ibounds::I32MIN...ibounds::I32MAX), I32(_)) => I32(a as i32),
-            (InferSigned(a @ ibounds::I64MIN...ibounds::I64MAX), I64(_)) => I64(a as i64),
-            (InferSigned(a @ ibounds::I128MIN...ibounds::I128MAX), I128(_)) => I128(a as i128),
-            (InferSigned(a @ ibounds::I16MIN...ibounds::I16MAX), Isize(Is16(_))) => {
-                Isize(Is16(a as i16))
-            },
-            (InferSigned(a @ ibounds::I32MIN...ibounds::I32MAX), Isize(Is32(_))) => {
-                Isize(Is32(a as i32))
-            },
-            (InferSigned(a @ ibounds::I64MIN...ibounds::I64MAX), Isize(Is64(_))) => {
-                Isize(Is64(a as i64))
-            },
-            (InferSigned(a @ 0...ibounds::U8MAX), U8(_)) => U8(a as u8),
-            (InferSigned(a @ 0...ibounds::U16MAX), U16(_)) => U16(a as u16),
-            (InferSigned(a @ 0...ibounds::U32MAX), U32(_)) => U32(a as u32),
-            (InferSigned(a @ 0...ibounds::U64MAX), U64(_)) => U64(a as u64),
-            (InferSigned(a @ 0...ibounds::I128MAX), U128(_)) => U128(a as u128),
-            (InferSigned(a @ 0...ibounds::U16MAX), Usize(Us16(_))) => Usize(Us16(a as u16)),
-            (InferSigned(a @ 0...ibounds::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)),
-            (InferSigned(a @ 0...ibounds::U64MAX), Usize(Us64(_))) => Usize(Us64(a as u64)),
-            (InferSigned(_), _) => return Err(ConstMathErr::NotInRange),
-            _ => self, // already known types
-        };
-        Ok((inferred, other))
+    /// Creates a new unsigned ConstInt with matching type.
+    pub fn new_unsigned_truncating(val: u128, ty: UintTy, usize_ty: UintTy) -> ConstInt {
+        match ty {
+            UintTy::U8 => U8(val as u8),
+            UintTy::U16 => U16(val as u16),
+            UintTy::U32 => U32(val as u32),
+            UintTy::U64 => U64(val as u64),
+            UintTy::Us => Usize(ConstUsize::new_truncating(val, usize_ty)),
+            UintTy::U128 => U128(val)
+        }
     }
 
-    /// Turn this value into an `Infer` or an `InferSigned`
-    pub fn erase_type(self) -> Self {
-        match self {
-            Infer(i) => Infer(i),
-            InferSigned(i) if i < 0 => InferSigned(i),
-            I8(i) if i < 0 => InferSigned(i as i128),
-            I16(i) if i < 0 => InferSigned(i as i128),
-            I32(i) if i < 0 => InferSigned(i as i128),
-            I64(i) if i < 0 => InferSigned(i as i128),
-            I128(i) if i < 0 => InferSigned(i as i128),
-            Isize(Is16(i)) if i < 0 => InferSigned(i as i128),
-            Isize(Is32(i)) if i < 0 => InferSigned(i as i128),
-            Isize(Is64(i)) if i < 0 => InferSigned(i as i128),
-            InferSigned(i) => Infer(i as u128),
-            I8(i) => Infer(i as u128),
-            I16(i) => Infer(i as u128),
-            I32(i) => Infer(i as u128),
-            I64(i) => Infer(i as u128),
-            I128(i) => Infer(i as u128),
-            Isize(Is16(i)) => Infer(i as u128),
-            Isize(Is32(i)) => Infer(i as u128),
-            Isize(Is64(i)) => Infer(i as u128),
-            U8(i) => Infer(i as u128),
-            U16(i) => Infer(i as u128),
-            U32(i) => Infer(i as u128),
-            U64(i) => Infer(i as u128),
-            U128(i) => Infer(i as u128),
-            Usize(Us16(i)) => Infer(i as u128),
-            Usize(Us32(i)) => Infer(i as u128),
-            Usize(Us64(i)) => Infer(i as u128),
+    /// Creates a new signed ConstInt with matching type.
+    pub fn new_signed_truncating(val: i128, ty: IntTy, isize_ty: IntTy) -> ConstInt {
+        match ty {
+            IntTy::I8 => I8(val as i8),
+            IntTy::I16 => I16(val as i16),
+            IntTy::I32 => I32(val as i32),
+            IntTy::I64 => I64(val as i64),
+            IntTy::Is => Isize(ConstIsize::new_truncating(val, isize_ty)),
+            IntTy::I128 => I128(val)
         }
     }
 
     /// Description of the type, not the value
     pub fn description(&self) -> &'static str {
         match *self {
-            Infer(_) => "not yet inferred integral",
-            InferSigned(_) => "not yet inferred signed integral",
             I8(_) => "i8",
             I16(_) => "i16",
             I32(_) => "i32",
@@ -222,10 +150,23 @@ impl ConstInt {
     /// Erases the type and returns a u128.
     /// This is not the same as `-5i8 as u128` but as `-5i8 as i128 as u128`
     pub fn to_u128_unchecked(self) -> u128 {
-        match self.erase_type() {
-            ConstInt::Infer(i) => i,
-            ConstInt::InferSigned(i) => i as u128,
-            _ => unreachable!(),
+        match self {
+            I8(i) => i as i128 as u128,
+            I16(i) => i as i128 as u128,
+            I32(i) => i as i128 as u128,
+            I64(i) => i as i128 as u128,
+            I128(i) => i as i128 as u128,
+            Isize(Is16(i)) => i as i128 as u128,
+            Isize(Is32(i)) => i as i128 as u128,
+            Isize(Is64(i)) => i as i128 as u128,
+            U8(i) => i as u128,
+            U16(i) => i as u128,
+            U32(i) => i as u128,
+            U64(i) => i as u128,
+            U128(i) => i as u128,
+            Usize(Us16(i)) => i as u128,
+            Usize(Us32(i)) => i as u128,
+            Usize(Us64(i)) => i as u128,
         }
     }
 
@@ -250,8 +191,6 @@ impl ConstInt {
     /// Converts the value to a `u128` if it's in the range 0...std::u128::MAX
     pub fn to_u128(&self) -> Option<u128> {
         match *self {
-            Infer(v) => Some(v),
-            InferSigned(v) if v >= 0 => Some(v as u128),
             I8(v) if v >= 0 => Some(v as u128),
             I16(v) if v >= 0 => Some(v as u128),
             I32(v) if v >= 0 => Some(v as u128),
@@ -272,6 +211,48 @@ impl ConstInt {
         }
     }
 
+    pub fn to_f32(self) -> f32 {
+        match self {
+            I8(i) => i as f32,
+            I16(i) => i as f32,
+            I32(i) => i as f32,
+            I64(i) => i as f32,
+            I128(i) => i as f32,
+            Isize(Is16(i)) => i as f32,
+            Isize(Is32(i)) => i as f32,
+            Isize(Is64(i)) => i as f32,
+            U8(i) => i as f32,
+            U16(i) => i as f32,
+            U32(i) => i as f32,
+            U64(i) => i as f32,
+            U128(i) => i as f32,
+            Usize(Us16(i)) => i as f32,
+            Usize(Us32(i)) => i as f32,
+            Usize(Us64(i)) => i as f32,
+        }
+    }
+
+    pub fn to_f64(self) -> f64 {
+        match self {
+            I8(i) => i as f64,
+            I16(i) => i as f64,
+            I32(i) => i as f64,
+            I64(i) => i as f64,
+            I128(i) => i as f64,
+            Isize(Is16(i)) => i as f64,
+            Isize(Is32(i)) => i as f64,
+            Isize(Is64(i)) => i as f64,
+            U8(i) => i as f64,
+            U16(i) => i as f64,
+            U32(i) => i as f64,
+            U64(i) => i as f64,
+            U128(i) => i as f64,
+            Usize(Us16(i)) => i as f64,
+            Usize(Us32(i)) => i as f64,
+            Usize(Us64(i)) => i as f64,
+        }
+    }
+
     pub fn is_negative(&self) -> bool {
         match *self {
             I8(v) => v < 0,
@@ -282,14 +263,13 @@ impl ConstInt {
             Isize(Is16(v)) => v < 0,
             Isize(Is32(v)) => v < 0,
             Isize(Is64(v)) => v < 0,
-            InferSigned(v) => v < 0,
             _ => false,
         }
     }
 
     /// Compares the values if they are of the same type
     pub fn try_cmp(self, rhs: Self) -> Result<::std::cmp::Ordering, ConstMathErr> {
-        match self.infer(rhs)? {
+        match (self, rhs) {
             (I8(a), I8(b)) => Ok(a.cmp(&b)),
             (I16(a), I16(b)) => Ok(a.cmp(&b)),
             (I32(a), I32(b)) => Ok(a.cmp(&b)),
@@ -306,8 +286,6 @@ impl ConstInt {
             (Usize(Us16(a)), Usize(Us16(b))) => Ok(a.cmp(&b)),
             (Usize(Us32(a)), Usize(Us32(b))) => Ok(a.cmp(&b)),
             (Usize(Us64(a)), Usize(Us64(b))) => Ok(a.cmp(&b)),
-            (Infer(a), Infer(b)) => Ok(a.cmp(&b)),
-            (InferSigned(a), InferSigned(b)) => Ok(a.cmp(&b)),
             _ => Err(CmpBetweenUnequalTypes),
         }
     }
@@ -334,25 +312,23 @@ impl ConstInt {
             ConstInt::Usize(ConstUsize::Us16(i)) => ConstInt::Usize(ConstUsize::Us16(add1!(i))),
             ConstInt::Usize(ConstUsize::Us32(i)) => ConstInt::Usize(ConstUsize::Us32(add1!(i))),
             ConstInt::Usize(ConstUsize::Us64(i)) => ConstInt::Usize(ConstUsize::Us64(add1!(i))),
-            ConstInt::Infer(_) | ConstInt::InferSigned(_) => panic!("no type info for const int"),
         }
     }
 
-    pub fn int_type(self) -> Option<IntType> {
+    pub fn int_type(self) -> IntType {
         match self {
-            ConstInt::I8(_) => Some(IntType::SignedInt(IntTy::I8)),
-            ConstInt::I16(_) => Some(IntType::SignedInt(IntTy::I16)),
-            ConstInt::I32(_) => Some(IntType::SignedInt(IntTy::I32)),
-            ConstInt::I64(_) => Some(IntType::SignedInt(IntTy::I64)),
-            ConstInt::I128(_) => Some(IntType::SignedInt(IntTy::I128)),
-            ConstInt::Isize(_) => Some(IntType::SignedInt(IntTy::Is)),
-            ConstInt::U8(_) => Some(IntType::UnsignedInt(UintTy::U8)),
-            ConstInt::U16(_) => Some(IntType::UnsignedInt(UintTy::U16)),
-            ConstInt::U32(_) => Some(IntType::UnsignedInt(UintTy::U32)),
-            ConstInt::U64(_) => Some(IntType::UnsignedInt(UintTy::U64)),
-            ConstInt::U128(_) => Some(IntType::UnsignedInt(UintTy::U128)),
-            ConstInt::Usize(_) => Some(IntType::UnsignedInt(UintTy::Us)),
-            _ => None,
+            ConstInt::I8(_) => IntType::SignedInt(IntTy::I8),
+            ConstInt::I16(_) => IntType::SignedInt(IntTy::I16),
+            ConstInt::I32(_) => IntType::SignedInt(IntTy::I32),
+            ConstInt::I64(_) => IntType::SignedInt(IntTy::I64),
+            ConstInt::I128(_) => IntType::SignedInt(IntTy::I128),
+            ConstInt::Isize(_) => IntType::SignedInt(IntTy::Is),
+            ConstInt::U8(_) => IntType::UnsignedInt(UintTy::U8),
+            ConstInt::U16(_) => IntType::UnsignedInt(UintTy::U16),
+            ConstInt::U32(_) => IntType::UnsignedInt(UintTy::U32),
+            ConstInt::U64(_) => IntType::UnsignedInt(UintTy::U64),
+            ConstInt::U128(_) => IntType::UnsignedInt(UintTy::U128),
+            ConstInt::Usize(_) => IntType::UnsignedInt(UintTy::Us),
         }
     }
 }
@@ -372,8 +348,6 @@ impl ::std::cmp::Ord for ConstInt {
 impl ::std::fmt::Display for ConstInt {
     fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
         match *self {
-            Infer(i) => write!(fmt, "{}", i),
-            InferSigned(i) => write!(fmt, "{}", i),
             I8(i) => write!(fmt, "{}i8", i),
             I16(i) => write!(fmt, "{}i16", i),
             I32(i) => write!(fmt, "{}i32", i),
@@ -409,7 +383,7 @@ macro_rules! impl_binop {
         impl ::std::ops::$op for ConstInt {
             type Output = Result<Self, ConstMathErr>;
             fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
-                match self.infer(rhs)? {
+                match (self, rhs) {
                     (I8(a), I8(b)) => a.$checked_func(b).map(I8),
                     (I16(a), I16(b)) => a.$checked_func(b).map(I16),
                     (I32(a), I32(b)) => a.$checked_func(b).map(I32),
@@ -426,8 +400,6 @@ macro_rules! impl_binop {
                     (Usize(Us16(a)), Usize(Us16(b))) => a.$checked_func(b).map(Us16).map(Usize),
                     (Usize(Us32(a)), Usize(Us32(b))) => a.$checked_func(b).map(Us32).map(Usize),
                     (Usize(Us64(a)), Usize(Us64(b))) => a.$checked_func(b).map(Us64).map(Usize),
-                    (Infer(a), Infer(b)) => a.$checked_func(b).map(Infer),
-                    (InferSigned(a), InferSigned(b)) => a.$checked_func(b).map(InferSigned),
                     _ => return Err(UnequalTypes(Op::$op)),
                 }.ok_or(Overflow(Op::$op))
             }
@@ -440,7 +412,7 @@ macro_rules! derive_binop {
         impl ::std::ops::$op for ConstInt {
             type Output = Result<Self, ConstMathErr>;
             fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
-                match self.infer(rhs)? {
+                match (self, rhs) {
                     (I8(a), I8(b)) => Ok(I8(a.$func(b))),
                     (I16(a), I16(b)) => Ok(I16(a.$func(b))),
                     (I32(a), I32(b)) => Ok(I32(a.$func(b))),
@@ -457,8 +429,6 @@ macro_rules! derive_binop {
                     (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a.$func(b)))),
                     (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a.$func(b)))),
                     (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a.$func(b)))),
-                    (Infer(a), Infer(b)) => Ok(Infer(a.$func(b))),
-                    (InferSigned(a), InferSigned(b)) => Ok(InferSigned(a.$func(b))),
                     _ => Err(UnequalTypes(Op::$op)),
                 }
             }
@@ -490,7 +460,6 @@ fn check_division(
         (Isize(_), Isize(Is16(0))) => Err(zerr),
         (Isize(_), Isize(Is32(0))) => Err(zerr),
         (Isize(_), Isize(Is64(0))) => Err(zerr),
-        (InferSigned(_), InferSigned(0)) => Err(zerr),
 
         (U8(_), U8(0)) => Err(zerr),
         (U16(_), U16(0)) => Err(zerr),
@@ -500,7 +469,6 @@ fn check_division(
         (Usize(_), Usize(Us16(0))) => Err(zerr),
         (Usize(_), Usize(Us32(0))) => Err(zerr),
         (Usize(_), Usize(Us64(0))) => Err(zerr),
-        (Infer(_), Infer(0)) => Err(zerr),
 
         (I8(::std::i8::MIN), I8(-1)) => Err(Overflow(op)),
         (I16(::std::i16::MIN), I16(-1)) => Err(Overflow(op)),
@@ -510,7 +478,6 @@ fn check_division(
         (Isize(Is16(::std::i16::MIN)), Isize(Is16(-1))) => Err(Overflow(op)),
         (Isize(Is32(::std::i32::MIN)), Isize(Is32(-1))) => Err(Overflow(op)),
         (Isize(Is64(::std::i64::MIN)), Isize(Is64(-1))) => Err(Overflow(op)),
-        (InferSigned(I128_MIN), InferSigned(-1)) => Err(Overflow(op)),
 
         _ => Ok(()),
     }
@@ -519,7 +486,7 @@ fn check_division(
 impl ::std::ops::Div for ConstInt {
     type Output = Result<Self, ConstMathErr>;
     fn div(self, rhs: Self) -> Result<Self, ConstMathErr> {
-        let (lhs, rhs) = self.infer(rhs)?;
+        let (lhs, rhs) = (self, rhs);
         check_division(lhs, rhs, Op::Div, DivisionByZero)?;
         match (lhs, rhs) {
             (I8(a), I8(b)) => Ok(I8(a/b)),
@@ -530,7 +497,6 @@ impl ::std::ops::Div for ConstInt {
             (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a/b))),
             (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a/b))),
             (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a/b))),
-            (InferSigned(a), InferSigned(b)) => Ok(InferSigned(a/b)),
 
             (U8(a), U8(b)) => Ok(U8(a/b)),
             (U16(a), U16(b)) => Ok(U16(a/b)),
@@ -540,7 +506,6 @@ impl ::std::ops::Div for ConstInt {
             (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a/b))),
             (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a/b))),
             (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a/b))),
-            (Infer(a), Infer(b)) => Ok(Infer(a/b)),
 
             _ => Err(UnequalTypes(Op::Div)),
         }
@@ -550,7 +515,7 @@ impl ::std::ops::Div for ConstInt {
 impl ::std::ops::Rem for ConstInt {
     type Output = Result<Self, ConstMathErr>;
     fn rem(self, rhs: Self) -> Result<Self, ConstMathErr> {
-        let (lhs, rhs) = self.infer(rhs)?;
+        let (lhs, rhs) = (self, rhs);
         // should INT_MIN%-1 be zero or an error?
         check_division(lhs, rhs, Op::Rem, RemainderByZero)?;
         match (lhs, rhs) {
@@ -562,7 +527,6 @@ impl ::std::ops::Rem for ConstInt {
             (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a%b))),
             (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a%b))),
             (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a%b))),
-            (InferSigned(a), InferSigned(b)) => Ok(InferSigned(a%b)),
 
             (U8(a), U8(b)) => Ok(U8(a%b)),
             (U16(a), U16(b)) => Ok(U16(a%b)),
@@ -572,7 +536,6 @@ impl ::std::ops::Rem for ConstInt {
             (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a%b))),
             (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a%b))),
             (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a%b))),
-            (Infer(a), Infer(b)) => Ok(Infer(a%b)),
 
             _ => Err(UnequalTypes(Op::Rem)),
         }
@@ -600,8 +563,6 @@ impl ::std::ops::Shl<ConstInt> for ConstInt {
             Usize(Us16(a)) => Ok(Usize(Us16(overflowing!(a.overflowing_shl(b), Op::Shl)))),
             Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shl(b), Op::Shl)))),
             Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shl(b), Op::Shl)))),
-            Infer(a) => Ok(Infer(overflowing!(a.overflowing_shl(b), Op::Shl))),
-            InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_shl(b), Op::Shl))),
         }
     }
 }
@@ -627,8 +588,6 @@ impl ::std::ops::Shr<ConstInt> for ConstInt {
             Usize(Us16(a)) => Ok(Usize(Us16(overflowing!(a.overflowing_shr(b), Op::Shr)))),
             Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shr(b), Op::Shr)))),
             Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shr(b), Op::Shr)))),
-            Infer(a) => Ok(Infer(overflowing!(a.overflowing_shr(b), Op::Shr))),
-            InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_shr(b), Op::Shr))),
         }
     }
 }
@@ -648,9 +607,6 @@ impl ::std::ops::Neg for ConstInt {
             a@U8(0) | a@U16(0) | a@U32(0) | a@U64(0) | a@U128(0) |
             a@Usize(Us16(0)) | a@Usize(Us32(0)) | a@Usize(Us64(0)) => Ok(a),
             U8(_) | U16(_) | U32(_) | U64(_) | U128(_) | Usize(_) => Err(UnsignedNegation),
-            Infer(a @ 0...ubounds::I128MAX) => Ok(InferSigned(-(a as i128))),
-            Infer(_) => Err(Overflow(Op::Neg)),
-            InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_neg(), Op::Neg))),
         }
     }
 }
@@ -675,8 +631,6 @@ impl ::std::ops::Not for ConstInt {
             Usize(Us16(a)) => Ok(Usize(Us16(!a))),
             Usize(Us32(a)) => Ok(Usize(Us32(!a))),
             Usize(Us64(a)) => Ok(Usize(Us64(!a))),
-            Infer(a) => Ok(Infer(!a)),
-            InferSigned(a) => Ok(InferSigned(!a)),
         }
     }
 }
diff --git a/src/librustc_const_math/lib.rs b/src/librustc_const_math/lib.rs
index 13764ce5bbb..b7833a54403 100644
--- a/src/librustc_const_math/lib.rs
+++ b/src/librustc_const_math/lib.rs
@@ -21,7 +21,7 @@
 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/")]
-
+#![deny(warnings)]
 
 #![feature(rustc_private)]
 #![feature(staged_api)]
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 3301a98968e..529afe0215e 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -17,7 +17,6 @@ use rustc::ty::layout::{Layout, Primitive};
 use rustc::traits::Reveal;
 use middle::const_val::ConstVal;
 use rustc_const_eval::ConstContext;
-use rustc_const_eval::EvalHint::ExprTypeChecked;
 use util::nodemap::FxHashSet;
 use lint::{LateContext, LintContext, LintArray};
 use lint::{LintPass, LateLintPass};
@@ -109,7 +108,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
                             }
                         } else {
                             let const_cx = ConstContext::with_tables(cx.tcx, cx.tables);
-                            match const_cx.eval(&r, ExprTypeChecked) {
+                            match const_cx.eval(&r) {
                                 Ok(ConstVal::Integral(i)) => {
                                     i.is_negative() ||
                                     i.to_u64()
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index fa39b687355..26d907523a8 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -230,9 +230,9 @@ pub enum EntryKind<'tcx> {
     Type,
     Enum(ReprOptions),
     Field,
-    Variant(Lazy<VariantData>),
-    Struct(Lazy<VariantData>, ReprOptions),
-    Union(Lazy<VariantData>, ReprOptions),
+    Variant(Lazy<VariantData<'tcx>>),
+    Struct(Lazy<VariantData<'tcx>>, ReprOptions),
+    Union(Lazy<VariantData<'tcx>>, ReprOptions),
     Fn(Lazy<FnData>),
     ForeignFn(Lazy<FnData>),
     Mod(Lazy<ModData>),
@@ -263,10 +263,10 @@ pub struct FnData {
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
-pub struct VariantData {
+pub struct VariantData<'tcx> {
     pub ctor_kind: CtorKind,
     pub discr: ty::VariantDiscr,
-    pub evaluated_discr: Option<ConstVal>,
+    pub evaluated_discr: Option<ConstVal<'tcx>>,
 
     /// If this is a struct's only variant, this
     /// is the index of the "struct ctor" item.
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index a28bc5d6ce3..6b6acb054b1 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -309,13 +309,13 @@ enum TestKind<'tcx> {
     // test the branches of enum
     SwitchInt {
         switch_ty: Ty<'tcx>,
-        options: Vec<ConstVal>,
-        indices: FxHashMap<ConstVal, usize>,
+        options: Vec<ConstVal<'tcx>>,
+        indices: FxHashMap<ConstVal<'tcx>, usize>,
     },
 
     // test for equality
     Eq {
-        value: ConstVal,
+        value: ConstVal<'tcx>,
         ty: Ty<'tcx>,
     },
 
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index fa8d7ffccde..f4fdf8ade90 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -112,8 +112,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                                      test_lvalue: &Lvalue<'tcx>,
                                      candidate: &Candidate<'pat, 'tcx>,
                                      switch_ty: Ty<'tcx>,
-                                     options: &mut Vec<ConstVal>,
-                                     indices: &mut FxHashMap<ConstVal, usize>)
+                                     options: &mut Vec<ConstVal<'tcx>>,
+                                     indices: &mut FxHashMap<ConstVal<'tcx>, usize>)
                                      -> bool
     {
         let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) {
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index ecdc58ba55d..41374a00123 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -223,6 +223,17 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
     builder.finish(vec![], ty)
 }
 
+pub fn construct_error<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
+                                       body_id: hir::BodyId)
+                                       -> Mir<'tcx> {
+    let span = hir.tcx().hir.span(hir.tcx().hir.body_owner(body_id));
+    let ty = hir.tcx().types.err;
+    let mut builder = Builder::new(hir, span, 0, ty);
+    let source_info = builder.source_info(span);
+    builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
+    builder.finish(vec![], ty)
+}
+
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     fn new(hir: Cx<'a, 'gcx, 'tcx>,
            span: Span,
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 2cb26eed1ff..f2b89309e4a 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -17,7 +17,7 @@ use hair::cx::to_ref::ToRef;
 use rustc::hir::map;
 use rustc::hir::def::{Def, CtorKind};
 use rustc::middle::const_val::ConstVal;
-use rustc_const_eval::{ConstContext, EvalHint, fatal_const_eval_err};
+use rustc_const_eval::{ConstContext, fatal_const_eval_err};
 use rustc::ty::{self, AdtKind, VariantDef, Ty};
 use rustc::ty::cast::CastKind as TyCastKind;
 use rustc::hir;
@@ -594,7 +594,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         hir::ExprRepeat(ref v, count) => {
             let tcx = cx.tcx.global_tcx();
             let c = &cx.tcx.hir.body(count).value;
-            let count = match ConstContext::new(tcx, count).eval(c, EvalHint::ExprTypeChecked) {
+            let count = match ConstContext::new(tcx, count).eval(c) {
                 Ok(ConstVal::Integral(ConstInt::Usize(u))) => u,
                 Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other),
                 Err(s) => fatal_const_eval_err(tcx, &s, c.span, "expression")
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 852c34a544a..c555ce1ab9c 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -18,7 +18,7 @@ use hair::*;
 use rustc::mir::transform::MirSource;
 
 use rustc::middle::const_val::ConstVal;
-use rustc_const_eval::{ConstContext, EvalHint, fatal_const_eval_err};
+use rustc_const_eval::{ConstContext, fatal_const_eval_err};
 use rustc_data_structures::indexed_vec::Idx;
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::blocks::FnLikeNode;
@@ -113,7 +113,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
 
     pub fn const_eval_literal(&mut self, e: &hir::Expr) -> Literal<'tcx> {
         let tcx = self.tcx.global_tcx();
-        match ConstContext::with_tables(tcx, self.tables()).eval(e, EvalHint::ExprTypeChecked) {
+        match ConstContext::with_tables(tcx, self.tables()).eval(e) {
             Ok(value) => Literal::Value { value: value },
             Err(s) => fatal_const_eval_err(tcx, &s, e.span, "expression")
         }
diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs
index 0d7be189f88..e0eb09fbf5d 100644
--- a/src/librustc_mir/mir_map.rs
+++ b/src/librustc_mir/mir_map.rs
@@ -98,7 +98,9 @@ fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
     let src = MirSource::from_node(tcx, id);
     tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
         let cx = Cx::new(&infcx, src);
-        let mut mir = if let MirSource::Fn(id) = src {
+        let mut mir = if cx.tables().tainted_by_errors {
+            build::construct_error(cx, body_id)
+        } else if let MirSource::Fn(id) = src {
             // fetch the fully liberated fn signature (that is, all bound
             // types/lifetimes replaced)
             let fn_sig = cx.tables().liberated_fn_sigs[&id].clone();
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index e3a77a93599..930a13e36bd 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -28,9 +28,8 @@ use rustc::dep_graph::DepNode;
 use rustc::ty::cast::CastKind;
 use rustc_const_eval::{ConstEvalErr, ConstContext};
 use rustc_const_eval::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll, Math};
-use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath, BadType};
-use rustc_const_eval::ErrKind::UnresolvedPath;
-use rustc_const_eval::EvalHint::ExprTypeChecked;
+use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath};
+use rustc_const_eval::ErrKind::{TypeckError};
 use rustc_const_math::{ConstMathErr, Op};
 use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::def_id::DefId;
@@ -66,12 +65,12 @@ struct CheckCrateVisitor<'a, 'tcx: 'a> {
 impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
     fn check_const_eval(&self, expr: &'gcx hir::Expr) {
         let const_cx = ConstContext::with_tables(self.tcx, self.tables);
-        if let Err(err) = const_cx.eval(expr, ExprTypeChecked) {
+        if let Err(err) = const_cx.eval(expr) {
             match err.kind {
                 UnimplementedConstVal(_) => {}
                 IndexOpFeatureGated => {}
                 ErroneousReferencedConstant(_) => {}
-                BadType(_) => {}
+                TypeckError => {}
                 _ => {
                     self.tcx.sess.add_lint(CONST_ERR,
                                            expr.id,
@@ -240,18 +239,17 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
 
         if self.in_fn && self.promotable {
             let const_cx = ConstContext::with_tables(self.tcx, self.tables);
-            match const_cx.eval(ex, ExprTypeChecked) {
+            match const_cx.eval(ex) {
                 Ok(_) => {}
                 Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }) |
                 Err(ConstEvalErr { kind: MiscCatchAll, .. }) |
                 Err(ConstEvalErr { kind: MiscBinaryOp, .. }) |
                 Err(ConstEvalErr { kind: NonConstPath, .. }) |
-                Err(ConstEvalErr { kind: UnresolvedPath, .. }) |
                 Err(ConstEvalErr { kind: ErroneousReferencedConstant(_), .. }) |
                 Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shr)), .. }) |
                 Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shl)), .. }) |
                 Err(ConstEvalErr { kind: IndexOpFeatureGated, .. }) => {}
-                Err(ConstEvalErr { kind: BadType(_), .. }) => {}
+                Err(ConstEvalErr { kind: TypeckError, .. }) => {}
                 Err(msg) => {
                     self.tcx.sess.add_lint(CONST_ERR,
                                            ex.id,
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index b68de7b46c8..011f7748f2c 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -213,11 +213,11 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
     g
 }
 
-pub fn trans_static(ccx: &CrateContext,
-                    m: hir::Mutability,
-                    id: ast::NodeId,
-                    attrs: &[ast::Attribute])
-                    -> Result<ValueRef, ConstEvalErr> {
+pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                              m: hir::Mutability,
+                              id: ast::NodeId,
+                              attrs: &[ast::Attribute])
+                              -> Result<ValueRef, ConstEvalErr<'tcx>> {
     unsafe {
         let def_id = ccx.tcx().hir.local_def_id(id);
         let g = get_static(ccx, def_id);
diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs
index d34b1aa2060..3cad2bc1d84 100644
--- a/src/librustc_trans/mir/block.rs
+++ b/src/librustc_trans/mir/block.rs
@@ -139,7 +139,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                 if switch_ty == bcx.tcx().types.bool {
                     let lltrue = llblock(self, targets[0]);
                     let llfalse = llblock(self, targets[1]);
-                    if let [ConstInt::Infer(0)] = values[..] {
+                    if let [ConstInt::U8(0)] = values[..] {
                         bcx.cond_br(discr.immediate(), llfalse, lltrue);
                     } else {
                         bcx.cond_br(discr.immediate(), lltrue, llfalse);
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 1f595cae6a8..771a5b7f366 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -83,7 +83,6 @@ impl<'tcx> Const<'tcx> {
                 let u = v.as_u64(ccx.tcx().sess.target.uint_type);
                 (C_integral(Type::int(ccx), u, false), tcx.types.usize)
             },
-            Infer(_) | InferSigned(_) => bug!("MIR must not use `{:?}`", ci),
         };
         Const { llval: llval, ty: ty }
     }
@@ -97,14 +96,13 @@ impl<'tcx> Const<'tcx> {
         let val = match cv {
             ConstVal::Float(F32(v)) => C_floating_f64(v as f64, llty),
             ConstVal::Float(F64(v)) => C_floating_f64(v, llty),
-            ConstVal::Float(FInfer {..}) => bug!("MIR must not use `{:?}`", cv),
             ConstVal::Bool(v) => C_bool(ccx, v),
             ConstVal::Integral(ref i) => return Const::from_constint(ccx, i),
             ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
             ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
             ConstVal::Struct(_) | ConstVal::Tuple(_) |
             ConstVal::Array(..) | ConstVal::Repeat(..) |
-            ConstVal::Function(_) => {
+            ConstVal::Function(..) => {
                 bug!("MIR must not use `{:?}` (which refers to a local ID)", cv)
             }
             ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
@@ -249,7 +247,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
     fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
                  instance: Instance<'tcx>,
                  args: IndexVec<mir::Local, Const<'tcx>>)
-                 -> Result<Const<'tcx>, ConstEvalErr> {
+                 -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
         let instance = instance.resolve_const(ccx.shared());
         let mir = ccx.tcx().item_mir(instance.def);
         MirConstContext::new(ccx, &mir, instance.substs, args).trans()
@@ -263,7 +261,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                                          value)
     }
 
-    fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr> {
+    fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
         let tcx = self.ccx.tcx();
         let mut bb = mir::START_BLOCK;
 
@@ -325,7 +323,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                         };
 
                         let err = ConstEvalErr{ span: span, kind: err };
-                        report_const_eval_err(tcx, &err, span, "expression").emit();
+                        report_const_eval_err(tcx, &err, span, "expression");
                         failure = Err(err);
                     }
                     target
@@ -373,7 +371,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
     }
 
     fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span)
-                    -> Result<ConstLvalue<'tcx>, ConstEvalErr> {
+                    -> Result<ConstLvalue<'tcx>, ConstEvalErr<'tcx>> {
         let tcx = self.ccx.tcx();
 
         if let mir::Lvalue::Local(index) = *lvalue {
@@ -468,7 +466,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
     }
 
     fn const_operand(&self, operand: &mir::Operand<'tcx>, span: Span)
-                     -> Result<Const<'tcx>, ConstEvalErr> {
+                     -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
         debug!("const_operand({:?} @ {:?})", operand, span);
         let result = match *operand {
             mir::Operand::Consume(ref lvalue) => {
@@ -523,7 +521,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
 
     fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
                     dest_ty: Ty<'tcx>, span: Span)
-                    -> Result<Const<'tcx>, ConstEvalErr> {
+                    -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
         let tcx = self.ccx.tcx();
         debug!("const_rvalue({:?}: {:?} @ {:?})", rvalue, dest_ty, span);
         let val = match *rvalue {
@@ -961,8 +959,11 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
 }
 
 
-pub fn trans_static_initializer(ccx: &CrateContext, def_id: DefId)
-                                -> Result<ValueRef, ConstEvalErr> {
+pub fn trans_static_initializer<'a, 'tcx>(
+    ccx: &CrateContext<'a, 'tcx>,
+    def_id: DefId)
+    -> Result<ValueRef, ConstEvalErr<'tcx>>
+{
     let instance = Instance::mono(ccx.shared(), def_id);
     MirConstContext::trans_def(ccx, instance, IndexVec::new()).map(|c| c.llval)
 }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index aae3947df14..577fe31eab0 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -189,7 +189,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                             &item_segment.parameters,
                                             None);
 
-        assoc_bindings.first().map(|b| self.tcx().prohibit_projection(b.span));
+        assoc_bindings.first().map(|b| self.prohibit_projection(b.span));
 
         substs
     }
@@ -446,7 +446,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                                  trait_def_id,
                                                  self_ty,
                                                  trait_segment);
-        assoc_bindings.first().map(|b| self.tcx().prohibit_projection(b.span));
+        assoc_bindings.first().map(|b| self.prohibit_projection(b.span));
         ty::TraitRef::new(trait_def_id, substs)
     }
 
@@ -844,7 +844,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         debug!("associated_path_def_to_ty: {:?}::{}", ty, assoc_name);
 
-        tcx.prohibit_type_params(slice::ref_slice(item_segment));
+        self.prohibit_type_params(slice::ref_slice(item_segment));
 
         // Find the type of the associated item, and the trait where the associated
         // item is declared.
@@ -917,7 +917,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     {
         let tcx = self.tcx();
 
-        tcx.prohibit_type_params(slice::ref_slice(item_segment));
+        self.prohibit_type_params(slice::ref_slice(item_segment));
 
         let self_ty = if let Some(ty) = opt_self_ty {
             ty
@@ -942,6 +942,36 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         self.projected_ty(span, trait_ref, item_segment.name)
     }
 
+    pub fn prohibit_type_params(&self, segments: &[hir::PathSegment]) {
+        for segment in segments {
+            for typ in segment.parameters.types() {
+                struct_span_err!(self.tcx().sess, typ.span, E0109,
+                                 "type parameters are not allowed on this type")
+                    .span_label(typ.span, &format!("type parameter not allowed"))
+                    .emit();
+                break;
+            }
+            for lifetime in segment.parameters.lifetimes() {
+                struct_span_err!(self.tcx().sess, lifetime.span, E0110,
+                                 "lifetime parameters are not allowed on this type")
+                    .span_label(lifetime.span,
+                                &format!("lifetime parameter not allowed on this type"))
+                    .emit();
+                break;
+            }
+            for binding in segment.parameters.bindings() {
+                self.prohibit_projection(binding.span);
+                break;
+            }
+        }
+    }
+
+    pub fn prohibit_projection(&self, span: Span) {
+        let mut err = struct_span_err!(self.tcx().sess, span, E0229,
+                                       "associated type bindings are not allowed here");
+        err.span_label(span, &format!("associate type not allowed here")).emit();
+    }
+
     // Check a type Path and convert it to a Ty.
     pub fn def_to_ty(&self,
                      opt_self_ty: Option<Ty<'tcx>>,
@@ -957,21 +987,21 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         match path.def {
             Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => {
                 assert_eq!(opt_self_ty, None);
-                tcx.prohibit_type_params(path.segments.split_last().unwrap().1);
+                self.prohibit_type_params(path.segments.split_last().unwrap().1);
                 self.ast_path_to_ty(span, did, path.segments.last().unwrap())
             }
             Def::Variant(did) if permit_variants => {
                 // Convert "variant type" as if it were a real type.
                 // The resulting `Ty` is type of the variant's enum for now.
                 assert_eq!(opt_self_ty, None);
-                tcx.prohibit_type_params(path.segments.split_last().unwrap().1);
+                self.prohibit_type_params(path.segments.split_last().unwrap().1);
                 self.ast_path_to_ty(span,
                                     tcx.parent_def_id(did).unwrap(),
                                     path.segments.last().unwrap())
             }
             Def::TyParam(did) => {
                 assert_eq!(opt_self_ty, None);
-                tcx.prohibit_type_params(&path.segments);
+                self.prohibit_type_params(&path.segments);
 
                 let node_id = tcx.hir.as_local_node_id(did).unwrap();
                 let item_id = tcx.hir.get_parent_node(node_id);
@@ -984,7 +1014,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 // Self in impl (we know the concrete type).
 
                 assert_eq!(opt_self_ty, None);
-                tcx.prohibit_type_params(&path.segments);
+                self.prohibit_type_params(&path.segments);
 
                 let ty = ty::queries::ty::get(tcx, span, def_id);
                 if let Some(free_substs) = self.get_free_substs() {
@@ -996,11 +1026,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             Def::SelfTy(Some(_), None) => {
                 // Self in trait.
                 assert_eq!(opt_self_ty, None);
-                tcx.prohibit_type_params(&path.segments);
+                self.prohibit_type_params(&path.segments);
                 tcx.mk_self_type()
             }
             Def::AssociatedTy(def_id) => {
-                tcx.prohibit_type_params(&path.segments[..path.segments.len()-2]);
+                self.prohibit_type_params(&path.segments[..path.segments.len()-2]);
                 let trait_did = tcx.parent_def_id(def_id).unwrap();
                 self.qpath_to_ty(span,
                                  opt_self_ty,
@@ -1010,7 +1040,15 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             }
             Def::PrimTy(prim_ty) => {
                 assert_eq!(opt_self_ty, None);
-                tcx.prim_ty_to_ty(&path.segments, prim_ty)
+                self.prohibit_type_params(&path.segments);
+                match prim_ty {
+                    hir::TyBool => tcx.types.bool,
+                    hir::TyChar => tcx.types.char,
+                    hir::TyInt(it) => tcx.mk_mach_int(it),
+                    hir::TyUint(uit) => tcx.mk_mach_uint(uit),
+                    hir::TyFloat(ft) => tcx.mk_mach_float(ft),
+                    hir::TyStr => tcx.mk_str()
+                }
             }
             Def::Err => {
                 self.set_tainted_by_errors();
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index aa1fc0f8579..0337727dcba 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -432,10 +432,6 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 
     body_id: ast::NodeId,
 
-    // This flag is set to true if, during the writeback phase, we encounter
-    // a type error in this function.
-    writeback_errors: Cell<bool>,
-
     // Number of errors that had been reported when we started
     // checking this function. On exit, if we find that *more* errors
     // have been reported, we will skip regionck and other work that
@@ -1493,7 +1489,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         FnCtxt {
             ast_ty_to_ty_cache: RefCell::new(NodeMap()),
             body_id: body_id,
-            writeback_errors: Cell::new(false),
             err_count_on_creation: inh.tcx.sess.err_count(),
             ret_ty: rty,
             ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal,
@@ -1609,6 +1604,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         if ty.references_error() {
             self.has_errors.set(true);
+            self.set_tainted_by_errors();
         }
 
         // FIXME(canndrew): This is_never should probably be an is_uninhabited
@@ -4326,7 +4322,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // errors if type parameters are provided in an inappropriate place.
         let poly_segments = type_segment.is_some() as usize +
                             fn_segment.is_some() as usize;
-        self.tcx.prohibit_type_params(&segments[..segments.len() - poly_segments]);
+        AstConv::prohibit_type_params(self, &segments[..segments.len() - poly_segments]);
 
         match def {
             Def::Local(def_id) | Def::Upvar(def_id, ..) => {
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 4f0cfa8d014..1382ab34ca5 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -20,7 +20,6 @@ use rustc::ty::fold::{TypeFolder,TypeFoldable};
 use rustc::infer::{InferCtxt, FixupError};
 use rustc::util::nodemap::{DefIdMap, DefIdSet};
 
-use std::cell::Cell;
 use std::mem;
 
 use syntax::ast;
@@ -35,8 +34,6 @@ use rustc::hir;
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn resolve_type_vars_in_body(&self, body: &'gcx hir::Body)
                                      -> &'gcx ty::TypeckTables<'gcx> {
-        assert_eq!(self.writeback_errors.get(), false);
-
         let item_id = self.tcx.hir.body_owner(body.id());
         let item_def_id = self.tcx.hir.local_def_id(item_id);
 
@@ -59,6 +56,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);
         wbcx.tables.used_trait_imports = used_trait_imports;
 
+        wbcx.tables.tainted_by_errors = self.is_tainted_by_errors();
+
         self.tcx.alloc_tables(wbcx.tables)
     }
 }
@@ -195,19 +194,11 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
     }
 
     fn visit_stmt(&mut self, s: &'gcx hir::Stmt) {
-        if self.fcx.writeback_errors.get() {
-            return;
-        }
-
         self.visit_node_id(ResolvingExpr(s.span), s.node.id());
         intravisit::walk_stmt(self, s);
     }
 
     fn visit_expr(&mut self, e: &'gcx hir::Expr) {
-        if self.fcx.writeback_errors.get() {
-            return;
-        }
-
         self.fix_scalar_builtin_expr(e);
 
         self.visit_node_id(ResolvingExpr(e.span), e.id);
@@ -227,29 +218,16 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
     }
 
     fn visit_block(&mut self, b: &'gcx hir::Block) {
-        if self.fcx.writeback_errors.get() {
-            return;
-        }
-
         self.visit_node_id(ResolvingExpr(b.span), b.id);
         intravisit::walk_block(self, b);
     }
 
     fn visit_pat(&mut self, p: &'gcx hir::Pat) {
-        if self.fcx.writeback_errors.get() {
-            return;
-        }
-
         self.visit_node_id(ResolvingPattern(p.span), p.id);
-
         intravisit::walk_pat(self, p);
     }
 
     fn visit_local(&mut self, l: &'gcx hir::Local) {
-        if self.fcx.writeback_errors.get() {
-            return;
-        }
-
         let var_ty = self.fcx.local_ty(l.span, l.id);
         let var_ty = self.resolve(&var_ty, ResolvingLocal(l.span));
         self.write_ty_to_tables(l.id, var_ty);
@@ -259,10 +237,6 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
 
 impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
     fn visit_upvar_borrow_map(&mut self) {
-        if self.fcx.writeback_errors.get() {
-            return;
-        }
-
         for (upvar_id, upvar_capture) in self.fcx.tables.borrow().upvar_capture_map.iter() {
             let new_upvar_capture = match *upvar_capture {
                 ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue,
@@ -281,10 +255,6 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
     }
 
     fn visit_closures(&mut self) {
-        if self.fcx.writeback_errors.get() {
-            return
-        }
-
         for (&id, closure_ty) in self.fcx.tables.borrow().closure_tys.iter() {
             let closure_ty = self.resolve(closure_ty, ResolvingClosure(id));
             self.tables.closure_tys.insert(id, closure_ty);
@@ -296,27 +266,15 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
     }
 
     fn visit_cast_types(&mut self) {
-        if self.fcx.writeback_errors.get() {
-            return
-        }
-
         self.tables.cast_kinds.extend(
             self.fcx.tables.borrow().cast_kinds.iter().map(|(&key, &value)| (key, value)));
     }
 
     fn visit_lints(&mut self) {
-        if self.fcx.writeback_errors.get() {
-            return
-        }
-
         self.fcx.tables.borrow_mut().lints.transfer(&mut self.tables.lints);
     }
 
     fn visit_anon_types(&mut self) {
-        if self.fcx.writeback_errors.get() {
-            return
-        }
-
         let gcx = self.tcx().global_tcx();
         for (&node_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() {
             let reason = ResolvingAnonTy(node_id);
@@ -542,7 +500,6 @@ impl<'a, 'gcx, 'tcx> ResolveReason {
 struct Resolver<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
     tcx: TyCtxt<'cx, 'gcx, 'tcx>,
     infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
-    writeback_errors: &'cx Cell<bool>,
     reason: ResolveReason,
 }
 
@@ -551,22 +508,19 @@ impl<'cx, 'gcx, 'tcx> Resolver<'cx, 'gcx, 'tcx> {
            reason: ResolveReason)
            -> Resolver<'cx, 'gcx, 'tcx>
     {
-        Resolver::from_infcx(fcx, &fcx.writeback_errors, reason)
+        Resolver::from_infcx(fcx, reason)
     }
 
     fn from_infcx(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
-                  writeback_errors: &'cx Cell<bool>,
                   reason: ResolveReason)
                   -> Resolver<'cx, 'gcx, 'tcx>
     {
         Resolver { infcx: infcx,
                    tcx: infcx.tcx,
-                   writeback_errors: writeback_errors,
                    reason: reason }
     }
 
     fn report_error(&self, e: FixupError) {
-        self.writeback_errors.set(true);
         if !self.tcx.sess.has_errors() {
             match self.reason {
                 ResolvingExpr(span) => {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index ecdbf170702..7f413a0dfc3 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -59,7 +59,6 @@ use constrained_type_params as ctp;
 use middle::lang_items::SizedTraitLangItem;
 use middle::const_val::ConstVal;
 use middle::resolve_lifetime as rl;
-use rustc_const_eval::EvalHint::UncheckedExprHint;
 use rustc_const_eval::{ConstContext, report_const_eval_err};
 use rustc::ty::subst::Substs;
 use rustc::ty::{ToPredicate, ReprOptions};
@@ -75,7 +74,7 @@ use rustc_const_math::ConstInt;
 use std::cell::RefCell;
 use std::collections::BTreeMap;
 
-use syntax::{abi, ast, attr};
+use syntax::{abi, ast};
 use syntax::codemap::Spanned;
 use syntax::symbol::{Symbol, keywords};
 use syntax_pos::{Span, DUMMY_SP};
@@ -596,6 +595,17 @@ fn convert_variant_ctor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     tcx.item_predicates(def_id);
 }
 
+fn evaluate_disr_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                body: hir::BodyId)
+                                -> Result<ConstVal<'tcx>, ()> {
+    let e = &tcx.hir.body(body).value;
+    ConstContext::new(tcx, body).eval(e).map_err(|err| {
+        // enum variant evaluation happens before the global constant check
+        // so we need to report the real error
+        report_const_eval_err(tcx, &err, e.span, "enum discriminant");
+    })
+}
+
 fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                         def_id: DefId,
                                         variants: &[hir::Variant]) {
@@ -610,7 +620,7 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         prev_discr = Some(if let Some(e) = variant.node.disr_expr {
             let expr_did = tcx.hir.local_def_id(e.node_id);
             let result = tcx.maps.monomorphic_const_eval.memoize(expr_did, || {
-                evaluate_disr_expr(tcx, repr_type, e).map(ConstVal::Integral)
+                evaluate_disr_expr(tcx, e)
             });
 
             match result {
@@ -738,60 +748,6 @@ fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     tcx.alloc_adt_def(def_id, kind, variants, repr)
 }
 
-fn evaluate_disr_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                repr_ty: attr::IntType,
-                                body: hir::BodyId)
-                      -> Result<ConstInt, ()> {
-    let e = &tcx.hir.body(body).value;
-    debug!("disr expr, checking {}", tcx.hir.node_to_pretty_string(e.id));
-
-    let ty_hint = repr_ty.to_ty(tcx);
-    let print_err = |cv: ConstVal| {
-        struct_span_err!(tcx.sess, e.span, E0079, "mismatched types")
-            .note_expected_found(&"type", &ty_hint, &format!("{}", cv.description()))
-            .span_label(e.span, &format!("expected '{}' type", ty_hint))
-            .emit();
-    };
-
-    let hint = UncheckedExprHint(ty_hint);
-    match ConstContext::new(tcx, body).eval(e, hint) {
-        Ok(ConstVal::Integral(i)) => {
-            // FIXME: eval should return an error if the hint does not match the type of the body.
-            // i.e. eventually the match below would not exist.
-            match (repr_ty, i) {
-                (attr::SignedInt(ast::IntTy::I8), ConstInt::I8(_)) |
-                (attr::SignedInt(ast::IntTy::I16), ConstInt::I16(_)) |
-                (attr::SignedInt(ast::IntTy::I32), ConstInt::I32(_)) |
-                (attr::SignedInt(ast::IntTy::I64), ConstInt::I64(_)) |
-                (attr::SignedInt(ast::IntTy::I128), ConstInt::I128(_)) |
-                (attr::SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) |
-                (attr::UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) |
-                (attr::UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) |
-                (attr::UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) |
-                (attr::UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) |
-                (attr::UnsignedInt(ast::UintTy::U128), ConstInt::U128(_)) |
-                (attr::UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => Ok(i),
-                (_, i) => {
-                    print_err(ConstVal::Integral(i));
-                    Err(())
-                },
-            }
-        },
-        Ok(cv) => {
-            print_err(cv);
-            Err(())
-        },
-        // enum variant evaluation happens before the global constant check
-        // so we need to report the real error
-        Err(err) => {
-            let mut diag = report_const_eval_err(
-                tcx, &err, e.span, "enum discriminant");
-            diag.emit();
-            Err(())
-        }
-    }
-}
-
 /// Ensures that the super-predicates of the trait with def-id
 /// trait_def_id are converted and stored. This also ensures that
 /// the transitive super-predicates are converted;
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index e8cb25cec4f..644e323a8db 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -1039,45 +1039,6 @@ struct Good(u32, u32, u32);
 ```
 "##,
 
-E0079: r##"
-Enum variants which contain no data can be given a custom integer
-representation. This error indicates that the value provided is not an integer
-literal and is therefore invalid.
-
-For example, in the following code:
-
-```compile_fail,E0079
-enum Foo {
-    Q = "32",
-}
-```
-
-We try to set the representation to a string.
-
-There's no general fix for this; if you can work with an integer then just set
-it to one:
-
-```
-enum Foo {
-    Q = 32,
-}
-```
-
-However if you actually wanted a mapping between variants and non-integer
-objects, it may be preferable to use a method with a match instead:
-
-```
-enum Foo { Q }
-impl Foo {
-    fn get_str(&self) -> &'static str {
-        match *self {
-            Foo::Q => "32",
-        }
-    }
-}
-```
-"##,
-
 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,
@@ -1427,6 +1388,44 @@ struct Baz<'a> {
 ```
 "##,
 
+E0109: r##"
+You tried to give a type parameter to a type which doesn't need it. Erroneous
+code example:
+
+```compile_fail,E0109
+type X = u32<i32>; // error: type parameters are not allowed on this type
+```
+
+Please check that you used the correct type and recheck its definition. Perhaps
+it doesn't need the type parameter.
+
+Example:
+
+```
+type X = u32; // this compiles
+```
+
+Note that type parameters for enum-variant constructors go after the variant,
+not after the enum (Option::None::<u32>, not Option::<u32>::None).
+"##,
+
+E0110: r##"
+You tried to give a lifetime parameter to a type which doesn't need it.
+Erroneous code example:
+
+```compile_fail,E0110
+type X = u32<'static>; // error: lifetime parameters are not allowed on
+                       //        this type
+```
+
+Please check that the correct type was used and recheck its definition; perhaps
+it doesn't need the lifetime parameter. Example:
+
+```
+type X = u32; // ok!
+```
+"##,
+
 E0116: r##"
 You can only define an inherent implementation for a type in the same crate
 where the type was defined. For example, an `impl` block as below is not allowed
@@ -2649,6 +2648,41 @@ fn main() {
 ```
 "##,
 
+E0229: r##"
+An associated type binding was done outside of the type parameter declaration
+and `where` clause. Erroneous code example:
+
+```compile_fail,E0229
+pub trait Foo {
+    type A;
+    fn boo(&self) -> <Self as Foo>::A;
+}
+
+struct Bar;
+
+impl Foo for isize {
+    type A = usize;
+    fn boo(&self) -> usize { 42 }
+}
+
+fn baz<I>(x: &<I as Foo<A=Bar>>::A) {}
+// error: associated type bindings are not allowed here
+```
+
+To solve this error, please move the type bindings in the type parameter
+declaration:
+
+```ignore
+fn baz<I: Foo<A=Bar>>(x: &<I as Foo>::A) {} // ok!
+```
+
+Or in the `where` clause:
+
+```ignore
+fn baz<I>(x: &<I as Foo>::A) where I: Foo<A=Bar> {}
+```
+"##,
+
 E0230: r##"
 The trait has more type parameters specified than appear in its definition.
 
diff --git a/src/test/compile-fail/E0306.rs b/src/test/compile-fail/E0306.rs
deleted file mode 100644
index 9ffaef7472b..00000000000
--- a/src/test/compile-fail/E0306.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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.
-
-const A: [u32; "hello"] = [];
-//~^ ERROR expected `usize` for array length, found string literal [E0306]
-//~| NOTE expected `usize`
-
-const B: [u32; true] = [];
-//~^ ERROR expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
-
-const C: [u32; 0.0] = [];
-//~^ ERROR expected `usize` for array length, found float [E0306]
-//~| NOTE expected `usize`
-
-fn main() {
-}
diff --git a/src/test/compile-fail/associated-const-array-len.rs b/src/test/compile-fail/associated-const-array-len.rs
index 0239986f5ad..7f77ae2ec1f 100644
--- a/src/test/compile-fail/associated-const-array-len.rs
+++ b/src/test/compile-fail/associated-const-array-len.rs
@@ -14,7 +14,8 @@ trait Foo {
     const ID: usize;
 }
 
-const X: [i32; <i32 as Foo>::ID] = [0, 1, 2]; //~ ERROR E0080
+const X: [i32; <i32 as Foo>::ID] = [0, 1, 2];
+//~^ ERROR the trait bound `i32: Foo` is not satisfied
 
 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 7c3f7a1d574..7fd9605ef2c 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
@@ -27,8 +27,6 @@ impl Foo for Def {
 pub fn test<A: Foo, B: Foo>() {
     let _array = [4; <A as Foo>::Y];
     //~^ ERROR cannot use an outer type parameter in this context [E0402]
-    //~| ERROR constant evaluation error [E0080]
-    //~| non-constant path in constant
 }
 
 fn main() {
diff --git a/src/test/compile-fail/associated-const-type-parameter-arrays.rs b/src/test/compile-fail/associated-const-type-parameter-arrays.rs
index dcf87d5f0fc..71c7a3965ec 100644
--- a/src/test/compile-fail/associated-const-type-parameter-arrays.rs
+++ b/src/test/compile-fail/associated-const-type-parameter-arrays.rs
@@ -27,8 +27,6 @@ impl Foo for Def {
 pub fn test<A: Foo, B: Foo>() {
     let _array: [u32; <A as Foo>::Y];
     //~^ ERROR cannot use an outer type parameter in this context [E0402]
-    //~| ERROR constant evaluation 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 b980bc02c85..108b7948dfc 100644
--- a/src/test/compile-fail/const-array-oob.rs
+++ b/src/test/compile-fail/const-array-oob.rs
@@ -12,8 +12,8 @@
 
 #![feature(const_indexing)]
 
-const FOO: [u32; 3] = [1, 2, 3];
-const BAR: u32 = FOO[5]; // no error, because the error below occurs before regular const eval
+const FOO: [usize; 3] = [1, 2, 3];
+const BAR: usize = FOO[5]; // no error, because the error below occurs before regular const eval
 
 const BLUB: [u32; FOO[4]] = [5, 6];
 //~^ ERROR constant evaluation error [E0080]
diff --git a/src/test/compile-fail/const-eval-overflow-4b.rs b/src/test/compile-fail/const-eval-overflow-4b.rs
index 9e7a5ecae10..02072e9a1a1 100644
--- a/src/test/compile-fail/const-eval-overflow-4b.rs
+++ b/src/test/compile-fail/const-eval-overflow-4b.rs
@@ -20,8 +20,9 @@ use std::{u8, u16, u32, u64, usize};
 
 const A_I8_T
     : [u32; (i8::MAX as i8 + 1u8) as usize]
-    //~^ ERROR constant evaluation error [E0080]
+    //~^ ERROR mismatched types
     //~| expected i8, found u8
+    //~| ERROR the trait bound `i8: std::ops::Add<u8>` is not satisfied
     = [0; (i8::MAX as usize) + 1];
 
 
@@ -32,8 +33,7 @@ const A_CHAR_USIZE
 
 const A_BAD_CHAR_USIZE
     : [u32; 5i8 as char as usize]
-    //~^ ERROR constant evaluation error
-    //~| only `u8` can be cast as `char`, not `i8`
+    //~^ ERROR only `u8` can be cast as `char`, not `i8`
     = [0; 5];
 
 fn main() {}
diff --git a/src/test/compile-fail/const-eval-span.rs b/src/test/compile-fail/const-eval-span.rs
index 73351429b50..16f89606b01 100644
--- a/src/test/compile-fail/const-eval-span.rs
+++ b/src/test/compile-fail/const-eval-span.rs
@@ -14,12 +14,13 @@
 struct S(i32);
 
 const CONSTANT: S = S(0);
-//~^ ERROR E0080
-//~| unimplemented constant expression: tuple struct constructors
 
 enum E {
     V = CONSTANT,
-    //~^ NOTE: for enum discriminant here
+    //~^ ERROR mismatched types
+    //~| expected isize, found struct `S`
+    //~| NOTE expected type `isize`
+    //~|         found type `S`
 }
 
 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 398dc2f2215..29bc665a22e 100644
--- a/src/test/compile-fail/const-integer-bool-ops.rs
+++ b/src/test/compile-fail/const-integer-bool-ops.rs
@@ -8,52 +8,71 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-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 X: usize = 42 && 39;
+//~^ ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected usize, found bool
+const ARR: [i32; X] = [99; 34];
 
-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 X1: usize = 42 || 39;
+//~^ ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected usize, found bool
+const ARR1: [i32; X1] = [99; 47];
 
-const X2: usize = -42 || -39; //~ ERROR E0080
-                              //~| unary negation of unsigned integer
-const ARR2: [i32; X2] = [99; 18446744073709551607]; //~ NOTE: for array length here
+const X2: usize = -42 || -39;
+//~^ ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected usize, found bool
+const ARR2: [i32; X2] = [99; 18446744073709551607];
 
-const X3: usize = -42 && -39; //~ ERROR E0080
-                              //~| unary negation of unsigned integer
-const ARR3: [i32; X3] = [99; 6]; //~ NOTE: for array length here
+const X3: usize = -42 && -39;
+//~^ ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected usize, found bool
+const ARR3: [i32; X3] = [99; 6];
 
 const Y: usize = 42.0 == 42.0;
+//~^ ERROR mismatched types
+//~| expected usize, found bool
 const ARRR: [i32; Y] = [99; 1];
-//~^ ERROR: expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
 
 const Y1: usize = 42.0 >= 42.0;
-const ARRR1: [i32; Y] = [99; 1];
-//~^ ERROR: expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
+//~^ ERROR mismatched types
+//~| expected usize, found bool
+const ARRR1: [i32; Y1] = [99; 1];
 
 const Y2: usize = 42.0 <= 42.0;
-const ARRR2: [i32; Y] = [99; 1];
-//~^ ERROR: expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
+//~^ ERROR mismatched types
+//~| expected usize, found bool
+const ARRR2: [i32; Y2] = [99; 1];
 
 const Y3: usize = 42.0 > 42.0;
-const ARRR3: [i32; Y] = [99; 0];
-//~^ ERROR: expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
+//~^ ERROR mismatched types
+//~| expected usize, found bool
+const ARRR3: [i32; Y3] = [99; 0];
 
 const Y4: usize = 42.0 < 42.0;
-const ARRR4: [i32; Y] = [99; 0];
-//~^ ERROR: expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
+//~^ ERROR mismatched types
+//~| expected usize, found bool
+const ARRR4: [i32; Y4] = [99; 0];
 
 const Y5: usize = 42.0 != 42.0;
-const ARRR5: [i32; Y] = [99; 0];
-//~^ ERROR: expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
-
+//~^ ERROR mismatched types
+//~| expected usize, found bool
+const ARRR5: [i32; Y5] = [99; 0];
 
 fn main() {
     let _ = ARR;
diff --git a/src/test/compile-fail/const-tup-index-span.rs b/src/test/compile-fail/const-tup-index-span.rs
index f3fb92e2b22..b42c440f87d 100644
--- a/src/test/compile-fail/const-tup-index-span.rs
+++ b/src/test/compile-fail/const-tup-index-span.rs
@@ -11,8 +11,8 @@
 // Test spans of errors
 
 const TUP: (usize,) = 5usize << 64;
-//~^ ERROR E0080
-//~| attempt to shift left with overflow
+//~^ ERROR mismatched types
+//~| expected tuple, found usize
 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 c73b7e831b3..62e54c3f237 100644
--- a/src/test/compile-fail/discrim-ill-typed.rs
+++ b/src/test/compile-fail/discrim-ill-typed.rs
@@ -25,7 +25,7 @@ fn f_i8() {
         Ok = i8::MAX - 1,
         Ok2,
         OhNo = 0_u8,
-        //~^ ERROR E0080
+        //~^ ERROR mismatched types
         //~| expected i8, found u8
     }
 
@@ -38,7 +38,7 @@ fn f_u8() {
         Ok = u8::MAX - 1,
         Ok2,
         OhNo = 0_i8,
-        //~^ ERROR E0080
+        //~^ ERROR mismatched types
         //~| expected u8, found i8
     }
 
@@ -51,7 +51,7 @@ fn f_i16() {
         Ok = i16::MAX - 1,
         Ok2,
         OhNo = 0_u16,
-        //~^ ERROR E0080
+        //~^ ERROR mismatched types
         //~| expected i16, found u16
     }
 
@@ -64,7 +64,7 @@ fn f_u16() {
         Ok = u16::MAX - 1,
         Ok2,
         OhNo = 0_i16,
-        //~^ ERROR E0080
+        //~^ ERROR mismatched types
         //~| expected u16, found i16
     }
 
@@ -77,7 +77,7 @@ fn f_i32() {
         Ok = i32::MAX - 1,
         Ok2,
         OhNo = 0_u32,
-        //~^ ERROR E0080
+        //~^ ERROR mismatched types
         //~| expected i32, found u32
     }
 
@@ -90,7 +90,7 @@ fn f_u32() {
         Ok = u32::MAX - 1,
         Ok2,
         OhNo = 0_i32,
-        //~^ ERROR E0080
+        //~^ ERROR mismatched types
         //~| expected u32, found i32
     }
 
@@ -103,7 +103,7 @@ fn f_i64() {
         Ok = i64::MAX - 1,
         Ok2,
         OhNo = 0_u64,
-        //~^ ERROR E0080
+        //~^ ERROR mismatched types
         //~| expected i64, found u64
     }
 
@@ -116,7 +116,7 @@ fn f_u64() {
         Ok = u64::MAX - 1,
         Ok2,
         OhNo = 0_i64,
-        //~^ ERROR E0080
+        //~^ ERROR mismatched types
         //~| expected u64, found i64
     }
 
diff --git a/src/test/compile-fail/enum-discrim-too-small.rs b/src/test/compile-fail/enum-discrim-too-small.rs
index bbdb3891d99..393a67be57f 100644
--- a/src/test/compile-fail/enum-discrim-too-small.rs
+++ b/src/test/compile-fail/enum-discrim-too-small.rs
@@ -13,32 +13,32 @@
 enum Eu8 {
     Au8 = 23,
     Bu8 = 223,
-    Cu8 = -23, //~ ERROR E0080
-               //~| unary negation of unsigned integer
+    Cu8 = -23,
+    //~^ ERROR cannot apply unary operator `-` to type `u8`
 }
 
 #[repr(u16)]
 enum Eu16 {
     Au16 = 23,
     Bu16 = 55555,
-    Cu16 = -22333, //~ ERROR E0080
-                   //~| unary negation of unsigned integer
+    Cu16 = -22333,
+    //~^ ERROR cannot apply unary operator `-` to type `u16`
 }
 
 #[repr(u32)]
 enum Eu32 {
     Au32 = 23,
     Bu32 = 3_000_000_000,
-    Cu32 = -2_000_000_000, //~ ERROR E0080
-                           //~| unary negation of unsigned integer
+    Cu32 = -2_000_000_000,
+    //~^ ERROR cannot apply unary operator `-` to type `u32`
 }
 
 #[repr(u64)]
 enum Eu64 {
     Au32 = 23,
     Bu32 = 3_000_000_000,
-    Cu32 = -2_000_000_000, //~ ERROR E0080
-                           //~| unary negation of unsigned integer
+    Cu32 = -2_000_000_000,
+    //~^ ERROR cannot apply unary operator `-` to type `u64`
 }
 
 // u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`.  This is a
diff --git a/src/test/compile-fail/invalid-path-in-const.rs b/src/test/compile-fail/invalid-path-in-const.rs
index 9a9358b787f..ab839e7630d 100644
--- a/src/test/compile-fail/invalid-path-in-const.rs
+++ b/src/test/compile-fail/invalid-path-in-const.rs
@@ -10,6 +10,5 @@
 
 fn main() {
     fn f(a: [u8; u32::DOESNOTEXIST]) {}
-    //~^ ERROR constant evaluation error
-    //~| unresolved path in constant expression
+    //~^ ERROR no associated item named `DOESNOTEXIST` found for type `u32`
 }
diff --git a/src/test/compile-fail/issue-22933-2.rs b/src/test/compile-fail/issue-22933-2.rs
index 54a24089354..c78e1f7f530 100644
--- a/src/test/compile-fail/issue-22933-2.rs
+++ b/src/test/compile-fail/issue-22933-2.rs
@@ -12,12 +12,10 @@ 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 no associated item named `PIE` found for type `Delicious`
 }
 
 const FOO: [u32; u8::MIN as usize] = [];
-//~^ ERROR constant evaluation error
-//~| unresolved path in constant expression
+//~^ ERROR no associated item named `MIN` found for type `u8`
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-23217.rs b/src/test/compile-fail/issue-23217.rs
index c2bcbb9d54a..95f6526f115 100644
--- a/src/test/compile-fail/issue-23217.rs
+++ b/src/test/compile-fail/issue-23217.rs
@@ -10,8 +10,7 @@
 
 pub enum SomeEnum {
     B = SomeEnum::A,
-    //~^ ERROR constant evaluation error
-    //~| unresolved path in constant expression
+    //~^ ERROR no associated item named `A` found for type `SomeEnum`
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-28586.rs b/src/test/compile-fail/issue-28586.rs
index 1dfd146985f..b8571d2e85e 100644
--- a/src/test/compile-fail/issue-28586.rs
+++ b/src/test/compile-fail/issue-28586.rs
@@ -11,6 +11,7 @@
 // Regression test for issue #28586
 
 pub trait Foo {}
-impl Foo for [u8; usize::BYTES] {} //~ ERROR E0080
+impl Foo for [u8; usize::BYTES] {}
+//~^ ERROR no associated item named `BYTES` found for type `usize`
 
 fn main() { }
diff --git a/src/test/compile-fail/issue-31910.rs b/src/test/compile-fail/issue-31910.rs
index 65fcd7df77e..aac8b89e882 100644
--- a/src/test/compile-fail/issue-31910.rs
+++ b/src/test/compile-fail/issue-31910.rs
@@ -11,7 +11,9 @@
 #![feature(associated_consts)]
 
 enum Enum<T: Trait> {
-    X = Trait::Number, //~ ERROR constant evaluation error
+    X = Trait::Number,
+    //~^ ERROR mismatched types
+    //~| expected isize, found i32
 }
 
 trait Trait {
diff --git a/src/test/compile-fail/issue-3521.rs b/src/test/compile-fail/issue-3521.rs
index e2acdcee3de..78af11a0b58 100644
--- a/src/test/compile-fail/issue-3521.rs
+++ b/src/test/compile-fail/issue-3521.rs
@@ -15,9 +15,7 @@ fn main() {
     enum Stuff {
         Bar = foo
         //~^ ERROR attempt to use a non-constant value in a constant
-        //~^^ ERROR constant evaluation error
-        //~| unresolved path in constant expression
     }
 
-    println!("{}", Stuff::Bar);
+    println!("{:?}", Stuff::Bar);
 }
diff --git a/src/test/compile-fail/issue-39559.rs b/src/test/compile-fail/issue-39559.rs
index a56a5e85489..bc492806b96 100644
--- a/src/test/compile-fail/issue-39559.rs
+++ b/src/test/compile-fail/issue-39559.rs
@@ -23,9 +23,13 @@ impl Dim for Dim3 {
 pub struct Vector<T, D: Dim> {
     entries: [T; D::dim()]
     //~^ ERROR cannot use an outer type parameter in this context
-    //~| ERROR constant evaluation error
 }
 
 fn main() {
-    let array: [usize; Dim3::dim()] = [0; Dim3::dim()];
+    let array: [usize; Dim3::dim()]
+    //~^ ERROR constant evaluation error
+    //~| non-constant path in constant expression
+        = [0; Dim3::dim()];
+        //~^ ERROR constant evaluation error
+        //~| non-constant path in constant expression
 }
diff --git a/src/test/compile-fail/issue-8761.rs b/src/test/compile-fail/issue-8761.rs
index 91a07dd9ba6..f8424ea64ef 100644
--- a/src/test/compile-fail/issue-8761.rs
+++ b/src/test/compile-fail/issue-8761.rs
@@ -10,10 +10,10 @@
 
 enum Foo {
     A = 1i64,
-    //~^ ERROR constant evaluation error
+    //~^ ERROR mismatched types
     //~| expected isize, found i64
     B = 2u8
-    //~^ ERROR constant evaluation error
+    //~^ ERROR mismatched types
     //~| expected isize, found u8
 }
 
diff --git a/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs b/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs
index 691d8d31b41..52cd4e8a3ed 100644
--- a/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs
+++ b/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs
@@ -14,6 +14,5 @@ fn main() {
     fn bar(n: isize) {
         let _x: [isize; n];
         //~^ ERROR attempt to use a non-constant value in a constant [E0435]
-        //~| ERROR constant evaluation error [E0080]
     }
 }
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 f4769a78587..1eda5087784 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
@@ -15,7 +15,5 @@ fn main() {
         let _x = [0; n];
         //~^ ERROR attempt to use a non-constant value in a constant [E0435]
         //~| NOTE non-constant used with constant
-        //~| NOTE unresolved path in constant expression
-        //~| ERROR constant evaluation error [E0080]
     }
 }
diff --git a/src/test/mir-opt/simplify_if.rs b/src/test/mir-opt/simplify_if.rs
index 0e8971269b0..6e80a917467 100644
--- a/src/test/mir-opt/simplify_if.rs
+++ b/src/test/mir-opt/simplify_if.rs
@@ -17,7 +17,7 @@ fn main() {
 // END RUST SOURCE
 // START rustc.node4.SimplifyBranches.initial-before.mir
 // bb0: {
-//     switchInt(const false) -> [0: bb2, otherwise: bb1];
+//     switchInt(const false) -> [0u8: bb2, otherwise: bb1];
 // }
 // END rustc.node4.SimplifyBranches.initial-before.mir
 // START rustc.node4.SimplifyBranches.initial-after.mir
diff --git a/src/test/compile-fail/issue-25145.rs b/src/test/run-pass/issue-25145.rs
index 93f75e9bfed..6f02f278381 100644
--- a/src/test/compile-fail/issue-25145.rs
+++ b/src/test/run-pass/issue-25145.rs
@@ -17,7 +17,7 @@ impl S {
 }
 
 static STUFF: [u8; S::N] = [0; S::N];
-//~^ ERROR constant evaluation error
-//~| unresolved path in constant expression
 
-fn main() {}
+fn main() {
+    assert_eq!(STUFF, [0; 3]);
+}
diff --git a/src/test/compile-fail/E0079.rs b/src/test/run-pass/issue-39548.rs
index c9b7f549d5a..7da50670d1d 100644
--- a/src/test/compile-fail/E0079.rs
+++ b/src/test/run-pass/issue-39548.rs
@@ -1,4 +1,4 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -8,10 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-enum Foo {
-    Q = "32" //~ ERROR E0079
-    //~^ expected 'isize' type
-}
+type Array = [(); ((1 < 2) == false) as usize];
 
 fn main() {
+    let _: Array = [];
 }
diff --git a/src/test/ui/resolve/levenshtein.stderr b/src/test/ui/resolve/levenshtein.stderr
index d01ffcb2839..c7c42bcf239 100644
--- a/src/test/ui/resolve/levenshtein.stderr
+++ b/src/test/ui/resolve/levenshtein.stderr
@@ -46,11 +46,5 @@ error[E0425]: cannot find value `second` in module `m`
 32 |     let b: m::first = m::second; // Misspelled item in module.
    |                       ^^^^^^^^^ did you mean `m::Second`?
 
-error[E0080]: constant evaluation error
-  --> $DIR/levenshtein.rs:30:20
-   |
-30 |     let v = [0u32; MAXITEM]; // Misspelled constant name.
-   |                    ^^^^^^^ unresolved path in constant expression
-
-error: aborting due to previous error
+error: aborting due to 8 previous errors