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

Introduce mir::Unevaluated #102056

Merged
merged 4 commits into from
Sep 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 2 additions & 11 deletions compiler/rustc_codegen_cranelift/src/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::interpret::{
read_target_uint, AllocId, ConstAllocation, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
};
use rustc_middle::ty::ConstKind;
use rustc_span::DUMMY_SP;

use cranelift_codegen::ir::GlobalValueData;
Expand Down Expand Up @@ -42,15 +41,7 @@ pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool {
let mut all_constants_ok = true;
for constant in &fx.mir.required_consts {
let unevaluated = match fx.monomorphize(constant.literal) {
ConstantKind::Ty(ct) => match ct.kind() {
ConstKind::Unevaluated(uv) => uv.expand(),
ConstKind::Value(_) => continue,
ConstKind::Param(_)
| ConstKind::Infer(_)
| ConstKind::Bound(_, _)
| ConstKind::Placeholder(_)
| ConstKind::Error(_) => unreachable!("{:?}", ct),
},
ConstantKind::Ty(_) => unreachable!(),
ConstantKind::Unevaluated(uv, _) => uv,
ConstantKind::Val(..) => continue,
};
Expand Down Expand Up @@ -118,7 +109,7 @@ pub(crate) fn codegen_constant<'tcx>(
) -> CValue<'tcx> {
let (const_val, ty) = match fx.monomorphize(constant.literal) {
ConstantKind::Ty(const_) => unreachable!("{:?}", const_),
ConstantKind::Unevaluated(ty::Unevaluated { def, substs, promoted }, ty)
ConstantKind::Unevaluated(mir::UnevaluatedConst { def, substs, promoted }, ty)
if fx.tcx.is_static(def.did) =>
{
assert!(substs.is_empty());
Expand Down
18 changes: 6 additions & 12 deletions compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use rustc_errors::ErrorGuaranteed;
use rustc_hir::LangItem;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
use rustc_span::DUMMY_SP;
Expand Down Expand Up @@ -350,29 +351,22 @@ where
// FIXME(valtrees): check whether const qualifs should behave the same
// way for type and mir constants.
let uneval = match constant.literal {
ConstantKind::Ty(ct) if matches!(ct.kind(), ty::ConstKind::Unevaluated(_)) => {
let ty::ConstKind::Unevaluated(uv) = ct.kind() else { unreachable!() };

Some(uv.expand())
}
ConstantKind::Ty(_) => None,
ConstantKind::Ty(ct) if matches!(ct.kind(), ty::ConstKind::Param(_)) => None,
ConstantKind::Ty(c) => bug!("expected ConstKind::Param here, found {:?}", c),
ConstantKind::Unevaluated(uv, _) => Some(uv),
ConstantKind::Val(..) => None,
};

if let Some(ty::Unevaluated { def, substs: _, promoted }) = uneval {
if let Some(mir::UnevaluatedConst { def, substs: _, promoted }) = uneval {
// Use qualifs of the type for the promoted. Promoteds in MIR body should be possible
// only for `NeedsNonConstDrop` with precise drop checking. This is the only const
// check performed after the promotion. Verify that with an assertion.
assert!(promoted.is_none() || Q::ALLOW_PROMOTED);

// Don't peek inside trait associated constants.
if promoted.is_none() && cx.tcx.trait_of_item(def.did).is_none() {
let qualifs = if let Some((did, param_did)) = def.as_const_arg() {
cx.tcx.at(constant.span).mir_const_qualif_const_arg((did, param_did))
} else {
cx.tcx.at(constant.span).mir_const_qualif(def.did)
};
assert_eq!(def.const_param_did, None, "expected associated const: {def:?}");
let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def.did);
lcnr marked this conversation as resolved.
Show resolved Hide resolved

if !Q::in_qualifs(&qualifs) {
return false;
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_const_eval/src/transform/promote_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
//! move analysis runs after promotion on broken MIR.

use rustc_hir as hir;
use rustc_middle::mir;
use rustc_middle::mir::traversal::ReversePostorderIter;
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
Expand Down Expand Up @@ -840,7 +841,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
promoted.span = span;
promoted.local_decls[RETURN_PLACE] = LocalDecl::new(ty, span);
let substs = tcx.erase_regions(InternalSubsts::identity_for_item(tcx, def.did));
let uneval = ty::Unevaluated { def, substs, promoted: Some(promoted_id) };
let uneval = mir::UnevaluatedConst { def, substs, promoted: Some(promoted_id) };

Operand::Constant(Box::new(Constant {
span,
Expand Down
12 changes: 4 additions & 8 deletions compiler/rustc_infer/src/infer/combine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -742,9 +742,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
}
}
}
ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
assert_eq!(promoted, ());

ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => {
let substs = self.relate_with_variance(
ty::Variance::Invariant,
ty::VarianceDiagInfo::default(),
Expand All @@ -753,7 +751,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
)?;
Ok(self.tcx().mk_const(ty::ConstS {
ty: c.ty(),
kind: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
kind: ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }),
}))
}
_ => relate::super_relate_consts(self, c, c),
Expand Down Expand Up @@ -964,9 +962,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
}
}
}
ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
assert_eq!(promoted, ());

ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => {
let substs = self.relate_with_variance(
ty::Variance::Invariant,
ty::VarianceDiagInfo::default(),
Expand All @@ -976,7 +972,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {

Ok(self.tcx().mk_const(ty::ConstS {
ty: c.ty(),
kind: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
kind: ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }),
}))
}
_ => relate::super_relate_consts(self, c, c),
Expand Down
11 changes: 5 additions & 6 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -705,8 +705,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
#[instrument(skip(self), level = "debug")]
pub fn try_unify_abstract_consts(
&self,
a: ty::Unevaluated<'tcx, ()>,
b: ty::Unevaluated<'tcx, ()>,
a: ty::UnevaluatedConst<'tcx>,
b: ty::UnevaluatedConst<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
// Reject any attempt to unify two unevaluated constants that contain inference
Expand Down Expand Up @@ -1690,7 +1690,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn try_const_eval_resolve(
&self,
param_env: ty::ParamEnv<'tcx>,
unevaluated: ty::Unevaluated<'tcx, ()>,
unevaluated: ty::UnevaluatedConst<'tcx>,
ty: Ty<'tcx>,
span: Option<Span>,
) -> Result<ty::Const<'tcx>, ErrorHandled> {
Expand Down Expand Up @@ -1725,7 +1725,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn const_eval_resolve(
&self,
mut param_env: ty::ParamEnv<'tcx>,
unevaluated: ty::Unevaluated<'tcx, ()>,
unevaluated: ty::UnevaluatedConst<'tcx>,
span: Option<Span>,
) -> EvalToValTreeResult<'tcx> {
let mut substs = self.resolve_vars_if_possible(unevaluated.substs);
Expand Down Expand Up @@ -1756,8 +1756,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
debug!(?param_env_erased);
debug!(?substs_erased);

let unevaluated =
ty::Unevaluated { def: unevaluated.def, substs: substs_erased, promoted: () };
let unevaluated = ty::UnevaluatedConst { def: unevaluated.def, substs: substs_erased };

// The return value is the evaluated value which doesn't contain any reference to inference
// variables, thus we don't need to substitute back the original values.
Expand Down
10 changes: 7 additions & 3 deletions compiler/rustc_middle/src/mir/interpret/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn const_eval_resolve(
self,
param_env: ty::ParamEnv<'tcx>,
ct: ty::Unevaluated<'tcx>,
ct: mir::UnevaluatedConst<'tcx>,
span: Option<Span>,
) -> EvalToConstValueResult<'tcx> {
// Cannot resolve `Unevaluated` constants that contain inference
Expand All @@ -49,7 +49,11 @@ impl<'tcx> TyCtxt<'tcx> {
bug!("did not expect inference variables here");
}

match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) {
match ty::Instance::resolve_opt_const_arg(
self, param_env,
// FIXME: maybe have a seperate version for resolving mir::UnevaluatedConst?
ct.def, ct.substs,
) {
Ok(Some(instance)) => {
let cid = GlobalId { instance, promoted: ct.promoted };
self.const_eval_global_id(param_env, cid, span)
Expand All @@ -63,7 +67,7 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn const_eval_resolve_for_typeck(
self,
param_env: ty::ParamEnv<'tcx>,
ct: ty::Unevaluated<'tcx, ()>,
ct: ty::UnevaluatedConst<'tcx>,
span: Option<Span>,
) -> EvalToValTreeResult<'tcx> {
// Cannot resolve `Unevaluated` constants that contain inference
Expand Down
37 changes: 32 additions & 5 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2055,7 +2055,7 @@ pub enum ConstantKind<'tcx> {
Ty(ty::Const<'tcx>),

/// An unevaluated mir constant which is not part of the type system.
Unevaluated(ty::Unevaluated<'tcx, Option<Promoted>>, Ty<'tcx>),
Unevaluated(UnevaluatedConst<'tcx>, Ty<'tcx>),

/// This constant cannot go back into the type system, as it represents
/// something the type system cannot handle (e.g. pointers).
Expand Down Expand Up @@ -2315,12 +2315,11 @@ impl<'tcx> ConstantKind<'tcx> {
ty::InlineConstSubsts::new(tcx, ty::InlineConstSubstsParts { parent_substs, ty })
.substs;

let uneval = ty::Unevaluated {
let uneval = UnevaluatedConst {
def: ty::WithOptConstParam::unknown(def_id).to_global(),
substs,
promoted: None,
};

debug_assert!(!uneval.has_free_regions());

Self::Unevaluated(uneval, ty)
Expand Down Expand Up @@ -2404,7 +2403,7 @@ impl<'tcx> ConstantKind<'tcx> {

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);
let uneval = UnevaluatedConst::new(def.to_global(), substs);
debug!(?span, ?param_env);

match tcx.const_eval_resolve(param_env, uneval, Some(span)) {
Expand All @@ -2417,7 +2416,7 @@ impl<'tcx> ConstantKind<'tcx> {
// Error was handled in `const_eval_resolve`. Here we just create a
// new unevaluated const and error hard later in codegen
Self::Unevaluated(
ty::Unevaluated {
UnevaluatedConst {
def: def.to_global(),
substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
promoted: None,
Expand All @@ -2440,6 +2439,34 @@ impl<'tcx> ConstantKind<'tcx> {
}
}

/// An unevaluated (potentially generic) constant used in MIR.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
#[derive(Hash, HashStable)]
pub struct UnevaluatedConst<'tcx> {
pub def: ty::WithOptConstParam<DefId>,
pub substs: SubstsRef<'tcx>,
pub promoted: Option<Promoted>,
}

impl<'tcx> UnevaluatedConst<'tcx> {
// FIXME: probably should get rid of this method. It's also wrong to
// shrink and then later expand a promoted.
#[inline]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, once we've removed visit_mir_constant we should be able to remove this, probably makes sense to do that in yet another pr 😁

pub fn shrink(self) -> ty::UnevaluatedConst<'tcx> {
ty::UnevaluatedConst { def: self.def, substs: self.substs }
}
}

impl<'tcx> UnevaluatedConst<'tcx> {
#[inline]
pub fn new(
def: ty::WithOptConstParam<DefId>,
substs: SubstsRef<'tcx>,
) -> UnevaluatedConst<'tcx> {
UnevaluatedConst { def, substs, promoted: Default::default() }
}
}

/// A collection of projections into user types.
///
/// They are projections because a binding can occur a part of a
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_middle/src/mir/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,10 +466,9 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
ty::ConstKind::Param(p) => format!("Param({})", p),
ty::ConstKind::Unevaluated(uv) => {
format!(
"Unevaluated({}, {:?}, {:?})",
"Unevaluated({}, {:?})",
self.tcx.def_path_str(uv.def.did),
uv.substs,
uv.promoted,
)
}
ty::ConstKind::Value(val) => format!("Value({})", fmt_valtree(&val)),
Expand Down
20 changes: 20 additions & 0 deletions compiler/rustc_middle/src/mir/type_foldable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use rustc_ast::InlineAsmTemplatePiece;

use super::*;
use crate::mir;
use crate::ty;

TrivialTypeTraversalAndLiftImpls! {
Expand Down Expand Up @@ -50,6 +51,25 @@ impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
}
}

impl<'tcx> TypeFoldable<'tcx> for mir::UnevaluatedConst<'tcx> {
fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
folder.try_fold_mir_unevaluated(self)
}
}

impl<'tcx> TypeSuperFoldable<'tcx> for mir::UnevaluatedConst<'tcx> {
fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
self,
folder: &mut F,
) -> Result<Self, F::Error> {
Ok(mir::UnevaluatedConst {
def: self.def,
substs: self.substs.try_fold_with(folder)?,
promoted: self.promoted,
})
}
}

impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> {
#[inline(always)]
fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
Expand Down
13 changes: 13 additions & 0 deletions compiler/rustc_middle/src/mir/type_visitable.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
//! `TypeVisitable` implementations for MIR types

use super::*;
use crate::mir;

impl<'tcx, R: Idx, C: Idx> TypeVisitable<'tcx> for BitMatrix<R, C> {
fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
ControlFlow::CONTINUE
}
}

impl<'tcx> TypeVisitable<'tcx> for mir::UnevaluatedConst<'tcx> {
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
visitor.visit_mir_unevaluated(*self)
}
}

impl<'tcx> TypeSuperVisitable<'tcx> for mir::UnevaluatedConst<'tcx> {
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
self.substs.visit_with(visitor)
}
}

impl<'tcx> TypeVisitable<'tcx> for ConstantKind<'tcx> {
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
visitor.visit_mir_const(*self)
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ rustc_queries! {
}

query try_unify_abstract_consts(key:
ty::ParamEnvAnd<'tcx, (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>
ty::ParamEnvAnd<'tcx, (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>
)>) -> bool {
desc {
|tcx| "trying to unify the generic constants {} and {}",
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/abstract_const.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub struct AbstractConst<'tcx> {
impl<'tcx> AbstractConst<'tcx> {
pub fn new(
tcx: TyCtxt<'tcx>,
uv: ty::Unevaluated<'tcx, ()>,
uv: ty::UnevaluatedConst<'tcx>,
) -> Result<Option<AbstractConst<'tcx>>, ErrorGuaranteed> {
let inner = tcx.thir_abstract_const_opt_const_arg(uv.def)?;
debug!("AbstractConst::new({:?}) = {:?}", uv, inner);
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_middle/src/ty/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,9 @@ impl<'tcx> Const<'tcx> {
match Self::try_eval_lit_or_param(tcx, ty, expr) {
Some(v) => v,
None => tcx.mk_const(ty::ConstS {
kind: ty::ConstKind::Unevaluated(ty::Unevaluated {
kind: ty::ConstKind::Unevaluated(ty::UnevaluatedConst {
def: def.to_global(),
substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
promoted: (),
}),
ty,
}),
Expand Down
Loading