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:
commit
d6d32ac25d
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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> {
|
||||
|
@ -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),
|
||||
|
@ -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;
|
||||
|
@ -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>) {
|
||||
|
@ -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)),
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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]
|
||||
|
@ -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(),
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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};
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)))
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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> {}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) => {
|
||||
|
@ -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, "]")
|
||||
|
@ -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| {
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
..
|
||||
},
|
||||
..
|
||||
},
|
||||
}),
|
||||
..
|
||||
}),
|
||||
..
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
);
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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>,
|
||||
},
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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>(
|
||||
|
@ -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,
|
||||
}
|
||||
},
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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])
|
||||
}
|
||||
|
@ -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))
|
||||
},
|
||||
|
@ -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),
|
||||
)),
|
||||
})))
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 }
|
||||
},
|
||||
|
@ -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())
|
||||
)),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user