about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorOliver Scherer <github35764891676564198441@oli-obk.de>2018-12-11 19:56:59 +0100
committerOliver Scherer <github35764891676564198441@oli-obk.de>2019-01-01 20:05:02 +0100
commitb903cb9d6001bf6c199f15ffc0c61fdad802f328 (patch)
tree02ae3b3547307e44694660ed5780ea10d7e28100 /src
parentcae164753f557f668cb75610abda4f790981e5e6 (diff)
downloadrust-b903cb9d6001bf6c199f15ffc0c61fdad802f328.tar.gz
rust-b903cb9d6001bf6c199f15ffc0c61fdad802f328.zip
Move the `Unevaluated` constant arm upwards in the type structure
Diffstat (limited to 'src')
-rw-r--r--src/librustc/ich/impls_ty.rs6
-rw-r--r--src/librustc/mir/interpret/value.rs10
-rw-r--r--src/librustc/mir/mod.rs16
-rw-r--r--src/librustc/mir/tcx.rs2
-rw-r--r--src/librustc/mir/visit.rs4
-rw-r--r--src/librustc/traits/error_reporting.rs26
-rw-r--r--src/librustc/traits/project.rs12
-rw-r--r--src/librustc/traits/query/normalize.rs13
-rw-r--r--src/librustc/ty/codec.rs16
-rw-r--r--src/librustc/ty/context.rs25
-rw-r--r--src/librustc/ty/error.rs7
-rw-r--r--src/librustc/ty/flags.rs14
-rw-r--r--src/librustc/ty/fold.rs9
-rw-r--r--src/librustc/ty/inhabitedness/mod.rs15
-rw-r--r--src/librustc/ty/layout.rs2
-rw-r--r--src/librustc/ty/mod.rs2
-rw-r--r--src/librustc/ty/relate.rs22
-rw-r--r--src/librustc/ty/structural_impls.rs38
-rw-r--r--src/librustc/ty/sty.rs45
-rw-r--r--src/librustc/ty/walk.rs12
-rw-r--r--src/librustc/ty/wf.rs11
-rw-r--r--src/librustc/util/ppaux.rs9
-rw-r--r--src/librustc_codegen_llvm/debuginfo/metadata.rs2
-rw-r--r--src/librustc_codegen_llvm/debuginfo/type_names.rs2
-rw-r--r--src/librustc_codegen_ssa/base.rs2
-rw-r--r--src/librustc_codegen_ssa/mir/constant.rs12
-rw-r--r--src/librustc_codegen_ssa/mir/operand.rs1
-rw-r--r--src/librustc_codegen_ssa/mir/rvalue.rs2
-rw-r--r--src/librustc_mir/borrow_check/error_reporting.rs5
-rw-r--r--src/librustc_mir/borrow_check/mutability_errors.rs4
-rw-r--r--src/librustc_mir/borrow_check/nll/renumber.rs2
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs15
-rw-r--r--src/librustc_mir/borrow_check/places_conflict.rs2
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs12
-rw-r--r--src/librustc_mir/build/matches/test.rs1
-rw-r--r--src/librustc_mir/build/misc.rs2
-rw-r--r--src/librustc_mir/build/mod.rs2
-rw-r--r--src/librustc_mir/const_eval.rs12
-rw-r--r--src/librustc_mir/hair/cx/expr.rs39
-rw-r--r--src/librustc_mir/hair/cx/mod.rs12
-rw-r--r--src/librustc_mir/hair/mod.rs4
-rw-r--r--src/librustc_mir/hair/pattern/_match.rs38
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs4
-rw-r--r--src/librustc_mir/interpret/cast.rs2
-rw-r--r--src/librustc_mir/interpret/operand.rs19
-rw-r--r--src/librustc_mir/monomorphize/collector.rs75
-rw-r--r--src/librustc_mir/monomorphize/item.rs2
-rw-r--r--src/librustc_mir/shim.rs14
-rw-r--r--src/librustc_mir/transform/const_prop.rs2
-rw-r--r--src/librustc_mir/transform/elaborate_drops.rs4
-rw-r--r--src/librustc_mir/transform/erase_regions.rs2
-rw-r--r--src/librustc_mir/transform/generator.rs8
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs14
-rw-r--r--src/librustc_mir/transform/simplify_branches.rs25
-rw-r--r--src/librustc_mir/transform/uniform_array_move_out.rs4
-rw-r--r--src/librustc_mir/util/elaborate_drops.rs6
-rw-r--r--src/librustc_mir/util/pretty.rs19
-rw-r--r--src/librustc_traits/chalk_context/program_clauses.rs2
-rw-r--r--src/librustc_typeck/astconv.rs3
-rw-r--r--src/librustc_typeck/check/_match.rs2
-rw-r--r--src/librustc_typeck/check/mod.rs4
-rw-r--r--src/librustdoc/clean/mod.rs23
62 files changed, 405 insertions, 316 deletions
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index b2fe4b7561c..57a53d3f09a 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -301,7 +301,6 @@ impl_stable_hash_for!(struct ty::FieldDef {
 
 impl_stable_hash_for!(
     impl<'tcx> for enum mir::interpret::ConstValue<'tcx> [ mir::interpret::ConstValue ] {
-        Unevaluated(def_id, substs),
         Scalar(val),
         ScalarPair(a, b),
         ByRef(id, alloc, offset),
@@ -378,6 +377,11 @@ impl_stable_hash_for!(struct ty::Const<'tcx> {
     val
 });
 
+impl_stable_hash_for!(impl<'tcx> for enum ty::LazyConst<'tcx> [ty::LazyConst] {
+    Unevaluated(did, substs),
+    Evaluated(c)
+});
+
 impl_stable_hash_for!(enum mir::interpret::ErrorHandled {
     Reported,
     TooGeneric
diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs
index 1e4cfedc2a6..26a8e632540 100644
--- a/src/librustc/mir/interpret/value.rs
+++ b/src/librustc/mir/interpret/value.rs
@@ -1,7 +1,6 @@
 use std::fmt;
 
-use crate::ty::{Ty, subst::Substs, layout::{HasDataLayout, Size}};
-use crate::hir::def_id::DefId;
+use crate::ty::{Ty, layout::{HasDataLayout, Size}};
 
 use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend, truncate};
 
@@ -18,12 +17,6 @@ pub struct RawConst<'tcx> {
 /// matches the LocalValue optimizations for easy conversions between Value and ConstValue.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
 pub enum ConstValue<'tcx> {
-    /// Never returned from the `const_eval` query, but the HIR contains these frequently in order
-    /// to allow HIR creation to happen for everything before needing to be able to run constant
-    /// evaluation
-    /// FIXME: The query should then return a type that does not even have this variant.
-    Unevaluated(DefId, &'tcx Substs<'tcx>),
-
     /// Used only for types with layout::abi::Scalar ABI and ZSTs
     ///
     /// Not using the enum `Value` to encode that this must not be `Undef`
@@ -43,7 +36,6 @@ impl<'tcx> ConstValue<'tcx> {
     #[inline]
     pub fn try_to_scalar(&self) -> Option<Scalar> {
         match *self {
-            ConstValue::Unevaluated(..) |
             ConstValue::ByRef(..) |
             ConstValue::ScalarPair(..) => None,
             ConstValue::Scalar(val) => Some(val),
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 2936405ebd0..eafae6d9c9e 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -2154,7 +2154,9 @@ impl<'tcx> Operand<'tcx> {
             span,
             ty,
             user_ty: None,
-            literal: ty::Const::zero_sized(tcx, ty),
+            literal: tcx.intern_lazy_const(
+                ty::LazyConst::Evaluated(ty::Const::zero_sized(tcx, ty)),
+            ),
         })
     }
 
@@ -2457,7 +2459,7 @@ pub struct Constant<'tcx> {
     /// Needed for NLL to impose user-given type constraints.
     pub user_ty: Option<UserTypeAnnotationIndex>,
 
-    pub literal: &'tcx ty::Const<'tcx>,
+    pub literal: &'tcx ty::LazyConst<'tcx>,
 }
 
 /// A collection of projections into user types.
@@ -2655,7 +2657,15 @@ newtype_index! {
 impl<'tcx> Debug for Constant<'tcx> {
     fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
         write!(fmt, "const ")?;
-        fmt_const_val(fmt, self.literal)
+        fmt_lazy_const_val(fmt, self.literal)
+    }
+}
+
+/// Write a `ConstValue` in a way closer to the original source code than the `Debug` output.
+pub fn fmt_lazy_const_val(f: &mut impl Write, const_val: &ty::LazyConst<'_>) -> fmt::Result {
+    match const_val {
+        ty::LazyConst::Unevaluated(..) => write!(f, "{:?}", const_val),
+        ty::LazyConst::Evaluated(c) => fmt_const_val(f, c),
     }
 }
 
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index c5b884525da..6dda1933bba 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -114,7 +114,7 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
                 PlaceTy::Ty {
                     ty: match ty.sty {
                         ty::Array(inner, size) => {
-                            let size = size.unwrap_usize(tcx);
+                            let size = size.unwrap_evaluated().unwrap_usize(tcx);
                             let len = size - (from as u64) - (to as u64);
                             tcx.mk_array(inner, len)
                         }
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 67f85fbc867..a0fae3aa927 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -233,7 +233,7 @@ macro_rules! make_mir_visitor {
             }
 
             fn visit_const(&mut self,
-                           constant: & $($mutability)* &'tcx ty::Const<'tcx>,
+                           constant: & $($mutability)* &'tcx ty::LazyConst<'tcx>,
                            _: Location) {
                 self.super_const(constant);
             }
@@ -892,7 +892,7 @@ macro_rules! make_mir_visitor {
             fn super_region(&mut self, _region: & $($mutability)* ty::Region<'tcx>) {
             }
 
-            fn super_const(&mut self, _const: & $($mutability)* &'tcx ty::Const<'tcx>) {
+            fn super_const(&mut self, _const: & $($mutability)* &'tcx ty::LazyConst<'tcx>) {
             }
 
             fn super_substs(&mut self, _substs: & $($mutability)* &'tcx Substs<'tcx>) {
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 0e63ef666c7..f66dcb8dffd 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -418,18 +418,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                     Some(format!("[{}]", self.tcx.type_of(def.did).to_string())),
                 ));
                 let tcx = self.tcx;
-                if let Some(len) = len.val.try_to_scalar().and_then(|scalar| {
-                    scalar.to_usize(&tcx).ok()
-                }) {
-                    flags.push((
-                        "_Self".to_owned(),
-                        Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)),
-                    ));
-                } else {
-                    flags.push((
-                        "_Self".to_owned(),
-                        Some(format!("[{}; _]", self.tcx.type_of(def.did).to_string())),
-                    ));
+                if let ty::LazyConst::Evaluated(len) = len {
+                    if let Some(len) = len.val.try_to_scalar().and_then(|scalar| {
+                        scalar.to_usize(&tcx).ok()
+                    }) {
+                        flags.push((
+                            "_Self".to_owned(),
+                            Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)),
+                        ));
+                    } else {
+                        flags.push((
+                            "_Self".to_owned(),
+                            Some(format!("[{}; _]", self.tcx.type_of(def.did).to_string())),
+                        ));
+                    }
                 }
             }
         }
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index 952b37b89f2..87e9c3b2c88 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -15,7 +15,6 @@ use super::util;
 use hir::def_id::DefId;
 use infer::{InferCtxt, InferOk};
 use infer::type_variable::TypeVariableOrigin;
-use mir::interpret::ConstValue;
 use mir::interpret::{GlobalId};
 use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
 use syntax::ast::Ident;
@@ -410,8 +409,8 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a,
         }
     }
 
-    fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
-        if let ConstValue::Unevaluated(def_id, substs) = constant.val {
+    fn fold_const(&mut self, constant: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> {
+        if let ty::LazyConst::Unevaluated(def_id, substs) = *constant {
             let tcx = self.selcx.tcx().global_tcx();
             if let Some(param_env) = self.tcx().lift_to_global(&self.param_env) {
                 if substs.needs_infer() || substs.has_placeholders() {
@@ -423,8 +422,9 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a,
                             promoted: None
                         };
                         if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) {
-                            let evaluated = evaluated.subst(self.tcx(), substs);
-                            return self.fold_const(evaluated);
+                            let substs = tcx.lift_to_global(&substs).unwrap();
+                            let evaluated = evaluated.subst(tcx, substs);
+                            return tcx.intern_lazy_const(ty::LazyConst::Evaluated(evaluated));
                         }
                     }
                 } else {
@@ -436,7 +436,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a,
                                 promoted: None
                             };
                             if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) {
-                                return self.fold_const(evaluated)
+                                return tcx.intern_lazy_const(ty::LazyConst::Evaluated(evaluated));
                             }
                         }
                     }
diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs
index 0d126d37546..be05445cfc6 100644
--- a/src/librustc/traits/query/normalize.rs
+++ b/src/librustc/traits/query/normalize.rs
@@ -5,7 +5,7 @@
 use infer::at::At;
 use infer::canonical::OriginalQueryValues;
 use infer::{InferCtxt, InferOk};
-use mir::interpret::{ConstValue, GlobalId};
+use mir::interpret::GlobalId;
 use traits::project::Normalized;
 use traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
 use ty::fold::{TypeFoldable, TypeFolder};
@@ -188,8 +188,8 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx
         }
     }
 
-    fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
-        if let ConstValue::Unevaluated(def_id, substs) = constant.val {
+    fn fold_const(&mut self, constant: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> {
+        if let ty::LazyConst::Unevaluated(def_id, substs) = *constant {
             let tcx = self.infcx.tcx.global_tcx();
             if let Some(param_env) = self.tcx().lift_to_global(&self.param_env) {
                 if substs.needs_infer() || substs.has_placeholders() {
@@ -201,8 +201,9 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx
                             promoted: None,
                         };
                         if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) {
-                            let evaluated = evaluated.subst(self.tcx(), substs);
-                            return self.fold_const(evaluated);
+                            let substs = tcx.lift_to_global(&substs).unwrap();
+                            let evaluated = evaluated.subst(tcx, substs);
+                            return tcx.intern_lazy_const(ty::LazyConst::Evaluated(evaluated));
                         }
                     }
                 } else {
@@ -214,7 +215,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx
                                 promoted: None,
                             };
                             if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) {
-                                return self.fold_const(evaluated)
+                                return tcx.intern_lazy_const(ty::LazyConst::Evaluated(evaluated));
                             }
                         }
                     }
diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs
index 6429e3249c4..57b99db0c7d 100644
--- a/src/librustc/ty/codec.rs
+++ b/src/librustc/ty/codec.rs
@@ -256,6 +256,15 @@ pub fn decode_const<'a, 'tcx, D>(decoder: &mut D)
 }
 
 #[inline]
+pub fn decode_lazy_const<'a, 'tcx, D>(decoder: &mut D)
+                                 -> Result<&'tcx ty::LazyConst<'tcx>, D::Error>
+    where D: TyDecoder<'a, 'tcx>,
+          'tcx: 'a,
+{
+    Ok(decoder.tcx().intern_lazy_const(Decodable::decode(decoder)?))
+}
+
+#[inline]
 pub fn decode_allocation<'a, 'tcx, D>(decoder: &mut D)
     -> Result<&'tcx Allocation, D::Error>
     where D: TyDecoder<'a, 'tcx>,
@@ -396,6 +405,13 @@ macro_rules! implement_ty_decoder {
                 }
             }
 
+            impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::ty::LazyConst<'tcx>>
+            for $DecoderName<$($typaram),*> {
+                fn specialized_decode(&mut self) -> Result<&'tcx ty::LazyConst<'tcx>, Self::Error> {
+                    decode_lazy_const(self)
+                }
+            }
+
             impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::mir::interpret::Allocation>
             for $DecoderName<$($typaram),*> {
                 fn specialized_decode(
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 32348e2e504..715e7367fad 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -29,7 +29,7 @@ use traits;
 use traits::{Clause, Clauses, GoalKind, Goal, Goals};
 use ty::{self, Ty, TypeAndMut};
 use ty::{TyS, TyKind, List};
-use ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorSubsts, Region, Const};
+use ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorSubsts, Region, Const, LazyConst};
 use ty::{PolyFnSig, InferTy, ParamTy, ProjectionTy, ExistentialPredicate, Predicate};
 use ty::RegionKind;
 use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
@@ -1112,6 +1112,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         })
     }
 
+    pub fn intern_lazy_const(self, c: ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> {
+        self.global_interners.arena.alloc(c)
+    }
+
     pub fn intern_layout(self, layout: LayoutDetails) -> &'gcx LayoutDetails {
         self.layout_interner.borrow_mut().intern(layout, |layout| {
             self.global_arenas.layout.alloc(layout)
@@ -1814,6 +1818,21 @@ impl<'a, 'tcx> Lift<'tcx> for &'a List<Clause<'a>> {
     }
 }
 
+impl<'a, 'tcx> Lift<'tcx> for &'a LazyConst<'a> {
+    type Lifted = &'tcx LazyConst<'tcx>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx LazyConst<'tcx>> {
+        if tcx.interners.arena.in_arena(*self as *const _) {
+            return Some(unsafe { mem::transmute(*self) });
+        }
+        // Also try in the global tcx if we're not that.
+        if !tcx.is_global() {
+            self.lift_to_tcx(tcx.global_tcx())
+        } else {
+            None
+        }
+    }
+}
+
 impl<'a, 'tcx> Lift<'tcx> for &'a Const<'a> {
     type Lifted = &'tcx Const<'tcx>;
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Const<'tcx>> {
@@ -2683,7 +2702,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
     #[inline]
     pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> {
-        self.mk_ty(Array(ty, ty::Const::from_usize(self, n)))
+        self.mk_ty(Array(ty, self.intern_lazy_const(
+            ty::LazyConst::Evaluated(ty::Const::from_usize(self.global_tcx(), n))
+        )))
     }
 
     #[inline]
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index c491fdd9957..67ff21e2a52 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -167,11 +167,12 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
 
             ty::Adt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)).into(),
             ty::Foreign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)).into(),
-            ty::Array(_, n) => {
-                match n.assert_usize(tcx) {
+            ty::Array(_, n) => match n {
+                ty::LazyConst::Evaluated(n) => match n.assert_usize(tcx) {
                     Some(n) => format!("array of {} elements", n).into(),
                     None => "array".into(),
-                }
+                },
+                ty::LazyConst::Unevaluated(..) => "array".into(),
             }
             ty::Slice(_) => "slice".into(),
             ty::RawPtr(_) => "*-ptr".into(),
diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs
index 6ee24187e33..4fa13a01d5a 100644
--- a/src/librustc/ty/flags.rs
+++ b/src/librustc/ty/flags.rs
@@ -1,4 +1,3 @@
-use mir::interpret::ConstValue;
 use ty::subst::Substs;
 use ty::{self, Ty, TypeFlags, TypeFoldable};
 
@@ -173,7 +172,10 @@ impl FlagComputation {
 
             &ty::Array(tt, len) => {
                 self.add_ty(tt);
-                self.add_const(len);
+                if let ty::LazyConst::Unevaluated(_, substs) = len {
+                    self.add_flags(TypeFlags::HAS_PROJECTION);
+                    self.add_substs(substs);
+                }
             }
 
             &ty::Slice(tt) => {
@@ -230,14 +232,6 @@ impl FlagComputation {
         }
     }
 
-    fn add_const(&mut self, constant: &ty::Const<'_>) {
-        self.add_ty(constant.ty);
-        if let ConstValue::Unevaluated(_, substs) = constant.val {
-            self.add_flags(TypeFlags::HAS_PROJECTION);
-            self.add_substs(substs);
-        }
-    }
-
     fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
         self.add_substs(projection.substs);
         self.add_ty(projection.ty);
diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs
index 0a72f733b51..4495e9654c9 100644
--- a/src/librustc/ty/fold.rs
+++ b/src/librustc/ty/fold.rs
@@ -29,7 +29,6 @@
 //! These methods return true to indicate that the visitor has found what it is looking for
 //! and does not need to visit anything else.
 
-use mir::interpret::ConstValue;
 use hir::def_id::DefId;
 use ty::{self, Binder, Ty, TyCtxt, TypeFlags};
 
@@ -164,7 +163,7 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized {
         r.super_fold_with(self)
     }
 
-    fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+    fn fold_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> {
         c.super_fold_with(self)
     }
 }
@@ -182,7 +181,7 @@ pub trait TypeVisitor<'tcx> : Sized {
         r.super_visit_with(self)
     }
 
-    fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
+    fn visit_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> bool {
         c.super_visit_with(self)
     }
 }
@@ -864,8 +863,8 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
         flags.intersects(self.flags)
     }
 
-    fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
-        if let ConstValue::Unevaluated(..) = c.val {
+    fn visit_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> bool {
+        if let ty::LazyConst::Unevaluated(..) = c {
             let projection_flags = TypeFlags::HAS_NORMALIZABLE_PROJECTION |
                 TypeFlags::HAS_PROJECTION;
             if projection_flags.intersects(self.flags) {
diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs
index 29d201c1179..6dfc9681cfd 100644
--- a/src/librustc/ty/inhabitedness/mod.rs
+++ b/src/librustc/ty/inhabitedness/mod.rs
@@ -1,6 +1,6 @@
 use ty::context::TyCtxt;
 use ty::{AdtDef, VariantDef, FieldDef, Ty, TyS};
-use ty::{DefId, Substs};
+use ty::{self, DefId, Substs};
 use ty::{AdtKind, Visibility};
 use ty::TyKind::*;
 
@@ -213,11 +213,14 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
             }
 
             Array(ty, len) => {
-                match len.assert_usize(tcx) {
-                    // If the array is definitely non-empty, it's uninhabited if
-                    // the type of its elements is uninhabited.
-                    Some(n) if n != 0 => ty.uninhabited_from(tcx),
-                    _ => DefIdForest::empty()
+                match len {
+                    ty::LazyConst::Unevaluated(..) => DefIdForest::empty(),
+                    ty::LazyConst::Evaluated(len) => match len.assert_usize(tcx) {
+                        // If the array is definitely non-empty, it's uninhabited if
+                        // the type of its elements is uninhabited.
+                        Some(n) if n != 0 => ty.uninhabited_from(tcx),
+                        _ => DefIdForest::empty()
+                    },
                 }
             }
 
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 171c53b7b20..1f25925a8e1 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -543,7 +543,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
                 }
 
                 let element = self.layout_of(element)?;
-                let count = count.unwrap_usize(tcx);
+                let count = count.unwrap_evaluated().unwrap_usize(tcx);
                 let size = element.size.checked_mul(count, dl)
                     .ok_or(LayoutError::SizeOverflow(ty))?;
 
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index d40dd830e9f..20167bd41fb 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -59,7 +59,7 @@ pub use self::sty::{InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
 pub use self::sty::{ClosureSubsts, GeneratorSubsts, UpvarSubsts, TypeAndMut};
 pub use self::sty::{TraitRef, TyKind, PolyTraitRef};
 pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef};
-pub use self::sty::{ExistentialProjection, PolyExistentialProjection, Const};
+pub use self::sty::{ExistentialProjection, PolyExistentialProjection, Const, LazyConst};
 pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region};
 pub use self::sty::RegionKind;
 pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid};
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index 84e15a75135..6d310a9500a 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -5,7 +5,6 @@
 //! subtyping, type equality, etc.
 
 use hir::def_id::DefId;
-use mir::interpret::ConstValue;
 use ty::subst::{Kind, UnpackedKind, Substs};
 use ty::{self, Ty, TyCtxt, TypeFoldable};
 use ty::error::{ExpectedFound, TypeError};
@@ -480,14 +479,9 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
         (&ty::Array(a_t, sz_a), &ty::Array(b_t, sz_b)) =>
         {
             let t = relation.relate(&a_t, &b_t)?;
-            assert_eq!(sz_a.ty, tcx.types.usize);
-            assert_eq!(sz_b.ty, tcx.types.usize);
-            let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result<u64, ErrorReported> {
-                if let Some(s) = x.assert_usize(tcx) {
-                    return Ok(s);
-                }
-                match x.val {
-                    ConstValue::Unevaluated(def_id, substs) => {
+            let to_u64 = |x: ty::LazyConst<'tcx>| -> Result<u64, ErrorReported> {
+                match x {
+                    ty::LazyConst::Unevaluated(def_id, substs) => {
                         // FIXME(eddyb) get the right param_env.
                         let param_env = ty::ParamEnv::empty();
                         if let Some(substs) = tcx.lift_to_global(&substs) {
@@ -513,14 +507,14 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
                             "array length could not be evaluated");
                         Err(ErrorReported)
                     }
-                    _ => {
+                    ty::LazyConst::Evaluated(c) => c.assert_usize(tcx).ok_or_else(|| {
                         tcx.sess.delay_span_bug(DUMMY_SP,
-                            &format!("arrays should not have {:?} as length", x));
-                        Err(ErrorReported)
-                    }
+                            "array length could not be evaluated");
+                        ErrorReported
+                    })
                 }
             };
-            match (to_u64(sz_a), to_u64(sz_b)) {
+            match (to_u64(*sz_a), to_u64(*sz_b)) {
                 (Ok(sz_a_u64), Ok(sz_b_u64)) => {
                     if sz_a_u64 == sz_b_u64 {
                         Ok(tcx.mk_ty(ty::Array(t, sz_a)))
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 4755adc4cd1..28184725b1c 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -53,6 +53,7 @@ CloneTypeFoldableAndLiftImpls! {
     ::ty::UniverseIndex,
     ::ty::Variance,
     ::syntax_pos::Span,
+    ConstValue<'tcx>,
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -1020,26 +1021,31 @@ EnumTypeFoldableImpl! {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> {
+impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::LazyConst<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        match *self {
-            ConstValue::Scalar(v) => ConstValue::Scalar(v),
-            ConstValue::ScalarPair(a, b) => ConstValue::ScalarPair(a, b),
-            ConstValue::ByRef(id, alloc, offset) => ConstValue::ByRef(id, alloc, offset),
-            ConstValue::Unevaluated(def_id, substs) => {
-                ConstValue::Unevaluated(def_id, substs.fold_with(folder))
+        let new = match self {
+            ty::LazyConst::Evaluated(v) => ty::LazyConst::Evaluated(v.fold_with(folder)),
+            ty::LazyConst::Unevaluated(def_id, substs) => {
+                ty::LazyConst::Unevaluated(*def_id, substs.fold_with(folder))
             }
-        }
+        };
+        folder.tcx().intern_lazy_const(new)
+    }
+
+    fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        folder.fold_const(*self)
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
         match *self {
-            ConstValue::Scalar(_) |
-            ConstValue::ScalarPair(_, _) |
-            ConstValue::ByRef(_, _, _) => false,
-            ConstValue::Unevaluated(_, substs) => substs.visit_with(visitor),
+            ty::LazyConst::Evaluated(c) => c.visit_with(visitor),
+            ty::LazyConst::Unevaluated(_, substs) => substs.visit_with(visitor),
         }
     }
+
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        visitor.visit_const(self)
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> {
@@ -1052,15 +1058,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> {
         })
     }
 
-    fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        folder.fold_const(*self)
-    }
-
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
         self.ty.visit_with(visitor) || self.val.visit_with(visitor)
     }
-
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        visitor.visit_const(self)
-    }
 }
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index f7adb83f8eb..ba380dfc7c8 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -113,7 +113,7 @@ pub enum TyKind<'tcx> {
     Str,
 
     /// An array with the given length. Written as `[T; n]`.
-    Array(Ty<'tcx>, &'tcx ty::Const<'tcx>),
+    Array(Ty<'tcx>, &'tcx ty::LazyConst<'tcx>),
 
     /// The pointee of an array slice.  Written as `[T]`.
     Slice(Ty<'tcx>),
@@ -2013,6 +2013,36 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
     }
 }
 
+#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq, Ord, PartialOrd)]
+/// Used in the HIR by using `Unevaluated` everywhere and later normalizing to `Evaluated` if the
+/// code is monomorphic enough for that.
+pub enum LazyConst<'tcx> {
+    Unevaluated(DefId, &'tcx Substs<'tcx>),
+    Evaluated(&'tcx Const<'tcx>),
+}
+
+static_assert!(MEM_SIZE_OF_LAZY_CONST: ::std::mem::size_of::<LazyConst<'_>>() == 24);
+
+impl<'tcx> LazyConst<'tcx> {
+    pub fn unwrap_evaluated(self) -> &'tcx Const<'tcx> {
+        match self {
+            LazyConst::Evaluated(c) => c,
+            LazyConst::Unevaluated(..) => bug!("unexpected unevaluated constant"),
+        }
+    }
+
+    pub fn map_evaluated<R>(self, f: impl FnOnce(&'tcx Const<'tcx>) -> Option<R>) -> Option<R> {
+        match self {
+            LazyConst::Evaluated(c) => f(c),
+            LazyConst::Unevaluated(..) => None,
+        }
+    }
+
+    pub fn assert_usize(self, tcx: TyCtxt<'_, '_, 'tcx>) -> Option<u64> {
+        self.map_evaluated(|c| c.assert_usize(tcx))
+    }
+}
+
 /// Typed constant value.
 #[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq, Ord, PartialOrd)]
 pub struct Const<'tcx> {
@@ -2022,18 +2052,6 @@ pub struct Const<'tcx> {
 }
 
 impl<'tcx> Const<'tcx> {
-    pub fn unevaluated(
-        tcx: TyCtxt<'_, '_, 'tcx>,
-        def_id: DefId,
-        substs: &'tcx Substs<'tcx>,
-        ty: Ty<'tcx>,
-    ) -> &'tcx Self {
-        tcx.mk_const(Const {
-            val: ConstValue::Unevaluated(def_id, substs),
-            ty,
-        })
-    }
-
     #[inline]
     pub fn from_const_value(
         tcx: TyCtxt<'_, '_, 'tcx>,
@@ -2149,3 +2167,4 @@ impl<'tcx> Const<'tcx> {
 }
 
 impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Const<'tcx> {}
+impl<'tcx> serialize::UseSpecializedDecodable for &'tcx LazyConst<'tcx> {}
diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs
index a2cc859e4a8..6887d092fcd 100644
--- a/src/librustc/ty/walk.rs
+++ b/src/librustc/ty/walk.rs
@@ -1,7 +1,6 @@
 //! An iterator over the type substructure.
 //! WARNING: this does not keep track of the region depth.
 
-use mir::interpret::ConstValue;
 use ty::{self, Ty};
 use smallvec::{self, SmallVec};
 
@@ -75,7 +74,9 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
         ty::Placeholder(..) | ty::Bound(..) | ty::Foreign(..) => {
         }
         ty::Array(ty, len) => {
-            push_const(stack, len);
+            if let ty::LazyConst::Unevaluated(_, substs) = len {
+                stack.extend(substs.types().rev());
+            }
             stack.push(ty);
         }
         ty::Slice(ty) => {
@@ -128,10 +129,3 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
         }
     }
 }
-
-fn push_const<'tcx>(stack: &mut TypeWalkerStack<'tcx>, constant: &'tcx ty::Const<'tcx>) {
-    if let ConstValue::Unevaluated(_, substs) = constant.val {
-        stack.extend(substs.types().rev());
-    }
-    stack.push(constant.ty);
-}
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index aacc63c47de..517cfd9edfa 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -1,5 +1,4 @@
 use hir::def_id::DefId;
-use mir::interpret::ConstValue;
 use infer::InferCtxt;
 use ty::subst::Substs;
 use traits;
@@ -202,11 +201,10 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
         }
     }
 
-    /// Pushes the obligations required for a constant value to be WF
+    /// Pushes the obligations required for an array length to be WF
     /// into `self.out`.
-    fn compute_const(&mut self, constant: &'tcx ty::Const<'tcx>) {
-        self.require_sized(constant.ty, traits::ConstSized);
-        if let ConstValue::Unevaluated(def_id, substs) = constant.val {
+    fn compute_array_len(&mut self, constant: ty::LazyConst<'tcx>) {
+        if let ty::LazyConst::Unevaluated(def_id, substs) = constant {
             let obligations = self.nominal_obligations(def_id, substs);
             self.out.extend(obligations);
 
@@ -260,8 +258,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
 
                 ty::Array(subty, len) => {
                     self.require_sized(subty, traits::SliceOrArrayElem);
-                    assert_eq!(len.ty, self.infcx.tcx.types.usize);
-                    self.compute_const(len);
+                    self.compute_array_len(*len);
                 }
 
                 ty::Tuple(ref tys) => {
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 318d7adb190..1356fbb6489 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -1,6 +1,5 @@
 use hir::def_id::DefId;
 use hir::map::definitions::DefPathData;
-use mir::interpret::ConstValue;
 use middle::region;
 use ty::subst::{self, Subst};
 use ty::{BrAnon, BrEnv, BrFresh, BrNamed};
@@ -1272,12 +1271,12 @@ define_print! {
                 }),
                 Array(ty, sz) => {
                     print!(f, cx, write("["), print(ty), write("; "))?;
-                    match sz.val {
-                        ConstValue::Unevaluated(_def_id, _substs) => {
+                    match sz {
+                        ty::LazyConst::Unevaluated(_def_id, _substs) => {
                             write!(f, "_")?;
                         }
-                        _ => ty::tls::with(|tcx| {
-                            write!(f, "{}", sz.unwrap_usize(tcx))
+                        ty::LazyConst::Evaluated(c) => ty::tls::with(|tcx| {
+                            write!(f, "{}", c.unwrap_usize(tcx))
                         })?,
                     }
                     write!(f, "]")
diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs
index 0fd04e9d203..bec0cfa0d86 100644
--- a/src/librustc_codegen_llvm/debuginfo/metadata.rs
+++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs
@@ -302,7 +302,7 @@ fn fixed_vec_metadata(
 
     let upper_bound = match array_or_slice_type.sty {
         ty::Array(_, len) => {
-            len.unwrap_usize(cx.tcx) as c_longlong
+            len.unwrap_evaluated().unwrap_usize(cx.tcx) as c_longlong
         }
         _ => -1
     };
diff --git a/src/librustc_codegen_llvm/debuginfo/type_names.rs b/src/librustc_codegen_llvm/debuginfo/type_names.rs
index c8cbd735e85..c1309569c79 100644
--- a/src/librustc_codegen_llvm/debuginfo/type_names.rs
+++ b/src/librustc_codegen_llvm/debuginfo/type_names.rs
@@ -88,7 +88,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
         ty::Array(inner_type, len) => {
             output.push('[');
             push_debuginfo_type_name(cx, inner_type, true, output);
-            output.push_str(&format!("; {}", len.unwrap_usize(cx.tcx)));
+            output.push_str(&format!("; {}", len.unwrap_evaluated().unwrap_usize(cx.tcx)));
             output.push(']');
         },
         ty::Slice(inner_type) => {
diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs
index b88ec075653..166655f6a80 100644
--- a/src/librustc_codegen_ssa/base.rs
+++ b/src/librustc_codegen_ssa/base.rs
@@ -171,7 +171,7 @@ pub fn unsized_info<'tcx, Cx: CodegenMethods<'tcx>>(
     let (source, target) = cx.tcx().struct_lockstep_tails(source, target);
     match (&source.sty, &target.sty) {
         (&ty::Array(_, len), &ty::Slice(_)) => {
-            cx.const_usize(len.unwrap_usize(cx.tcx()))
+            cx.const_usize(len.unwrap_evaluated().unwrap_usize(cx.tcx()))
         }
         (&ty::Dynamic(..), &ty::Dynamic(..)) => {
             // For now, upcasts are limited to changes in marker
diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs
index 1a48ad87a6e..58325e34432 100644
--- a/src/librustc_codegen_ssa/mir/constant.rs
+++ b/src/librustc_codegen_ssa/mir/constant.rs
@@ -2,7 +2,7 @@ use rustc::mir::interpret::ErrorHandled;
 use rustc_mir::const_eval::const_field;
 use rustc::mir;
 use rustc_data_structures::indexed_vec::Idx;
-use rustc::mir::interpret::{GlobalId, ConstValue};
+use rustc::mir::interpret::GlobalId;
 use rustc::ty::{self, Ty};
 use rustc::ty::layout;
 use syntax::source_map::Span;
@@ -14,10 +14,10 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     fn fully_evaluate(
         &mut self,
         bx: &Bx,
-        constant: &'tcx ty::Const<'tcx>,
+        constant: &'tcx ty::LazyConst<'tcx>,
     ) -> Result<&'tcx ty::Const<'tcx>, ErrorHandled> {
-        match constant.val {
-            ConstValue::Unevaluated(def_id, ref substs) => {
+        match *constant {
+            ty::LazyConst::Unevaluated(def_id, ref substs) => {
                 let tcx = bx.tcx();
                 let param_env = ty::ParamEnv::reveal_all();
                 let instance = ty::Instance::resolve(tcx, param_env, def_id, substs).unwrap();
@@ -27,7 +27,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 };
                 tcx.const_eval(param_env.and(cid))
             },
-            _ => Ok(constant),
+            ty::LazyConst::Evaluated(constant) => Ok(constant),
         }
     }
 
@@ -52,7 +52,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             .and_then(|c| {
                 let field_ty = c.ty.builtin_index().unwrap();
                 let fields = match c.ty.sty {
-                    ty::Array(_, n) => n.unwrap_usize(bx.tcx()),
+                    ty::Array(_, n) => n.unwrap_evaluated().unwrap_usize(bx.tcx()),
                     ref other => bug!("invalid simd shuffle type: {}", other),
                 };
                 let values: Result<Vec<_>, ErrorHandled> = (0..fields).map(|field| {
diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs
index 1dbed30842a..bb55bf3b46c 100644
--- a/src/librustc_codegen_ssa/mir/operand.rs
+++ b/src/librustc_codegen_ssa/mir/operand.rs
@@ -76,7 +76,6 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> {
         }
 
         let val = match val.val {
-            ConstValue::Unevaluated(..) => bug!(),
             ConstValue::Scalar(x) => {
                 let scalar = match layout.abi {
                     layout::Abi::Scalar(ref x) => x,
diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs
index 9ca5414fa71..404ee86c6a1 100644
--- a/src/librustc_codegen_ssa/mir/rvalue.rs
+++ b/src/librustc_codegen_ssa/mir/rvalue.rs
@@ -537,7 +537,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         if let mir::Place::Local(index) = *place {
             if let LocalRef::Operand(Some(op)) = self.locals[index] {
                 if let ty::Array(_, n) = op.layout.ty.sty {
-                    let n = n.unwrap_usize(bx.cx().tcx());
+                    let n = n.unwrap_evaluated().unwrap_usize(bx.cx().tcx());
                     return bx.cx().const_usize(n);
                 }
             }
diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs
index 6a5b5d172bb..ab5a16a4744 100644
--- a/src/librustc_mir/borrow_check/error_reporting.rs
+++ b/src/librustc_mir/borrow_check/error_reporting.rs
@@ -1380,7 +1380,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         );
         if let TerminatorKind::Call {
             func: Operand::Constant(box Constant {
-                literal: ty::Const { ty: &ty::TyS { sty: ty::TyKind::FnDef(id, _), ..  }, ..  },
+                literal: ty::LazyConst::Evaluated(ty::Const {
+                    ty: &ty::TyS { sty: ty::TyKind::FnDef(id, _), ..  },
+                    ..
+                }),
                 ..
             }),
             args,
diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs
index 0be8ecffcdf..63bf6faed40 100644
--- a/src/librustc_mir/borrow_check/mutability_errors.rs
+++ b/src/librustc_mir/borrow_check/mutability_errors.rs
@@ -468,13 +468,13 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
                             Terminator {
                                 kind: TerminatorKind::Call {
                                     func: Operand::Constant(box Constant {
-                                        literal: Const {
+                                        literal: ty::LazyConst::Evaluated(Const {
                                             ty: &TyS {
                                                 sty: TyKind::FnDef(id, substs),
                                                 ..
                                             },
                                             ..
-                                        },
+                                        }),
                                         ..
                                     }),
                                     ..
diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs
index 55af7399aab..5c24da7621b 100644
--- a/src/librustc_mir/borrow_check/nll/renumber.rs
+++ b/src/librustc_mir/borrow_check/nll/renumber.rs
@@ -88,7 +88,7 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
         debug!("visit_region: region={:?}", region);
     }
 
-    fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _location: Location) {
+    fn visit_const(&mut self, constant: &mut &'tcx ty::LazyConst<'tcx>, _location: Location) {
         *constant = self.renumber_regions(&*constant);
     }
 
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 796a2f79f75..3681c3d74eb 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -382,6 +382,11 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
             constant, location
         );
 
+        let literal = match constant.literal {
+            ty::LazyConst::Evaluated(lit) => lit,
+            ty::LazyConst::Unevaluated(..) => return,
+        };
+
         // FIXME(#46702) -- We need some way to get the predicates
         // associated with the "pre-evaluated" form of the
         // constant. For example, consider that the constant
@@ -390,7 +395,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
         // constraints on `'a` and `'b`. These constraints
         // would be lost if we just look at the normalized
         // value.
-        if let ty::FnDef(def_id, substs) = constant.literal.ty.sty {
+        if let ty::FnDef(def_id, substs) = literal.ty.sty {
             let tcx = self.tcx();
             let type_checker = &mut self.cx;
 
@@ -411,10 +416,10 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
             );
         }
 
-        debug!("sanitize_constant: expected_ty={:?}", constant.literal.ty);
+        debug!("sanitize_constant: expected_ty={:?}", literal.ty);
 
         if let Err(terr) = self.cx.eq_types(
-            constant.literal.ty,
+            literal.ty,
             constant.ty,
             location.to_locations(),
             ConstraintCategory::Boring,
@@ -424,7 +429,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
                 constant,
                 "constant {:?} should have type {:?} but has {:?} ({:?})",
                 constant,
-                constant.literal.ty,
+                literal.ty,
                 constant.ty,
                 terr,
             );
@@ -563,7 +568,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
             ProjectionElem::Subslice { from, to } => PlaceTy::Ty {
                 ty: match base_ty.sty {
                     ty::Array(inner, size) => {
-                        let size = size.unwrap_usize(tcx);
+                        let size = size.unwrap_evaluated().unwrap_usize(tcx);
                         let min_size = (from as u64) + (to as u64);
                         if let Some(rest_size) = size.checked_sub(min_size) {
                             tcx.mk_array(inner, rest_size)
diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs
index ac7182abb36..88c27a869c0 100644
--- a/src/librustc_mir/borrow_check/places_conflict.rs
+++ b/src/librustc_mir/borrow_check/places_conflict.rs
@@ -388,7 +388,7 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>(
         (Place::Promoted(p1), Place::Promoted(p2)) => {
             if p1.0 == p2.0 {
                 if let ty::Array(_, size) = p1.1.sty {
-                    if size.unwrap_usize(tcx) == 0 {
+                    if size.unwrap_evaluated().unwrap_usize(tcx) == 0 {
                         // Ignore conflicts with promoted [T; 0].
                         debug!("place_element_conflict: IGNORE-LEN-0-PROMOTED");
                         return Overlap::Disjoint;
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 7dcac05e702..a66da50c484 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -270,11 +270,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                             span: expr_span,
                             ty: this.hir.tcx().types.u32,
                             user_ty: None,
-                            literal: ty::Const::from_bits(
-                                this.hir.tcx(),
-                                0,
-                                ty::ParamEnv::empty().and(this.hir.tcx().types.u32),
-                            ),
+                            literal: this.hir.tcx().intern_lazy_const(ty::LazyConst::Evaluated(
+                                ty::Const::from_bits(
+                                    this.hir.tcx(),
+                                    0,
+                                    ty::ParamEnv::empty().and(this.hir.tcx().types.u32),
+                                ),
+                            )),
                         }));
                         box AggregateKind::Generator(closure_id, substs, movability)
                     }
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index 21109a223bf..f601e38717f 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -302,6 +302,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     }
                     let eq_def_id = self.hir.tcx().lang_items().eq_trait().unwrap();
                     let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty.into()]);
+                    let method = self.hir.tcx().intern_lazy_const(ty::LazyConst::Evaluated(method));
 
                     // take the argument by reference
                     let region_scope = self.topmost_scope();
diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs
index 472f05a101f..0689dcfceea 100644
--- a/src/librustc_mir/build/misc.rs
+++ b/src/librustc_mir/build/misc.rs
@@ -33,7 +33,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             span,
             ty,
             user_ty: None,
-            literal,
+            literal: self.hir.tcx().intern_lazy_const(ty::LazyConst::Evaluated(literal)),
         };
         Operand::Constant(constant)
     }
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 8acdecf6fa2..727b769cf4d 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -202,7 +202,7 @@ impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> {
         }
     }
 
-    fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _: Location) {
+    fn visit_const(&mut self, constant: &mut &'tcx ty::LazyConst<'tcx>, _: Location) {
         if let Some(lifted) = self.tcx.lift(constant) {
             *constant = lifted;
         } else {
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index b9432997b7e..58a0f13733e 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -136,12 +136,14 @@ pub fn op_to_const<'tcx>(
     };
     Ok(ty::Const::from_const_value(ecx.tcx.tcx, val, op.layout.ty))
 }
+
 pub fn const_to_op<'tcx>(
     ecx: &CompileTimeEvalContext<'_, '_, 'tcx>,
-    cnst: &ty::Const<'tcx>,
+    cnst: ty::LazyConst<'tcx>,
+    ty: ty::Ty<'tcx>,
 ) -> EvalResult<'tcx, OpTy<'tcx>> {
-    let op = ecx.const_value_to_op(cnst.val)?;
-    Ok(OpTy { op, layout: ecx.layout_of(cnst.ty)? })
+    let op = ecx.const_value_to_op(cnst)?;
+    Ok(OpTy { op, layout: ecx.layout_of(ty)? })
 }
 
 fn eval_body_and_ecx<'a, 'mir, 'tcx>(
@@ -514,7 +516,7 @@ pub fn const_field<'a, 'tcx>(
     let ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
     let result = (|| {
         // get the operand again
-        let op = const_to_op(&ecx, value)?;
+        let op = const_to_op(&ecx, ty::LazyConst::Evaluated(value), value.ty)?;
         // downcast
         let down = match variant {
             None => op,
@@ -541,7 +543,7 @@ pub fn const_variant_index<'a, 'tcx>(
 ) -> EvalResult<'tcx, VariantIdx> {
     trace!("const_variant_index: {:?}, {:?}", instance, val);
     let ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
-    let op = const_to_op(&ecx, val)?;
+    let op = const_to_op(&ecx, ty::LazyConst::Evaluated(val), val.ty)?;
     Ok(ecx.read_discriminant(op)?.1)
 }
 
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 293058a0f26..e2d0f6b0ae6 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -356,7 +356,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprKind::Lit(ref lit) => ExprKind::Literal {
-            literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, false),
+            literal: cx.tcx.intern_lazy_const(ty::LazyConst::Evaluated(
+                cx.const_eval_literal(&lit.node, expr_ty, lit.span, false)
+            )),
             user_ty: None,
         },
 
@@ -454,7 +456,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             } else {
                 if let hir::ExprKind::Lit(ref lit) = arg.node {
                     ExprKind::Literal {
-                        literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true),
+                        literal: cx.tcx.intern_lazy_const(ty::LazyConst::Evaluated(
+                            cx.const_eval_literal(&lit.node, expr_ty, lit.span, true)
+                        )),
                         user_ty: None,
                     }
                 } else {
@@ -711,24 +715,22 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                         temp_lifetime,
                         ty: var_ty,
                         span: expr.span,
-                        kind: ExprKind::Literal { literal, user_ty: None },
+                        kind: ExprKind::Literal {
+                            literal: cx.tcx.intern_lazy_const(literal),
+                            user_ty: None
+                        },
                     }.to_ref();
-                    let offset = mk_const(ty::Const::from_bits(
+                    let offset = mk_const(ty::LazyConst::Evaluated(ty::Const::from_bits(
                         cx.tcx,
                         offset as u128,
                         cx.param_env.and(var_ty),
-                    ));
+                    )));
                     match did {
                         Some(did) => {
                             // in case we are offsetting from a computed discriminant
                             // and not the beginning of discriminants (which is always `0`)
                             let substs = Substs::identity_for_item(cx.tcx(), did);
-                            let lhs = mk_const(ty::Const::unevaluated(
-                                cx.tcx(),
-                                did,
-                                substs,
-                                var_ty,
-                            ));
+                            let lhs = mk_const(ty::LazyConst::Unevaluated(did, substs));
                             let bin = ExprKind::Binary {
                                 op: BinOp::Add,
                                 lhs,
@@ -868,7 +870,9 @@ fn method_callee<'a, 'gcx, 'tcx>(
         ty,
         span,
         kind: ExprKind::Literal {
-            literal: ty::Const::zero_sized(cx.tcx(), ty),
+            literal: cx.tcx().intern_lazy_const(ty::LazyConst::Evaluated(
+                ty::Const::zero_sized(cx.tcx(), ty)
+            )),
             user_ty,
         },
     }
@@ -928,10 +932,10 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             let user_ty = user_substs_applied_to_def(cx, expr.hir_id, &def);
             debug!("convert_path_expr: user_ty={:?}", user_ty);
             ExprKind::Literal {
-                literal: ty::Const::zero_sized(
+                literal: cx.tcx.intern_lazy_const(ty::LazyConst::Evaluated(ty::Const::zero_sized(
                     cx.tcx,
                     cx.tables().node_id_to_type(expr.hir_id),
-                ),
+                ))),
                 user_ty,
             }
         },
@@ -941,12 +945,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             let user_ty = user_substs_applied_to_def(cx, expr.hir_id, &def);
             debug!("convert_path_expr: (const) user_ty={:?}", user_ty);
             ExprKind::Literal {
-                literal: ty::Const::unevaluated(
-                    cx.tcx,
-                    def_id,
-                    substs,
-                    cx.tables().node_id_to_type(expr.hir_id),
-                ),
+                literal: cx.tcx.intern_lazy_const(ty::LazyConst::Unevaluated(def_id, substs)),
                 user_ty,
             }
         },
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 60c8022a374..5681237c14b 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -108,8 +108,8 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
         self.tcx.types.usize
     }
 
-    pub fn usize_literal(&mut self, value: u64) -> &'tcx ty::Const<'tcx> {
-        ty::Const::from_usize(self.tcx, value)
+    pub fn usize_literal(&mut self, value: u64) -> &'tcx ty::LazyConst<'tcx> {
+        self.tcx.intern_lazy_const(ty::LazyConst::Evaluated(ty::Const::from_usize(self.tcx, value)))
     }
 
     pub fn bool_ty(&mut self) -> Ty<'tcx> {
@@ -120,12 +120,12 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
         self.tcx.mk_unit()
     }
 
-    pub fn true_literal(&mut self) -> &'tcx ty::Const<'tcx> {
-        ty::Const::from_bool(self.tcx, true)
+    pub fn true_literal(&mut self) -> &'tcx ty::LazyConst<'tcx> {
+        self.tcx.intern_lazy_const(ty::LazyConst::Evaluated(ty::Const::from_bool(self.tcx, true)))
     }
 
-    pub fn false_literal(&mut self) -> &'tcx ty::Const<'tcx> {
-        ty::Const::from_bool(self.tcx, false)
+    pub fn false_literal(&mut self) -> &'tcx ty::LazyConst<'tcx> {
+        self.tcx.intern_lazy_const(ty::LazyConst::Evaluated(ty::Const::from_bool(self.tcx, false)))
     }
 
     pub fn const_eval_literal(
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index b56e3d4e773..676b9845748 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -9,7 +9,7 @@ use rustc::hir::def_id::DefId;
 use rustc::infer::canonical::Canonical;
 use rustc::middle::region;
 use rustc::ty::subst::Substs;
-use rustc::ty::{AdtDef, UpvarSubsts, Region, Ty, Const, UserTypeAnnotation};
+use rustc::ty::{AdtDef, UpvarSubsts, Region, Ty, Const, LazyConst, UserTypeAnnotation};
 use rustc::ty::layout::VariantIdx;
 use rustc::hir;
 use syntax::ast;
@@ -288,7 +288,7 @@ pub enum ExprKind<'tcx> {
         movability: Option<hir::GeneratorMovability>,
     },
     Literal {
-        literal: &'tcx Const<'tcx>,
+        literal: &'tcx LazyConst<'tcx>,
         user_ty: Option<Canonical<'tcx, UserTypeAnnotation<'tcx>>>,
     },
     InlineAsm {
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index 13838e5d85d..176c2f65643 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -635,7 +635,7 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
             }).collect()
         }
         ty::Array(ref sub_ty, len) if len.assert_usize(cx.tcx).is_some() => {
-            let len = len.unwrap_usize(cx.tcx);
+            let len = len.unwrap_evaluated().unwrap_usize(cx.tcx);
             if len != 0 && cx.is_uninhabited(sub_ty) {
                 vec![]
             } else {
@@ -1310,7 +1310,7 @@ fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>,
             )]),
         PatternKind::Array { .. } => match pcx.ty.sty {
             ty::Array(_, length) => Some(vec![
-                Slice(length.unwrap_usize(cx.tcx))
+                Slice(length.unwrap_evaluated().unwrap_usize(cx.tcx))
             ]),
             _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty)
         },
@@ -1751,23 +1751,23 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
                     // necessarily point to memory, they are usually just integers. The only time
                     // they should be pointing to memory is when they are subslices of nonzero
                     // slices
-                    let (opt_ptr, n, ty) = match (value.val, &value.ty.sty) {
-                        (ConstValue::ByRef(id, alloc, offset), ty::TyKind::Array(t, n)) => (
-                            Some((
-                                Pointer::new(id, offset),
-                                alloc,
-                            )),
-                            n.unwrap_usize(cx.tcx),
-                            t,
-                        ),
-                        (ConstValue::ScalarPair(ptr, n), ty::TyKind::Slice(t)) => (
-                            ptr.to_ptr().ok().map(|ptr| (
-                                ptr,
-                                cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id),
-                            )),
-                            n.to_bits(cx.tcx.data_layout.pointer_size).unwrap() as u64,
-                            t,
-                        ),
+                    let (opt_ptr, n, ty) = match value.ty.builtin_deref(false).unwrap().ty.sty {
+                        ty::TyKind::Array(t, n) =>
+                            (value.to_ptr(), n.unwrap_evaluated().unwrap_usize(cx.tcx), t),
+                        ty::TyKind::Slice(t) => {
+                            match value.val {
+                                ConstValue::ScalarPair(ptr, n) => (
+                                    ptr.to_ptr().ok(),
+                                    n.to_bits(cx.tcx.data_layout.pointer_size).unwrap() as u64,
+                                    t,
+                                ),
+                                _ => span_bug!(
+                                    pat.span,
+                                    "slice pattern constant must be scalar pair but is {:?}",
+                                    value,
+                                ),
+                            }
+                        },
                         _ => span_bug!(
                             pat.span,
                             "unexpected const-val {:?} with ctor {:?}",
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 10d2d7bc1b1..d7eeaf43651 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -650,7 +650,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
 
             ty::Array(_, len) => {
                 // fixed-length array
-                let len = len.unwrap_usize(self.tcx);
+                let len = len.unwrap_evaluated().unwrap_usize(self.tcx);
                 assert!(len >= prefix.len() as u64 + suffix.len() as u64);
                 PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix }
             }
@@ -934,7 +934,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
             }
             ty::Array(_, n) => {
                 PatternKind::Array {
-                    prefix: (0..n.unwrap_usize(self.tcx))
+                    prefix: (0..n.unwrap_evaluated().unwrap_usize(self.tcx))
                         .map(|i| adt_subpattern(i as usize, None))
                         .collect(),
                     slice: None,
diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs
index 190a381cf52..37c5340e0a2 100644
--- a/src/librustc_mir/interpret/cast.rs
+++ b/src/librustc_mir/interpret/cast.rs
@@ -307,7 +307,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                 // u64 cast is from usize to u64, which is always good
                 let val = Immediate::new_slice(
                     ptr,
-                    length.unwrap_usize(self.tcx.tcx),
+                    length.unwrap_evaluated().unwrap_usize(self.tcx.tcx),
                     self,
                 );
                 self.write_immediate(val, dest)
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index 1ea3f78c210..04e0955ad61 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -3,7 +3,7 @@
 
 use std::convert::TryInto;
 
-use rustc::mir;
+use rustc::{mir, ty};
 use rustc::ty::layout::{self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerExt, VariantIdx};
 
 use rustc::mir::interpret::{
@@ -517,7 +517,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                     let ty = self.monomorphize(mir_op.ty(self.mir(), *self.tcx), self.substs());
                     self.layout_of(ty)
                 })?;
-                let op = self.const_value_to_op(constant.literal.val)?;
+                let op = self.const_value_to_op(*constant.literal)?;
                 OpTy { op, layout }
             }
         };
@@ -540,17 +540,20 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     // `eval_operand`, ideally).
     pub(crate) fn const_value_to_op(
         &self,
-        val: ConstValue<'tcx>,
+        val: ty::LazyConst<'tcx>,
     ) -> EvalResult<'tcx, Operand<M::PointerTag>> {
         trace!("const_value_to_op: {:?}", val);
-        match val {
-            ConstValue::Unevaluated(def_id, substs) => {
+        let val = match val {
+            ty::LazyConst::Unevaluated(def_id, substs) => {
                 let instance = self.resolve(def_id, substs)?;
-                Ok(*OpTy::from(self.const_eval_raw(GlobalId {
+                return Ok(*OpTy::from(self.const_eval_raw(GlobalId {
                     instance,
                     promoted: None,
-                })?))
-            }
+                })?));
+            },
+            ty::LazyConst::Evaluated(c) => c,
+        };
+        match val.val {
             ConstValue::ByRef(id, alloc, offset) => {
                 // We rely on mutability being set correctly in that allocation to prevent writes
                 // where none should happen -- and for `static mut`, we copy on demand anyway.
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index d81a4d6a4bc..757f94f2076 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -381,7 +381,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             let param_env = ty::ParamEnv::reveal_all();
 
             if let Ok(val) = tcx.const_eval(param_env.and(cid)) {
-                collect_const(tcx, val, instance.substs, &mut neighbors);
+                collect_const(tcx, val, &mut neighbors);
             }
         }
         MonoItem::Fn(instance) => {
@@ -583,10 +583,10 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
         self.super_rvalue(rvalue, location);
     }
 
-    fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) {
+    fn visit_const(&mut self, constant: &&'tcx ty::LazyConst<'tcx>, location: Location) {
         debug!("visiting const {:?} @ {:?}", *constant, location);
 
-        collect_const(self.tcx, constant, self.param_substs, self.output);
+        collect_lazy_const(self.tcx, constant, self.param_substs, self.output);
 
         self.super_const(constant);
     }
@@ -987,7 +987,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
                 let param_env = ty::ParamEnv::reveal_all();
 
                 if let Ok(val) = self.tcx.const_eval(param_env.and(cid)) {
-                    collect_const(self.tcx, val, instance.substs, &mut self.output);
+                    collect_const(self.tcx, val, &mut self.output);
                 }
             }
             hir::ItemKind::Fn(..) => {
@@ -1198,7 +1198,7 @@ fn collect_neighbours<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             promoted: Some(i),
         };
         match tcx.const_eval(param_env.and(cid)) {
-            Ok(val) => collect_const(tcx, val, instance.substs, output),
+            Ok(val) => collect_const(tcx, val, output),
             Err(ErrorHandled::Reported) => {},
             Err(ErrorHandled::TooGeneric) => span_bug!(
                 mir.promoted[i].span, "collection encountered polymorphic constant",
@@ -1216,43 +1216,48 @@ fn def_id_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     output
 }
 
+fn collect_lazy_const<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    constant: &ty::LazyConst<'tcx>,
+    param_substs: &'tcx Substs<'tcx>,
+    output: &mut Vec<MonoItem<'tcx>>,
+) {
+    let (def_id, substs) = match *constant {
+        ty::LazyConst::Evaluated(c) => return collect_const(tcx, c, output),
+        ty::LazyConst::Unevaluated(did, substs) => (did, substs),
+    };
+    let param_env = ty::ParamEnv::reveal_all();
+    let substs = tcx.subst_and_normalize_erasing_regions(
+        param_substs,
+        param_env,
+        &substs,
+    );
+    let instance = ty::Instance::resolve(tcx,
+                                        param_env,
+                                        def_id,
+                                        substs).unwrap();
+
+    let cid = GlobalId {
+        instance,
+        promoted: None,
+    };
+    match tcx.const_eval(param_env.and(cid)) {
+        Ok(val) => collect_const(tcx, val, output),
+        Err(ErrorHandled::Reported) => {},
+        Err(ErrorHandled::TooGeneric) => span_bug!(
+            tcx.def_span(def_id), "collection encountered polymorphic constant",
+        ),
+    }
+}
+
 fn collect_const<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     constant: &ty::Const<'tcx>,
-    param_substs: &'tcx Substs<'tcx>,
     output: &mut Vec<MonoItem<'tcx>>,
 ) {
     debug!("visiting const {:?}", *constant);
 
-    let val = match constant.val {
-        ConstValue::Unevaluated(def_id, substs) => {
-            let param_env = ty::ParamEnv::reveal_all();
-            let substs = tcx.subst_and_normalize_erasing_regions(
-                param_substs,
-                param_env,
-                &substs,
-            );
-            let instance = ty::Instance::resolve(tcx,
-                                                param_env,
-                                                def_id,
-                                                substs).unwrap();
-
-            let cid = GlobalId {
-                instance,
-                promoted: None,
-            };
-            match tcx.const_eval(param_env.and(cid)) {
-                Ok(val) => val.val,
-                Err(ErrorHandled::Reported) => return,
-                Err(ErrorHandled::TooGeneric) => span_bug!(
-                    tcx.def_span(def_id), "collection encountered polymorphic constant",
-                ),
-            }
-        },
-        _ => constant.val,
-    };
-    match val {
-        ConstValue::Unevaluated(..) => bug!("const eval yielded unevaluated const"),
+    match constant.val {
         ConstValue::ScalarPair(Scalar::Ptr(a), Scalar::Ptr(b)) => {
             collect_miri(tcx, a.alloc_id, output);
             collect_miri(tcx, b.alloc_id, output);
diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs
index e7f4451fdd7..8cd8eb3ad64 100644
--- a/src/librustc_mir/monomorphize/item.rs
+++ b/src/librustc_mir/monomorphize/item.rs
@@ -295,7 +295,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
             ty::Array(inner_type, len) => {
                 output.push('[');
                 self.push_type_name(inner_type, output);
-                write!(output, "; {}", len.unwrap_usize(self.tcx)).unwrap();
+                write!(output, "; {}", len.unwrap_evaluated().unwrap_usize(self.tcx)).unwrap();
                 output.push(']');
             },
             ty::Slice(inner_type) => {
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index 4c123d4a44b..835a5dede74 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -318,7 +318,7 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     match self_ty.sty {
         _ if is_copy => builder.copy_shim(),
         ty::Array(ty, len) => {
-            let len = len.unwrap_usize(tcx);
+            let len = len.unwrap_evaluated().unwrap_usize(tcx);
             builder.array_shim(dest, src, ty, len)
         }
         ty::Closure(def_id, substs) => {
@@ -459,7 +459,9 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
             span: self.span,
             ty: func_ty,
             user_ty: None,
-            literal: ty::Const::zero_sized(self.tcx, func_ty),
+            literal: tcx.intern_lazy_const(ty::LazyConst::Evaluated(
+                ty::Const::zero_sized(self.tcx, func_ty),
+            )),
         });
 
         let ref_loc = self.make_place(
@@ -519,7 +521,9 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
             span: self.span,
             ty: self.tcx.types.usize,
             user_ty: None,
-            literal: ty::Const::from_usize(self.tcx, value),
+            literal: self.tcx.intern_lazy_const(ty::LazyConst::Evaluated(
+                ty::Const::from_usize(self.tcx, value),
+            )),
         }
     }
 
@@ -755,7 +759,9 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 span,
                 ty,
                 user_ty: None,
-                literal: ty::Const::zero_sized(tcx, ty),
+                literal: tcx.intern_lazy_const(ty::LazyConst::Evaluated(
+                    ty::Const::zero_sized(tcx, ty)
+                )),
              }),
              vec![rcvr])
         }
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 34f544745a7..a2a416e54d8 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -255,7 +255,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
         source_info: SourceInfo,
     ) -> Option<Const<'tcx>> {
         self.ecx.tcx.span = source_info.span;
-        match const_to_op(&self.ecx, c.literal) {
+        match const_to_op(&self.ecx, *c.literal, c.ty) {
             Ok(op) => {
                 Some((op, c.span))
             },
diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs
index b98e3d7d8bb..06e16de8b43 100644
--- a/src/librustc_mir/transform/elaborate_drops.rs
+++ b/src/librustc_mir/transform/elaborate_drops.rs
@@ -533,7 +533,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
             span,
             ty: self.tcx.types.bool,
             user_ty: None,
-            literal: ty::Const::from_bool(self.tcx, val),
+            literal: self.tcx.intern_lazy_const(ty::LazyConst::Evaluated(
+                ty::Const::from_bool(self.tcx, val),
+            )),
         })))
     }
 
diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs
index 009570c378a..b464b7d65e4 100644
--- a/src/librustc_mir/transform/erase_regions.rs
+++ b/src/librustc_mir/transform/erase_regions.rs
@@ -32,7 +32,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> {
         *region = self.tcx.types.re_erased;
     }
 
-    fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _: Location) {
+    fn visit_const(&mut self, constant: &mut &'tcx ty::LazyConst<'tcx>, _: Location) {
         *constant = self.tcx.erase_regions(constant);
     }
 
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index b43e8392718..808c3aad292 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -171,11 +171,11 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
             span: source_info.span,
             ty: self.tcx.types.u32,
             user_ty: None,
-            literal: ty::Const::from_bits(
+            literal: self.tcx.intern_lazy_const(ty::LazyConst::Evaluated(ty::Const::from_bits(
                 self.tcx,
                 state_disc.into(),
                 ty::ParamEnv::empty().and(self.tcx.types.u32)
-            ),
+            ))),
         });
         Statement {
             source_info,
@@ -717,7 +717,9 @@ fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             span: mir.span,
             ty: tcx.types.bool,
             user_ty: None,
-            literal: ty::Const::from_bool(tcx, false),
+            literal: tcx.intern_lazy_const(ty::LazyConst::Evaluated(
+                ty::Const::from_bool(tcx, false),
+            )),
         }),
         expected: true,
         msg: message,
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 7b04af62fe6..209c26a0c6c 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -11,7 +11,6 @@ use rustc_data_structures::sync::Lrc;
 use rustc_target::spec::abi::Abi;
 use rustc::hir;
 use rustc::hir::def_id::DefId;
-use rustc::mir::interpret::ConstValue;
 use rustc::traits::{self, TraitEngine};
 use rustc::ty::{self, TyCtxt, Ty, TypeFoldable};
 use rustc::ty::cast::CastTy;
@@ -625,12 +624,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                 }
             }
             Operand::Constant(ref constant) => {
-                if let ConstValue::Unevaluated(def_id, _) = constant.literal.val {
+                if let ty::LazyConst::Unevaluated(def_id, _) = constant.literal {
                     // Don't peek inside trait associated constants.
-                    if self.tcx.trait_of_item(def_id).is_some() {
-                        self.add_type(constant.literal.ty);
+                    if self.tcx.trait_of_item(*def_id).is_some() {
+                        self.add_type(constant.ty);
                     } else {
-                        let (bits, _) = self.tcx.at(constant.span).mir_const_qualif(def_id);
+                        let (bits, _) = self.tcx.at(constant.span).mir_const_qualif(*def_id);
 
                         let qualif = Qualif::from_bits(bits).expect("invalid mir_const_qualif");
                         self.add(qualif);
@@ -638,7 +637,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                         // Just in case the type is more specific than
                         // the definition, e.g., impl associated const
                         // with type parameters, take it into account.
-                        self.qualif.restrict(constant.literal.ty, self.tcx, self.param_env);
+                        self.qualif.restrict(constant.ty, self.tcx, self.param_env);
                     }
                 }
             }
@@ -713,7 +712,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                     } else if let ty::Array(_, len) = ty.sty {
                         // FIXME(eddyb) the `self.mode == Mode::Fn` condition
                         // seems unnecessary, given that this is merely a ZST.
-                        if len.unwrap_usize(self.tcx) == 0 && self.mode == Mode::Fn {
+                        let len = len.unwrap_evaluated().unwrap_usize(self.tcx);
+                        if len == 0 && self.mode == Mode::Fn {
                             forbidden_mut = false;
                         }
                     }
diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs
index 6cf9f43877b..1d5bc4f9cc3 100644
--- a/src/librustc_mir/transform/simplify_branches.rs
+++ b/src/librustc_mir/transform/simplify_branches.rs
@@ -1,6 +1,6 @@
 //! A pass that simplifies branches when their condition is known.
 
-use rustc::ty::{TyCtxt, ParamEnv};
+use rustc::ty::{self, TyCtxt, ParamEnv};
 use rustc::mir::*;
 use transform::{MirPass, MirSource};
 
@@ -30,23 +30,28 @@ impl MirPass for SimplifyBranches {
                     discr: Operand::Constant(ref c), switch_ty, ref values, ref targets, ..
                 } => {
                     let switch_ty = ParamEnv::empty().and(switch_ty);
-                    if let Some(constint) = c.literal.assert_bits(tcx, switch_ty) {
-                        let (otherwise, targets) = targets.split_last().unwrap();
-                        let mut ret = TerminatorKind::Goto { target: *otherwise };
-                        for (&v, t) in values.iter().zip(targets.iter()) {
-                            if v == constint {
-                                ret = TerminatorKind::Goto { target: *t };
-                                break;
+                    if let ty::LazyConst::Evaluated(c) = c.literal {
+                        let c = c.assert_bits(tcx, switch_ty);
+                        if let Some(constant) = c {
+                            let (otherwise, targets) = targets.split_last().unwrap();
+                            let mut ret = TerminatorKind::Goto { target: *otherwise };
+                            for (&v, t) in values.iter().zip(targets.iter()) {
+                                if v == constant {
+                                    ret = TerminatorKind::Goto { target: *t };
+                                    break;
+                                }
                             }
+                            ret
+                        } else {
+                            continue
                         }
-                        ret
                     } else {
                         continue
                     }
                 },
                 TerminatorKind::Assert {
                     target, cond: Operand::Constant(ref c), expected, ..
-                } if (c.literal.assert_bool(tcx) == Some(true)) == expected => {
+                } if (c.literal.unwrap_evaluated().assert_bool(tcx) == Some(true)) == expected => {
                     TerminatorKind::Goto { target }
                 },
                 TerminatorKind::FalseEdges { real_target, .. } => {
diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs
index 5ab9669baac..172993daa9a 100644
--- a/src/librustc_mir/transform/uniform_array_move_out.rs
+++ b/src/librustc_mir/transform/uniform_array_move_out.rs
@@ -71,7 +71,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
                 } else {
                     let place_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
                     if let ty::Array(item_ty, const_size) = place_ty.sty {
-                        if let Some(size) = const_size.assert_usize(self.tcx) {
+                        if let Some(size) = const_size.unwrap_evaluated().assert_usize(self.tcx) {
                             assert!(size <= u32::max_value() as u64,
                                     "uniform array move out doesn't supported
                                      for array bigger then u32");
@@ -193,7 +193,7 @@ impl MirPass for RestoreSubsliceArrayMoveOut {
                         let opt_size = opt_src_place.and_then(|src_place| {
                             let src_ty = src_place.ty(mir, tcx).to_ty(tcx);
                             if let ty::Array(_, ref size_o) = src_ty.sty {
-                                size_o.assert_usize(tcx)
+                                size_o.unwrap_evaluated().assert_usize(tcx)
                             } else {
                                 None
                             }
diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs
index 5a2f4be71cc..221c2d55eec 100644
--- a/src/librustc_mir/util/elaborate_drops.rs
+++ b/src/librustc_mir/util/elaborate_drops.rs
@@ -809,7 +809,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
                 self.complete_drop(Some(DropFlagMode::Deep), succ, unwind)
             }
             ty::Array(ety, size) => {
-                let size = size.assert_usize(self.tcx());
+                let size = size.unwrap_evaluated().assert_usize(self.tcx());
                 self.open_drop_for_array(ety, size)
             },
             ty::Slice(ety) => self.open_drop_for_array(ety, None),
@@ -963,7 +963,9 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
             span: self.source_info.span,
             ty: self.tcx().types.usize,
             user_ty: None,
-            literal: ty::Const::from_usize(self.tcx(), val.into()),
+            literal: self.tcx().intern_lazy_const(ty::LazyConst::Evaluated(
+                ty::Const::from_usize(self.tcx(), val.into())
+            )),
         })
     }
 
diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs
index 6353eab6f65..fca208b340d 100644
--- a/src/librustc_mir/util/pretty.rs
+++ b/src/librustc_mir/util/pretty.rs
@@ -399,12 +399,21 @@ impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ExtraComments<'cx, 'gcx, 'tcx> {
         self.push(&format!("+ literal: {:?}", literal));
     }
 
-    fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) {
+    fn visit_const(&mut self, constant: &&'tcx ty::LazyConst<'tcx>, _: Location) {
         self.super_const(constant);
-        let ty::Const { ty, val, .. } = constant;
-        self.push("ty::Const");
-        self.push(&format!("+ ty: {:?}", ty));
-        self.push(&format!("+ val: {:?}", val));
+        match constant {
+            ty::LazyConst::Evaluated(constant) => {
+                let ty::Const { ty, val, .. } = constant;
+                self.push("ty::Const");
+                self.push(&format!("+ ty: {:?}", ty));
+                self.push(&format!("+ val: {:?}", val));
+            },
+            ty::LazyConst::Unevaluated(did, substs) => {
+                self.push("ty::LazyConst::Unevaluated");
+                self.push(&format!("+ did: {:?}", did));
+                self.push(&format!("+ substs: {:?}", substs));
+            },
+        }
     }
 
     fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
diff --git a/src/librustc_traits/chalk_context/program_clauses.rs b/src/librustc_traits/chalk_context/program_clauses.rs
index 98a2f4bf0a1..71f4945fd64 100644
--- a/src/librustc_traits/chalk_context/program_clauses.rs
+++ b/src/librustc_traits/chalk_context/program_clauses.rs
@@ -239,7 +239,7 @@ fn wf_clause_for_slice<'tcx>(tcx: ty::TyCtxt<'_, '_, 'tcx>) -> Clauses<'tcx> {
 
 fn wf_clause_for_array<'tcx>(
     tcx: ty::TyCtxt<'_, '_, 'tcx>,
-    length: &'tcx ty::Const<'tcx>
+    length: &'tcx ty::LazyConst<'tcx>
 ) -> Clauses<'tcx> {
     let ty = generic_types::bound(tcx, 0);
     let array_ty = tcx.mk_ty(ty::Array(ty, length));
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 1db7141917f..e018aa3b26d 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1772,7 +1772,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             hir::TyKind::Array(ref ty, ref length) => {
                 let length_def_id = tcx.hir().local_def_id(length.id);
                 let substs = Substs::identity_for_item(tcx, length_def_id);
-                let length = ty::Const::unevaluated(tcx, length_def_id, substs, tcx.types.usize);
+                let length = ty::LazyConst::Unevaluated(length_def_id, substs);
+                let length = tcx.intern_lazy_const(length);
                 let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(&ty), length));
                 self.normalize_ty(ast_ty.span, array_ty)
             }
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index b66c383edb5..13311a2efd5 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -377,7 +377,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 let expected_ty = self.structurally_resolved_type(pat.span, expected);
                 let (inner_ty, slice_ty) = match expected_ty.sty {
                     ty::Array(inner_ty, size) => {
-                        let size = size.unwrap_usize(tcx);
+                        let size = size.unwrap_evaluated().unwrap_usize(tcx);
                         let min_len = before.len() as u64 + after.len() as u64;
                         if slice.is_none() {
                             if min_len != size {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index d78d7273a36..d664eed0a34 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3453,7 +3453,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     }
                     ty::Array(_, len) => {
                         if let (Some(len), Ok(user_index)) = (
-                            len.assert_usize(self.tcx),
+                            len.unwrap_evaluated().assert_usize(self.tcx),
                             field.as_str().parse::<u64>()
                         ) {
                             let base = self.tcx.sess.source_map()
@@ -4442,7 +4442,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 if element_ty.references_error() {
                     tcx.types.err
                 } else if let Ok(count) = count {
-                    tcx.mk_ty(ty::Array(t, count))
+                    tcx.mk_ty(ty::Array(t, tcx.intern_lazy_const(ty::LazyConst::Evaluated(count))))
                 } else {
                     tcx.types.err
                 }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 38b2452b420..3aa752b35ad 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -13,7 +13,6 @@ use rustc_data_structures::sync::Lrc;
 use rustc_target::spec::abi::Abi;
 use rustc_typeck::hir_ty_to_ty;
 use rustc::infer::region_constraints::{RegionConstraintData, Constraint};
-use rustc::mir::interpret::ConstValue;
 use rustc::middle::resolve_lifetime as rl;
 use rustc::middle::lang_items;
 use rustc::middle::stability;
@@ -2420,10 +2419,10 @@ impl Clean<Type> for hir::Ty {
                     instance: ty::Instance::new(def_id, substs),
                     promoted: None
                 };
-                let length = cx.tcx.const_eval(param_env.and(cid)).unwrap_or_else(|_| {
-                    ty::Const::unevaluated(cx.tcx, def_id, substs, cx.tcx.types.usize)
-                });
-                let length = print_const(cx, length);
+                let length = match cx.tcx.const_eval(param_env.and(cid)) {
+                    Ok(length) => print_const(cx, ty::LazyConst::Evaluated(length)),
+                    Err(_) => "_".to_string(),
+                };
                 Array(box ty.clean(cx), length)
             },
             TyKind::Tup(ref tys) => Tuple(tys.clean(cx)),
@@ -2583,15 +2582,15 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
             ty::Str => Primitive(PrimitiveType::Str),
             ty::Slice(ty) => Slice(box ty.clean(cx)),
             ty::Array(ty, n) => {
-                let mut n = cx.tcx.lift(&n).expect("array lift failed");
-                if let ConstValue::Unevaluated(def_id, substs) = n.val {
+                let mut n = *cx.tcx.lift(&n).expect("array lift failed");
+                if let ty::LazyConst::Unevaluated(def_id, substs) = n {
                     let param_env = cx.tcx.param_env(def_id);
                     let cid = GlobalId {
                         instance: ty::Instance::new(def_id, substs),
                         promoted: None
                     };
                     if let Ok(new_n) = cx.tcx.const_eval(param_env.and(cid)) {
-                        n = new_n;
+                        n = ty::LazyConst::Evaluated(new_n);
                     }
                 };
                 let n = print_const(cx, n);
@@ -3691,16 +3690,16 @@ fn name_from_pat(p: &hir::Pat) -> String {
     }
 }
 
-fn print_const(cx: &DocContext, n: &ty::Const) -> String {
-    match n.val {
-        ConstValue::Unevaluated(def_id, _) => {
+fn print_const(cx: &DocContext, n: ty::LazyConst) -> String {
+    match n {
+        ty::LazyConst::Unevaluated(def_id, _) => {
             if let Some(node_id) = cx.tcx.hir().as_local_node_id(def_id) {
                 print_const_expr(cx, cx.tcx.hir().body_owned_by(node_id))
             } else {
                 inline::print_inlined_const(cx, def_id)
             }
         },
-        _ => {
+        ty::LazyConst::Evaluated(n) => {
             let mut s = String::new();
             ::rustc::mir::fmt_const_val(&mut s, n).expect("fmt_const_val failed");
             // array lengths are obviously usize