Auto merge of #83207 - oli-obk:valtree2, r=lcnr
normalize mir::Constant differently from ty::Const in preparation for valtrees Valtrees are unable to represent many kind of constant values (this is on purpose). For constants that are used at runtime, we do not need a valtree representation and can thus use a different form of evaluation. In order to make this explicit and less fragile, I added a `fold_constant` method to `TypeFolder` and implemented it for normalization. Normalization can now, when it wants to eagerly evaluate a constant, normalize `mir::Constant` directly into a `mir::ConstantKind::Val` instead of relying on the `ty::Const` evaluation. In the future we can get rid of the `ty::Const` in there entirely and add our own `Unevaluated` variant to `mir::ConstantKind`. This would allow us to remove the `promoted` field from `ty::ConstKind::Unevaluated`, as promoteds can never occur in the type system. cc `@rust-lang/wg-const-eval` r? `@lcnr`
This commit is contained in:
commit
0978a9eb99
41 changed files with 183 additions and 55 deletions
|
@ -110,7 +110,7 @@ fn const_to_valtree_inner<'tcx>(
|
|||
|
||||
let variant = ecx.read_discriminant(&place.into()).unwrap().1;
|
||||
|
||||
branches(def.variants[variant].fields.len(), Some(variant))
|
||||
branches(def.variants[variant].fields.len(), def.is_enum().then_some(variant))
|
||||
}
|
||||
|
||||
ty::Never
|
||||
|
|
|
@ -524,6 +524,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn layout_of_local(
|
||||
&self,
|
||||
frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
|
||||
|
|
|
@ -171,8 +171,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
};
|
||||
let val =
|
||||
self.tcx.const_eval_global_id(self.param_env, gid, Some(self.tcx.span))?;
|
||||
let const_ = ty::Const { val: ty::ConstKind::Value(val), ty };
|
||||
let val = self.const_to_op(&const_, None)?;
|
||||
let val = self.const_val_to_op(val, ty, Some(dest.layout))?;
|
||||
self.copy_op(&val, dest)?;
|
||||
}
|
||||
|
||||
|
|
|
@ -570,7 +570,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
|
||||
match val {
|
||||
mir::ConstantKind::Ty(ct) => self.const_to_op(ct, layout),
|
||||
mir::ConstantKind::Val(val, ty) => self.const_val_to_op(*val, ty, None),
|
||||
mir::ConstantKind::Val(val, ty) => self.const_val_to_op(*val, ty, layout),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -184,7 +184,6 @@ use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
|
|||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_index::bit_set::GrowableBitSet;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::mir::interpret::{AllocId, ConstValue};
|
||||
use rustc_middle::mir::interpret::{ErrorHandled, GlobalAlloc, Scalar};
|
||||
use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
|
||||
|
@ -193,6 +192,7 @@ use rustc_middle::mir::{self, Local, Location};
|
|||
use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast};
|
||||
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
|
||||
use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext};
|
||||
use rustc_session::config::EntryFnType;
|
||||
use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP};
|
||||
use smallvec::SmallVec;
|
||||
|
@ -638,6 +638,35 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
|
|||
self.super_rvalue(rvalue, location);
|
||||
}
|
||||
|
||||
/// This does not walk the constant, as it has been handled entirely here and trying
|
||||
/// to walk it would attempt to evaluate the `ty::Const` inside, which doesn't necessarily
|
||||
/// work, as some constants cannot be represented in the type system.
|
||||
fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location) {
|
||||
let literal = self.monomorphize(constant.literal);
|
||||
let val = match literal {
|
||||
mir::ConstantKind::Val(val, _) => val,
|
||||
mir::ConstantKind::Ty(ct) => match ct.val {
|
||||
ty::ConstKind::Value(val) => val,
|
||||
ty::ConstKind::Unevaluated(ct) => {
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
match self.tcx.const_eval_resolve(param_env, ct, None) {
|
||||
// The `monomorphize` call should have evaluated that constant already.
|
||||
Ok(val) => val,
|
||||
Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted) => return,
|
||||
Err(ErrorHandled::TooGeneric) => span_bug!(
|
||||
self.body.source_info(location).span,
|
||||
"collection encountered polymorphic constant: {:?}",
|
||||
literal
|
||||
),
|
||||
}
|
||||
}
|
||||
_ => return,
|
||||
},
|
||||
};
|
||||
collect_const_value(self.tcx, val, self.output);
|
||||
self.visit_ty(literal.ty(), TyContext::Location(location));
|
||||
}
|
||||
|
||||
fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) {
|
||||
debug!("visiting const {:?} @ {:?}", *constant, location);
|
||||
|
||||
|
@ -648,7 +677,13 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
|
|||
ty::ConstKind::Value(val) => collect_const_value(self.tcx, val, self.output),
|
||||
ty::ConstKind::Unevaluated(unevaluated) => {
|
||||
match self.tcx.const_eval_resolve(param_env, unevaluated, None) {
|
||||
Ok(val) => collect_const_value(self.tcx, val, self.output),
|
||||
// The `monomorphize` call should have evaluated that constant already.
|
||||
Ok(val) => span_bug!(
|
||||
self.body.source_info(location).span,
|
||||
"collection encountered the unevaluated constant {} which evaluated to {:?}",
|
||||
substituted_constant,
|
||||
val
|
||||
),
|
||||
Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted) => {}
|
||||
Err(ErrorHandled::TooGeneric) => span_bug!(
|
||||
self.body.source_info(location).span,
|
||||
|
|
|
@ -452,7 +452,11 @@ impl Visitor<'tcx> for ExtraComments<'tcx> {
|
|||
match literal {
|
||||
ConstantKind::Ty(literal) => self.push(&format!("+ literal: {:?}", literal)),
|
||||
ConstantKind::Val(val, ty) => {
|
||||
self.push(&format!("+ literal: {:?}, {}", val, ty))
|
||||
// To keep the diffs small, we render this almost like we render ty::Const
|
||||
self.push(&format!(
|
||||
"+ literal: Const {{ ty: {}, val: Value({:?}) }}",
|
||||
ty, val
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -465,7 +469,21 @@ impl Visitor<'tcx> for ExtraComments<'tcx> {
|
|||
if use_verbose(ty) {
|
||||
self.push("ty::Const");
|
||||
self.push(&format!("+ ty: {:?}", ty));
|
||||
self.push(&format!("+ val: {:?}", val));
|
||||
let val = match val {
|
||||
ty::ConstKind::Param(p) => format!("Param({})", p),
|
||||
ty::ConstKind::Infer(infer) => format!("Infer({:?})", infer),
|
||||
ty::ConstKind::Bound(idx, var) => format!("Bound({:?}, {:?})", idx, var),
|
||||
ty::ConstKind::Placeholder(ph) => format!("PlaceHolder({:?})", ph),
|
||||
ty::ConstKind::Unevaluated(uv) => format!(
|
||||
"Unevaluated({}, {:?}, {:?})",
|
||||
self.tcx.def_path_str(uv.def.did),
|
||||
uv.substs,
|
||||
uv.promoted
|
||||
),
|
||||
ty::ConstKind::Value(val) => format!("Value({:?})", val),
|
||||
ty::ConstKind::Error(_) => format!("Error"),
|
||||
};
|
||||
self.push(&format!("+ val: {}", val));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue