make the eval() functions on our const types return the resulting value

This commit is contained in:
Ralf Jung 2023-09-12 23:28:25 +02:00
parent e5fedceabf
commit 6e4779ab17
16 changed files with 167 additions and 245 deletions

View File

@ -723,11 +723,8 @@ fn codegen_stmt<'tcx>(
} }
Rvalue::Repeat(ref operand, times) => { Rvalue::Repeat(ref operand, times) => {
let operand = codegen_operand(fx, operand); let operand = codegen_operand(fx, operand);
let times = fx let times =
.monomorphize(times) fx.monomorphize(times).eval_target_usize(fx.tcx, ParamEnv::reveal_all());
.eval(fx.tcx, ParamEnv::reveal_all())
.try_to_bits(fx.tcx.data_layout.pointer_size)
.unwrap();
if operand.layout().size.bytes() == 0 { if operand.layout().size.bytes() == 0 {
// Do nothing for ZST's // Do nothing for ZST's
} else if fx.clif_type(operand.layout().ty) == Some(types::I8) { } else if fx.clif_type(operand.layout().ty) == Some(types::I8) {

View File

@ -77,31 +77,9 @@ pub(crate) fn eval_mir_constant<'tcx>(
fx: &FunctionCx<'_, '_, 'tcx>, fx: &FunctionCx<'_, '_, 'tcx>,
constant: &Constant<'tcx>, constant: &Constant<'tcx>,
) -> Option<(ConstValue<'tcx>, Ty<'tcx>)> { ) -> Option<(ConstValue<'tcx>, Ty<'tcx>)> {
let constant_kind = fx.monomorphize(constant.literal); let cv = fx.monomorphize(constant.literal);
let uv = match constant_kind { let val = cv
ConstantKind::Ty(const_) => match const_.kind() { .eval(fx.tcx, ty::ParamEnv::reveal_all(), Some(constant.span))
ty::ConstKind::Unevaluated(uv) => uv.expand(),
ty::ConstKind::Value(val) => {
return Some((fx.tcx.valtree_to_const_val((const_.ty(), val)), const_.ty()));
}
err => span_bug!(
constant.span,
"encountered bad ConstKind after monomorphizing: {:?}",
err
),
},
ConstantKind::Unevaluated(mir::UnevaluatedConst { def, .. }, _)
if fx.tcx.is_static(def) =>
{
span_bug!(constant.span, "MIR constant refers to static");
}
ConstantKind::Unevaluated(uv, _) => uv,
ConstantKind::Val(val, _) => return Some((val, constant_kind.ty())),
};
let val = fx
.tcx
.const_eval_resolve(ty::ParamEnv::reveal_all(), uv, None)
.map_err(|err| match err { .map_err(|err| match err {
ErrorHandled::Reported(_) => { ErrorHandled::Reported(_) => {
fx.tcx.sess.span_err(constant.span, "erroneous constant encountered"); fx.tcx.sess.span_err(constant.span, "erroneous constant encountered");
@ -111,7 +89,7 @@ pub(crate) fn eval_mir_constant<'tcx>(
} }
}) })
.ok(); .ok();
val.map(|val| (val, constant_kind.ty())) val.map(|val| (val, cv.ty()))
} }
pub(crate) fn codegen_constant_operand<'tcx>( pub(crate) fn codegen_constant_operand<'tcx>(

View File

@ -670,10 +670,8 @@ 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. // avoiding collisions and will make the emitted type names shorter.
let hash_short = tcx.with_stable_hashing_context(|mut hcx| { let hash_short = tcx.with_stable_hashing_context(|mut hcx| {
let mut hasher = StableHasher::new(); let mut hasher = StableHasher::new();
let ct = ct.eval(tcx, ty::ParamEnv::reveal_all()); let ct = ct.eval(tcx, ty::ParamEnv::reveal_all(), None).unwrap();
hcx.while_hashing_spans(false, |hcx| { hcx.while_hashing_spans(false, |hcx| ct.hash_stable(hcx, &mut hasher));
ct.to_valtree().hash_stable(hcx, &mut hasher)
});
hasher.finish::<Hash64>() hasher.finish::<Hash64>()
}); });

View File

@ -24,34 +24,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
&self, &self,
constant: &mir::Constant<'tcx>, constant: &mir::Constant<'tcx>,
) -> Result<ConstValue<'tcx>, ErrorHandled> { ) -> Result<ConstValue<'tcx>, ErrorHandled> {
let ct = self.monomorphize(constant.literal); self.monomorphize(constant.literal)
let uv = match ct { .eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), Some(constant.span))
mir::ConstantKind::Ty(ct) => match ct.kind() { .map_err(|err| {
ty::ConstKind::Unevaluated(uv) => uv.expand(),
ty::ConstKind::Value(val) => {
return Ok(self.cx.tcx().valtree_to_const_val((ct.ty(), val)));
}
err => span_bug!(
constant.span,
"encountered bad ConstKind after monomorphizing: {:?}",
err
),
},
mir::ConstantKind::Unevaluated(uv, _) => uv,
mir::ConstantKind::Val(val, _) => return Ok(val),
};
self.cx.tcx().const_eval_resolve(ty::ParamEnv::reveal_all(), uv, None).map_err(|err| {
match err { match err {
ErrorHandled::Reported(_) => { ErrorHandled::Reported(_) => {
self.cx.tcx().sess.emit_err(errors::ErroneousConstant { span: constant.span });
}
ErrorHandled::TooGeneric => {
self.cx self.cx
.tcx() .tcx()
.sess .sess
.diagnostic() .emit_err(errors::ErroneousConstant { span: constant.span });
.emit_bug(errors::PolymorphicConstantTooGeneric { span: constant.span }); }
ErrorHandled::TooGeneric => {
self.cx.tcx().sess.diagnostic().emit_bug(
errors::PolymorphicConstantTooGeneric { span: constant.span },
);
} }
} }
err err
@ -61,6 +47,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
/// This is a convenience helper for `simd_shuffle_indices`. It has the precondition /// This is a convenience helper for `simd_shuffle_indices`. It has the precondition
/// that the given `constant` is an `ConstantKind::Unevaluated` and must be convertible to /// that the given `constant` is an `ConstantKind::Unevaluated` and must be convertible to
/// a `ValTree`. If you want a more general version of this, talk to `wg-const-eval` on zulip. /// a `ValTree`. If you want a more general version of this, talk to `wg-const-eval` on zulip.
///
/// Note that this function is cursed, since usually MIR consts should not be evaluated to valtrees!
pub fn eval_unevaluated_mir_constant_to_valtree( pub fn eval_unevaluated_mir_constant_to_valtree(
&self, &self,
constant: &mir::Constant<'tcx>, constant: &mir::Constant<'tcx>,
@ -80,7 +68,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// `simd_shuffle` call without wrapping the constant argument in a `const {}` block, but // `simd_shuffle` call without wrapping the constant argument in a `const {}` block, but
// the user pass through arbitrary expressions. // the user pass through arbitrary expressions.
// FIXME(oli-obk): replace the magic const generic argument of `simd_shuffle` with a real // FIXME(oli-obk): replace the magic const generic argument of `simd_shuffle` with a real
// const generic. // const generic, and get rid of this entire function.
other => span_bug!(constant.span, "{other:#?}"), other => span_bug!(constant.span, "{other:#?}"),
}; };
let uv = self.monomorphize(uv); let uv = self.monomorphize(uv);

View File

@ -71,6 +71,8 @@ TrivialTypeTraversalAndLiftImpls! { ErrorHandled }
pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>; pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>; pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
/// `Ok(None)` indicates the constant was fine, but the valtree couldn't be constructed.
/// This is needed in `thir::pattern::lower_inline_const`.
pub type EvalToValTreeResult<'tcx> = Result<Option<ValTree<'tcx>>, ErrorHandled>; pub type EvalToValTreeResult<'tcx> = Result<Option<ValTree<'tcx>>, ErrorHandled>;
pub fn struct_error<'tcx>( pub fn struct_error<'tcx>(

View File

@ -2342,29 +2342,39 @@ impl<'tcx> ConstantKind<'tcx> {
} }
#[inline] #[inline]
pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self { pub fn eval(
match self { self,
Self::Ty(c) => { tcx: TyCtxt<'tcx>,
if let Some(val) = c.try_eval_for_mir(tcx, param_env) { param_env: ty::ParamEnv<'tcx>,
match val { span: Option<Span>,
Ok(val) => Self::Val(val, c.ty()), ) -> Result<interpret::ConstValue<'tcx>, ErrorHandled> {
Err(guar) => Self::Ty(ty::Const::new_error(tcx, guar, self.ty())), let uneval = match self {
} ConstantKind::Ty(c) => {
if let ty::ConstKind::Unevaluated(uv) = c.kind() {
// Avoid the round-trip via valtree, evaluate directly to ConstValue.
uv.expand()
} else { } else {
self // It's already a valtree, or an error.
let val = c.eval(tcx, param_env, span)?;
return Ok(tcx.valtree_to_const_val((self.ty(), val)));
} }
} }
Self::Val(_, _) => self, ConstantKind::Unevaluated(uneval, _) => uneval,
Self::Unevaluated(uneval, ty) => { ConstantKind::Val(val, _) => return Ok(val),
};
// FIXME: We might want to have a `try_eval`-like function on `Unevaluated` // FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
match tcx.const_eval_resolve(param_env, uneval, None) { tcx.const_eval_resolve(param_env, uneval, span)
Ok(val) => Self::Val(val, ty), }
Err(ErrorHandled::TooGeneric) => self,
/// Normalizes the constant to a value or an error if possible.
#[inline]
pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
match self.eval(tcx, param_env, None) {
Ok(val) => Self::Val(val, self.ty()),
Err(ErrorHandled::Reported(guar)) => { Err(ErrorHandled::Reported(guar)) => {
Self::Ty(ty::Const::new_error(tcx, guar.into(), ty)) Self::Ty(ty::Const::new_error(tcx, guar.into(), self.ty()))
}
}
} }
Err(ErrorHandled::TooGeneric) => self,
} }
} }
@ -2406,35 +2416,35 @@ impl<'tcx> ConstantKind<'tcx> {
} }
#[inline] #[inline]
pub fn try_eval_bool(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<bool> { pub fn try_eval_scalar(
match self { self,
Self::Ty(ct) => ct.try_eval_bool(tcx, param_env), tcx: TyCtxt<'tcx>,
Self::Val(val, _) => val.try_to_bool(), param_env: ty::ParamEnv<'tcx>,
Self::Unevaluated(uneval, _) => { ) -> Option<Scalar> {
match tcx.const_eval_resolve(param_env, *uneval, None) { self.eval(tcx, param_env, None).ok()?.try_to_scalar()
Ok(val) => val.try_to_bool(),
Err(_) => None,
}
} }
#[inline]
pub fn try_eval_scalar_int(
self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Option<ScalarInt> {
self.try_eval_scalar(tcx, param_env)?.try_to_int().ok()
} }
#[inline]
pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<bool> {
self.try_eval_scalar_int(tcx, param_env)?.try_into().ok()
} }
#[inline] #[inline]
pub fn try_eval_target_usize( pub fn try_eval_target_usize(
&self, self,
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
) -> Option<u64> { ) -> Option<u64> {
match self { self.try_eval_scalar_int(tcx, param_env)?.try_to_target_usize(tcx).ok()
Self::Ty(ct) => ct.try_eval_target_usize(tcx, param_env),
Self::Val(val, _) => val.try_to_target_usize(tcx),
Self::Unevaluated(uneval, _) => {
match tcx.const_eval_resolve(param_env, *uneval, None) {
Ok(val) => val.try_to_target_usize(tcx),
Err(_) => None,
}
}
}
} }
#[inline] #[inline]
@ -2610,6 +2620,11 @@ impl<'tcx> UnevaluatedConst<'tcx> {
pub fn new(def: DefId, args: GenericArgsRef<'tcx>) -> UnevaluatedConst<'tcx> { pub fn new(def: DefId, args: GenericArgsRef<'tcx>) -> UnevaluatedConst<'tcx> {
UnevaluatedConst { def, args, promoted: Default::default() } UnevaluatedConst { def, args, promoted: Default::default() }
} }
#[inline]
pub fn from_instance(instance: ty::Instance<'tcx>) -> Self {
UnevaluatedConst::new(instance.def_id(), instance.args)
}
} }
/// A collection of projections into user types. /// A collection of projections into user types.

View File

@ -1,5 +1,5 @@
use crate::middle::resolve_bound_vars as rbv; use crate::middle::resolve_bound_vars as rbv;
use crate::mir::interpret::{AllocId, ConstValue, LitToConstInput, Scalar}; use crate::mir::interpret::{AllocId, ErrorHandled, LitToConstInput, Scalar};
use crate::ty::{self, GenericArgs, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; use crate::ty::{self, GenericArgs, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
use rustc_data_structures::intern::Interned; use rustc_data_structures::intern::Interned;
use rustc_error_messages::MultiSpan; use rustc_error_messages::MultiSpan;
@ -14,7 +14,7 @@ mod valtree;
pub use int::*; pub use int::*;
pub use kind::*; pub use kind::*;
use rustc_span::ErrorGuaranteed; use rustc_span::Span;
use rustc_span::DUMMY_SP; use rustc_span::DUMMY_SP;
use rustc_target::abi::Size; use rustc_target::abi::Size;
pub use valtree::*; pub use valtree::*;
@ -36,16 +36,6 @@ pub struct ConstData<'tcx> {
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
static_assert_size!(ConstData<'_>, 40); static_assert_size!(ConstData<'_>, 40);
enum EvalMode {
Typeck,
Mir,
}
enum EvalResult<'tcx> {
ValTree(ty::ValTree<'tcx>),
ConstVal(ConstValue<'tcx>),
}
impl<'tcx> Const<'tcx> { impl<'tcx> Const<'tcx> {
#[inline] #[inline]
pub fn ty(self) -> Ty<'tcx> { pub fn ty(self) -> Ty<'tcx> {
@ -302,6 +292,18 @@ impl<'tcx> Const<'tcx> {
} }
} }
#[inline]
/// 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).
pub fn try_eval_scalar_int(
self,
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
) -> Option<ScalarInt> {
self.eval(tcx, param_env, None).ok()?.try_to_scalar_int()
}
#[inline] #[inline]
/// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of /// 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 /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
@ -312,15 +314,16 @@ impl<'tcx> Const<'tcx> {
param_env: ParamEnv<'tcx>, param_env: ParamEnv<'tcx>,
ty: Ty<'tcx>, ty: Ty<'tcx>,
) -> Option<u128> { ) -> Option<u128> {
let int = self.try_eval_scalar_int(tcx, param_env)?;
assert_eq!(self.ty(), ty); assert_eq!(self.ty(), ty);
let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size; let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
// if `ty` does not depend on generic parameters, use an empty param_env // if `ty` does not depend on generic parameters, use an empty param_env
self.eval(tcx, param_env).try_to_bits(size) int.to_bits(size).ok()
} }
#[inline] #[inline]
pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> { pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
self.eval(tcx, param_env).try_to_bool() self.try_eval_scalar_int(tcx, param_env)?.try_into().ok()
} }
#[inline] #[inline]
@ -329,21 +332,16 @@ impl<'tcx> Const<'tcx> {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>, param_env: ParamEnv<'tcx>,
) -> Option<u64> { ) -> Option<u64> {
self.eval(tcx, param_env).try_to_target_usize(tcx) self.try_eval_scalar_int(tcx, param_env)?.try_to_target_usize(tcx).ok()
} }
/// Normalizes the constant to a value or an error if possible.
#[inline] #[inline]
/// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
/// unevaluated constant. match self.eval(tcx, param_env, None) {
pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Const<'tcx> { Ok(val) => Self::new_value(tcx, val, self.ty()),
if let Some(val) = self.try_eval_for_typeck(tcx, param_env) { Err(ErrorHandled::Reported(r)) => Self::new_error(tcx, r.into(), self.ty()),
match val { Err(ErrorHandled::TooGeneric) => self,
Ok(val) => ty::Const::new_value(tcx, val, self.ty()),
Err(guar) => ty::Const::new_error(tcx, guar, self.ty()),
}
} else {
// Either the constant isn't evaluatable or ValTree creation failed.
self
} }
} }
@ -361,51 +359,16 @@ impl<'tcx> Const<'tcx> {
.unwrap_or_else(|| bug!("expected usize, got {:#?}", self)) .unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
} }
#[inline] /// Returns the evaluated constant
/// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary pub fn eval(
/// return `None`.
// FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
pub fn try_eval_for_mir(
self, self,
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>, param_env: ParamEnv<'tcx>,
) -> Option<Result<ConstValue<'tcx>, ErrorGuaranteed>> { span: Option<Span>,
match self.try_eval_inner(tcx, param_env, EvalMode::Mir) { ) -> Result<ValTree<'tcx>, ErrorHandled> {
Some(Ok(EvalResult::ValTree(_))) => unreachable!(),
Some(Ok(EvalResult::ConstVal(v))) => Some(Ok(v)),
Some(Err(e)) => Some(Err(e)),
None => None,
}
}
#[inline]
/// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
/// return `None`.
// FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
pub fn try_eval_for_typeck(
self,
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
) -> Option<Result<ty::ValTree<'tcx>, ErrorGuaranteed>> {
match self.try_eval_inner(tcx, param_env, EvalMode::Typeck) {
Some(Ok(EvalResult::ValTree(v))) => Some(Ok(v)),
Some(Ok(EvalResult::ConstVal(_))) => unreachable!(),
Some(Err(e)) => Some(Err(e)),
None => None,
}
}
#[inline]
fn try_eval_inner(
self,
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
eval_mode: EvalMode,
) -> Option<Result<EvalResult<'tcx>, ErrorGuaranteed>> {
assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}"); assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
if let ConstKind::Unevaluated(unevaluated) = self.kind() { match self.kind() {
use crate::mir::interpret::ErrorHandled; ConstKind::Unevaluated(unevaluated) => {
// HACK(eddyb) this erases lifetimes even though `const_eval_resolve` // HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
// also does later, but we want to do it before checking for // also does later, but we want to do it before checking for
// inference variables. // inference variables.
@ -434,32 +397,16 @@ impl<'tcx> Const<'tcx> {
let (param_env, unevaluated) = param_env_and.into_parts(); let (param_env, unevaluated) = param_env_and.into_parts();
// try to resolve e.g. associated constants to their definition on an impl, and then // try to resolve e.g. associated constants to their definition on an impl, and then
// evaluate the const. // evaluate the const.
match eval_mode { let c = tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span)?;
EvalMode::Typeck => { Ok(c.expect("`ty::Const::eval` called on a non-valtree-compatible type"))
match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, None) {
// NOTE(eddyb) `val` contains no lifetimes/types/consts,
// and we use the original type, so nothing from `args`
// (which may be identity args, see above),
// can leak through `val` into the const we return.
Ok(val) => Some(Ok(EvalResult::ValTree(val?))),
Err(ErrorHandled::TooGeneric) => None,
Err(ErrorHandled::Reported(e)) => Some(Err(e.into())),
} }
} ConstKind::Value(val) => Ok(val),
EvalMode::Mir => { ConstKind::Error(g) => Err(g.into()),
match tcx.const_eval_resolve(param_env, unevaluated.expand(), None) { ConstKind::Param(_)
// NOTE(eddyb) `val` contains no lifetimes/types/consts, | ConstKind::Infer(_)
// and we use the original type, so nothing from `args` | ConstKind::Bound(_, _)
// (which may be identity args, see above), | ConstKind::Placeholder(_)
// can leak through `val` into the const we return. | ConstKind::Expr(_) => Err(ErrorHandled::TooGeneric),
Ok(val) => Some(Ok(EvalResult::ConstVal(val))),
Err(ErrorHandled::TooGeneric) => None,
Err(ErrorHandled::Reported(e)) => Some(Err(e.into())),
}
}
}
} else {
None
} }
} }

View File

@ -626,6 +626,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args: args }; let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args: args };
// First try using a valtree in order to destructure the constant into a pattern. // First try using a valtree in order to destructure the constant into a pattern.
// FIXME: replace "try to do a thing, then fall back to another thing"
// but something more principled, like a trait query checking whether this can be turned into a valtree.
if let Ok(Some(valtree)) = if let Ok(Some(valtree)) =
self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span)) self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span))
{ {

View File

@ -209,7 +209,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
&& let operand_ty = operand.ty(self.local_decls, self.tcx) && let operand_ty = operand.ty(self.local_decls, self.tcx)
&& let Some(operand_ty) = operand_ty.builtin_deref(true) && let Some(operand_ty) = operand_ty.builtin_deref(true)
&& let ty::Array(_, len) = operand_ty.ty.kind() && let ty::Array(_, len) = operand_ty.ty.kind()
&& let Some(len) = ConstantKind::Ty(*len).eval(self.tcx, self.param_env).try_to_scalar_int() && let Some(len) = ConstantKind::Ty(*len).try_eval_scalar_int(self.tcx, self.param_env)
{ {
state.insert_value_idx(target_len, FlatSet::Elem(len.into()), self.map()); state.insert_value_idx(target_len, FlatSet::Elem(len.into()), self.map());
} }
@ -228,8 +228,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
let place_ty = place.ty(self.local_decls, self.tcx); let place_ty = place.ty(self.local_decls, self.tcx);
if let ty::Array(_, len) = place_ty.ty.kind() { if let ty::Array(_, len) = place_ty.ty.kind() {
ConstantKind::Ty(*len) ConstantKind::Ty(*len)
.eval(self.tcx, self.param_env) .try_eval_scalar(self.tcx, self.param_env)
.try_to_scalar()
.map_or(FlatSet::Top, FlatSet::Elem) .map_or(FlatSet::Top, FlatSet::Elem)
} else if let [ProjectionElem::Deref] = place.projection[..] { } else if let [ProjectionElem::Deref] = place.projection[..] {
state.get_len(place.local.into(), self.map()) state.get_len(place.local.into(), self.map())
@ -304,8 +303,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
) -> Self::Value { ) -> Self::Value {
constant constant
.literal .literal
.eval(self.tcx, self.param_env) .try_eval_scalar(self.tcx, self.param_env)
.try_to_scalar()
.map_or(FlatSet::Top, FlatSet::Elem) .map_or(FlatSet::Top, FlatSet::Elem)
} }

View File

@ -562,7 +562,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
fn print_const(mut self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { fn print_const(mut self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
// We only mangle a typed value if the const can be evaluated. // We only mangle a typed value if the const can be evaluated.
let ct = ct.eval(self.tcx, ty::ParamEnv::reveal_all()); let ct = ct.normalize(self.tcx, ty::ParamEnv::reveal_all());
match ct.kind() { match ct.kind() {
ty::ConstKind::Value(_) => {} ty::ConstKind::Value(_) => {}

View File

@ -2054,7 +2054,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
tcx: self.tcx, tcx: self.tcx,
ty_op: |ty| ty, ty_op: |ty| ty,
lt_op: |lt| lt, lt_op: |lt| lt,
ct_op: |ct| ct.eval(self.tcx, ty::ParamEnv::empty()), ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
}); });
cand cand
}) })

View File

@ -288,7 +288,7 @@ pub fn normalize_param_env_or_error<'tcx>(
// should actually be okay since without `feature(generic_const_exprs)` the only // should actually be okay since without `feature(generic_const_exprs)` the only
// const arguments that have a non-empty param env are array repeat counts. These // const arguments that have a non-empty param env are array repeat counts. These
// do not appear in the type system though. // do not appear in the type system though.
c.eval(self.0, ty::ParamEnv::empty()) c.normalize(self.0, ty::ParamEnv::empty())
} }
} }

View File

@ -761,7 +761,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
self.selcx.infcx, self.selcx.infcx,
&mut self.universes, &mut self.universes,
constant, constant,
|constant| constant.eval(tcx, self.param_env), |constant| constant.normalize(tcx, self.param_env),
) )
} }
} }

View File

@ -358,7 +358,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
self.infcx, self.infcx,
&mut self.universes, &mut self.universes,
constant, constant,
|constant| constant.eval(self.infcx.tcx, self.param_env), |constant| constant.normalize(self.infcx.tcx, self.param_env),
)) ))
} }

View File

@ -129,19 +129,16 @@ mod rustc {
c: Const<'tcx>, c: Const<'tcx>,
) -> Option<Self> { ) -> Option<Self> {
use rustc_middle::ty::ScalarInt; use rustc_middle::ty::ScalarInt;
use rustc_middle::ty::TypeVisitableExt;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
let c = c.eval(tcx, param_env); let Ok(cv) = c.eval(tcx, param_env, None) else {
if let Err(err) = c.error_reported() {
return Some(Self { return Some(Self {
alignment: true, alignment: true,
lifetimes: true, lifetimes: true,
safety: true, safety: true,
validity: true, validity: true,
}); });
} };
let adt_def = c.ty().ty_adt_def()?; let adt_def = c.ty().ty_adt_def()?;
@ -153,8 +150,8 @@ mod rustc {
); );
let variant = adt_def.non_enum_variant(); let variant = adt_def.non_enum_variant();
let fields = match c.try_to_valtree() { let fields = match cv {
Some(ValTree::Branch(branch)) => branch, ValTree::Branch(branch) => branch,
_ => { _ => {
return Some(Self { return Some(Self {
alignment: true, alignment: true,

View File

@ -1863,7 +1863,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
// does nothing for `ConstKind::Param`. // does nothing for `ConstKind::Param`.
let ct = ty::Const::from_anon_const(cx.tcx, anon_const.def_id); let ct = ty::Const::from_anon_const(cx.tcx, anon_const.def_id);
let param_env = cx.tcx.param_env(anon_const.def_id); let param_env = cx.tcx.param_env(anon_const.def_id);
print_const(cx, ct.eval(cx.tcx, param_env)) print_const(cx, ct.normalize(cx.tcx, param_env))
} }
}; };
@ -2082,7 +2082,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
ty::Str => Primitive(PrimitiveType::Str), ty::Str => Primitive(PrimitiveType::Str),
ty::Slice(ty) => Slice(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None))), ty::Slice(ty) => Slice(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None))),
ty::Array(ty, mut n) => { ty::Array(ty, mut n) => {
n = n.eval(cx.tcx, ty::ParamEnv::reveal_all()); n = n.normalize(cx.tcx, ty::ParamEnv::reveal_all());
let n = print_const(cx, n); let n = print_const(cx, n);
Array(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None)), n.into()) Array(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None)), n.into())
} }