introduce ty::Value
Co-authored-by: FedericoBruzzone <federico.bruzzone.i@gmail.com>
This commit is contained in:
parent
5a45ab9738
commit
10fc0b159e
44 changed files with 214 additions and 205 deletions
|
@ -129,12 +129,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
return;
|
||||
}
|
||||
|
||||
let idx = generic_args[2]
|
||||
.expect_const()
|
||||
.try_to_valtree()
|
||||
.expect("expected monomorphic const in codegen")
|
||||
.0
|
||||
.unwrap_branch();
|
||||
let idx = generic_args[2].expect_const().to_value().valtree.unwrap_branch();
|
||||
|
||||
assert_eq!(x.layout(), y.layout());
|
||||
let layout = x.layout();
|
||||
|
|
|
@ -1329,7 +1329,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
}
|
||||
|
||||
if name == sym::simd_shuffle_generic {
|
||||
let idx = fn_args[2].expect_const().try_to_valtree().unwrap().0.unwrap_branch();
|
||||
let idx = fn_args[2].expect_const().to_value().valtree.unwrap_branch();
|
||||
let n = idx.len() as u64;
|
||||
|
||||
let (out_len, out_ty) = require_simd!(ret_ty, SimdReturn);
|
||||
|
|
|
@ -673,25 +673,23 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
|
|||
ty::ConstKind::Param(param) => {
|
||||
write!(output, "{}", param.name)
|
||||
}
|
||||
ty::ConstKind::Value(ty, valtree) => {
|
||||
match ty.kind() {
|
||||
ty::ConstKind::Value(cv) => {
|
||||
match cv.ty.kind() {
|
||||
ty::Int(ity) => {
|
||||
// FIXME: directly extract the bits from a valtree instead of evaluating an
|
||||
// already evaluated `Const` in order to get the bits.
|
||||
let bits = ct
|
||||
let bits = cv
|
||||
.try_to_bits(tcx, ty::TypingEnv::fully_monomorphized())
|
||||
.expect("expected monomorphic const in codegen");
|
||||
let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
|
||||
write!(output, "{val}")
|
||||
}
|
||||
ty::Uint(_) => {
|
||||
let val = ct
|
||||
let val = cv
|
||||
.try_to_bits(tcx, ty::TypingEnv::fully_monomorphized())
|
||||
.expect("expected monomorphic const in codegen");
|
||||
write!(output, "{val}")
|
||||
}
|
||||
ty::Bool => {
|
||||
let val = ct.try_to_bool().expect("expected monomorphic const in codegen");
|
||||
let val = cv.try_to_bool().expect("expected monomorphic const in codegen");
|
||||
write!(output, "{val}")
|
||||
}
|
||||
_ => {
|
||||
|
@ -703,9 +701,7 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
|
|||
// avoiding collisions and will make the emitted type names shorter.
|
||||
let hash_short = tcx.with_stable_hashing_context(|mut hcx| {
|
||||
let mut hasher = StableHasher::new();
|
||||
hcx.while_hashing_spans(false, |hcx| {
|
||||
(ty, valtree).hash_stable(hcx, &mut hasher)
|
||||
});
|
||||
hcx.while_hashing_spans(false, |hcx| cv.hash_stable(hcx, &mut hasher));
|
||||
hasher.finish::<Hash64>()
|
||||
});
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
mir::Const::Ty(_, c) => match c.kind() {
|
||||
// A constant that came from a const generic but was then used as an argument to
|
||||
// old-style simd_shuffle (passing as argument instead of as a generic param).
|
||||
rustc_type_ir::ConstKind::Value(_, valtree) => return Ok(Ok(valtree)),
|
||||
rustc_type_ir::ConstKind::Value(cv) => return Ok(Ok(cv.valtree)),
|
||||
other => span_bug!(constant.span, "{other:#?}"),
|
||||
},
|
||||
// We should never encounter `Const::Val` unless MIR opts (like const prop) evaluate
|
||||
|
|
|
@ -345,7 +345,7 @@ where
|
|||
Const::Ty(_, ct)
|
||||
if matches!(
|
||||
ct.kind(),
|
||||
ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_, _)
|
||||
ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_)
|
||||
) =>
|
||||
{
|
||||
None
|
||||
|
|
|
@ -46,8 +46,13 @@ pub fn provide(providers: &mut Providers) {
|
|||
};
|
||||
providers.hooks.try_destructure_mir_constant_for_user_output =
|
||||
const_eval::try_destructure_mir_constant_for_user_output;
|
||||
providers.valtree_to_const_val = |tcx, (ty, valtree)| {
|
||||
const_eval::valtree_to_const_value(tcx, ty::TypingEnv::fully_monomorphized(), ty, valtree)
|
||||
providers.valtree_to_const_val = |tcx, cv| {
|
||||
const_eval::valtree_to_const_value(
|
||||
tcx,
|
||||
ty::TypingEnv::fully_monomorphized(),
|
||||
cv.ty,
|
||||
cv.valtree,
|
||||
)
|
||||
};
|
||||
providers.check_validity_requirement = |tcx, (init_kind, param_env_and_ty)| {
|
||||
util::check_validity_requirement(tcx, init_kind, param_env_and_ty)
|
||||
|
|
|
@ -170,7 +170,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
|
|||
}
|
||||
|
||||
ty::ConstKind::Param(_)
|
||||
| ty::ConstKind::Value(_, _)
|
||||
| ty::ConstKind::Value(_)
|
||||
| ty::ConstKind::Unevaluated(..)
|
||||
| ty::ConstKind::Expr(..)
|
||||
| ty::ConstKind::Error(_) => ct.super_fold_with(self),
|
||||
|
|
|
@ -1055,7 +1055,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
| ty::ConstKind::Bound(_, _)
|
||||
| ty::ConstKind::Placeholder(_)
|
||||
| ty::ConstKind::Unevaluated(_)
|
||||
| ty::ConstKind::Value(_, _)
|
||||
| ty::ConstKind::Value(_)
|
||||
| ty::ConstKind::Error(_)
|
||||
| ty::ConstKind::Expr(_) => ct,
|
||||
}
|
||||
|
|
|
@ -250,7 +250,7 @@ impl<'tcx> Const<'tcx> {
|
|||
// Dont use the outer ty as on invalid code we can wind up with them not being the same.
|
||||
// this then results in allowing const eval to add `1_i64 + 1_usize` in cases where the mir
|
||||
// was originally `({N: usize} + 1_usize)` under `generic_const_exprs`.
|
||||
ty::ConstKind::Value(ty, _) => ty,
|
||||
ty::ConstKind::Value(cv) => cv.ty,
|
||||
_ => *ty,
|
||||
}
|
||||
}
|
||||
|
@ -264,7 +264,7 @@ impl<'tcx> Const<'tcx> {
|
|||
pub fn is_required_const(&self) -> bool {
|
||||
match self {
|
||||
Const::Ty(_, c) => match c.kind() {
|
||||
ty::ConstKind::Value(_, _) => false, // already a value, cannot error
|
||||
ty::ConstKind::Value(_) => false, // already a value, cannot error
|
||||
_ => true,
|
||||
},
|
||||
Const::Val(..) => false, // already a value, cannot error
|
||||
|
@ -276,11 +276,11 @@ impl<'tcx> Const<'tcx> {
|
|||
pub fn try_to_scalar(self) -> Option<Scalar> {
|
||||
match self {
|
||||
Const::Ty(_, c) => match c.kind() {
|
||||
ty::ConstKind::Value(ty, valtree) if ty.is_primitive() => {
|
||||
ty::ConstKind::Value(cv) if cv.ty.is_primitive() => {
|
||||
// A valtree of a type where leaves directly represent the scalar const value.
|
||||
// Just checking whether it is a leaf is insufficient as e.g. references are leafs
|
||||
// but the leaf value is the value they point to, not the reference itself!
|
||||
Some(valtree.unwrap_leaf().into())
|
||||
Some(cv.valtree.unwrap_leaf().into())
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
|
@ -295,9 +295,7 @@ impl<'tcx> Const<'tcx> {
|
|||
match self {
|
||||
Const::Val(ConstValue::Scalar(Scalar::Int(x)), _) => Some(x),
|
||||
Const::Ty(_, c) => match c.kind() {
|
||||
ty::ConstKind::Value(ty, valtree) if ty.is_primitive() => {
|
||||
Some(valtree.unwrap_leaf())
|
||||
}
|
||||
ty::ConstKind::Value(cv) if cv.ty.is_primitive() => Some(cv.valtree.unwrap_leaf()),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
|
@ -328,7 +326,7 @@ impl<'tcx> Const<'tcx> {
|
|||
}
|
||||
|
||||
match c.kind() {
|
||||
ConstKind::Value(ty, val) => Ok(tcx.valtree_to_const_val((ty, val))),
|
||||
ConstKind::Value(cv) => Ok(tcx.valtree_to_const_val(cv)),
|
||||
ConstKind::Expr(_) => {
|
||||
bug!("Normalization of `ty::ConstKind::Expr` is unimplemented")
|
||||
}
|
||||
|
@ -353,13 +351,13 @@ impl<'tcx> Const<'tcx> {
|
|||
typing_env: ty::TypingEnv<'tcx>,
|
||||
) -> Option<Scalar> {
|
||||
if let Const::Ty(_, c) = self
|
||||
&& let ty::ConstKind::Value(ty, val) = c.kind()
|
||||
&& ty.is_primitive()
|
||||
&& let ty::ConstKind::Value(cv) = c.kind()
|
||||
&& cv.ty.is_primitive()
|
||||
{
|
||||
// Avoid the `valtree_to_const_val` query. Can only be done on primitive types that
|
||||
// are valtree leaves, and *not* on references. (References should return the
|
||||
// pointer here, which valtrees don't represent.)
|
||||
Some(val.unwrap_leaf().into())
|
||||
Some(cv.valtree.unwrap_leaf().into())
|
||||
} else {
|
||||
self.eval(tcx, typing_env, DUMMY_SP).ok()?.try_to_scalar()
|
||||
}
|
||||
|
@ -473,7 +471,7 @@ impl<'tcx> Const<'tcx> {
|
|||
// A valtree may be a reference. Valtree references correspond to a
|
||||
// different allocation each time they are evaluated. Valtrees for primitive
|
||||
// types are fine though.
|
||||
ty::ConstKind::Value(ty, _) => ty.is_primitive(),
|
||||
ty::ConstKind::Value(cv) => cv.ty.is_primitive(),
|
||||
ty::ConstKind::Unevaluated(..) | ty::ConstKind::Expr(..) => false,
|
||||
// This can happen if evaluation of a constant failed. The result does not matter
|
||||
// much since compilation is doomed.
|
||||
|
|
|
@ -1441,7 +1441,9 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
|
|||
ty::ConstKind::Unevaluated(uv) => {
|
||||
format!("ty::Unevaluated({}, {:?})", self.tcx.def_path_str(uv.def), uv.args,)
|
||||
}
|
||||
ty::ConstKind::Value(_, val) => format!("ty::Valtree({})", fmt_valtree(&val)),
|
||||
ty::ConstKind::Value(cv) => {
|
||||
format!("ty::Valtree({})", fmt_valtree(&cv.valtree))
|
||||
}
|
||||
// No `ty::` prefix since we also use this to represent errors from `mir::Unevaluated`.
|
||||
ty::ConstKind::Error(_) => "Error".to_string(),
|
||||
// These variants shouldn't exist in the MIR.
|
||||
|
|
|
@ -550,7 +550,7 @@ impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>) {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) {
|
||||
impl<'tcx> Key for ty::Value<'tcx> {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _: TyCtxt<'_>) -> Span {
|
||||
|
|
|
@ -1256,9 +1256,9 @@ rustc_queries! {
|
|||
desc { "evaluating type-level constant" }
|
||||
}
|
||||
|
||||
/// Converts a type level constant value into `ConstValue`
|
||||
query valtree_to_const_val(key: (Ty<'tcx>, ty::ValTree<'tcx>)) -> mir::ConstValue<'tcx> {
|
||||
desc { "converting type-level constant value to mir constant value"}
|
||||
/// Converts a type-level constant value into a MIR constant value.
|
||||
query valtree_to_const_val(key: ty::Value<'tcx>) -> mir::ConstValue<'tcx> {
|
||||
desc { "converting type-level constant value to MIR constant value"}
|
||||
}
|
||||
|
||||
/// Destructures array, ADT or tuple constants into the constants
|
||||
|
|
|
@ -110,8 +110,8 @@ impl<'tcx> Const<'tcx> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new_value(tcx: TyCtxt<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
|
||||
Const::new(tcx, ty::ConstKind::Value(ty, val))
|
||||
pub fn new_value(tcx: TyCtxt<'tcx>, valtree: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
|
||||
Const::new(tcx, ty::ConstKind::Value(ty::Value { ty, valtree }))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -214,47 +214,31 @@ impl<'tcx> Const<'tcx> {
|
|||
Self::from_bits(tcx, n as u128, ty::TypingEnv::fully_monomorphized(), tcx.types.usize)
|
||||
}
|
||||
|
||||
/// Panics if self.kind != ty::ConstKind::Value
|
||||
pub fn to_valtree(self) -> (ty::ValTree<'tcx>, Ty<'tcx>) {
|
||||
/// Panics if `self.kind != ty::ConstKind::Value`.
|
||||
pub fn to_value(self) -> ty::Value<'tcx> {
|
||||
match self.kind() {
|
||||
ty::ConstKind::Value(ty, valtree) => (valtree, ty),
|
||||
ty::ConstKind::Value(cv) => cv,
|
||||
_ => bug!("expected ConstKind::Value, got {:?}", self.kind()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to convert to a `ValTree`
|
||||
pub fn try_to_valtree(self) -> Option<(ty::ValTree<'tcx>, Ty<'tcx>)> {
|
||||
/// Attempts to convert to a value.
|
||||
pub fn try_to_value(self) -> Option<ty::Value<'tcx>> {
|
||||
match self.kind() {
|
||||
ty::ConstKind::Value(ty, valtree) => Some((valtree, ty)),
|
||||
ty::ConstKind::Value(cv) => Some(cv),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_scalar(self) -> Option<(Scalar, Ty<'tcx>)> {
|
||||
let (valtree, ty) = self.try_to_valtree()?;
|
||||
Some((valtree.try_to_scalar()?, ty))
|
||||
}
|
||||
|
||||
pub fn try_to_bool(self) -> Option<bool> {
|
||||
self.try_to_valtree()?.0.try_to_scalar_int()?.try_to_bool().ok()
|
||||
let cv = self.try_to_value()?;
|
||||
Some((cv.valtree.try_to_scalar()?, cv.ty))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
|
||||
self.try_to_valtree()?.0.try_to_target_usize(tcx)
|
||||
}
|
||||
|
||||
/// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of
|
||||
/// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
|
||||
/// contains const generic parameters or pointers).
|
||||
#[inline]
|
||||
pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option<u128> {
|
||||
let (scalar, ty) = self.try_to_scalar()?;
|
||||
let scalar = scalar.try_to_scalar_int().ok()?;
|
||||
let input = typing_env.with_post_analysis_normalized(tcx).as_query_input(ty);
|
||||
let size = tcx.layout_of(input).ok()?.size;
|
||||
Some(scalar.to_bits(size))
|
||||
self.try_to_value()?.try_to_target_usize(tcx)
|
||||
}
|
||||
|
||||
pub fn is_ct_infer(self) -> bool {
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
|
||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
|
||||
|
||||
use super::ScalarInt;
|
||||
use crate::mir::interpret::Scalar;
|
||||
use crate::ty::{self, Ty, TyCtxt};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq)]
|
||||
#[derive(HashStable)]
|
||||
/// This datastructure is used to represent the value of constants used in the type system.
|
||||
///
|
||||
/// We explicitly choose a different datastructure from the way values are processed within
|
||||
|
@ -18,6 +16,8 @@ use crate::ty::{self, Ty, TyCtxt};
|
|||
///
|
||||
/// `ValTree` does not have this problem with representation, as it only contains integers or
|
||||
/// lists of (nested) `ValTree`.
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
#[derive(HashStable, TyEncodable, TyDecodable)]
|
||||
pub enum ValTree<'tcx> {
|
||||
/// integers, `bool`, `char` are represented as scalars.
|
||||
/// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values
|
||||
|
@ -79,10 +79,6 @@ impl<'tcx> ValTree<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
|
||||
self.try_to_scalar_int().map(|s| s.to_target_usize(tcx))
|
||||
}
|
||||
|
||||
/// Get the values inside the ValTree as a slice of bytes. This only works for
|
||||
/// constants with types &str, &[u8], or [u8; _].
|
||||
pub fn try_to_raw_bytes(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx [u8]> {
|
||||
|
@ -107,3 +103,44 @@ impl<'tcx> ValTree<'tcx> {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// A type-level constant value.
|
||||
///
|
||||
/// Represents a typed, fully evaluated constant.
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
#[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)]
|
||||
pub struct Value<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
pub valtree: ValTree<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> Value<'tcx> {
|
||||
/// Attempts to extract the raw bits from the constant.
|
||||
///
|
||||
/// Fails if the value can't be represented as bits (e.g. because it is an aggregate).
|
||||
#[inline]
|
||||
pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option<u128> {
|
||||
let scalar = self.valtree.try_to_scalar_int()?;
|
||||
let input = typing_env.with_post_analysis_normalized(tcx).as_query_input(self.ty);
|
||||
let size = tcx.layout_of(input).ok()?.size;
|
||||
Some(scalar.to_bits(size))
|
||||
}
|
||||
|
||||
pub fn try_to_bool(self) -> Option<bool> {
|
||||
self.valtree.try_to_scalar_int()?.try_to_bool().ok()
|
||||
}
|
||||
|
||||
pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
|
||||
self.valtree.try_to_scalar_int().map(|s| s.to_target_usize(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::ValueConst<TyCtxt<'tcx>> for Value<'tcx> {
|
||||
fn ty(self) -> Ty<'tcx> {
|
||||
self.ty
|
||||
}
|
||||
|
||||
fn valtree(self) -> ValTree<'tcx> {
|
||||
self.valtree
|
||||
}
|
||||
}
|
||||
|
|
|
@ -142,10 +142,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
|
||||
type ParamConst = ty::ParamConst;
|
||||
type BoundConst = ty::BoundVar;
|
||||
type ValueConst = ty::ValTree<'tcx>;
|
||||
type ValueConst = ty::Value<'tcx>;
|
||||
type ExprConst = ty::Expr<'tcx>;
|
||||
type Region = Region<'tcx>;
|
||||
type ValTree = ty::ValTree<'tcx>;
|
||||
|
||||
type Region = Region<'tcx>;
|
||||
type EarlyParamRegion = ty::EarlyParamRegion;
|
||||
type LateParamRegion = ty::LateParamRegion;
|
||||
type BoundRegion = ty::BoundRegion;
|
||||
|
@ -1118,15 +1119,18 @@ impl<'tcx> CommonConsts<'tcx> {
|
|||
};
|
||||
|
||||
CommonConsts {
|
||||
unit: mk_const(ty::ConstKind::Value(types.unit, ty::ValTree::zst())),
|
||||
true_: mk_const(ty::ConstKind::Value(
|
||||
types.bool,
|
||||
ty::ValTree::Leaf(ty::ScalarInt::TRUE),
|
||||
)),
|
||||
false_: mk_const(ty::ConstKind::Value(
|
||||
types.bool,
|
||||
ty::ValTree::Leaf(ty::ScalarInt::FALSE),
|
||||
)),
|
||||
unit: mk_const(ty::ConstKind::Value(ty::Value {
|
||||
ty: types.unit,
|
||||
valtree: ty::ValTree::zst(),
|
||||
})),
|
||||
true_: mk_const(ty::ConstKind::Value(ty::Value {
|
||||
ty: types.bool,
|
||||
valtree: ty::ValTree::Leaf(ty::ScalarInt::TRUE),
|
||||
})),
|
||||
false_: mk_const(ty::ConstKind::Value(ty::Value {
|
||||
ty: types.bool,
|
||||
valtree: ty::ValTree::Leaf(ty::ScalarInt::FALSE),
|
||||
})),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -381,7 +381,7 @@ impl FlagComputation {
|
|||
self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER);
|
||||
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
|
||||
}
|
||||
ty::ConstKind::Value(ty, _) => self.add_ty(ty),
|
||||
ty::ConstKind::Value(cv) => self.add_ty(cv.ty),
|
||||
ty::ConstKind::Expr(e) => self.add_args(e.args()),
|
||||
ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ pub use self::closure::{
|
|||
place_to_string_for_capture,
|
||||
};
|
||||
pub use self::consts::{
|
||||
Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree,
|
||||
Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree, Value,
|
||||
};
|
||||
pub use self::context::{
|
||||
CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt,
|
||||
|
|
|
@ -1484,8 +1484,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
|||
_ => write!(self, "_")?,
|
||||
},
|
||||
ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)),
|
||||
ty::ConstKind::Value(ty, value) => {
|
||||
return self.pretty_print_const_valtree(value, ty, print_ty);
|
||||
ty::ConstKind::Value(cv) => {
|
||||
return self.pretty_print_const_valtree(cv.valtree, cv.ty, print_ty);
|
||||
}
|
||||
|
||||
ty::ConstKind::Bound(debruijn, bound_var) => {
|
||||
|
@ -1637,33 +1637,32 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
|||
match ty.kind() {
|
||||
// Byte strings (&[u8; N])
|
||||
ty::Ref(_, inner, _) => {
|
||||
if let ty::Array(elem, len) = inner.kind() {
|
||||
if let ty::Uint(ty::UintTy::U8) = elem.kind() {
|
||||
if let ty::ConstKind::Value(_, ty::ValTree::Leaf(int)) = len.kind() {
|
||||
match self.tcx().try_get_global_alloc(prov.alloc_id()) {
|
||||
Some(GlobalAlloc::Memory(alloc)) => {
|
||||
let len = int.to_bits(self.tcx().data_layout.pointer_size);
|
||||
let range =
|
||||
AllocRange { start: offset, size: Size::from_bytes(len) };
|
||||
if let Ok(byte_str) =
|
||||
alloc.inner().get_bytes_strip_provenance(&self.tcx(), range)
|
||||
{
|
||||
p!(pretty_print_byte_str(byte_str))
|
||||
} else {
|
||||
p!("<too short allocation>")
|
||||
}
|
||||
}
|
||||
// FIXME: for statics, vtables, and functions, we could in principle print more detail.
|
||||
Some(GlobalAlloc::Static(def_id)) => {
|
||||
p!(write("<static({:?})>", def_id))
|
||||
}
|
||||
Some(GlobalAlloc::Function { .. }) => p!("<function>"),
|
||||
Some(GlobalAlloc::VTable(..)) => p!("<vtable>"),
|
||||
None => p!("<dangling pointer>"),
|
||||
if let ty::Array(elem, len) = inner.kind()
|
||||
&& let ty::Uint(ty::UintTy::U8) = elem.kind()
|
||||
&& let ty::ConstKind::Value(cv) = len.kind()
|
||||
&& let ty::ValTree::Leaf(int) = cv.valtree
|
||||
{
|
||||
match self.tcx().try_get_global_alloc(prov.alloc_id()) {
|
||||
Some(GlobalAlloc::Memory(alloc)) => {
|
||||
let len = int.to_bits(self.tcx().data_layout.pointer_size);
|
||||
let range = AllocRange { start: offset, size: Size::from_bytes(len) };
|
||||
if let Ok(byte_str) =
|
||||
alloc.inner().get_bytes_strip_provenance(&self.tcx(), range)
|
||||
{
|
||||
p!(pretty_print_byte_str(byte_str))
|
||||
} else {
|
||||
p!("<too short allocation>")
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
// FIXME: for statics, vtables, and functions, we could in principle print more detail.
|
||||
Some(GlobalAlloc::Static(def_id)) => {
|
||||
p!(write("<static({:?})>", def_id))
|
||||
}
|
||||
Some(GlobalAlloc::Function { .. }) => p!("<function>"),
|
||||
Some(GlobalAlloc::VTable(..)) => p!("<vtable>"),
|
||||
None => p!("<dangling pointer>"),
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
ty::FnPtr(..) => {
|
||||
|
|
|
@ -162,16 +162,15 @@ impl<'tcx> fmt::Debug for ty::consts::Expr<'tcx> {
|
|||
impl<'tcx> fmt::Debug for ty::Const<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// If this is a value, we spend some effort to make it look nice.
|
||||
if let ConstKind::Value(_, _) = self.kind() {
|
||||
if let ConstKind::Value(_) = self.kind() {
|
||||
return ty::tls::with(move |tcx| {
|
||||
// Somehow trying to lift the valtree results in lifetime errors, so we lift the
|
||||
// entire constant.
|
||||
// ValTrees aren't interned, so we lift the entire constant.
|
||||
let lifted = tcx.lift(*self).unwrap();
|
||||
let ConstKind::Value(ty, valtree) = lifted.kind() else {
|
||||
let ConstKind::Value(cv) = lifted.kind() else {
|
||||
bug!("we checked that this is a valtree")
|
||||
};
|
||||
let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
|
||||
cx.pretty_print_const_valtree(valtree, ty, /*print_ty*/ true)?;
|
||||
cx.pretty_print_const_valtree(cv.valtree, cv.ty, /*print_ty*/ true)?;
|
||||
f.write_str(&cx.into_buffer())
|
||||
});
|
||||
}
|
||||
|
@ -589,9 +588,7 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Const<'tcx> {
|
|||
}
|
||||
ConstKind::Placeholder(p) => ConstKind::Placeholder(p.try_fold_with(folder)?),
|
||||
ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.try_fold_with(folder)?),
|
||||
ConstKind::Value(t, v) => {
|
||||
ConstKind::Value(t.try_fold_with(folder)?, v.try_fold_with(folder)?)
|
||||
}
|
||||
ConstKind::Value(v) => ConstKind::Value(v.try_fold_with(folder)?),
|
||||
ConstKind::Error(e) => ConstKind::Error(e.try_fold_with(folder)?),
|
||||
ConstKind::Expr(e) => ConstKind::Expr(e.try_fold_with(folder)?),
|
||||
};
|
||||
|
@ -610,10 +607,7 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Const<'tcx> {
|
|||
}
|
||||
ConstKind::Placeholder(p) => p.visit_with(visitor),
|
||||
ConstKind::Unevaluated(uv) => uv.visit_with(visitor),
|
||||
ConstKind::Value(t, v) => {
|
||||
try_visit!(t.visit_with(visitor));
|
||||
v.visit_with(visitor)
|
||||
}
|
||||
ConstKind::Value(v) => v.visit_with(visitor),
|
||||
ConstKind::Error(e) => e.visit_with(visitor),
|
||||
ConstKind::Expr(e) => e.visit_with(visitor),
|
||||
}
|
||||
|
|
|
@ -206,7 +206,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
|
|||
| ty::ConstKind::Bound(..)
|
||||
| ty::ConstKind::Error(_) => {}
|
||||
|
||||
ty::ConstKind::Value(ty, _) => stack.push(ty.into()),
|
||||
ty::ConstKind::Value(cv) => stack.push(cv.ty.into()),
|
||||
|
||||
ty::ConstKind::Expr(expr) => stack.extend(expr.args().iter().rev()),
|
||||
ty::ConstKind::Unevaluated(ct) => {
|
||||
|
|
|
@ -46,7 +46,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
|
||||
match c.kind() {
|
||||
ty::ConstKind::Unevaluated(uv) => convert.unevaluated_to_pat(uv, ty),
|
||||
ty::ConstKind::Value(_, val) => convert.valtree_to_pat(val, ty),
|
||||
ty::ConstKind::Value(cv) => convert.valtree_to_pat(cv.valtree, cv.ty),
|
||||
_ => span_bug!(span, "Invalid `ConstKind` for `const_to_pat`: {:?}", c),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -522,7 +522,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
|
|||
// FIXME: See comment above -- we could fold the region separately or something.
|
||||
ty::ConstKind::Bound(_, _)
|
||||
| ty::ConstKind::Unevaluated(_)
|
||||
| ty::ConstKind::Value(_, _)
|
||||
| ty::ConstKind::Value(_)
|
||||
| ty::ConstKind::Error(_)
|
||||
| ty::ConstKind::Expr(_) => return c.super_fold_with(self),
|
||||
};
|
||||
|
|
|
@ -160,9 +160,7 @@ where
|
|||
ty::ConstKind::Infer(_) => {
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||
}
|
||||
ty::ConstKind::Placeholder(_)
|
||||
| ty::ConstKind::Value(_, _)
|
||||
| ty::ConstKind::Error(_) => {
|
||||
ty::ConstKind::Placeholder(_) | ty::ConstKind::Value(_) | ty::ConstKind::Error(_) => {
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
// We can freely ICE here as:
|
||||
|
@ -199,7 +197,7 @@ where
|
|||
unreachable!("`ConstKind::Param` should have been canonicalized to `Placeholder`")
|
||||
}
|
||||
ty::ConstKind::Bound(_, _) => panic!("escaping bound vars in {:?}", ct),
|
||||
ty::ConstKind::Value(ty, _) => ty,
|
||||
ty::ConstKind::Value(cv) => cv.ty(),
|
||||
ty::ConstKind::Placeholder(placeholder) => {
|
||||
self.cx().find_const_ty_from_env(goal.param_env, placeholder)
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ fn encode_args<'tcx>(
|
|||
/// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling.literal>).
|
||||
fn encode_const<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
c: Const<'tcx>,
|
||||
ct: Const<'tcx>,
|
||||
ct_ty: Ty<'tcx>,
|
||||
dict: &mut FxHashMap<DictKey<'tcx>, usize>,
|
||||
options: EncodeTyOptions,
|
||||
|
@ -111,7 +111,7 @@ fn encode_const<'tcx>(
|
|||
// L<element-type>[n][<element-value>]E as literal argument
|
||||
let mut s = String::from('L');
|
||||
|
||||
match c.kind() {
|
||||
match ct.kind() {
|
||||
// Const parameters
|
||||
ty::ConstKind::Param(..) => {
|
||||
// L<element-type>E as literal argument
|
||||
|
@ -121,18 +121,18 @@ fn encode_const<'tcx>(
|
|||
}
|
||||
|
||||
// Literal arguments
|
||||
ty::ConstKind::Value(ct_ty, ..) => {
|
||||
ty::ConstKind::Value(cv) => {
|
||||
// L<element-type>[n]<element-value>E as literal argument
|
||||
|
||||
// Element type
|
||||
s.push_str(&encode_ty(tcx, ct_ty, dict, options));
|
||||
s.push_str(&encode_ty(tcx, cv.ty, dict, options));
|
||||
|
||||
// The only allowed types of const values are bool, u8, u16, u32,
|
||||
// u64, u128, usize i8, i16, i32, i64, i128, isize, and char. The
|
||||
// bool value false is encoded as 0 and true as 1.
|
||||
match ct_ty.kind() {
|
||||
match cv.ty.kind() {
|
||||
ty::Int(ity) => {
|
||||
let bits = c
|
||||
let bits = cv
|
||||
.try_to_bits(tcx, ty::TypingEnv::fully_monomorphized())
|
||||
.expect("expected monomorphic const in cfi");
|
||||
let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
|
||||
|
@ -142,30 +142,30 @@ fn encode_const<'tcx>(
|
|||
let _ = write!(s, "{val}");
|
||||
}
|
||||
ty::Uint(_) => {
|
||||
let val = c
|
||||
let val = cv
|
||||
.try_to_bits(tcx, ty::TypingEnv::fully_monomorphized())
|
||||
.expect("expected monomorphic const in cfi");
|
||||
let _ = write!(s, "{val}");
|
||||
}
|
||||
ty::Bool => {
|
||||
let val = c.try_to_bool().expect("expected monomorphic const in cfi");
|
||||
let val = cv.try_to_bool().expect("expected monomorphic const in cfi");
|
||||
let _ = write!(s, "{val}");
|
||||
}
|
||||
_ => {
|
||||
bug!("encode_const: unexpected type `{:?}`", ct_ty);
|
||||
bug!("encode_const: unexpected type `{:?}`", cv.ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
bug!("encode_const: unexpected kind `{:?}`", c.kind());
|
||||
bug!("encode_const: unexpected kind `{:?}`", ct.kind());
|
||||
}
|
||||
}
|
||||
|
||||
// Close the "L..E" pair
|
||||
s.push('E');
|
||||
|
||||
compress(dict, DictKey::Const(c), &mut s);
|
||||
compress(dict, DictKey::Const(ct), &mut s);
|
||||
|
||||
s
|
||||
}
|
||||
|
|
|
@ -450,8 +450,9 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
let tcx = tables.tcx;
|
||||
let ty = ty::Ty::new_static_str(tcx);
|
||||
let bytes = value.as_bytes();
|
||||
let val_tree = ty::ValTree::from_raw_bytes(tcx, bytes);
|
||||
let val = tcx.valtree_to_const_val((ty, val_tree));
|
||||
let valtree = ty::ValTree::from_raw_bytes(tcx, bytes);
|
||||
let cv = ty::Value { ty, valtree };
|
||||
let val = tcx.valtree_to_const_val(cv);
|
||||
mir::Const::from_value(val, ty).stable(&mut tables)
|
||||
}
|
||||
|
||||
|
|
|
@ -418,23 +418,16 @@ impl<'tcx> Stable<'tcx> for ty::Const<'tcx> {
|
|||
type T = stable_mir::ty::TyConst;
|
||||
|
||||
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
|
||||
let kind = match self.kind() {
|
||||
ty::ConstKind::Value(ty, val) => {
|
||||
let val = match val {
|
||||
ty::ValTree::Leaf(scalar) => ty::ValTree::Leaf(scalar),
|
||||
ty::ValTree::Branch(branch) => {
|
||||
ty::ValTree::Branch(tables.tcx.lift(branch).unwrap())
|
||||
}
|
||||
};
|
||||
|
||||
let ty = tables.tcx.lift(ty).unwrap();
|
||||
let const_val = tables.tcx.valtree_to_const_val((ty, val));
|
||||
let ct = tables.tcx.lift(*self).unwrap();
|
||||
let kind = match ct.kind() {
|
||||
ty::ConstKind::Value(cv) => {
|
||||
let const_val = tables.tcx.valtree_to_const_val(cv);
|
||||
if matches!(const_val, mir::ConstValue::ZeroSized) {
|
||||
stable_mir::ty::TyConstKind::ZSTValue(ty.stable(tables))
|
||||
stable_mir::ty::TyConstKind::ZSTValue(cv.ty.stable(tables))
|
||||
} else {
|
||||
stable_mir::ty::TyConstKind::Value(
|
||||
ty.stable(tables),
|
||||
alloc::new_allocation(ty, const_val, tables),
|
||||
cv.ty.stable(tables),
|
||||
alloc::new_allocation(cv.ty, const_val, tables),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -449,7 +442,7 @@ impl<'tcx> Stable<'tcx> for ty::Const<'tcx> {
|
|||
ty::ConstKind::Placeholder(_) => unimplemented!(),
|
||||
ty::ConstKind::Expr(_) => unimplemented!(),
|
||||
};
|
||||
let id = tables.intern_ty_const(tables.tcx.lift(*self).unwrap());
|
||||
let id = tables.intern_ty_const(ct);
|
||||
stable_mir::ty::TyConst::new(kind, id)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -274,14 +274,15 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
|
|||
fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> {
|
||||
// only print integers
|
||||
match ct.kind() {
|
||||
ty::ConstKind::Value(ty, ty::ValTree::Leaf(scalar)) if ty.is_integral() => {
|
||||
ty::ConstKind::Value(cv) if cv.ty.is_integral() => {
|
||||
// The `pretty_print_const` formatting depends on -Zverbose-internals
|
||||
// flag, so we cannot reuse it here.
|
||||
let signed = matches!(ty.kind(), ty::Int(_));
|
||||
let scalar = cv.valtree.unwrap_leaf();
|
||||
let signed = matches!(cv.ty.kind(), ty::Int(_));
|
||||
write!(
|
||||
self,
|
||||
"{:#?}",
|
||||
ty::ConstInt::new(scalar, signed, ty.is_ptr_sized_integral())
|
||||
ty::ConstInt::new(scalar, signed, cv.ty.is_ptr_sized_integral())
|
||||
)?;
|
||||
}
|
||||
_ => self.write_str("_")?,
|
||||
|
|
|
@ -590,8 +590,8 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
|
|||
|
||||
fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> {
|
||||
// We only mangle a typed value if the const can be evaluated.
|
||||
let (ct_ty, valtree) = match ct.kind() {
|
||||
ty::ConstKind::Value(ty, val) => (ty, val),
|
||||
let cv = match ct.kind() {
|
||||
ty::ConstKind::Value(cv) => cv,
|
||||
|
||||
// Should only be encountered within the identity-substituted
|
||||
// impl header of an item nested within an impl item.
|
||||
|
@ -619,13 +619,14 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
let ty::Value { ty: ct_ty, valtree } = cv;
|
||||
let start = self.out.len();
|
||||
|
||||
match ct_ty.kind() {
|
||||
ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => {
|
||||
ct_ty.print(self)?;
|
||||
|
||||
let mut bits = ct
|
||||
let mut bits = cv
|
||||
.try_to_bits(self.tcx, ty::TypingEnv::fully_monomorphized())
|
||||
.expect("expected const to be monomorphic");
|
||||
|
||||
|
|
|
@ -264,7 +264,7 @@ fn fulfillment_error_for_no_solution<'tcx>(
|
|||
infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args)
|
||||
}
|
||||
ty::ConstKind::Param(param_ct) => param_ct.find_ty_from_env(obligation.param_env),
|
||||
ty::ConstKind::Value(ty, _) => ty,
|
||||
ty::ConstKind::Value(cv) => cv.ty,
|
||||
kind => span_bug!(
|
||||
obligation.cause.span,
|
||||
"ConstArgHasWrongType failed but we don't know how to compute type for {kind:?}"
|
||||
|
|
|
@ -35,7 +35,7 @@ pub fn is_const_evaluatable<'tcx>(
|
|||
ty::ConstKind::Param(_)
|
||||
| ty::ConstKind::Bound(_, _)
|
||||
| ty::ConstKind::Placeholder(_)
|
||||
| ty::ConstKind::Value(_, _)
|
||||
| ty::ConstKind::Value(_)
|
||||
| ty::ConstKind::Error(_) => return Ok(()),
|
||||
ty::ConstKind::Infer(_) => return Err(NotConstEvaluatable::MentionsInfer),
|
||||
};
|
||||
|
|
|
@ -479,7 +479,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
|||
ty::ConstKind::Error(_) => {
|
||||
return ProcessResult::Changed(PendingPredicateObligations::new());
|
||||
}
|
||||
ty::ConstKind::Value(ty, _) => ty,
|
||||
ty::ConstKind::Value(cv) => cv.ty,
|
||||
ty::ConstKind::Unevaluated(uv) => {
|
||||
infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args)
|
||||
}
|
||||
|
|
|
@ -962,7 +962,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
return Ok(EvaluatedToAmbig);
|
||||
}
|
||||
ty::ConstKind::Error(_) => return Ok(EvaluatedToOk),
|
||||
ty::ConstKind::Value(ty, _) => ty,
|
||||
ty::ConstKind::Value(cv) => cv.ty,
|
||||
ty::ConstKind::Unevaluated(uv) => {
|
||||
self.tcx().type_of(uv.def).instantiate(self.tcx(), uv.args)
|
||||
}
|
||||
|
|
|
@ -128,16 +128,16 @@ mod rustc {
|
|||
pub fn from_const<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
c: Const<'tcx>,
|
||||
ct: Const<'tcx>,
|
||||
) -> Option<Self> {
|
||||
use rustc_middle::ty::ScalarInt;
|
||||
use rustc_span::sym;
|
||||
|
||||
let Some((cv, ty)) = c.try_to_valtree() else {
|
||||
let Some(cv) = ct.try_to_value() else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let adt_def = ty.ty_adt_def()?;
|
||||
let adt_def = cv.ty.ty_adt_def()?;
|
||||
|
||||
assert_eq!(
|
||||
tcx.require_lang_item(LangItem::TransmuteOpts, None),
|
||||
|
@ -147,7 +147,7 @@ mod rustc {
|
|||
);
|
||||
|
||||
let variant = adt_def.non_enum_variant();
|
||||
let fields = match cv {
|
||||
let fields = match cv.valtree {
|
||||
ValTree::Branch(branch) => branch,
|
||||
_ => {
|
||||
return Some(Self {
|
||||
|
|
|
@ -22,16 +22,16 @@ fn destructure_const<'tcx>(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
const_: ty::Const<'tcx>,
|
||||
) -> ty::DestructuredConst<'tcx> {
|
||||
let ty::ConstKind::Value(ct_ty, valtree) = const_.kind() else {
|
||||
let ty::ConstKind::Value(cv) = const_.kind() else {
|
||||
bug!("cannot destructure constant {:?}", const_)
|
||||
};
|
||||
|
||||
let branches = match valtree {
|
||||
let branches = match cv.valtree {
|
||||
ty::ValTree::Branch(b) => b,
|
||||
_ => bug!("cannot destructure constant {:?}", const_),
|
||||
};
|
||||
|
||||
let (fields, variant) = match ct_ty.kind() {
|
||||
let (fields, variant) = match cv.ty.kind() {
|
||||
ty::Array(inner_ty, _) | ty::Slice(inner_ty) => {
|
||||
// construct the consts for the elements of the array/slice
|
||||
let field_consts = branches
|
||||
|
|
|
@ -144,13 +144,13 @@ fn univariant_uninterned<'tcx>(
|
|||
cx.calc.univariant(fields, repr, kind).map_err(|err| map_error(cx, ty, err))
|
||||
}
|
||||
|
||||
fn validate_const_with_value<'tcx>(
|
||||
fn extract_const_value<'tcx>(
|
||||
const_: ty::Const<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
cx: &LayoutCx<'tcx>,
|
||||
) -> Result<ty::Const<'tcx>, &'tcx LayoutError<'tcx>> {
|
||||
) -> Result<ty::Value<'tcx>, &'tcx LayoutError<'tcx>> {
|
||||
match const_.kind() {
|
||||
ty::ConstKind::Value(..) => Ok(const_),
|
||||
ty::ConstKind::Value(cv) => Ok(cv),
|
||||
ty::ConstKind::Error(guar) => {
|
||||
return Err(error(cx, LayoutError::ReferencesError(guar)));
|
||||
}
|
||||
|
@ -209,13 +209,12 @@ fn layout_of_uncached<'tcx>(
|
|||
&mut layout.backend_repr
|
||||
{
|
||||
if let Some(start) = start {
|
||||
scalar.valid_range_mut().start =
|
||||
validate_const_with_value(start, ty, cx)?
|
||||
.try_to_bits(tcx, cx.typing_env)
|
||||
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
|
||||
scalar.valid_range_mut().start = extract_const_value(start, ty, cx)?
|
||||
.try_to_bits(tcx, cx.typing_env)
|
||||
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
|
||||
}
|
||||
if let Some(end) = end {
|
||||
let mut end = validate_const_with_value(end, ty, cx)?
|
||||
let mut end = extract_const_value(end, ty, cx)?
|
||||
.try_to_bits(tcx, cx.typing_env)
|
||||
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
|
||||
if !include_end {
|
||||
|
@ -348,9 +347,7 @@ fn layout_of_uncached<'tcx>(
|
|||
|
||||
// Arrays and slices.
|
||||
ty::Array(element, count) => {
|
||||
let count = validate_const_with_value(count, ty, cx)?
|
||||
.to_valtree()
|
||||
.0
|
||||
let count = extract_const_value(count, ty, cx)?
|
||||
.try_to_target_usize(tcx)
|
||||
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ pub enum ConstKind<I: Interner> {
|
|||
Unevaluated(ty::UnevaluatedConst<I>),
|
||||
|
||||
/// Used to hold computed value.
|
||||
Value(I::Ty, I::ValueConst),
|
||||
Value(I::ValueConst),
|
||||
|
||||
/// A placeholder for a const which could not be computed; this is
|
||||
/// propagated to avoid useless error messages.
|
||||
|
@ -52,7 +52,7 @@ impl<I: Interner> fmt::Debug for ConstKind<I> {
|
|||
Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var),
|
||||
Placeholder(placeholder) => write!(f, "{placeholder:?}"),
|
||||
Unevaluated(uv) => write!(f, "{uv:?}"),
|
||||
Value(ty, valtree) => write!(f, "({valtree:?}: {ty:?})"),
|
||||
Value(val) => write!(f, "{val:?}"),
|
||||
Error(_) => write!(f, "{{const error}}"),
|
||||
Expr(expr) => write!(f, "{expr:?}"),
|
||||
}
|
||||
|
|
|
@ -483,8 +483,8 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
|
|||
};
|
||||
|
||||
match lhs.kind() {
|
||||
ty::ConstKind::Value(_, lhs_val) => match rhs.kind() {
|
||||
ty::ConstKind::Value(_, rhs_val) => lhs_val == rhs_val,
|
||||
ty::ConstKind::Value(lhs_val) => match rhs.kind() {
|
||||
ty::ConstKind::Value(rhs_val) => lhs_val.valtree() == rhs_val.valtree(),
|
||||
_ => false,
|
||||
},
|
||||
|
||||
|
|
|
@ -286,6 +286,11 @@ pub trait Const<I: Interner<Const = Self>>:
|
|||
}
|
||||
}
|
||||
|
||||
pub trait ValueConst<I: Interner<ValueConst = Self>>: Copy + Debug + Hash + Eq {
|
||||
fn ty(self) -> I::Ty;
|
||||
fn valtree(self) -> I::ValTree;
|
||||
}
|
||||
|
||||
pub trait ExprConst<I: Interner<ExprConst = Self>>: Copy + Debug + Hash + Eq + Relate<I> {
|
||||
fn args(self) -> I::GenericArgs;
|
||||
}
|
||||
|
|
|
@ -112,8 +112,9 @@ pub trait Interner:
|
|||
type PlaceholderConst: PlaceholderLike;
|
||||
type ParamConst: Copy + Debug + Hash + Eq + ParamLike;
|
||||
type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
|
||||
type ValueConst: Copy + Debug + Hash + Eq;
|
||||
type ValueConst: ValueConst<Self>;
|
||||
type ExprConst: ExprConst<Self>;
|
||||
type ValTree: Copy + Debug + Hash + Eq;
|
||||
|
||||
// Kinds of regions
|
||||
type Region: Region<Self>;
|
||||
|
|
|
@ -606,7 +606,9 @@ pub fn structurally_relate_consts<I: Interner, R: TypeRelation<I>>(
|
|||
true
|
||||
}
|
||||
(ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2,
|
||||
(ty::ConstKind::Value(_, a_val), ty::ConstKind::Value(_, b_val)) => a_val == b_val,
|
||||
(ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => {
|
||||
a_val.valtree() == b_val.valtree()
|
||||
}
|
||||
|
||||
// While this is slightly incorrect, it shouldn't matter for `min_const_generics`
|
||||
// and is the better alternative to waiting until `generic_const_exprs` can
|
||||
|
|
|
@ -344,10 +344,8 @@ pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String {
|
|||
s
|
||||
}
|
||||
// array lengths are obviously usize
|
||||
ty::ConstKind::Value(ty, ty::ValTree::Leaf(scalar))
|
||||
if *ty.kind() == ty::Uint(ty::UintTy::Usize) =>
|
||||
{
|
||||
scalar.to_string()
|
||||
ty::ConstKind::Value(cv) if *cv.ty.kind() == ty::Uint(ty::UintTy::Usize) => {
|
||||
cv.valtree.unwrap_leaf().to_string()
|
||||
}
|
||||
_ => n.to_string(),
|
||||
}
|
||||
|
|
|
@ -56,9 +56,8 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
|
|||
&& !item.span.from_expansion()
|
||||
&& let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
|
||||
&& let ty::Array(element_type, cst) = ty.kind()
|
||||
&& let Some((ty::ValTree::Leaf(element_count), _)) = cx.tcx
|
||||
.try_normalize_erasing_regions(cx.typing_env(), *cst).unwrap_or(*cst).try_to_valtree()
|
||||
&& let element_count = element_count.to_target_usize(cx.tcx)
|
||||
&& let Some(element_count) = cx.tcx
|
||||
.try_normalize_erasing_regions(cx.typing_env(), *cst).unwrap_or(*cst).try_to_target_usize(cx.tcx)
|
||||
&& let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
|
||||
&& u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size)
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@ use clippy_utils::source::snippet;
|
|||
use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
use rustc_middle::ty::{self, ConstKind};
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::{Span, sym};
|
||||
|
||||
|
@ -81,8 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays {
|
|||
&& let ExprKind::Repeat(_, _) | ExprKind::Array(_) = expr.kind
|
||||
&& !self.is_from_vec_macro(cx, expr.span)
|
||||
&& let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind()
|
||||
&& let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind()
|
||||
&& let element_count = element_count.to_target_usize(cx.tcx)
|
||||
&& let Some(element_count) = cst.try_to_target_usize(cx.tcx)
|
||||
&& let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
|
||||
&& !cx.tcx.hir().parent_iter(expr.hir_id).any(|(_, node)| {
|
||||
matches!(
|
||||
|
|
|
@ -640,7 +640,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
let (dest, dest_len) = this.project_to_simd(dest)?;
|
||||
|
||||
let index =
|
||||
generic_args[2].expect_const().try_to_valtree().unwrap().0.unwrap_branch();
|
||||
generic_args[2].expect_const().to_value().valtree.unwrap_branch();
|
||||
let index_len = index.len();
|
||||
|
||||
assert_eq!(left_len, right_len);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue