mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Auto merge of #115803 - RalfJung:const-eval, r=oli-obk
make the eval() functions on our const types return the resulting value This is a part of https://github.com/rust-lang/rust/pull/115748 that's hopefully perf-neutral, and that does not depend on https://github.com/rust-lang/rust/pull/115764.
This commit is contained in:
commit
76e59c71e8
@ -723,11 +723,8 @@ fn codegen_stmt<'tcx>(
|
||||
}
|
||||
Rvalue::Repeat(ref operand, times) => {
|
||||
let operand = codegen_operand(fx, operand);
|
||||
let times = fx
|
||||
.monomorphize(times)
|
||||
.eval(fx.tcx, ParamEnv::reveal_all())
|
||||
.try_to_bits(fx.tcx.data_layout.pointer_size)
|
||||
.unwrap();
|
||||
let times =
|
||||
fx.monomorphize(times).eval_target_usize(fx.tcx, ParamEnv::reveal_all());
|
||||
if operand.layout().size.bytes() == 0 {
|
||||
// Do nothing for ZST's
|
||||
} else if fx.clif_type(operand.layout().ty) == Some(types::I8) {
|
||||
|
@ -77,31 +77,9 @@ pub(crate) fn eval_mir_constant<'tcx>(
|
||||
fx: &FunctionCx<'_, '_, 'tcx>,
|
||||
constant: &Constant<'tcx>,
|
||||
) -> Option<(ConstValue<'tcx>, Ty<'tcx>)> {
|
||||
let constant_kind = fx.monomorphize(constant.literal);
|
||||
let uv = match constant_kind {
|
||||
ConstantKind::Ty(const_) => match const_.kind() {
|
||||
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)
|
||||
let cv = fx.monomorphize(constant.literal);
|
||||
let val = cv
|
||||
.eval(fx.tcx, ty::ParamEnv::reveal_all(), Some(constant.span))
|
||||
.map_err(|err| match err {
|
||||
ErrorHandled::Reported(_) => {
|
||||
fx.tcx.sess.span_err(constant.span, "erroneous constant encountered");
|
||||
@ -111,7 +89,7 @@ pub(crate) fn eval_mir_constant<'tcx>(
|
||||
}
|
||||
})
|
||||
.ok();
|
||||
val.map(|val| (val, constant_kind.ty()))
|
||||
val.map(|val| (val, cv.ty()))
|
||||
}
|
||||
|
||||
pub(crate) fn codegen_constant_operand<'tcx>(
|
||||
|
@ -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.
|
||||
let hash_short = tcx.with_stable_hashing_context(|mut hcx| {
|
||||
let mut hasher = StableHasher::new();
|
||||
let ct = ct.eval(tcx, ty::ParamEnv::reveal_all());
|
||||
hcx.while_hashing_spans(false, |hcx| {
|
||||
ct.to_valtree().hash_stable(hcx, &mut hasher)
|
||||
});
|
||||
let ct = ct.eval(tcx, ty::ParamEnv::reveal_all(), None).unwrap();
|
||||
hcx.while_hashing_spans(false, |hcx| ct.hash_stable(hcx, &mut hasher));
|
||||
hasher.finish::<Hash64>()
|
||||
});
|
||||
|
||||
|
@ -24,43 +24,31 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
&self,
|
||||
constant: &mir::Constant<'tcx>,
|
||||
) -> Result<ConstValue<'tcx>, ErrorHandled> {
|
||||
let ct = self.monomorphize(constant.literal);
|
||||
let uv = match ct {
|
||||
mir::ConstantKind::Ty(ct) => match ct.kind() {
|
||||
ty::ConstKind::Unevaluated(uv) => uv.expand(),
|
||||
ty::ConstKind::Value(val) => {
|
||||
return Ok(self.cx.tcx().valtree_to_const_val((ct.ty(), val)));
|
||||
self.monomorphize(constant.literal)
|
||||
.eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), Some(constant.span))
|
||||
.map_err(|err| {
|
||||
match err {
|
||||
ErrorHandled::Reported(_) => {
|
||||
self.cx
|
||||
.tcx()
|
||||
.sess
|
||||
.emit_err(errors::ErroneousConstant { span: constant.span });
|
||||
}
|
||||
ErrorHandled::TooGeneric => {
|
||||
self.cx.tcx().sess.diagnostic().emit_bug(
|
||||
errors::PolymorphicConstantTooGeneric { span: constant.span },
|
||||
);
|
||||
}
|
||||
}
|
||||
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 {
|
||||
ErrorHandled::Reported(_) => {
|
||||
self.cx.tcx().sess.emit_err(errors::ErroneousConstant { span: constant.span });
|
||||
}
|
||||
ErrorHandled::TooGeneric => {
|
||||
self.cx
|
||||
.tcx()
|
||||
.sess
|
||||
.diagnostic()
|
||||
.emit_bug(errors::PolymorphicConstantTooGeneric { span: constant.span });
|
||||
}
|
||||
}
|
||||
err
|
||||
})
|
||||
err
|
||||
})
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// 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(
|
||||
&self,
|
||||
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
|
||||
// the user pass through arbitrary expressions.
|
||||
// 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:#?}"),
|
||||
};
|
||||
let uv = self.monomorphize(uv);
|
||||
|
@ -71,6 +71,8 @@ TrivialTypeTraversalAndLiftImpls! { ErrorHandled }
|
||||
|
||||
pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'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 fn struct_error<'tcx>(
|
||||
|
@ -2299,18 +2299,6 @@ impl<'tcx> ConstantKind<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_value(self, tcx: TyCtxt<'tcx>) -> Option<interpret::ConstValue<'tcx>> {
|
||||
match self {
|
||||
ConstantKind::Ty(c) => match c.kind() {
|
||||
ty::ConstKind::Value(valtree) => Some(tcx.valtree_to_const_val((c.ty(), valtree))),
|
||||
_ => None,
|
||||
},
|
||||
ConstantKind::Val(val, _) => Some(val),
|
||||
ConstantKind::Unevaluated(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_scalar(self) -> Option<Scalar> {
|
||||
match self {
|
||||
@ -2342,32 +2330,74 @@ impl<'tcx> ConstantKind<'tcx> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
|
||||
match self {
|
||||
Self::Ty(c) => {
|
||||
if let Some(val) = c.try_eval_for_mir(tcx, param_env) {
|
||||
match val {
|
||||
Ok(val) => Self::Val(val, c.ty()),
|
||||
Err(guar) => Self::Ty(ty::Const::new_error(tcx, guar, self.ty())),
|
||||
}
|
||||
pub fn eval(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
span: Option<Span>,
|
||||
) -> Result<interpret::ConstValue<'tcx>, ErrorHandled> {
|
||||
let (uneval, param_env) = match self {
|
||||
ConstantKind::Ty(c) => {
|
||||
if let ty::ConstKind::Unevaluated(uneval) = c.kind() {
|
||||
// Avoid the round-trip via valtree, evaluate directly to ConstValue.
|
||||
let (param_env, uneval) = uneval.prepare_for_eval(tcx, param_env);
|
||||
(uneval.expand(), param_env)
|
||||
} 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,
|
||||
Self::Unevaluated(uneval, ty) => {
|
||||
// FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
|
||||
match tcx.const_eval_resolve(param_env, uneval, None) {
|
||||
Ok(val) => Self::Val(val, ty),
|
||||
Err(ErrorHandled::TooGeneric) => self,
|
||||
Err(ErrorHandled::Reported(guar)) => {
|
||||
Self::Ty(ty::Const::new_error(tcx, guar.into(), ty))
|
||||
}
|
||||
}
|
||||
ConstantKind::Unevaluated(uneval, _) => (uneval, param_env),
|
||||
ConstantKind::Val(val, _) => return Ok(val),
|
||||
};
|
||||
// FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
|
||||
tcx.const_eval_resolve(param_env, uneval, span)
|
||||
}
|
||||
|
||||
/// 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)) => {
|
||||
Self::Ty(ty::Const::new_error(tcx, guar.into(), self.ty()))
|
||||
}
|
||||
Err(ErrorHandled::TooGeneric) => self,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_eval_scalar(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Option<Scalar> {
|
||||
self.eval(tcx, param_env, None).ok()?.try_to_scalar()
|
||||
}
|
||||
|
||||
#[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_bits(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Option<u128> {
|
||||
let int = self.try_eval_scalar_int(tcx, param_env)?;
|
||||
assert_eq!(self.ty(), ty);
|
||||
let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
|
||||
int.to_bits(size).ok()
|
||||
}
|
||||
|
||||
/// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
|
||||
#[inline]
|
||||
pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
|
||||
@ -2375,66 +2405,25 @@ impl<'tcx> ConstantKind<'tcx> {
|
||||
.unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_eval_bits(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Option<u128> {
|
||||
match self {
|
||||
Self::Ty(ct) => ct.try_eval_bits(tcx, param_env, ty),
|
||||
Self::Val(val, t) => {
|
||||
assert_eq!(*t, ty);
|
||||
let size =
|
||||
tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
|
||||
val.try_to_bits(size)
|
||||
}
|
||||
Self::Unevaluated(uneval, ty) => {
|
||||
match tcx.const_eval_resolve(param_env, *uneval, None) {
|
||||
Ok(val) => {
|
||||
let size = tcx
|
||||
.layout_of(param_env.with_reveal_all_normalized(tcx).and(*ty))
|
||||
.ok()?
|
||||
.size;
|
||||
val.try_to_bits(size)
|
||||
}
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_eval_bool(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<bool> {
|
||||
match self {
|
||||
Self::Ty(ct) => ct.try_eval_bool(tcx, param_env),
|
||||
Self::Val(val, _) => val.try_to_bool(),
|
||||
Self::Unevaluated(uneval, _) => {
|
||||
match tcx.const_eval_resolve(param_env, *uneval, None) {
|
||||
Ok(val) => val.try_to_bool(),
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_eval_target_usize(
|
||||
&self,
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Option<u64> {
|
||||
match self {
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
self.try_eval_scalar_int(tcx, param_env)?.try_to_target_usize(tcx).ok()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Panics if the value cannot be evaluated or doesn't contain a valid `usize`.
|
||||
pub fn eval_target_usize(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> u64 {
|
||||
self.try_eval_target_usize(tcx, param_env)
|
||||
.unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
|
||||
}
|
||||
|
||||
#[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]
|
||||
@ -2576,7 +2565,7 @@ impl<'tcx> ConstantKind<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_const(c: ty::Const<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
|
||||
pub fn from_ty_const(c: ty::Const<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
|
||||
match c.kind() {
|
||||
ty::ConstKind::Value(valtree) => {
|
||||
let const_val = tcx.valtree_to_const_val((c.ty(), valtree));
|
||||
@ -2610,6 +2599,11 @@ impl<'tcx> UnevaluatedConst<'tcx> {
|
||||
pub fn new(def: DefId, args: GenericArgsRef<'tcx>) -> UnevaluatedConst<'tcx> {
|
||||
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.
|
||||
@ -2884,7 +2878,7 @@ fn pretty_print_const_value<'tcx>(
|
||||
}
|
||||
}
|
||||
(ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => {
|
||||
let n = n.try_to_bits(tcx.data_layout.pointer_size).unwrap();
|
||||
let n = n.try_to_target_usize(tcx).unwrap();
|
||||
// cast is ok because we already checked for pointer size (32 or 64 bit) above
|
||||
let range = AllocRange { start: offset, size: Size::from_bytes(n) };
|
||||
let byte_str = alloc.inner().get_bytes_strip_provenance(&tcx, range).unwrap();
|
||||
|
@ -1,5 +1,5 @@
|
||||
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 rustc_data_structures::intern::Interned;
|
||||
use rustc_error_messages::MultiSpan;
|
||||
@ -14,9 +14,8 @@ mod valtree;
|
||||
|
||||
pub use int::*;
|
||||
pub use kind::*;
|
||||
use rustc_span::ErrorGuaranteed;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_target::abi::Size;
|
||||
pub use valtree::*;
|
||||
|
||||
use super::sty::ConstKind;
|
||||
@ -36,16 +35,6 @@ pub struct ConstData<'tcx> {
|
||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||
static_assert_size!(ConstData<'_>, 40);
|
||||
|
||||
enum EvalMode {
|
||||
Typeck,
|
||||
Mir,
|
||||
}
|
||||
|
||||
enum EvalResult<'tcx> {
|
||||
ValTree(ty::ValTree<'tcx>),
|
||||
ConstVal(ConstValue<'tcx>),
|
||||
}
|
||||
|
||||
impl<'tcx> Const<'tcx> {
|
||||
#[inline]
|
||||
pub fn ty(self) -> Ty<'tcx> {
|
||||
@ -165,7 +154,7 @@ impl<'tcx> Const<'tcx> {
|
||||
|
||||
let ty = tcx.type_of(def).no_bound_vars().expect("const parameter types cannot be generic");
|
||||
|
||||
match Self::try_eval_lit_or_param(tcx, ty, expr) {
|
||||
match Self::try_from_lit_or_param(tcx, ty, expr) {
|
||||
Some(v) => v,
|
||||
None => ty::Const::new_unevaluated(
|
||||
tcx,
|
||||
@ -179,7 +168,7 @@ impl<'tcx> Const<'tcx> {
|
||||
}
|
||||
|
||||
#[instrument(skip(tcx), level = "debug")]
|
||||
fn try_eval_lit_or_param(
|
||||
fn try_from_lit_or_param(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
@ -254,14 +243,6 @@ impl<'tcx> Const<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Panics if self.kind != ty::ConstKind::Value
|
||||
pub fn to_valtree(self) -> ty::ValTree<'tcx> {
|
||||
match self.kind() {
|
||||
ty::ConstKind::Value(valtree) => valtree,
|
||||
_ => bug!("expected ConstKind::Value, got {:?}", self.kind()),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Creates a constant with the given integer value and interns it.
|
||||
pub fn from_bits(tcx: TyCtxt<'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> Self {
|
||||
@ -294,14 +275,66 @@ impl<'tcx> Const<'tcx> {
|
||||
Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize))
|
||||
}
|
||||
|
||||
/// Attempts to convert to a `ValTree`
|
||||
pub fn try_to_valtree(self) -> Option<ty::ValTree<'tcx>> {
|
||||
/// Returns the evaluated constant
|
||||
#[inline]
|
||||
pub fn eval(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
span: Option<Span>,
|
||||
) -> Result<ValTree<'tcx>, ErrorHandled> {
|
||||
assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
|
||||
match self.kind() {
|
||||
ty::ConstKind::Value(valtree) => Some(valtree),
|
||||
_ => None,
|
||||
ConstKind::Unevaluated(unevaluated) => {
|
||||
// FIXME(eddyb) maybe the `const_eval_*` methods should take
|
||||
// `ty::ParamEnvAnd` instead of having them separate.
|
||||
let (param_env, unevaluated) = unevaluated.prepare_for_eval(tcx, param_env);
|
||||
// try to resolve e.g. associated constants to their definition on an impl, and then
|
||||
// evaluate the const.
|
||||
let c = tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span)?;
|
||||
Ok(c.expect("`ty::Const::eval` called on a non-valtree-compatible type"))
|
||||
}
|
||||
ConstKind::Value(val) => Ok(val),
|
||||
ConstKind::Error(g) => Err(g.into()),
|
||||
ConstKind::Param(_)
|
||||
| ConstKind::Infer(_)
|
||||
| ConstKind::Bound(_, _)
|
||||
| ConstKind::Placeholder(_)
|
||||
| ConstKind::Expr(_) => Err(ErrorHandled::TooGeneric),
|
||||
}
|
||||
}
|
||||
|
||||
/// Normalizes the constant to a value or an error if possible.
|
||||
#[inline]
|
||||
pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
|
||||
match self.eval(tcx, param_env, None) {
|
||||
Ok(val) => Self::new_value(tcx, val, self.ty()),
|
||||
Err(ErrorHandled::Reported(r)) => Self::new_error(tcx, r.into(), self.ty()),
|
||||
Err(ErrorHandled::TooGeneric) => self,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_eval_scalar(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Option<Scalar> {
|
||||
self.eval(tcx, param_env, None).ok()?.try_to_scalar()
|
||||
}
|
||||
|
||||
#[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.try_eval_scalar(tcx, param_env)?.try_to_int().ok()
|
||||
}
|
||||
|
||||
#[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
|
||||
@ -312,39 +345,11 @@ impl<'tcx> Const<'tcx> {
|
||||
param_env: ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Option<u128> {
|
||||
let int = self.try_eval_scalar_int(tcx, param_env)?;
|
||||
assert_eq!(self.ty(), ty);
|
||||
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
|
||||
self.eval(tcx, param_env).try_to_bits(size)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
|
||||
self.eval(tcx, param_env).try_to_bool()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_eval_target_usize(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
) -> Option<u64> {
|
||||
self.eval(tcx, param_env).try_to_target_usize(tcx)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
|
||||
/// unevaluated constant.
|
||||
pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Const<'tcx> {
|
||||
if let Some(val) = self.try_eval_for_typeck(tcx, param_env) {
|
||||
match val {
|
||||
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
|
||||
}
|
||||
int.to_bits(size).ok()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -354,6 +359,20 @@ impl<'tcx> Const<'tcx> {
|
||||
.unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_eval_target_usize(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
) -> Option<u64> {
|
||||
self.try_eval_scalar_int(tcx, param_env)?.try_to_target_usize(tcx).ok()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
|
||||
self.try_eval_scalar_int(tcx, param_env)?.try_into().ok()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Panics if the value cannot be evaluated or doesn't contain a valid `usize`.
|
||||
pub fn eval_target_usize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u64 {
|
||||
@ -361,136 +380,30 @@ impl<'tcx> Const<'tcx> {
|
||||
.unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
|
||||
}
|
||||
|
||||
#[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_mir(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
) -> Option<Result<ConstValue<'tcx>, ErrorGuaranteed>> {
|
||||
match self.try_eval_inner(tcx, param_env, EvalMode::Mir) {
|
||||
Some(Ok(EvalResult::ValTree(_))) => unreachable!(),
|
||||
Some(Ok(EvalResult::ConstVal(v))) => Some(Ok(v)),
|
||||
Some(Err(e)) => Some(Err(e)),
|
||||
None => None,
|
||||
/// Panics if self.kind != ty::ConstKind::Value
|
||||
pub fn to_valtree(self) -> ty::ValTree<'tcx> {
|
||||
match self.kind() {
|
||||
ty::ConstKind::Value(valtree) => valtree,
|
||||
_ => bug!("expected ConstKind::Value, got {:?}", self.kind()),
|
||||
}
|
||||
}
|
||||
|
||||
#[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,
|
||||
/// Attempts to convert to a `ValTree`
|
||||
pub fn try_to_valtree(self) -> Option<ty::ValTree<'tcx>> {
|
||||
match self.kind() {
|
||||
ty::ConstKind::Value(valtree) => Some(valtree),
|
||||
_ => 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:?}");
|
||||
if let ConstKind::Unevaluated(unevaluated) = self.kind() {
|
||||
use crate::mir::interpret::ErrorHandled;
|
||||
|
||||
// HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
|
||||
// also does later, but we want to do it before checking for
|
||||
// inference variables.
|
||||
// Note that we erase regions *before* calling `with_reveal_all_normalized`,
|
||||
// so that we don't try to invoke this query with
|
||||
// any region variables.
|
||||
|
||||
// HACK(eddyb) when the query key would contain inference variables,
|
||||
// attempt using identity args and `ParamEnv` instead, that will succeed
|
||||
// when the expression doesn't depend on any parameters.
|
||||
// FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
|
||||
// we can call `infcx.const_eval_resolve` which handles inference variables.
|
||||
let param_env_and = if (param_env, unevaluated).has_non_region_infer() {
|
||||
tcx.param_env(unevaluated.def).and(ty::UnevaluatedConst {
|
||||
def: unevaluated.def,
|
||||
args: GenericArgs::identity_for_item(tcx, unevaluated.def),
|
||||
})
|
||||
} else {
|
||||
tcx.erase_regions(param_env)
|
||||
.with_reveal_all_normalized(tcx)
|
||||
.and(tcx.erase_regions(unevaluated))
|
||||
};
|
||||
|
||||
// FIXME(eddyb) maybe the `const_eval_*` methods should take
|
||||
// `ty::ParamEnvAnd` instead of having them separate.
|
||||
let (param_env, unevaluated) = param_env_and.into_parts();
|
||||
// try to resolve e.g. associated constants to their definition on an impl, and then
|
||||
// evaluate the const.
|
||||
match eval_mode {
|
||||
EvalMode::Typeck => {
|
||||
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())),
|
||||
}
|
||||
}
|
||||
EvalMode::Mir => {
|
||||
match tcx.const_eval_resolve(param_env, unevaluated.expand(), 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::ConstVal(val))),
|
||||
Err(ErrorHandled::TooGeneric) => None,
|
||||
Err(ErrorHandled::Reported(e)) => Some(Err(e.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_value(self) -> Option<ty::ValTree<'tcx>> {
|
||||
if let ConstKind::Value(val) = self.kind() { Some(val) } else { None }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> {
|
||||
self.try_to_value()?.try_to_scalar()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
|
||||
self.try_to_value()?.try_to_scalar_int()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_bits(self, size: Size) -> Option<u128> {
|
||||
self.try_to_scalar_int()?.to_bits(size).ok()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_bool(self) -> Option<bool> {
|
||||
self.try_to_scalar_int()?.try_into().ok()
|
||||
self.try_to_valtree()?.try_to_scalar()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
|
||||
self.try_to_value()?.try_to_target_usize(tcx)
|
||||
self.try_to_valtree()?.try_to_target_usize(tcx)
|
||||
}
|
||||
|
||||
pub fn is_ct_infer(self) -> bool {
|
||||
|
@ -2,7 +2,7 @@ use super::Const;
|
||||
use crate::mir;
|
||||
use crate::ty::abstract_const::CastKind;
|
||||
use crate::ty::GenericArgsRef;
|
||||
use crate::ty::{self, List, Ty};
|
||||
use crate::ty::{self, visit::TypeVisitableExt as _, List, Ty, TyCtxt};
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_macros::HashStable;
|
||||
@ -26,6 +26,39 @@ impl<'tcx> UnevaluatedConst<'tcx> {
|
||||
pub fn expand(self) -> mir::UnevaluatedConst<'tcx> {
|
||||
mir::UnevaluatedConst { def: self.def, args: self.args, promoted: None }
|
||||
}
|
||||
|
||||
/// FIXME(RalfJung): I cannot explain what this does or why it makes sense, but not doing this
|
||||
/// hurts performance.
|
||||
#[inline]
|
||||
pub(crate) fn prepare_for_eval(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> (ty::ParamEnv<'tcx>, Self) {
|
||||
// HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
|
||||
// also does later, but we want to do it before checking for
|
||||
// inference variables.
|
||||
// Note that we erase regions *before* calling `with_reveal_all_normalized`,
|
||||
// so that we don't try to invoke this query with
|
||||
// any region variables.
|
||||
|
||||
// HACK(eddyb) when the query key would contain inference variables,
|
||||
// attempt using identity args and `ParamEnv` instead, that will succeed
|
||||
// when the expression doesn't depend on any parameters.
|
||||
// FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
|
||||
// we can call `infcx.const_eval_resolve` which handles inference variables.
|
||||
if (param_env, self).has_non_region_infer() {
|
||||
(
|
||||
tcx.param_env(self.def),
|
||||
ty::UnevaluatedConst {
|
||||
def: self.def,
|
||||
args: ty::GenericArgs::identity_for_item(tcx, self.def),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
(tcx.erase_regions(param_env).with_reveal_all_normalized(tcx), tcx.erase_regions(self))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UnevaluatedConst<'tcx> {
|
||||
|
@ -198,11 +198,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
}
|
||||
(Some(PatKind::Constant { value: lo }), None) => {
|
||||
let hi = ty.numeric_max_val(self.tcx)?;
|
||||
Some((*lo, mir::ConstantKind::from_const(hi, self.tcx)))
|
||||
Some((*lo, mir::ConstantKind::from_ty_const(hi, self.tcx)))
|
||||
}
|
||||
(None, Some(PatKind::Constant { value: hi })) => {
|
||||
let lo = ty.numeric_min_val(self.tcx)?;
|
||||
Some((mir::ConstantKind::from_const(lo, self.tcx), *hi))
|
||||
Some((mir::ConstantKind::from_ty_const(lo, self.tcx), *hi))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
@ -626,6 +626,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
|
||||
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.
|
||||
// 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)) =
|
||||
self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span))
|
||||
{
|
||||
|
@ -209,7 +209,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
|
||||
&& let operand_ty = operand.ty(self.local_decls, self.tcx)
|
||||
&& let Some(operand_ty) = operand_ty.builtin_deref(true)
|
||||
&& 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());
|
||||
}
|
||||
@ -228,8 +228,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
|
||||
let place_ty = place.ty(self.local_decls, self.tcx);
|
||||
if let ty::Array(_, len) = place_ty.ty.kind() {
|
||||
ConstantKind::Ty(*len)
|
||||
.eval(self.tcx, self.param_env)
|
||||
.try_to_scalar()
|
||||
.try_eval_scalar(self.tcx, self.param_env)
|
||||
.map_or(FlatSet::Top, FlatSet::Elem)
|
||||
} else if let [ProjectionElem::Deref] = place.projection[..] {
|
||||
state.get_len(place.local.into(), self.map())
|
||||
@ -304,8 +303,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
|
||||
) -> Self::Value {
|
||||
constant
|
||||
.literal
|
||||
.eval(self.tcx, self.param_env)
|
||||
.try_to_scalar()
|
||||
.try_eval_scalar(self.tcx, self.param_env)
|
||||
.map_or(FlatSet::Top, FlatSet::Elem)
|
||||
}
|
||||
|
||||
|
@ -136,7 +136,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
|
||||
return;
|
||||
}
|
||||
|
||||
let literal = ConstantKind::from_const(len, self.tcx);
|
||||
let literal = ConstantKind::from_ty_const(len, self.tcx);
|
||||
let constant = Constant { span: source_info.span, literal, user_ty: None };
|
||||
*rvalue = Rvalue::Use(Operand::Constant(Box::new(constant)));
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
|
||||
*rvalue = Rvalue::Use(Operand::Constant(Box::new(Constant {
|
||||
span: rustc_span::DUMMY_SP,
|
||||
user_ty: None,
|
||||
literal: ConstantKind::from_const(len, self.tcx),
|
||||
literal: ConstantKind::from_ty_const(len, self.tcx),
|
||||
})));
|
||||
}
|
||||
self.super_rvalue(rvalue, loc);
|
||||
|
@ -230,7 +230,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> {
|
||||
self.write_str("[")?;
|
||||
self = self.print_type(ty)?;
|
||||
self.write_str("; ")?;
|
||||
if let Some(size) = size.try_to_bits(self.tcx().data_layout.pointer_size) {
|
||||
if let Some(size) = size.try_to_target_usize(self.tcx()) {
|
||||
write!(self, "{size}")?
|
||||
} else if let ty::ConstKind::Param(param) = size.kind() {
|
||||
self = param.print(self)?
|
||||
|
@ -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> {
|
||||
// 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() {
|
||||
ty::ConstKind::Value(_) => {}
|
||||
|
||||
|
@ -2054,7 +2054,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
tcx: self.tcx,
|
||||
ty_op: |ty| ty,
|
||||
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
|
||||
})
|
||||
|
@ -257,7 +257,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
// Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]`
|
||||
if let ty::Array(aty, len) = self_ty.kind() {
|
||||
flags.push((sym::_Self, Some("[]".to_string())));
|
||||
let len = len.try_to_value().and_then(|v| v.try_to_target_usize(self.tcx));
|
||||
let len = len.try_to_valtree().and_then(|v| v.try_to_target_usize(self.tcx));
|
||||
flags.push((sym::_Self, Some(format!("[{aty}; _]"))));
|
||||
if let Some(n) = len {
|
||||
flags.push((sym::_Self, Some(format!("[{aty}; {n}]"))));
|
||||
|
@ -288,7 +288,7 @@ pub fn normalize_param_env_or_error<'tcx>(
|
||||
// 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
|
||||
// do not appear in the type system though.
|
||||
c.eval(self.0, ty::ParamEnv::empty())
|
||||
c.normalize(self.0, ty::ParamEnv::empty())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -761,7 +761,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
|
||||
self.selcx.infcx,
|
||||
&mut self.universes,
|
||||
constant,
|
||||
|constant| constant.eval(tcx, self.param_env),
|
||||
|constant| constant.normalize(tcx, self.param_env),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -358,7 +358,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
|
||||
self.infcx,
|
||||
&mut self.universes,
|
||||
constant,
|
||||
|constant| constant.eval(self.infcx.tcx, self.param_env),
|
||||
|constant| constant.normalize(self.infcx.tcx, self.param_env),
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -129,19 +129,16 @@ mod rustc {
|
||||
c: Const<'tcx>,
|
||||
) -> Option<Self> {
|
||||
use rustc_middle::ty::ScalarInt;
|
||||
use rustc_middle::ty::TypeVisitableExt;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
let c = c.eval(tcx, param_env);
|
||||
|
||||
if let Err(err) = c.error_reported() {
|
||||
let Ok(cv) = c.eval(tcx, param_env, None) else {
|
||||
return Some(Self {
|
||||
alignment: true,
|
||||
lifetimes: true,
|
||||
safety: true,
|
||||
validity: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let adt_def = c.ty().ty_adt_def()?;
|
||||
|
||||
@ -153,8 +150,8 @@ mod rustc {
|
||||
);
|
||||
|
||||
let variant = adt_def.non_enum_variant();
|
||||
let fields = match c.try_to_valtree() {
|
||||
Some(ValTree::Branch(branch)) => branch,
|
||||
let fields = match cv {
|
||||
ValTree::Branch(branch) => branch,
|
||||
_ => {
|
||||
return Some(Self {
|
||||
alignment: true,
|
||||
|
@ -1863,7 +1863,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
|
||||
// does nothing for `ConstKind::Param`.
|
||||
let ct = ty::Const::from_anon_const(cx.tcx, 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::Slice(ty) => Slice(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None))),
|
||||
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);
|
||||
Array(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None)), n.into())
|
||||
}
|
||||
|
@ -37,22 +37,14 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
|
||||
Some(lhs) => constant(cx, cx.typeck_results(), lhs)?,
|
||||
None => {
|
||||
let min_val_const = ty.numeric_min_val(cx.tcx)?;
|
||||
let min_constant = mir::ConstantKind::from_value(
|
||||
cx.tcx.valtree_to_const_val((ty, min_val_const.to_valtree())),
|
||||
ty,
|
||||
);
|
||||
miri_to_const(cx, min_constant)?
|
||||
miri_to_const(cx, mir::ConstantKind::from_ty_const(min_val_const, cx.tcx))?
|
||||
},
|
||||
};
|
||||
let rhs_const = match rhs {
|
||||
Some(rhs) => constant(cx, cx.typeck_results(), rhs)?,
|
||||
None => {
|
||||
let max_val_const = ty.numeric_max_val(cx.tcx)?;
|
||||
let max_constant = mir::ConstantKind::from_value(
|
||||
cx.tcx.valtree_to_const_val((ty, max_val_const.to_valtree())),
|
||||
ty,
|
||||
);
|
||||
miri_to_const(cx, max_constant)?
|
||||
miri_to_const(cx, mir::ConstantKind::from_ty_const(max_val_const, cx.tcx))?
|
||||
},
|
||||
};
|
||||
let lhs_val = lhs_const.int_value(cx, ty)?;
|
||||
|
Loading…
Reference in New Issue
Block a user