1
Fork 0

Auto merge of #113291 - oli-obk:pretty_print_mir_const, r=RalfJung

Specialize `try_destructure_mir_constant` for its sole user (pretty printing)

We can't remove the query, as we need to invoke it from rustc_middle, but can only implement it in mir interpretation/const eval.

r? `@RalfJung` for a first round.

While we could move all the logic into pretty printing, that would end up duplicating a bit of code with const eval, which doesn't seem great either.
This commit is contained in:
bors 2023-07-06 00:00:38 +00:00
commit bd8aabef31
9 changed files with 72 additions and 86 deletions

View file

@ -2776,7 +2776,7 @@ impl<'tcx> Display for ConstantKind<'tcx> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
match *self {
ConstantKind::Ty(c) => pretty_print_const(c, fmt, true),
ConstantKind::Val(val, ty) => pretty_print_const_value(val, ty, fmt, true),
ConstantKind::Val(val, ty) => pretty_print_const_value(val, ty, fmt),
// FIXME(valtrees): Correctly print mir constants.
ConstantKind::Unevaluated(..) => {
fmt.write_str("_")?;
@ -2806,13 +2806,16 @@ fn pretty_print_byte_str(fmt: &mut Formatter<'_>, byte_str: &[u8]) -> fmt::Resul
write!(fmt, "b\"{}\"", byte_str.escape_ascii())
}
fn comma_sep<'tcx>(fmt: &mut Formatter<'_>, elems: Vec<ConstantKind<'tcx>>) -> fmt::Result {
fn comma_sep<'tcx>(
fmt: &mut Formatter<'_>,
elems: Vec<(ConstValue<'tcx>, Ty<'tcx>)>,
) -> fmt::Result {
let mut first = true;
for elem in elems {
for (ct, ty) in elems {
if !first {
fmt.write_str(", ")?;
}
fmt.write_str(&format!("{}", elem))?;
pretty_print_const_value(ct, ty, fmt)?;
first = false;
}
Ok(())
@ -2823,7 +2826,6 @@ fn pretty_print_const_value<'tcx>(
ct: ConstValue<'tcx>,
ty: Ty<'tcx>,
fmt: &mut Formatter<'_>,
print_ty: bool,
) -> fmt::Result {
use crate::ty::print::PrettyPrinter;
@ -2882,16 +2884,11 @@ fn pretty_print_const_value<'tcx>(
// introducing ICEs (e.g. via `layout_of`) from missing bounds.
// E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized`
// to be able to destructure the tuple into `(0u8, *mut T)`
//
// FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the
// correct `ty::ParamEnv` to allow printing *all* constant values.
(_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_non_region_param() => {
let ct = tcx.lift(ct).unwrap();
let ty = tcx.lift(ty).unwrap();
if let Some(contents) = tcx.try_destructure_mir_constant(
ty::ParamEnv::reveal_all().and(ConstantKind::Val(ct, ty)),
) {
let fields = contents.fields.to_vec();
if let Some(contents) = tcx.try_destructure_mir_constant_for_diagnostics((ct, ty)) {
let fields: Vec<(ConstValue<'_>, Ty<'_>)> = contents.fields.to_vec();
match *ty.kind() {
ty::Array(..) => {
fmt.write_str("[")?;
@ -2930,12 +2927,14 @@ fn pretty_print_const_value<'tcx>(
None => {
fmt.write_str(" {{ ")?;
let mut first = true;
for (field_def, field) in iter::zip(&variant_def.fields, fields)
for (field_def, (ct, ty)) in
iter::zip(&variant_def.fields, fields)
{
if !first {
fmt.write_str(", ")?;
}
fmt.write_str(&format!("{}: {}", field_def.name, field))?;
write!(fmt, "{}: ", field_def.name)?;
pretty_print_const_value(ct, ty, fmt)?;
first = false;
}
fmt.write_str(" }}")?;
@ -2945,20 +2944,13 @@ fn pretty_print_const_value<'tcx>(
_ => unreachable!(),
}
return Ok(());
} else {
// Fall back to debug pretty printing for invalid constants.
fmt.write_str(&format!("{:?}", ct))?;
if print_ty {
fmt.write_str(&format!(": {}", ty))?;
}
return Ok(());
};
}
}
(ConstValue::Scalar(scalar), _) => {
let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
cx.print_alloc_ids = true;
let ty = tcx.lift(ty).unwrap();
cx = cx.pretty_print_const_scalar(scalar, ty, print_ty)?;
cx = cx.pretty_print_const_scalar(scalar, ty)?;
fmt.write_str(&cx.into_buffer())?;
return Ok(());
}
@ -2973,12 +2965,8 @@ fn pretty_print_const_value<'tcx>(
// their fields instead of just dumping the memory.
_ => {}
}
// fallback
fmt.write_str(&format!("{:?}", ct))?;
if print_ty {
fmt.write_str(&format!(": {}", ty))?;
}
Ok(())
// Fall back to debug pretty printing for invalid constants.
write!(fmt, "{ct:?}: {ty}")
})
}

View file

@ -1,6 +1,6 @@
//! Values computed by queries that use MIR.
use crate::mir::ConstantKind;
use crate::mir::interpret::ConstValue;
use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt};
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::unord::UnordSet;
@ -444,7 +444,7 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
#[derive(Copy, Clone, Debug, HashStable)]
pub struct DestructuredConstant<'tcx> {
pub variant: Option<VariantIdx>,
pub fields: &'tcx [ConstantKind<'tcx>],
pub fields: &'tcx [(ConstValue<'tcx>, Ty<'tcx>)],
}
/// Coverage information summarized from a MIR if instrumented for source code coverage (see

View file

@ -2,6 +2,7 @@
use crate::infer::canonical::Canonical;
use crate::mir;
use crate::mir::interpret::ConstValue;
use crate::traits;
use crate::ty::fast_reject::SimplifiedType;
use crate::ty::layout::{TyAndLayout, ValidityRequirement};
@ -333,6 +334,14 @@ impl<'tcx> Key for (ty::Const<'tcx>, FieldIdx) {
}
}
impl<'tcx> Key for (ConstValue<'tcx>, Ty<'tcx>) {
type CacheSelector = DefaultCacheSelector<Self>;
fn default_span(&self, _: TyCtxt<'_>) -> Span {
DUMMY_SP
}
}
impl<'tcx> Key for mir::interpret::ConstAlloc<'tcx> {
type CacheSelector = DefaultCacheSelector<Self>;

View file

@ -1087,11 +1087,13 @@ rustc_queries! {
}
/// Tries to destructure an `mir::ConstantKind` ADT or array into its variant index
/// and its field values.
query try_destructure_mir_constant(
key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
/// and its field values. This should only be used for pretty printing.
query try_destructure_mir_constant_for_diagnostics(
key: (ConstValue<'tcx>, Ty<'tcx>)
) -> Option<mir::DestructuredConstant<'tcx>> {
desc { "destructuring MIR constant"}
no_hash
eval_always
}
query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> {

View file

@ -1393,11 +1393,12 @@ pub trait PrettyPrinter<'tcx>:
self,
scalar: Scalar,
ty: Ty<'tcx>,
print_ty: bool,
) -> Result<Self::Const, Self::Error> {
match scalar {
Scalar::Ptr(ptr, _size) => self.pretty_print_const_scalar_ptr(ptr, ty, print_ty),
Scalar::Int(int) => self.pretty_print_const_scalar_int(int, ty, print_ty),
Scalar::Ptr(ptr, _size) => self.pretty_print_const_scalar_ptr(ptr, ty),
Scalar::Int(int) => {
self.pretty_print_const_scalar_int(int, ty, /* print_ty */ true)
}
}
}
@ -1405,7 +1406,6 @@ pub trait PrettyPrinter<'tcx>:
mut self,
ptr: Pointer,
ty: Ty<'tcx>,
print_ty: bool,
) -> Result<Self::Const, Self::Error> {
define_scoped_cx!(self);
@ -1459,7 +1459,7 @@ pub trait PrettyPrinter<'tcx>:
_ => {}
}
// Any pointer values not covered by a branch above
self = self.pretty_print_const_pointer(ptr, ty, print_ty)?;
self = self.pretty_print_const_pointer(ptr, ty)?;
Ok(self)
}
@ -1527,24 +1527,18 @@ pub trait PrettyPrinter<'tcx>:
/// This is overridden for MIR printing because we only want to hide alloc ids from users, not
/// from MIR where it is actually useful.
fn pretty_print_const_pointer<Prov: Provenance>(
mut self,
self,
_: Pointer<Prov>,
ty: Ty<'tcx>,
print_ty: bool,
) -> Result<Self::Const, Self::Error> {
if print_ty {
self.typed_value(
|mut this| {
this.write_str("&_")?;
Ok(this)
},
|this| this.print_type(ty),
": ",
)
} else {
self.write_str("&_")?;
Ok(self)
}
self.typed_value(
|mut this| {
this.write_str("&_")?;
Ok(this)
},
|this| this.print_type(ty),
": ",
)
}
fn pretty_print_byte_str(mut self, byte_str: &'tcx [u8]) -> Result<Self::Const, Self::Error> {
@ -2156,7 +2150,6 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
self,
p: Pointer<Prov>,
ty: Ty<'tcx>,
print_ty: bool,
) -> Result<Self::Const, Self::Error> {
let print = |mut this: Self| {
define_scoped_cx!(this);
@ -2167,11 +2160,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
}
Ok(this)
};
if print_ty {
self.typed_value(print, |this| this.print_type(ty), ": ")
} else {
print(self)
}
self.typed_value(print, |this| this.print_type(ty), ": ")
}
}