Skip to content

Commit

Permalink
make the set of methods between our two Const types more consistent
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Sep 12, 2023
1 parent e16a6d0 commit 6086a68
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 166 deletions.
84 changes: 31 additions & 53 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -2378,43 +2366,6 @@ impl<'tcx> ConstantKind<'tcx> {
}
}

/// 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 {
self.try_eval_bits(tcx, param_env, ty)
.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_scalar(
self,
Expand All @@ -2434,8 +2385,23 @@ impl<'tcx> ConstantKind<'tcx> {
}

#[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()
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 {
self.try_eval_bits(tcx, param_env, ty)
.unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
}

#[inline]
Expand All @@ -2447,6 +2413,18 @@ impl<'tcx> ConstantKind<'tcx> {
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]
pub fn from_value(val: ConstValue<'tcx>, ty: Ty<'tcx>) -> Self {
Self::Val(val, ty)
Expand Down Expand Up @@ -2586,7 +2564,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));
Expand Down Expand Up @@ -2899,7 +2877,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();
Expand Down
182 changes: 85 additions & 97 deletions compiler/rustc_middle/src/ty/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ pub use int::*;
pub use kind::*;
use rustc_span::Span;
use rustc_span::DUMMY_SP;
use rustc_target::abi::Size;
pub use valtree::*;

use super::sty::ConstKind;
Expand Down Expand Up @@ -155,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,
Expand All @@ -169,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>,
Expand Down Expand Up @@ -244,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 {
Expand Down Expand Up @@ -284,81 +275,6 @@ 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>> {
match self.kind() {
ty::ConstKind::Value(valtree) => Some(valtree),
_ => None,
}
}

#[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]
/// 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_bits(
self,
tcx: TyCtxt<'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
int.to_bits(size).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]
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()
}

/// 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]
/// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
self.try_eval_bits(tcx, param_env, ty)
.unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
}

#[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 {
self.try_eval_target_usize(tcx, param_env)
.unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
}

/// Returns the evaluated constant
pub fn eval(
self,
Expand Down Expand Up @@ -410,34 +326,106 @@ impl<'tcx> Const<'tcx> {
}
}

/// Normalizes the constant to a value or an error if possible.
#[inline]
pub fn try_to_value(self) -> Option<ty::ValTree<'tcx>> {
if let ConstKind::Value(val) = self.kind() { Some(val) } else { None }
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_to_scalar(self) -> Option<Scalar<AllocId>> {
self.try_to_value()?.try_to_scalar()
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_to_scalar_int(self) -> Option<ScalarInt> {
self.try_to_value()?.try_to_scalar_int()
/// 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]
pub fn try_to_bits(self, size: Size) -> Option<u128> {
self.try_to_scalar_int()?.to_bits(size).ok()
/// 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_bits(
self,
tcx: TyCtxt<'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
int.to_bits(size).ok()
}

#[inline]
pub fn try_to_bool(self) -> Option<bool> {
self.try_to_scalar_int()?.try_into().ok()
/// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
self.try_eval_bits(tcx, param_env, ty)
.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 {
self.try_eval_target_usize(tcx, param_env)
.unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
}

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

/// 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]
pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> {
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 {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_mir_build/src/thir/pattern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/instsimplify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/normalize_array_len.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading

0 comments on commit 6086a68

Please sign in to comment.