Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use mir constant in thir instead of ty::Const #94255

Merged
merged 9 commits into from
Apr 13, 2022
Merged
171 changes: 162 additions & 9 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{GenericArg, 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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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(_) => Self::Ty(tcx.const_error(self.ty())),
}
} else {
self
}
}
Self::Val(_, _) => self,
}
}

/// 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,
Expand Down Expand Up @@ -2726,25 +2762,142 @@ 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)
/// 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,
param_env: ty::ParamEnv<'tcx>,
) -> Self {
Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id), param_env)
}

#[instrument(skip(tcx), level = "debug")]
fn from_opt_const_arg_anon_const(
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
param_env: ty::ParamEnv<'tcx>,
) -> 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);

// 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 ty = tcx.type_of(def.def_id_for_type_of());

// FIXME(const_generics): We currently have to special case parameters because `min_const_generics`
// does not provide the parents generics to anonymous constants. We still allow generic const
// parameters by themselves however, e.g. `N`. These constants would cause an ICE if we were to
// ever try to substitute the generic parameters in their bodies.
//
// While this doesn't happen as these constants are always used as `ty::ConstKind::Param`, it does
// cause issues if we were to remove that special-case and try to evaluate the constant instead.
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,
});

return Self::Ty(ty_const);
}
_ => {}
}

let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
let parent_substs = if let Some(parent_hir_id) = tcx.hir().find_parent_node(hir_id) {
if let Some(parent_did) = tcx.hir().opt_local_def_id(parent_hir_id) {
InternalSubsts::identity_for_item(tcx, parent_did.to_def_id())
} else {
tcx.mk_substs(Vec::<GenericArg<'tcx>>::new().into_iter())
}
} else {
tcx.mk_substs(Vec::<GenericArg<'tcx>>::new().into_iter())
};
debug!(?parent_substs);

let did = def.did.to_def_id();
let child_substs = InternalSubsts::identity_for_item(tcx, did);
let substs = tcx.mk_substs(parent_substs.into_iter().chain(child_substs.into_iter()));
debug!(?substs);

let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
let span = tcx.hir().span(hir_id);
let uneval = ty::Unevaluated::new(def.to_global(), substs);
debug!(?span, ?param_env);

match tcx.const_eval_resolve(param_env, uneval, Some(span)) {
Ok(val) => Self::Val(val, ty),
Err(_) => {
// Error was handled in `const_eval_resolve`. Here we just create a
// new unevaluated const and error hard later in codegen
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)
}
}
}
}

Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_middle/src/thir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -522,7 +522,7 @@ pub enum InlineAsmOperand<'tcx> {
out_expr: Option<ExprId>,
},
Const {
value: Const<'tcx>,
value: mir::ConstantKind<'tcx>,
span: Span,
},
SymFn {
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_middle/src/thir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ pub trait Visitor<'a, 'tcx: 'a>: Sized {
fn visit_pat(&mut self, pat: &Pat<'tcx>) {
walk_pat(self, pat);
}

// Note: We don't have visitors for `ty::Const` and `mir::ConstantKind`
// (even though these types occur in THIR) for consistency and to reduce confusion,
// since the lazy creation of constants during thir construction causes most
// 'constants' to not be of type `ty::Const` or `mir::ConstantKind` at that
// stage (they are mostly still identified by `DefId` or `hir::Lit`, see
// the variants `Literal`, `NonHirLiteral` and `NamedConst` in `thir::ExprKind`).
// You have to manually visit `ty::Const` and `mir::ConstantKind` through the
// other `visit*` functions.
}

pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) {
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_middle/src/ty/consts/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ impl<'tcx> ConstKind<'tcx> {
#[inline]
/// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
/// return `None`.
b-naber marked this conversation as resolved.
Show resolved Hide resolved
pub(super) fn try_eval(
// FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
pub fn try_eval(
self,
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/build/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ impl<'tcx> CFG<'tcx> {
Rvalue::Use(Operand::Constant(Box::new(Constant {
span: source_info.span,
user_ty: None,
literal: ConstantKind::from_zero_sized(tcx.types.unit),
literal: ConstantKind::zero_sized(tcx.types.unit),
}))),
);
}
Expand Down
14 changes: 7 additions & 7 deletions compiler/rustc_mir_build/src/build/expr/as_constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@

use crate::build::Builder;
use crate::thir::constant::parse_float;
use rustc_ast::ast;
use rustc_ast as ast;
use rustc_hir::def_id::DefId;
use rustc_middle::mir::interpret::{
Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar,
};
use rustc_middle::mir::interpret::Allocation;
use rustc_middle::mir::interpret::{ConstValue, LitToConstError, LitToConstInput, Scalar};
use rustc_middle::mir::*;
use rustc_middle::thir::*;
use rustc_middle::ty::subst::SubstsRef;
Expand All @@ -32,11 +31,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
ExprKind::Literal { lit, neg } => {
let literal =
match lit_to_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) {
match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) {
Ok(c) => c,
Err(LitToConstError::Reported) => ConstantKind::Ty(tcx.const_error(ty)),
Err(LitToConstError::TypeError) => {
bug!("encountered type error in `lit_to_constant")
bug!("encountered type error in `lit_to_mir_constant")
}
};

Expand Down Expand Up @@ -90,7 +89,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}

crate fn lit_to_constant<'tcx>(
#[instrument(skip(tcx, lit_input))]
fn lit_to_mir_constant<'tcx>(
tcx: TyCtxt<'tcx>,
lit_input: LitToConstInput<'tcx>,
) -> Result<ConstantKind<'tcx>, LitToConstError> {
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block.and(Rvalue::Use(Operand::Constant(Box::new(Constant {
span: expr_span,
user_ty: None,
literal: ty::Const::zero_sized(this.tcx, this.tcx.types.unit).into(),
literal: ConstantKind::zero_sized(this.tcx.types.unit),
}))))
}
ExprKind::Yield { .. }
Expand Down Expand Up @@ -552,7 +552,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
let param_ty = ty::ParamEnv::empty().and(ty);
let size = self.tcx.layout_of(param_ty).unwrap().size;
let literal = ty::Const::from_bits(self.tcx, size.unsigned_int_max(), param_ty);
let literal = ConstantKind::from_bits(self.tcx, size.unsigned_int_max(), param_ty);

self.literal_operand(span, literal)
}
Expand All @@ -563,7 +563,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let param_ty = ty::ParamEnv::empty().and(ty);
let bits = self.tcx.layout_of(param_ty).unwrap().size.bits();
let n = 1 << (bits - 1);
let literal = ty::Const::from_bits(self.tcx, n, param_ty);
let literal = ConstantKind::from_bits(self.tcx, n, param_ty);

self.literal_operand(span, literal)
}
Expand Down
13 changes: 7 additions & 6 deletions compiler/rustc_mir_build/src/build/matches/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
);
} else if let [success, fail] = *make_target_blocks(self) {
assert_eq!(value.ty(), ty);
let expect = self.literal_operand(test.span, value);
let expect = self.literal_operand(test.span, value.into());
let val = Operand::Copy(place);
self.compare(block, success, fail, source_info, BinOp::Eq, expect, val);
} else {
Expand All @@ -277,8 +277,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let target_blocks = make_target_blocks(self);

// Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
let lo = self.literal_operand(test.span, lo);
let hi = self.literal_operand(test.span, hi);
let lo = self.literal_operand(test.span, lo.into());
let hi = self.literal_operand(test.span, hi.into());
let val = Operand::Copy(place);

let [success, fail] = *target_blocks else {
Expand Down Expand Up @@ -370,7 +370,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
place: Place<'tcx>,
mut ty: Ty<'tcx>,
) {
let mut expect = self.literal_operand(source_info.span, value);
let mut expect = self.literal_operand(source_info.span, value.into());
let mut val = Operand::Copy(place);

// If we're using `b"..."` as a pattern, we need to insert an
Expand Down Expand Up @@ -823,7 +823,7 @@ fn trait_method<'tcx>(
method_name: Symbol,
self_ty: Ty<'tcx>,
params: &[GenericArg<'tcx>],
) -> ty::Const<'tcx> {
) -> ConstantKind<'tcx> {
let substs = tcx.mk_substs_trait(self_ty, params);

// The unhygienic comparison here is acceptable because this is only
Expand All @@ -836,5 +836,6 @@ fn trait_method<'tcx>(

let method_ty = tcx.type_of(item.def_id);
let method_ty = method_ty.subst(tcx, substs);
ty::Const::zero_sized(tcx, method_ty)

ConstantKind::zero_sized(method_ty)
}
Loading