try to evaluate in from_opt_const_arg_anon_const
This commit is contained in:
parent
d0e05f0426
commit
9b28d3b494
2 changed files with 78 additions and 8 deletions
|
@ -9,7 +9,7 @@ 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::{InternalSubsts, 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};
|
||||
|
||||
|
@ -2901,14 +2901,19 @@ impl<'tcx> ConstantKind<'tcx> {
|
|||
|
||||
/// 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))
|
||||
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,
|
||||
|
@ -2921,11 +2926,72 @@ impl<'tcx> ConstantKind<'tcx> {
|
|||
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());
|
||||
|
||||
match Self::try_eval_lit_or_param(tcx, ty, expr) {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
// 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(),
|
||||
|
@ -2934,6 +3000,7 @@ impl<'tcx> ConstantKind<'tcx> {
|
|||
}),
|
||||
ty,
|
||||
});
|
||||
|
||||
Self::Ty(ty_const)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue