Refactor using the type-level constant value ty::Value
Signed-off-by: FedericoBruzzone <federico.bruzzone.i@gmail.com>
This commit is contained in:
parent
9e48dfe5e0
commit
6e0dfc813c
5 changed files with 62 additions and 59 deletions
|
@ -273,59 +273,63 @@ pub(crate) fn eval_to_valtree<'tcx>(
|
||||||
/// Converts a `ValTree` to a `ConstValue`, which is needed after mir
|
/// Converts a `ValTree` to a `ConstValue`, which is needed after mir
|
||||||
/// construction has finished.
|
/// construction has finished.
|
||||||
// FIXME(valtrees): Merge `valtree_to_const_value` and `valtree_into_mplace` into one function
|
// FIXME(valtrees): Merge `valtree_to_const_value` and `valtree_into_mplace` into one function
|
||||||
// FIXME(valtrees): Accept `ty::Value` instead of `Ty` and `ty::ValTree` separately.
|
|
||||||
#[instrument(skip(tcx), level = "debug", ret)]
|
#[instrument(skip(tcx), level = "debug", ret)]
|
||||||
pub fn valtree_to_const_value<'tcx>(
|
pub fn valtree_to_const_value<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
typing_env: ty::TypingEnv<'tcx>,
|
typing_env: ty::TypingEnv<'tcx>,
|
||||||
ty: Ty<'tcx>,
|
cv: ty::Value<'tcx>,
|
||||||
valtree: ty::ValTree<'tcx>,
|
|
||||||
) -> mir::ConstValue<'tcx> {
|
) -> mir::ConstValue<'tcx> {
|
||||||
// Basic idea: We directly construct `Scalar` values from trivial `ValTree`s
|
// Basic idea: We directly construct `Scalar` values from trivial `ValTree`s
|
||||||
// (those for constants with type bool, int, uint, float or char).
|
// (those for constants with type bool, int, uint, float or char).
|
||||||
// For all other types we create an `MPlace` and fill that by walking
|
// For all other types we create an `MPlace` and fill that by walking
|
||||||
// the `ValTree` and using `place_projection` and `place_field` to
|
// the `ValTree` and using `place_projection` and `place_field` to
|
||||||
// create inner `MPlace`s which are filled recursively.
|
// create inner `MPlace`s which are filled recursively.
|
||||||
// FIXME Does this need an example?
|
// FIXME: Does this need an example?
|
||||||
match *ty.kind() {
|
match *cv.ty.kind() {
|
||||||
ty::FnDef(..) => {
|
ty::FnDef(..) => {
|
||||||
assert!(valtree.unwrap_branch().is_empty());
|
assert!(cv.valtree.unwrap_branch().is_empty());
|
||||||
mir::ConstValue::ZeroSized
|
mir::ConstValue::ZeroSized
|
||||||
}
|
}
|
||||||
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char | ty::RawPtr(_, _) => {
|
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char | ty::RawPtr(_, _) => {
|
||||||
match valtree {
|
match cv.valtree {
|
||||||
ty::ValTree::Leaf(scalar_int) => mir::ConstValue::Scalar(Scalar::Int(scalar_int)),
|
ty::ValTree::Leaf(scalar_int) => mir::ConstValue::Scalar(Scalar::Int(scalar_int)),
|
||||||
ty::ValTree::Branch(_) => bug!(
|
ty::ValTree::Branch(_) => bug!(
|
||||||
"ValTrees for Bool, Int, Uint, Float, Char or RawPtr should have the form ValTree::Leaf"
|
"ValTrees for Bool, Int, Uint, Float, Char or RawPtr should have the form ValTree::Leaf"
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::Pat(ty, _) => valtree_to_const_value(tcx, typing_env, ty, valtree),
|
ty::Pat(ty, _) => {
|
||||||
|
let cv = ty::Value { valtree: cv.valtree, ty };
|
||||||
|
valtree_to_const_value(tcx, typing_env, cv)
|
||||||
|
}
|
||||||
ty::Ref(_, inner_ty, _) => {
|
ty::Ref(_, inner_ty, _) => {
|
||||||
let mut ecx =
|
let mut ecx =
|
||||||
mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, typing_env, CanAccessMutGlobal::No);
|
mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, typing_env, CanAccessMutGlobal::No);
|
||||||
let imm = valtree_to_ref(&mut ecx, valtree, inner_ty);
|
let imm = valtree_to_ref(&mut ecx, cv.valtree, inner_ty);
|
||||||
let imm =
|
let imm = ImmTy::from_immediate(
|
||||||
ImmTy::from_immediate(imm, tcx.layout_of(typing_env.as_query_input(ty)).unwrap());
|
imm,
|
||||||
|
tcx.layout_of(typing_env.as_query_input(cv.ty)).unwrap(),
|
||||||
|
);
|
||||||
op_to_const(&ecx, &imm.into(), /* for diagnostics */ false)
|
op_to_const(&ecx, &imm.into(), /* for diagnostics */ false)
|
||||||
}
|
}
|
||||||
ty::Tuple(_) | ty::Array(_, _) | ty::Adt(..) => {
|
ty::Tuple(_) | ty::Array(_, _) | ty::Adt(..) => {
|
||||||
let layout = tcx.layout_of(typing_env.as_query_input(ty)).unwrap();
|
let layout = tcx.layout_of(typing_env.as_query_input(cv.ty)).unwrap();
|
||||||
if layout.is_zst() {
|
if layout.is_zst() {
|
||||||
// Fast path to avoid some allocations.
|
// Fast path to avoid some allocations.
|
||||||
return mir::ConstValue::ZeroSized;
|
return mir::ConstValue::ZeroSized;
|
||||||
}
|
}
|
||||||
if layout.backend_repr.is_scalar()
|
if layout.backend_repr.is_scalar()
|
||||||
&& (matches!(ty.kind(), ty::Tuple(_))
|
&& (matches!(cv.ty.kind(), ty::Tuple(_))
|
||||||
|| matches!(ty.kind(), ty::Adt(def, _) if def.is_struct()))
|
|| matches!(cv.ty.kind(), ty::Adt(def, _) if def.is_struct()))
|
||||||
{
|
{
|
||||||
// A Scalar tuple/struct; we can avoid creating an allocation.
|
// A Scalar tuple/struct; we can avoid creating an allocation.
|
||||||
let branches = valtree.unwrap_branch();
|
let branches = cv.valtree.unwrap_branch();
|
||||||
// Find the non-ZST field. (There can be aligned ZST!)
|
// Find the non-ZST field. (There can be aligned ZST!)
|
||||||
for (i, &inner_valtree) in branches.iter().enumerate() {
|
for (i, &inner_valtree) in branches.iter().enumerate() {
|
||||||
let field = layout.field(&LayoutCx::new(tcx, typing_env), i);
|
let field = layout.field(&LayoutCx::new(tcx, typing_env), i);
|
||||||
if !field.is_zst() {
|
if !field.is_zst() {
|
||||||
return valtree_to_const_value(tcx, typing_env, field.ty, inner_valtree);
|
let cv = ty::Value { valtree: inner_valtree, ty: field.ty };
|
||||||
|
return valtree_to_const_value(tcx, typing_env, cv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bug!("could not find non-ZST field during in {layout:#?}");
|
bug!("could not find non-ZST field during in {layout:#?}");
|
||||||
|
@ -335,9 +339,9 @@ pub fn valtree_to_const_value<'tcx>(
|
||||||
mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, typing_env, CanAccessMutGlobal::No);
|
mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, typing_env, CanAccessMutGlobal::No);
|
||||||
|
|
||||||
// Need to create a place for this valtree.
|
// Need to create a place for this valtree.
|
||||||
let place = create_valtree_place(&mut ecx, layout, valtree);
|
let place = create_valtree_place(&mut ecx, layout, cv.valtree);
|
||||||
|
|
||||||
valtree_into_mplace(&mut ecx, &place, valtree);
|
valtree_into_mplace(&mut ecx, &place, cv.valtree);
|
||||||
dump_place(&ecx, &place);
|
dump_place(&ecx, &place);
|
||||||
intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &place).unwrap();
|
intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &place).unwrap();
|
||||||
|
|
||||||
|
@ -362,7 +366,7 @@ pub fn valtree_to_const_value<'tcx>(
|
||||||
| ty::Slice(_)
|
| ty::Slice(_)
|
||||||
| ty::Dynamic(..)
|
| ty::Dynamic(..)
|
||||||
| ty::UnsafeBinder(_) => {
|
| ty::UnsafeBinder(_) => {
|
||||||
bug!("no ValTree should have been created for type {:?}", ty.kind())
|
bug!("no ValTree should have been created for type {:?}", cv.ty.kind())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,14 +46,8 @@ pub fn provide(providers: &mut Providers) {
|
||||||
};
|
};
|
||||||
providers.hooks.try_destructure_mir_constant_for_user_output =
|
providers.hooks.try_destructure_mir_constant_for_user_output =
|
||||||
const_eval::try_destructure_mir_constant_for_user_output;
|
const_eval::try_destructure_mir_constant_for_user_output;
|
||||||
providers.valtree_to_const_val = |tcx, cv| {
|
providers.valtree_to_const_val =
|
||||||
const_eval::valtree_to_const_value(
|
|tcx, cv| const_eval::valtree_to_const_value(tcx, ty::TypingEnv::fully_monomorphized(), cv);
|
||||||
tcx,
|
|
||||||
ty::TypingEnv::fully_monomorphized(),
|
|
||||||
cv.ty,
|
|
||||||
cv.valtree,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
providers.check_validity_requirement = |tcx, (init_kind, param_env_and_ty)| {
|
providers.check_validity_requirement = |tcx, (init_kind, param_env_and_ty)| {
|
||||||
util::check_validity_requirement(tcx, init_kind, param_env_and_ty)
|
util::check_validity_requirement(tcx, init_kind, param_env_and_ty)
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,7 @@ use rustc_middle::mir::interpret::{
|
||||||
use rustc_middle::mir::visit::Visitor;
|
use rustc_middle::mir::visit::Visitor;
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
|
use ty::print::PrettyPrinter;
|
||||||
|
|
||||||
use super::graphviz::write_mir_fn_graphviz;
|
use super::graphviz::write_mir_fn_graphviz;
|
||||||
use crate::mir::interpret::ConstAllocation;
|
use crate::mir::interpret::ConstAllocation;
|
||||||
|
@ -1429,10 +1430,10 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: call pretty_print_const_valtree?
|
let fmt_valtree = |cv: &ty::Value<'tcx>| {
|
||||||
let fmt_valtree = |valtree: &ty::ValTree<'tcx>| match valtree {
|
let mut cx = FmtPrinter::new(self.tcx, Namespace::ValueNS);
|
||||||
ty::ValTree::Leaf(leaf) => format!("Leaf({leaf:?})"),
|
cx.pretty_print_const_valtree(*cv, /*print_ty*/ true).unwrap();
|
||||||
ty::ValTree::Branch(_) => "Branch(..)".to_string(),
|
cx.into_buffer()
|
||||||
};
|
};
|
||||||
|
|
||||||
let val = match const_ {
|
let val = match const_ {
|
||||||
|
@ -1442,7 +1443,7 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
|
||||||
format!("ty::Unevaluated({}, {:?})", self.tcx.def_path_str(uv.def), uv.args,)
|
format!("ty::Unevaluated({}, {:?})", self.tcx.def_path_str(uv.def), uv.args,)
|
||||||
}
|
}
|
||||||
ty::ConstKind::Value(cv) => {
|
ty::ConstKind::Value(cv) => {
|
||||||
format!("ty::Valtree({})", fmt_valtree(&cv.valtree))
|
format!("ty::Valtree({})", fmt_valtree(&cv))
|
||||||
}
|
}
|
||||||
// No `ty::` prefix since we also use this to represent errors from `mir::Unevaluated`.
|
// No `ty::` prefix since we also use this to represent errors from `mir::Unevaluated`.
|
||||||
ty::ConstKind::Error(_) => "Error".to_string(),
|
ty::ConstKind::Error(_) => "Error".to_string(),
|
||||||
|
|
|
@ -1485,7 +1485,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
||||||
},
|
},
|
||||||
ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)),
|
ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)),
|
||||||
ty::ConstKind::Value(cv) => {
|
ty::ConstKind::Value(cv) => {
|
||||||
return self.pretty_print_const_valtree(cv.valtree, cv.ty, print_ty);
|
return self.pretty_print_const_valtree(cv, print_ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::ConstKind::Bound(debruijn, bound_var) => {
|
ty::ConstKind::Bound(debruijn, bound_var) => {
|
||||||
|
@ -1785,48 +1785,49 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(valtrees): Accept `ty::Value` instead of `Ty` and `ty::ValTree` separately.
|
|
||||||
fn pretty_print_const_valtree(
|
fn pretty_print_const_valtree(
|
||||||
&mut self,
|
&mut self,
|
||||||
valtree: ty::ValTree<'tcx>,
|
cv: ty::Value<'tcx>,
|
||||||
ty: Ty<'tcx>,
|
|
||||||
print_ty: bool,
|
print_ty: bool,
|
||||||
) -> Result<(), PrintError> {
|
) -> Result<(), PrintError> {
|
||||||
define_scoped_cx!(self);
|
define_scoped_cx!(self);
|
||||||
|
|
||||||
if self.should_print_verbose() {
|
if self.should_print_verbose() {
|
||||||
p!(write("ValTree({:?}: ", valtree), print(ty), ")");
|
p!(write("ValTree({:?}: ", cv.valtree), print(cv.ty), ")");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let u8_type = self.tcx().types.u8;
|
let u8_type = self.tcx().types.u8;
|
||||||
match (valtree, ty.kind()) {
|
match (cv.valtree, cv.ty.kind()) {
|
||||||
(ty::ValTree::Branch(_), ty::Ref(_, inner_ty, _)) => match inner_ty.kind() {
|
(ty::ValTree::Branch(_), ty::Ref(_, inner_ty, _)) => match inner_ty.kind() {
|
||||||
ty::Slice(t) if *t == u8_type => {
|
ty::Slice(t) if *t == u8_type => {
|
||||||
let bytes = valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| {
|
let bytes =
|
||||||
|
cv.valtree.try_to_raw_bytes(self.tcx(), cv.ty).unwrap_or_else(|| {
|
||||||
bug!(
|
bug!(
|
||||||
"expected to convert valtree {:?} to raw bytes for type {:?}",
|
"expected to convert valtree {:?} to raw bytes for type {:?}",
|
||||||
valtree,
|
cv.valtree,
|
||||||
t
|
t
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
return self.pretty_print_byte_str(bytes);
|
return self.pretty_print_byte_str(bytes);
|
||||||
}
|
}
|
||||||
ty::Str => {
|
ty::Str => {
|
||||||
let bytes = valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| {
|
let bytes =
|
||||||
bug!("expected to convert valtree to raw bytes for type {:?}", ty)
|
cv.valtree.try_to_raw_bytes(self.tcx(), cv.ty).unwrap_or_else(|| {
|
||||||
|
bug!("expected to convert valtree to raw bytes for type {:?}", cv.ty)
|
||||||
});
|
});
|
||||||
p!(write("{:?}", String::from_utf8_lossy(bytes)));
|
p!(write("{:?}", String::from_utf8_lossy(bytes)));
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
let cv = ty::Value { valtree: cv.valtree, ty: *inner_ty };
|
||||||
p!("&");
|
p!("&");
|
||||||
p!(pretty_print_const_valtree(valtree, *inner_ty, print_ty));
|
p!(pretty_print_const_valtree(cv, print_ty));
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(ty::ValTree::Branch(_), ty::Array(t, _)) if *t == u8_type => {
|
(ty::ValTree::Branch(_), ty::Array(t, _)) if *t == u8_type => {
|
||||||
let bytes = valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| {
|
let bytes = cv.valtree.try_to_raw_bytes(self.tcx(), cv.ty).unwrap_or_else(|| {
|
||||||
bug!("expected to convert valtree to raw bytes for type {:?}", t)
|
bug!("expected to convert valtree to raw bytes for type {:?}", t)
|
||||||
});
|
});
|
||||||
p!("*");
|
p!("*");
|
||||||
|
@ -1835,10 +1836,13 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
||||||
}
|
}
|
||||||
// Aggregates, printed as array/tuple/struct/variant construction syntax.
|
// Aggregates, printed as array/tuple/struct/variant construction syntax.
|
||||||
(ty::ValTree::Branch(_), ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) => {
|
(ty::ValTree::Branch(_), ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) => {
|
||||||
let contents =
|
let contents = self.tcx().destructure_const(ty::Const::new_value(
|
||||||
self.tcx().destructure_const(ty::Const::new_value(self.tcx(), valtree, ty));
|
self.tcx(),
|
||||||
|
cv.valtree,
|
||||||
|
cv.ty,
|
||||||
|
));
|
||||||
let fields = contents.fields.iter().copied();
|
let fields = contents.fields.iter().copied();
|
||||||
match *ty.kind() {
|
match *cv.ty.kind() {
|
||||||
ty::Array(..) => {
|
ty::Array(..) => {
|
||||||
p!("[", comma_sep(fields), "]");
|
p!("[", comma_sep(fields), "]");
|
||||||
}
|
}
|
||||||
|
@ -1855,7 +1859,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
||||||
write!(this, "unreachable()")?;
|
write!(this, "unreachable()")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
|this| this.print_type(ty),
|
|this| this.print_type(cv.ty),
|
||||||
": ",
|
": ",
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
@ -1892,7 +1896,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
||||||
return self.pretty_print_const_scalar_int(leaf, *inner_ty, print_ty);
|
return self.pretty_print_const_scalar_int(leaf, *inner_ty, print_ty);
|
||||||
}
|
}
|
||||||
(ty::ValTree::Leaf(leaf), _) => {
|
(ty::ValTree::Leaf(leaf), _) => {
|
||||||
return self.pretty_print_const_scalar_int(leaf, ty, print_ty);
|
return self.pretty_print_const_scalar_int(leaf, cv.ty, print_ty);
|
||||||
}
|
}
|
||||||
// FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading
|
// FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading
|
||||||
// their fields instead of just dumping the memory.
|
// their fields instead of just dumping the memory.
|
||||||
|
@ -1900,13 +1904,13 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
||||||
}
|
}
|
||||||
|
|
||||||
// fallback
|
// fallback
|
||||||
if valtree == ty::ValTree::zst() {
|
if cv.valtree == ty::ValTree::zst() {
|
||||||
p!(write("<ZST>"));
|
p!(write("<ZST>"));
|
||||||
} else {
|
} else {
|
||||||
p!(write("{:?}", valtree));
|
p!(write("{:?}", cv.valtree));
|
||||||
}
|
}
|
||||||
if print_ty {
|
if print_ty {
|
||||||
p!(": ", print(ty));
|
p!(": ", print(cv.ty));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,7 +170,7 @@ impl<'tcx> fmt::Debug for ty::Const<'tcx> {
|
||||||
bug!("we checked that this is a valtree")
|
bug!("we checked that this is a valtree")
|
||||||
};
|
};
|
||||||
let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
|
let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
|
||||||
cx.pretty_print_const_valtree(cv.valtree, cv.ty, /*print_ty*/ true)?;
|
cx.pretty_print_const_valtree(cv, /*print_ty*/ true)?;
|
||||||
f.write_str(&cx.into_buffer())
|
f.write_str(&cx.into_buffer())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue