Rollup merge of #95426 - b-naber:valtrees-slice, r=RalfJung,oli-obk
Include Refs in Valtree Creation This adds references to `const_to_valtree`, which isn't used in the compiler yet, but after the previous changes we made to the thir and mir representations and this change we should be able to finally introduce them in the next PR. I wasn't able to properly test this code, except indirectly by including a call of `const_to_valtree` in the code that currently creates constants (`turn_into_const_value`). r? `@lcnr` cc `@oli-obk` `@RalfJung`
This commit is contained in:
commit
1dc672a766
@ -188,6 +188,7 @@ pub(super) fn op_to_const<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(tcx), level = "debug")]
|
||||||
fn turn_into_const_value<'tcx>(
|
fn turn_into_const_value<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
constant: ConstAlloc<'tcx>,
|
constant: ConstAlloc<'tcx>,
|
||||||
@ -206,6 +207,7 @@ fn turn_into_const_value<'tcx>(
|
|||||||
!is_static || cid.promoted.is_some(),
|
!is_static || cid.promoted.is_some(),
|
||||||
"the `eval_to_const_value_raw` query should not be used for statics, use `eval_to_allocation` instead"
|
"the `eval_to_const_value_raw` query should not be used for statics, use `eval_to_allocation` instead"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Turn this into a proper constant.
|
// Turn this into a proper constant.
|
||||||
op_to_const(&ecx, &mplace.into())
|
op_to_const(&ecx, &mplace.into())
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,14 @@
|
|||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
use rustc_hir::Mutability;
|
use rustc_hir::Mutability;
|
||||||
|
use rustc_middle::ty::layout::HasTyCtxt;
|
||||||
use rustc_middle::ty::{self, TyCtxt};
|
use rustc_middle::ty::{self, TyCtxt};
|
||||||
use rustc_middle::{
|
use rustc_middle::{
|
||||||
mir::{self, interpret::ConstAlloc},
|
mir::{self, interpret::ConstAlloc},
|
||||||
ty::ScalarInt,
|
ty::ScalarInt,
|
||||||
};
|
};
|
||||||
use rustc_span::{source_map::DUMMY_SP, symbol::Symbol};
|
use rustc_span::{source_map::DUMMY_SP, symbol::Symbol};
|
||||||
|
use rustc_target::abi::VariantIdx;
|
||||||
|
|
||||||
use crate::interpret::{
|
use crate::interpret::{
|
||||||
intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MPlaceTy,
|
intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MPlaceTy,
|
||||||
@ -55,28 +57,48 @@ pub(crate) fn const_to_valtree<'tcx>(
|
|||||||
const_to_valtree_inner(&ecx, &place)
|
const_to_valtree_inner(&ecx, &place)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(ecx), level = "debug")]
|
||||||
|
fn branches<'tcx>(
|
||||||
|
ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
|
||||||
|
place: &MPlaceTy<'tcx>,
|
||||||
|
n: usize,
|
||||||
|
variant: Option<VariantIdx>,
|
||||||
|
) -> Option<ty::ValTree<'tcx>> {
|
||||||
|
let place = match variant {
|
||||||
|
Some(variant) => ecx.mplace_downcast(&place, variant).unwrap(),
|
||||||
|
None => *place,
|
||||||
|
};
|
||||||
|
let variant = variant.map(|variant| Some(ty::ValTree::Leaf(ScalarInt::from(variant.as_u32()))));
|
||||||
|
debug!(?place, ?variant);
|
||||||
|
|
||||||
|
let fields = (0..n).map(|i| {
|
||||||
|
let field = ecx.mplace_field(&place, i).unwrap();
|
||||||
|
const_to_valtree_inner(ecx, &field)
|
||||||
|
});
|
||||||
|
// For enums, we prepend their variant index before the variant's fields so we can figure out
|
||||||
|
// the variant again when just seeing a valtree.
|
||||||
|
let branches = variant.into_iter().chain(fields);
|
||||||
|
Some(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches.collect::<Option<Vec<_>>>()?)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn slice_branches<'tcx>(
|
||||||
|
ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
|
||||||
|
place: &MPlaceTy<'tcx>,
|
||||||
|
) -> Option<ty::ValTree<'tcx>> {
|
||||||
|
let n = place.len(&ecx.tcx()).expect(&format!("expected to use len of place {:?}", place));
|
||||||
|
let branches = (0..n).map(|i| {
|
||||||
|
let place_elem = ecx.mplace_index(place, i).unwrap();
|
||||||
|
const_to_valtree_inner(ecx, &place_elem)
|
||||||
|
});
|
||||||
|
|
||||||
|
Some(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches.collect::<Option<Vec<_>>>()?)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(ecx), level = "debug")]
|
||||||
fn const_to_valtree_inner<'tcx>(
|
fn const_to_valtree_inner<'tcx>(
|
||||||
ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
|
ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
|
||||||
place: &MPlaceTy<'tcx>,
|
place: &MPlaceTy<'tcx>,
|
||||||
) -> Option<ty::ValTree<'tcx>> {
|
) -> Option<ty::ValTree<'tcx>> {
|
||||||
let branches = |n, variant| {
|
|
||||||
let place = match variant {
|
|
||||||
Some(variant) => ecx.mplace_downcast(&place, variant).unwrap(),
|
|
||||||
None => *place,
|
|
||||||
};
|
|
||||||
let variant =
|
|
||||||
variant.map(|variant| Some(ty::ValTree::Leaf(ScalarInt::from(variant.as_u32()))));
|
|
||||||
let fields = (0..n).map(|i| {
|
|
||||||
let field = ecx.mplace_field(&place, i).unwrap();
|
|
||||||
const_to_valtree_inner(ecx, &field)
|
|
||||||
});
|
|
||||||
// For enums, we preped their variant index before the variant's fields so we can figure out
|
|
||||||
// the variant again when just seeing a valtree.
|
|
||||||
let branches = variant.into_iter().chain(fields);
|
|
||||||
Some(ty::ValTree::Branch(
|
|
||||||
ecx.tcx.arena.alloc_from_iter(branches.collect::<Option<Vec<_>>>()?),
|
|
||||||
))
|
|
||||||
};
|
|
||||||
match place.layout.ty.kind() {
|
match place.layout.ty.kind() {
|
||||||
ty::FnDef(..) => Some(ty::ValTree::zst()),
|
ty::FnDef(..) => Some(ty::ValTree::zst()),
|
||||||
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
|
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
|
||||||
@ -90,19 +112,27 @@ fn const_to_valtree_inner<'tcx>(
|
|||||||
// Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to
|
// Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to
|
||||||
// agree with runtime equality tests.
|
// agree with runtime equality tests.
|
||||||
ty::FnPtr(_) | ty::RawPtr(_) => None,
|
ty::FnPtr(_) | ty::RawPtr(_) => None,
|
||||||
ty::Ref(..) => unimplemented!("need to use deref_const"),
|
|
||||||
|
|
||||||
|
ty::Ref(_, _, _) => {
|
||||||
|
let derefd_place = ecx.deref_operand(&place.into()).unwrap_or_else(|e| bug!("couldn't deref {:?}, error: {:?}", place, e));
|
||||||
|
debug!(?derefd_place);
|
||||||
|
|
||||||
|
const_to_valtree_inner(ecx, &derefd_place)
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::Str | ty::Slice(_) | ty::Array(_, _) => {
|
||||||
|
let valtree = slice_branches(ecx, place);
|
||||||
|
debug!(?valtree);
|
||||||
|
|
||||||
|
valtree
|
||||||
|
}
|
||||||
// Trait objects are not allowed in type level constants, as we have no concept for
|
// Trait objects are not allowed in type level constants, as we have no concept for
|
||||||
// resolving their backing type, even if we can do that at const eval time. We may
|
// resolving their backing type, even if we can do that at const eval time. We may
|
||||||
// hypothetically be able to allow `dyn StructuralEq` trait objects in the future,
|
// hypothetically be able to allow `dyn StructuralEq` trait objects in the future,
|
||||||
// but it is unclear if this is useful.
|
// but it is unclear if this is useful.
|
||||||
ty::Dynamic(..) => None,
|
ty::Dynamic(..) => None,
|
||||||
|
|
||||||
ty::Slice(_) | ty::Str => {
|
ty::Tuple(substs) => branches(ecx, place, substs.len(), None),
|
||||||
unimplemented!("need to find the backing data of the slice/str and recurse on that")
|
|
||||||
}
|
|
||||||
ty::Tuple(substs) => branches(substs.len(), None),
|
|
||||||
ty::Array(_, len) => branches(usize::try_from(len.eval_usize(ecx.tcx.tcx, ecx.param_env)).unwrap(), None),
|
|
||||||
|
|
||||||
ty::Adt(def, _) => {
|
ty::Adt(def, _) => {
|
||||||
if def.variants().is_empty() {
|
if def.variants().is_empty() {
|
||||||
@ -111,7 +141,7 @@ fn const_to_valtree_inner<'tcx>(
|
|||||||
|
|
||||||
let variant = ecx.read_discriminant(&place.into()).unwrap().1;
|
let variant = ecx.read_discriminant(&place.into()).unwrap().1;
|
||||||
|
|
||||||
branches(def.variant(variant).fields.len(), def.is_enum().then_some(variant))
|
branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant))
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Never
|
ty::Never
|
||||||
|
@ -191,7 +191,7 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
|
pub(crate) fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
|
||||||
if self.layout.is_unsized() {
|
if self.layout.is_unsized() {
|
||||||
// We need to consult `meta` metadata
|
// We need to consult `meta` metadata
|
||||||
match self.layout.ty.kind() {
|
match self.layout.ty.kind() {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use super::ScalarInt;
|
use super::ScalarInt;
|
||||||
use rustc_macros::HashStable;
|
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)]
|
#[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
#[derive(HashStable)]
|
#[derive(HashStable)]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user