Auto merge of #56723 - oli-obk:lazy_const, r=nikomatsakis

Don't emit `Unevaluated` from `const_eval`

cc @eddyb @RalfJung
This commit is contained in:
bors 2019-01-04 17:01:24 +00:00
commit d6d32ac25d
56 changed files with 496 additions and 594 deletions

View File

@ -119,6 +119,11 @@ impl<T> Default for TypedArena<T> {
}
impl<T> TypedArena<T> {
pub fn in_arena(&self, ptr: *const T) -> bool {
let ptr = ptr as *const T as *mut T;
self.chunks.borrow().iter().any(|chunk| chunk.start() <= ptr && ptr < chunk.end())
}
/// Allocates an object in the `TypedArena`, returning a reference to it.
#[inline]
pub fn alloc(&self, object: T) -> &mut T {

View File

@ -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

View File

@ -37,7 +37,7 @@ impl ErrorHandled {
}
pub type ConstEvalRawResult<'tcx> = Result<RawConst<'tcx>, ErrorHandled>;
pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ErrorHandled>;
pub type ConstEvalResult<'tcx> = Result<ty::Const<'tcx>, ErrorHandled>;
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct ConstEvalErr<'tcx> {

View File

@ -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),

View File

@ -1666,7 +1666,7 @@ impl<'tcx> TerminatorKind<'tcx> {
),
ty: switch_ty,
};
fmt_const_val(&mut s, &c).unwrap();
fmt_const_val(&mut s, c).unwrap();
s.into()
}).chain(iter::once("otherwise".into()))
.collect()
@ -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(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,12 +2657,20 @@ 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_const_val(f: &mut impl Write, const_val: &ty::Const<'_>) -> fmt::Result {
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),
}
}
/// Write a `ConstValue` in a way closer to the original source code than the `Debug` output.
pub fn fmt_const_val(f: &mut impl Write, const_val: ty::Const<'_>) -> fmt::Result {
use ty::TyKind::*;
let value = const_val.val;
let ty = const_val.ty;

View File

@ -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>) {

View File

@ -418,9 +418,7 @@ 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()
}) {
if let Some(len) = len.assert_usize(tcx) {
flags.push((
"_Self".to_owned(),
Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)),

View File

@ -15,7 +15,6 @@ use super::util;
use hir::def_id::DefId;
use infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
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;
@ -394,8 +393,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() {
@ -407,8 +406,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 {
@ -420,7 +420,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));
}
}
}

View File

@ -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));
}
}
}

View File

@ -247,12 +247,12 @@ pub fn decode_canonical_var_infos<'a, 'tcx, D>(decoder: &mut D)
}
#[inline]
pub fn decode_const<'a, 'tcx, D>(decoder: &mut D)
-> Result<&'tcx ty::Const<'tcx>, D::Error>
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().mk_const(Decodable::decode(decoder)?))
Ok(decoder.tcx().intern_lazy_const(Decodable::decode(decoder)?))
}
#[inline]
@ -389,10 +389,10 @@ macro_rules! implement_ty_decoder {
}
}
impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::ty::Const<'tcx>>
impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::ty::LazyConst<'tcx>>
for $DecoderName<$($typaram),*> {
fn specialized_decode(&mut self) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
decode_const(self)
fn specialized_decode(&mut self) -> Result<&'tcx ty::LazyConst<'tcx>, Self::Error> {
decode_lazy_const(self)
}
}

View File

@ -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};
@ -122,7 +122,6 @@ pub struct CtxtInterners<'tcx> {
region: InternedSet<'tcx, RegionKind>,
existential_predicates: InternedSet<'tcx, List<ExistentialPredicate<'tcx>>>,
predicates: InternedSet<'tcx, List<Predicate<'tcx>>>,
const_: InternedSet<'tcx, Const<'tcx>>,
clauses: InternedSet<'tcx, List<Clause<'tcx>>>,
goal: InternedSet<'tcx, GoalKind<'tcx>>,
goal_list: InternedSet<'tcx, List<Goal<'tcx>>>,
@ -140,7 +139,6 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
existential_predicates: Default::default(),
canonical_var_infos: Default::default(),
predicates: Default::default(),
const_: Default::default(),
clauses: Default::default(),
goal: Default::default(),
goal_list: Default::default(),
@ -1063,32 +1061,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.global_arenas.adt_def.alloc(def)
}
pub fn alloc_byte_array(self, bytes: &[u8]) -> &'gcx [u8] {
if bytes.is_empty() {
&[]
} else {
self.global_interners.arena.alloc_slice(bytes)
}
}
pub fn alloc_const_slice(self, values: &[&'tcx ty::Const<'tcx>])
-> &'tcx [&'tcx ty::Const<'tcx>] {
if values.is_empty() {
&[]
} else {
self.interners.arena.alloc_slice(values)
}
}
pub fn alloc_name_const_slice(self, values: &[(ast::Name, &'tcx ty::Const<'tcx>)])
-> &'tcx [(ast::Name, &'tcx ty::Const<'tcx>)] {
if values.is_empty() {
&[]
} else {
self.interners.arena.alloc_slice(values)
}
}
pub fn intern_const_alloc(
self,
alloc: Allocation,
@ -1112,6 +1084,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)
@ -1725,218 +1701,69 @@ pub trait Lift<'tcx>: fmt::Debug {
fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted>;
}
impl<'a, 'tcx> Lift<'tcx> for Ty<'a> {
type Lifted = Ty<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Ty<'tcx>> {
if tcx.interners.arena.in_arena(*self as *const _) {
return Some(unsafe { mem::transmute(*self) });
macro_rules! nop_lift {
($ty:ty => $lifted:ty) => {
impl<'a, 'tcx> Lift<'tcx> for $ty {
type Lifted = $lifted;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
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
}
}
}
// 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 Region<'a> {
type Lifted = Region<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Region<'tcx>> {
if tcx.interners.arena.in_arena(*self as *const _) {
return Some(unsafe { mem::transmute(*self) });
macro_rules! nop_list_lift {
($ty:ty => $lifted:ty) => {
impl<'a, 'tcx> Lift<'tcx> for &'a List<$ty> {
type Lifted = &'tcx List<$lifted>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
if self.is_empty() {
return Some(List::empty());
}
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
}
}
}
// 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 Goal<'a> {
type Lifted = Goal<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Goal<'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
}
}
}
nop_lift!{Ty<'a> => Ty<'tcx>}
nop_lift!{Region<'a> => Region<'tcx>}
nop_lift!{Goal<'a> => Goal<'tcx>}
nop_lift!{&'a LazyConst<'a> => &'tcx LazyConst<'tcx>}
impl<'a, 'tcx> Lift<'tcx> for &'a List<Goal<'a>> {
type Lifted = &'tcx List<Goal<'tcx>>;
fn lift_to_tcx<'b, 'gcx>(
&self,
tcx: TyCtxt<'b, 'gcx, 'tcx>,
) -> Option<&'tcx List<Goal<'tcx>>> {
if self.is_empty() {
return Some(List::empty());
}
nop_list_lift!{Goal<'a> => Goal<'tcx>}
nop_list_lift!{Clause<'a> => Clause<'tcx>}
nop_list_lift!{Ty<'a> => Ty<'tcx>}
nop_list_lift!{ExistentialPredicate<'a> => ExistentialPredicate<'tcx>}
nop_list_lift!{Predicate<'a> => Predicate<'tcx>}
nop_list_lift!{CanonicalVarInfo => CanonicalVarInfo}
nop_list_lift!{ProjectionKind<'a> => ProjectionKind<'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
}
}
}
// this is the impl for `&'a Substs<'a>`
nop_list_lift!{Kind<'a> => Kind<'tcx>}
impl<'a, 'tcx> Lift<'tcx> for &'a List<Clause<'a>> {
type Lifted = &'tcx List<Clause<'tcx>>;
fn lift_to_tcx<'b, 'gcx>(
&self,
tcx: TyCtxt<'b, 'gcx, 'tcx>,
) -> Option<&'tcx List<Clause<'tcx>>> {
if self.is_empty() {
return Some(List::empty());
}
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>> {
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 Substs<'a> {
type Lifted = &'tcx Substs<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Substs<'tcx>> {
if self.len() == 0 {
return Some(List::empty());
}
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 List<Ty<'a>> {
type Lifted = &'tcx List<Ty<'tcx>>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
-> Option<&'tcx List<Ty<'tcx>>> {
if self.len() == 0 {
return Some(List::empty());
}
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 List<ExistentialPredicate<'a>> {
type Lifted = &'tcx List<ExistentialPredicate<'tcx>>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
-> Option<&'tcx List<ExistentialPredicate<'tcx>>> {
if self.is_empty() {
return Some(List::empty());
}
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 List<Predicate<'a>> {
type Lifted = &'tcx List<Predicate<'tcx>>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
-> Option<&'tcx List<Predicate<'tcx>>> {
if self.is_empty() {
return Some(List::empty());
}
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 List<CanonicalVarInfo> {
type Lifted = &'tcx List<CanonicalVarInfo>;
impl<'a, 'tcx> Lift<'tcx> for &'a mir::interpret::Allocation {
type Lifted = &'tcx mir::interpret::Allocation;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
if self.len() == 0 {
return Some(List::empty());
}
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 List<ProjectionKind<'a>> {
type Lifted = &'tcx List<ProjectionKind<'tcx>>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
if self.len() == 0 {
return Some(List::empty());
}
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
}
assert!(tcx.global_arenas.const_allocs.in_arena(*self as *const _));
Some(unsafe { mem::transmute(*self) })
}
}
@ -2497,7 +2324,6 @@ pub fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool {
direct_interners!('tcx,
region: mk_region(|r: &RegionKind| r.keep_in_local_tcx()) -> RegionKind,
const_: mk_const(|c: &Const<'_>| keep_local(&c.ty) || keep_local(&c.val)) -> Const<'tcx>,
goal: mk_goal(|c: &GoalKind<'_>| keep_local(c)) -> GoalKind<'tcx>
);
@ -2683,7 +2509,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]

View File

@ -157,11 +157,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(),

View File

@ -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);

View File

@ -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) {

View File

@ -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()
},
}
}

View File

@ -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};

View File

@ -136,7 +136,7 @@ impl<'tcx> Key for ty::PolyTraitRef<'tcx>{
}
}
impl<'tcx> Key for &'tcx ty::Const<'tcx> {
impl<'tcx> Key for ty::Const<'tcx> {
fn query_crate(&self) -> CrateNum {
LOCAL_CRATE
}

View File

@ -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)))

View File

@ -486,6 +486,26 @@ BraceStructLiftImpl! {
}
}
BraceStructLiftImpl! {
impl<'a, 'tcx> Lift<'tcx> for ty::Const<'a> {
type Lifted = ty::Const<'tcx>;
val, ty
}
}
impl<'a, 'tcx> Lift<'tcx> for ConstValue<'a> {
type Lifted = ConstValue<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
match *self {
ConstValue::Scalar(x) => Some(ConstValue::Scalar(x)),
ConstValue::ScalarPair(x, y) => Some(ConstValue::ScalarPair(x, y)),
ConstValue::ByRef(x, alloc, z) => Some(ConstValue::ByRef(
x, alloc.lift_to_tcx(tcx)?, z,
)),
}
}
}
///////////////////////////////////////////////////////////////////////////
// TypeFoldable implementations.
//
@ -1014,36 +1034,15 @@ 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))
}
}
}
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),
}
}
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
let ty = self.ty.fold_with(folder);
let val = self.val.fold_with(folder);
folder.tcx().mk_const(ty::Const {
ty,
val
})
};
folder.tcx().intern_lazy_const(new)
}
fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
@ -1051,10 +1050,38 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> {
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.ty.visit_with(visitor) || self.val.visit_with(visitor)
match *self {
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 ty::Const<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
let ty = self.ty.fold_with(folder);
let val = self.val.fold_with(folder);
ty::Const {
ty,
val
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.ty.visit_with(visitor) || self.val.visit_with(visitor)
}
}
impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self {
*self
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool {
false
}
}

View File

@ -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>),
@ -2020,6 +2020,32 @@ 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(Const<'tcx>),
}
impl<'tcx> LazyConst<'tcx> {
pub fn map_evaluated<R>(self, f: impl FnOnce(Const<'tcx>) -> Option<R>) -> Option<R> {
match self {
LazyConst::Evaluated(c) => f(c),
LazyConst::Unevaluated(..) => None,
}
}
pub fn assert_usize(self, tcx: TyCtxt<'_, '_, '_>) -> Option<u64> {
self.map_evaluated(|c| c.assert_usize(tcx))
}
#[inline]
pub fn unwrap_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> u64 {
self.assert_usize(tcx).expect("expected `LazyConst` to contain a usize")
}
}
/// Typed constant value.
#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq, Ord, PartialOrd)]
pub struct Const<'tcx> {
@ -2029,37 +2055,15 @@ 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>,
val: ConstValue<'tcx>,
ty: Ty<'tcx>,
) -> &'tcx Self {
tcx.mk_const(Const {
val,
ty,
})
}
#[inline]
pub fn from_scalar(
tcx: TyCtxt<'_, '_, 'tcx>,
val: Scalar,
ty: Ty<'tcx>,
) -> &'tcx Self {
Self::from_const_value(tcx, ConstValue::Scalar(val), ty)
) -> Self {
Self {
val: ConstValue::Scalar(val),
ty,
}
}
#[inline]
@ -2067,7 +2071,7 @@ impl<'tcx> Const<'tcx> {
tcx: TyCtxt<'_, '_, 'tcx>,
bits: u128,
ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
) -> &'tcx Self {
) -> Self {
let ty = tcx.lift_to_global(&ty).unwrap();
let size = tcx.layout_of(ty).unwrap_or_else(|e| {
panic!("could not compute layout for {:?}: {:?}", ty, e)
@ -2075,21 +2079,21 @@ impl<'tcx> Const<'tcx> {
let shift = 128 - size.bits();
let truncated = (bits << shift) >> shift;
assert_eq!(truncated, bits, "from_bits called with untruncated value");
Self::from_scalar(tcx, Scalar::Bits { bits, size: size.bytes() as u8 }, ty.value)
Self::from_scalar(Scalar::Bits { bits, size: size.bytes() as u8 }, ty.value)
}
#[inline]
pub fn zero_sized(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> &'tcx Self {
Self::from_scalar(tcx, Scalar::Bits { bits: 0, size: 0 }, ty)
pub fn zero_sized(ty: Ty<'tcx>) -> Self {
Self::from_scalar(Scalar::Bits { bits: 0, size: 0 }, ty)
}
#[inline]
pub fn from_bool(tcx: TyCtxt<'_, '_, 'tcx>, v: bool) -> &'tcx Self {
pub fn from_bool(tcx: TyCtxt<'_, '_, 'tcx>, v: bool) -> Self {
Self::from_bits(tcx, v as u128, ParamEnv::empty().and(tcx.types.bool))
}
#[inline]
pub fn from_usize(tcx: TyCtxt<'_, '_, 'tcx>, n: u64) -> &'tcx Self {
pub fn from_usize(tcx: TyCtxt<'_, '_, 'tcx>, n: u64) -> Self {
Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize))
}
@ -2155,4 +2159,4 @@ impl<'tcx> Const<'tcx> {
}
}
impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Const<'tcx> {}
impl<'tcx> serialize::UseSpecializedDecodable for &'tcx LazyConst<'tcx> {}

View File

@ -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);
}

View File

@ -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) => {

View File

@ -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};
@ -1412,12 +1411,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, "]")

View File

@ -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>,
) -> Result<&'tcx ty::Const<'tcx>, ErrorHandled> {
match constant.val {
ConstValue::Unevaluated(def_id, ref substs) => {
constant: &'tcx ty::LazyConst<'tcx>,
) -> Result<ty::Const<'tcx>, ErrorHandled> {
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),
}
}
@ -35,7 +35,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
&mut self,
bx: &Bx,
constant: &mir::Constant<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, ErrorHandled> {
) -> Result<ty::Const<'tcx>, ErrorHandled> {
let c = self.monomorphize(&constant.literal);
self.fully_evaluate(bx, c)
}
@ -46,7 +46,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
bx: &Bx,
span: Span,
ty: Ty<'tcx>,
constant: Result<&'tcx ty::Const<'tcx>, ErrorHandled>,
constant: Result<ty::Const<'tcx>, ErrorHandled>,
) -> (Bx::Value, Ty<'tcx>) {
constant
.and_then(|c| {

View File

@ -67,7 +67,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> {
pub fn from_const<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
bx: &mut Bx,
val: &'tcx ty::Const<'tcx>
val: ty::Const<'tcx>
) -> Result<Self, ErrorHandled> {
let layout = bx.cx().layout_of(val.ty);
@ -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,

View File

@ -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,

View File

@ -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),
..
},
..
},
}),
..
}),
..

View File

@ -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);
}

View File

@ -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,
);

View File

@ -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)
}

View File

@ -658,12 +658,12 @@ enum TestKind<'tcx> {
SwitchInt {
switch_ty: Ty<'tcx>,
options: Vec<u128>,
indices: FxHashMap<&'tcx ty::Const<'tcx>, usize>,
indices: FxHashMap<ty::Const<'tcx>, usize>,
},
// test for equality
Eq {
value: &'tcx ty::Const<'tcx>,
value: ty::Const<'tcx>,
ty: Ty<'tcx>,
},

View File

@ -101,7 +101,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
candidate: &Candidate<'pat, 'tcx>,
switch_ty: Ty<'tcx>,
options: &mut Vec<u128>,
indices: &mut FxHashMap<&'tcx ty::Const<'tcx>, usize>)
indices: &mut FxHashMap<ty::Const<'tcx>, usize>)
-> bool
{
let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) {
@ -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();
@ -657,7 +658,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}
}
(&TestKind::Range(range), &PatternKind::Constant { ref value }) => {
(&TestKind::Range(range), &PatternKind::Constant { value }) => {
if self.const_range_contains(range, value) == Some(false) {
// `value` is not contained in the testing range,
// so `value` can be matched only if this test fails.
@ -786,7 +787,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
fn const_range_contains(
&self,
range: PatternRange<'tcx>,
value: &'tcx ty::Const<'tcx>,
value: ty::Const<'tcx>,
) -> Option<bool> {
use std::cmp::Ordering::*;
@ -806,9 +807,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
fn values_not_contained_in_range(
&self,
range: PatternRange<'tcx>,
indices: &FxHashMap<&'tcx ty::Const<'tcx>, usize>,
indices: &FxHashMap<ty::Const<'tcx>, usize>,
) -> Option<bool> {
for val in indices.keys() {
for &val in indices.keys() {
if self.const_range_contains(range, val)? {
return Some(false);
}

View File

@ -27,13 +27,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
pub fn literal_operand(&mut self,
span: Span,
ty: Ty<'tcx>,
literal: &'tcx ty::Const<'tcx>)
literal: ty::Const<'tcx>)
-> Operand<'tcx> {
let constant = box Constant {
span,
ty,
user_ty: None,
literal,
literal: self.hir.tcx().intern_lazy_const(ty::LazyConst::Evaluated(literal)),
};
Operand::Constant(constant)
}

View File

@ -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 {

View File

@ -95,7 +95,7 @@ pub fn op_to_const<'tcx>(
ecx: &CompileTimeEvalContext<'_, '_, 'tcx>,
op: OpTy<'tcx>,
may_normalize: bool,
) -> EvalResult<'tcx, &'tcx ty::Const<'tcx>> {
) -> EvalResult<'tcx, ty::Const<'tcx>> {
// We do not normalize just any data. Only scalar layout and fat pointers.
let normalize = may_normalize
&& match op.layout.abi {
@ -134,14 +134,16 @@ pub fn op_to_const<'tcx>(
Ok(Immediate::ScalarPair(a, b)) =>
ConstValue::ScalarPair(a.not_undef()?, b.not_undef()?),
};
Ok(ty::Const::from_const_value(ecx.tcx.tcx, val, op.layout.ty))
Ok(ty::Const { val, ty: op.layout.ty })
}
pub fn const_to_op<'tcx>(
pub fn lazy_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>(
@ -508,13 +510,13 @@ pub fn const_field<'a, 'tcx>(
instance: ty::Instance<'tcx>,
variant: Option<VariantIdx>,
field: mir::Field,
value: &'tcx ty::Const<'tcx>,
value: ty::Const<'tcx>,
) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
trace!("const_field: {:?}, {:?}, {:?}", instance, field, value);
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 = lazy_const_to_op(&ecx, ty::LazyConst::Evaluated(value), value.ty)?;
// downcast
let down = match variant {
None => op,
@ -537,11 +539,11 @@ pub fn const_variant_index<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
instance: ty::Instance<'tcx>,
val: &'tcx ty::Const<'tcx>,
val: ty::Const<'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 = lazy_const_to_op(&ecx, ty::LazyConst::Evaluated(val), val.ty)?;
Ok(ecx.read_discriminant(op)?.1)
}

View File

@ -14,7 +14,7 @@ crate fn lit_to_const<'a, 'gcx, 'tcx>(
tcx: TyCtxt<'a, 'gcx, 'tcx>,
ty: Ty<'tcx>,
neg: bool,
) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> {
) -> Result<ty::Const<'tcx>, LitToConstError> {
use syntax::ast::*;
let trunc = |n| {
@ -64,7 +64,7 @@ crate fn lit_to_const<'a, 'gcx, 'tcx>(
LitKind::Bool(b) => ConstValue::Scalar(Scalar::from_bool(b)),
LitKind::Char(c) => ConstValue::Scalar(Scalar::from_char(c)),
};
Ok(ty::Const::from_const_value(tcx, lit, ty))
Ok(ty::Const { val: lit, ty })
}
fn parse_float<'tcx>(

View File

@ -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(ty)
)),
user_ty,
},
}
@ -928,10 +932,9 @@ 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(
cx.tcx,
literal: cx.tcx.intern_lazy_const(ty::LazyConst::Evaluated(ty::Const::zero_sized(
cx.tables().node_id_to_type(expr.hir_id),
),
))),
user_ty,
}
},
@ -941,12 +944,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,
}
},

View File

@ -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(
@ -134,7 +134,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
ty: Ty<'tcx>,
sp: Span,
neg: bool,
) -> &'tcx ty::Const<'tcx> {
) -> ty::Const<'tcx> {
trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg);
match lit_to_const(lit, self.tcx, ty, neg) {
@ -169,14 +169,14 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
method_name: &str,
self_ty: Ty<'tcx>,
params: &[Kind<'tcx>])
-> (Ty<'tcx>, &'tcx ty::Const<'tcx>) {
-> (Ty<'tcx>, ty::Const<'tcx>) {
let method_name = Symbol::intern(method_name);
let substs = self.tcx.mk_substs_trait(self_ty, params);
for item in self.tcx.associated_items(trait_def_id) {
if item.kind == ty::AssociatedKind::Method && item.ident.name == method_name {
let method_ty = self.tcx.type_of(item.def_id);
let method_ty = method_ty.subst(self.tcx, substs);
return (method_ty, ty::Const::zero_sized(self.tcx, method_ty));
return (method_ty, ty::Const::zero_sized(method_ty));
}
}

View File

@ -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 {

View File

@ -223,7 +223,7 @@ impl<'a, 'tcx> LiteralExpander<'a, 'tcx> {
assert_eq!(t, u);
ConstValue::ScalarPair(
Scalar::Ptr(p),
n.val.try_to_scalar().unwrap(),
n.map_evaluated(|val| val.val.try_to_scalar()).unwrap(),
)
},
// fat pointers stay the same
@ -251,11 +251,10 @@ impl<'a, 'tcx> PatternFolder<'tcx> for LiteralExpander<'a, 'tcx> {
subpattern: Pattern {
ty: rty,
span: pat.span,
kind: box PatternKind::Constant { value: Const::from_const_value(
self.tcx,
self.fold_const_value_deref(*val, rty, crty),
rty,
) },
kind: box PatternKind::Constant { value: Const {
val: self.fold_const_value_deref(val, rty, crty),
ty: rty,
} },
}
}
}
@ -420,7 +419,7 @@ pub enum Constructor<'tcx> {
/// Enum variants.
Variant(DefId),
/// Literal values.
ConstantValue(&'tcx ty::Const<'tcx>),
ConstantValue(ty::Const<'tcx>),
/// Ranges of literal values (`2...5` and `2..5`).
ConstantRange(u128, u128, Ty<'tcx>, RangeEnd),
/// Array patterns of length n.
@ -1396,7 +1395,7 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
fn slice_pat_covered_by_const<'tcx>(
tcx: TyCtxt<'_, 'tcx, '_>,
_span: Span,
const_val: &ty::Const<'tcx>,
const_val: ty::Const<'tcx>,
prefix: &[Pattern<'tcx>],
slice: &Option<Pattern<'tcx>>,
suffix: &[Pattern<'tcx>]
@ -1751,23 +1750,37 @@ 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.sty {
ty::TyKind::Array(t, n) => {
match value.val {
ConstValue::ByRef(id, alloc, offset) => (
Some((Pointer::new(id, offset), alloc)),
n.unwrap_usize(cx.tcx),
t,
),
_ => span_bug!(
pat.span,
"array pattern is {:?}", value,
),
}
},
ty::TyKind::Slice(t) => {
match value.val {
ConstValue::ScalarPair(ptr, n) => (
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,
),
_ => span_bug!(
pat.span,
"slice pattern constant must be scalar pair but is {:?}",
value,
),
}
},
_ => span_bug!(
pat.span,
"unexpected const-val {:?} with ctor {:?}",
@ -1787,7 +1800,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
&cx.tcx, ptr, layout.size,
).ok()?;
let scalar = scalar.not_undef().ok()?;
let value = ty::Const::from_scalar(cx.tcx, scalar, ty);
let value = ty::Const::from_scalar(scalar, ty);
let pattern = Pattern {
ty,
span: pat.span,

View File

@ -123,7 +123,7 @@ pub enum PatternKind<'tcx> {
},
Constant {
value: &'tcx ty::Const<'tcx>,
value: ty::Const<'tcx>,
},
Range(PatternRange<'tcx>),
@ -147,8 +147,8 @@ pub enum PatternKind<'tcx> {
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct PatternRange<'tcx> {
pub lo: &'tcx ty::Const<'tcx>,
pub hi: &'tcx ty::Const<'tcx>,
pub lo: ty::Const<'tcx>,
pub hi: ty::Const<'tcx>,
pub ty: Ty<'tcx>,
pub end: RangeEnd,
}
@ -857,7 +857,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
fn const_to_pat(
&self,
instance: ty::Instance<'tcx>,
cv: &'tcx ty::Const<'tcx>,
cv: ty::Const<'tcx>,
id: hir::HirId,
span: Span,
) -> Pattern<'tcx> {
@ -1018,7 +1018,7 @@ macro_rules! CloneImpls {
}
CloneImpls!{ <'tcx>
Span, Field, Mutability, ast::Name, ast::NodeId, usize, &'tcx ty::Const<'tcx>,
Span, Field, Mutability, ast::Name, ast::NodeId, usize, ty::Const<'tcx>,
Region<'tcx>, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
&'tcx Substs<'tcx>, &'tcx Kind<'tcx>, UserTypeAnnotation<'tcx>,
UserTypeProjection<'tcx>, PatternTypeProjection<'tcx>
@ -1140,8 +1140,8 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
pub fn compare_const_vals<'a, 'gcx, 'tcx>(
tcx: TyCtxt<'a, 'gcx, 'tcx>,
a: &'tcx ty::Const<'tcx>,
b: &'tcx ty::Const<'tcx>,
a: ty::Const<'tcx>,
b: ty::Const<'tcx>,
ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
) -> Option<Ordering> {
trace!("compare_const_vals: {:?}, {:?}", a, b);

View File

@ -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.

View File

@ -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_const<'a, 'tcx>(
fn collect_lazy_const<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
constant: &ty::Const<'tcx>,
constant: &ty::LazyConst<'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,
let (def_id, substs) = match *constant {
ty::LazyConst::Evaluated(c) => return collect_const(tcx, c, output),
ty::LazyConst::Unevaluated(did, substs) => (did, substs),
};
match val {
ConstValue::Unevaluated(..) => bug!("const eval yielded unevaluated const"),
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>,
output: &mut Vec<MonoItem<'tcx>>,
) {
debug!("visiting const {:?}", constant);
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);

View File

@ -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(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(ty)
)),
}),
vec![rcvr])
}

View File

@ -20,7 +20,8 @@ use rustc::ty::layout::{
use interpret::{self, EvalContext, ScalarMaybeUndef, Immediate, OpTy, MemoryKind};
use const_eval::{
CompileTimeInterpreter, const_to_op, error_to_const_error, eval_promoted, mk_borrowck_eval_cx
CompileTimeInterpreter, error_to_const_error, eval_promoted, mk_borrowck_eval_cx,
lazy_const_to_op,
};
use transform::{MirPass, MirSource};
@ -255,7 +256,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 lazy_const_to_op(&self.ecx, *c.literal, c.ty) {
Ok(op) => {
Some((op, c.span))
},

View File

@ -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),
)),
})))
}

View File

@ -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);
}

View File

@ -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,

View File

@ -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);
}
}
}

View File

@ -30,11 +30,12 @@ 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 constant = c.literal.map_evaluated(|c| c.assert_bits(tcx, switch_ty));
if let Some(constant) = constant {
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 {
if v == constant {
ret = TerminatorKind::Goto { target: *t };
break;
}
@ -46,9 +47,8 @@ impl MirPass for SimplifyBranches {
},
TerminatorKind::Assert {
target, cond: Operand::Constant(ref c), expected, ..
} if (c.literal.assert_bool(tcx) == Some(true)) == expected => {
TerminatorKind::Goto { target }
},
} if (c.literal.map_evaluated(|e| e.assert_bool(tcx)) == Some(true)) == expected =>
TerminatorKind::Goto { target },
TerminatorKind::FalseEdges { real_target, .. } => {
TerminatorKind::Goto { target: real_target }
},

View File

@ -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())
)),
})
}

View File

@ -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) {

View File

@ -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));

View File

@ -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)
}

View File

@ -4472,7 +4472,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
}

View File

@ -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