1
Fork 0

change thir to use mir::ConstantKind instead of ty::Const

This commit is contained in:
b-naber 2022-02-21 22:43:15 +01:00
parent 9d843171d1
commit b38077ea0b
29 changed files with 534 additions and 112 deletions

View file

@ -9,13 +9,13 @@ use crate::ty::adjustment::PointerCast;
use crate::ty::codec::{TyDecoder, TyEncoder};
use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor};
use crate::ty::print::{FmtPrinter, Printer};
use crate::ty::subst::{Subst, SubstsRef};
use crate::ty::subst::{InternalSubsts, Subst, SubstsRef};
use crate::ty::{self, List, Ty, TyCtxt};
use crate::ty::{AdtDef, InstanceDef, Region, ScalarInt, UserTypeAnnotationIndex};
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def::{CtorKind, Namespace};
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
use rustc_hir::{self, GeneratorKind};
use rustc_hir::{self as hir, HirId};
use rustc_session::Session;
@ -2664,6 +2664,16 @@ impl<'tcx> ConstantKind<'tcx> {
}
}
pub fn try_val(&self) -> Option<ConstValue<'tcx>> {
match self {
ConstantKind::Ty(c) => match c.val() {
ty::ConstKind::Value(v) => Some(v),
_ => None,
},
ConstantKind::Val(v, _) => Some(*v),
}
}
#[inline]
pub fn try_to_value(self) -> Option<interpret::ConstValue<'tcx>> {
match self {
@ -2692,6 +2702,32 @@ impl<'tcx> ConstantKind<'tcx> {
self.try_to_scalar_int()?.try_into().ok()
}
#[inline]
pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
match self {
Self::Ty(c) => {
// FIXME Need to use a different evaluation function that directly returns a `ConstValue`
// if evaluation succeeds and does not create a ValTree first
if let Some(val) = c.val().try_eval(tcx, param_env) {
match val {
Ok(val) => Self::Val(val, c.ty()),
Err(ErrorReported) => Self::Ty(tcx.const_error(self.ty())),
}
} else {
self
}
}
Self::Val(_, _) => 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: 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,
@ -2726,25 +2762,181 @@ impl<'tcx> ConstantKind<'tcx> {
}
}
pub fn from_bits(
tcx: TyCtxt<'tcx>,
bits: u128,
param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
) -> Self {
let size = tcx
.layout_of(param_env_ty)
.unwrap_or_else(|e| {
bug!("could not compute layout for {:?}: {:?}", param_env_ty.value, e)
})
.size;
let cv = ConstValue::Scalar(Scalar::from_uint(bits, size));
Self::Val(cv, param_env_ty.value)
}
pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self {
let cv = ConstValue::from_bool(v);
Self::Val(cv, tcx.types.bool)
}
pub fn from_zero_sized(ty: Ty<'tcx>) -> Self {
pub fn zero_sized(ty: Ty<'tcx>) -> Self {
let cv = ConstValue::Scalar(Scalar::ZST);
Self::Val(cv, ty)
}
pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
let ty = tcx.types.usize;
let size = tcx
.layout_of(ty::ParamEnv::empty().and(ty))
.unwrap_or_else(|e| bug!("could not compute layout for {:?}: {:?}", ty, e))
.size;
let cv = ConstValue::Scalar(Scalar::from_uint(n as u128, size));
Self::from_bits(tcx, n as u128, ty::ParamEnv::empty().and(ty))
}
Self::Val(cv, ty)
#[instrument(skip(tcx), level = "debug")]
pub fn try_eval_lit_or_param(
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
expr: &'tcx hir::Expr<'tcx>,
) -> Option<Self> {
// Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
// currently have to be wrapped in curly brackets, so it's necessary to special-case.
let expr = match &expr.kind {
hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => {
block.expr.as_ref().unwrap()
}
_ => expr,
};
let lit_input = match expr.kind {
hir::ExprKind::Lit(ref lit) => {
Some(interpret::LitToConstInput { lit: &lit.node, ty, neg: false })
}
hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind {
hir::ExprKind::Lit(ref lit) => {
Some(interpret::LitToConstInput { lit: &lit.node, ty, neg: true })
}
_ => None,
},
_ => None,
};
if let Some(lit_input) = lit_input {
// If an error occurred, ignore that it's a literal and leave reporting the error up to
// mir.
match tcx.at(expr.span).lit_to_mir_constant(lit_input) {
Ok(c) => return Some(c),
Err(e) => {
tcx.sess.delay_span_bug(
expr.span,
&format!("Const::from_anon_const: couldn't lit_to_const {:?}", e),
);
}
}
}
use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath};
match expr.kind {
ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => {
// Find the name and index of the const parameter by indexing the generics of
// the parent item and construct a `ParamConst`.
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
let item_id = tcx.hir().get_parent_node(hir_id);
let item_def_id = tcx.hir().local_def_id(item_id);
let generics = tcx.generics_of(item_def_id.to_def_id());
let index = generics.param_def_id_to_index[&def_id];
let name = tcx.hir().name(hir_id);
let ty_const = tcx.mk_const(ty::ConstS {
val: ty::ConstKind::Param(ty::ParamConst::new(index, name)),
ty,
});
Some(Self::Ty(ty_const))
}
_ => None,
}
}
#[instrument(skip(tcx), level = "debug")]
pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let body_id = match tcx.hir().get(hir_id) {
hir::Node::AnonConst(ac) => ac.body,
_ => span_bug!(
tcx.def_span(def_id.to_def_id()),
"from_inline_const can only process anonymous constants"
),
};
let expr = &tcx.hir().body(body_id).value;
let ty = tcx.typeck(def_id).node_type(hir_id);
let ret = match Self::try_eval_lit_or_param(tcx, ty, expr) {
Some(v) => v,
None => {
let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id());
let parent_substs =
tcx.erase_regions(InternalSubsts::identity_for_item(tcx, typeck_root_def_id));
let substs = ty::InlineConstSubsts::new(
tcx,
ty::InlineConstSubstsParts { parent_substs, ty },
)
.substs;
let ty_const = tcx.mk_const(ty::ConstS {
val: ty::ConstKind::Unevaluated(ty::Unevaluated {
def: ty::WithOptConstParam::unknown(def_id).to_global(),
substs,
promoted: None,
}),
ty,
});
Self::Ty(ty_const)
}
};
debug_assert!(!ret.has_free_regions());
ret
}
/// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly
/// converted to a constant, everything else becomes `Unevaluated`.
pub fn from_anon_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id))
}
#[instrument(skip(tcx), level = "debug")]
fn from_opt_const_arg_anon_const(
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
) -> Self {
let body_id = match tcx.hir().get_by_def_id(def.did) {
hir::Node::AnonConst(ac) => ac.body,
_ => span_bug!(
tcx.def_span(def.did.to_def_id()),
"from_anon_const can only process anonymous constants"
),
};
let expr = &tcx.hir().body(body_id).value;
debug!(?expr);
let ty = tcx.type_of(def.def_id_for_type_of());
match Self::try_eval_lit_or_param(tcx, ty, expr) {
Some(v) => v,
None => {
let ty_const = tcx.mk_const(ty::ConstS {
val: ty::ConstKind::Unevaluated(ty::Unevaluated {
def: def.to_global(),
substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
promoted: None,
}),
ty,
});
Self::Ty(ty_const)
}
}
}
}

View file

@ -1,6 +1,6 @@
//! Values computed by queries that use MIR.
use crate::mir::{Body, Promoted};
use crate::mir::{self, Body, Promoted};
use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt};
use rustc_data_structures::stable_map::FxHashMap;
use rustc_data_structures::vec_map::VecMap;
@ -421,6 +421,13 @@ pub struct DestructuredConst<'tcx> {
pub fields: &'tcx [ty::Const<'tcx>],
}
/// The constituent parts of an ADT or array.
#[derive(Copy, Clone, Debug, HashStable)]
pub struct DestructuredMirConstant<'tcx> {
pub variant: Option<VariantIdx>,
pub fields: &'tcx [mir::ConstantKind<'tcx>],
}
/// Coverage information summarized from a MIR if instrumented for source code coverage (see
/// compiler option `-Cinstrument-coverage`). This information is generated by the
/// `InstrumentCoverage` MIR pass and can be retrieved via the `coverageinfo` query.

View file

@ -940,6 +940,13 @@ rustc_queries! {
remap_env_constness
}
/// Destructure an `mir::ConstantKind` ADT or array into its variant index
/// and its field values.
query destructure_mir_constant(key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>) -> mir::DestructuredMirConstant<'tcx> {
desc { "destructure mir constant"}
remap_env_constness
}
/// Dereference a constant reference or raw pointer and turn the result into a constant
/// again.
query deref_const(
@ -949,6 +956,15 @@ rustc_queries! {
remap_env_constness
}
/// Dereference a constant reference or raw pointer and turn the result into a constant
/// again.
query deref_mir_constant(
key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
) -> mir::ConstantKind<'tcx> {
desc { "deref constant" }
remap_env_constness
}
query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> {
desc { "get a &core::panic::Location referring to a span" }
}
@ -960,6 +976,10 @@ rustc_queries! {
desc { "converting literal to const" }
}
query lit_to_mir_constant(key: LitToConstInput<'tcx>) -> Result<mir::ConstantKind<'tcx>, LitToConstError> {
desc { "converting literal to mir constant" }
}
query check_match(key: DefId) {
desc { |tcx| "match-checking `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }

View file

@ -19,11 +19,11 @@ use rustc_middle::infer::canonical::Canonical;
use rustc_middle::middle::region;
use rustc_middle::mir::interpret::AllocId;
use rustc_middle::mir::{
BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp, UserTypeProjection,
self, BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp, UserTypeProjection,
};
use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, AdtDef, Const, Ty, UpvarSubsts, UserType};
use rustc_middle::ty::{self, AdtDef, Ty, UpvarSubsts, UserType};
use rustc_middle::ty::{
CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
};
@ -193,7 +193,7 @@ pub enum StmtKind<'tcx> {
// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(Expr<'_>, 104);
rustc_data_structures::static_assert_size!(Expr<'_>, 144);
/// A THIR expression.
#[derive(Debug, HashStable)]
@ -375,7 +375,7 @@ pub enum ExprKind<'tcx> {
/// An array literal constructed from one repeated element, e.g. `[1; 5]`.
Repeat {
value: ExprId,
count: Const<'tcx>,
count: ty::Const<'tcx>,
},
/// An array, e.g. `[a, b, c, d]`.
Array {
@ -522,7 +522,7 @@ pub enum InlineAsmOperand<'tcx> {
out_expr: Option<ExprId>,
},
Const {
value: Const<'tcx>,
value: mir::ConstantKind<'tcx>,
span: Span,
},
SymFn {
@ -661,7 +661,7 @@ pub enum PatKind<'tcx> {
/// * Opaque constants, that must not be matched structurally. So anything that does not derive
/// `PartialEq` and `Eq`.
Constant {
value: ty::Const<'tcx>,
value: mir::ConstantKind<'tcx>,
},
Range(PatRange<'tcx>),
@ -691,8 +691,8 @@ pub enum PatKind<'tcx> {
#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
pub struct PatRange<'tcx> {
pub lo: ty::Const<'tcx>,
pub hi: ty::Const<'tcx>,
pub lo: mir::ConstantKind<'tcx>,
pub hi: mir::ConstantKind<'tcx>,
pub end: RangeEnd,
}

View file

@ -22,7 +22,7 @@ pub enum CastKind {
/// A node of an `AbstractConst`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
pub enum Node<'tcx> {
Leaf(ty::Const<'tcx>),
Leaf(mir::ConstantKind<'tcx>),
Binop(mir::BinOp, NodeId, NodeId),
UnaryOp(mir::UnOp, NodeId),
FunctionCall(NodeId, &'tcx [NodeId]),

View file

@ -1,6 +1,8 @@
use super::{
Arm, Block, Expr, ExprKind, Guard, InlineAsmOperand, Pat, PatKind, Stmt, StmtKind, Thir,
};
use crate::mir::ConstantKind;
use crate::ty::Const;
pub trait Visitor<'a, 'tcx: 'a>: Sized {
fn thir(&self) -> &'a Thir<'tcx>;
@ -24,6 +26,8 @@ pub trait Visitor<'a, 'tcx: 'a>: Sized {
fn visit_pat(&mut self, pat: &Pat<'tcx>) {
walk_pat(self, pat);
}
fn visit_constant(&mut self, _constant: ConstantKind<'tcx>) {}
}
pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) {
@ -90,8 +94,13 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp
visitor.visit_expr(&visitor.thir()[value])
}
}
<<<<<<< HEAD
ConstBlock { did: _, substs: _ } => {}
Repeat { value, count: _ } => {
=======
ConstBlock { value } => visitor.visit_constant(value),
Repeat { value, count } => {
>>>>>>> 6064f16d846 (change thir to use mir::ConstantKind instead of ty::Const)
visitor.visit_expr(&visitor.thir()[value]);
}
Array { ref fields } | Tuple { ref fields } => {

View file

@ -126,7 +126,7 @@ impl<'tcx> ConstKind<'tcx> {
#[inline]
/// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
/// return `None`.
pub(super) fn try_eval(
pub fn try_eval(
self,
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,

View file

@ -662,8 +662,8 @@ impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> {
impl<'tcx> Ty<'tcx> {
/// Returns the maximum value for the given numeric type (including `char`s)
/// or returns `None` if the type is not numeric.
pub fn numeric_max_val(self, tcx: TyCtxt<'tcx>) -> Option<Const<'tcx>> {
let val = match self.kind() {
pub fn numeric_max_val(self, tcx: TyCtxt<'tcx>) -> Option<u128> {
match self.kind() {
ty::Int(_) | ty::Uint(_) => {
let (size, signed) = int_size_and_signed(tcx, self);
let val =
@ -676,14 +676,13 @@ impl<'tcx> Ty<'tcx> {
ty::FloatTy::F64 => rustc_apfloat::ieee::Double::INFINITY.to_bits(),
}),
_ => None,
};
val.map(|v| Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
}
}
/// Returns the minimum value for the given numeric type (including `char`s)
/// or returns `None` if the type is not numeric.
pub fn numeric_min_val(self, tcx: TyCtxt<'tcx>) -> Option<Const<'tcx>> {
let val = match self.kind() {
pub fn numeric_min_val(self, tcx: TyCtxt<'tcx>) -> Option<u128> {
match self.kind() {
ty::Int(_) | ty::Uint(_) => {
let (size, signed) = int_size_and_signed(tcx, self);
let val = if signed { size.truncate(size.signed_int_min() as u128) } else { 0 };
@ -695,8 +694,7 @@ impl<'tcx> Ty<'tcx> {
ty::FloatTy::F64 => (-::rustc_apfloat::ieee::Double::INFINITY).to_bits(),
}),
_ => None,
};
val.map(|v| Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
}
}
/// Checks whether values of this type `T` are *moved* or *copied*