Skip to content

Commit

Permalink
Auto merge of rust-lang#71232 - eddyb:print-const-adts, r=oli-obk
Browse files Browse the repository at this point in the history
ty/print: pretty-print constant aggregates (arrays, tuples and ADTs).

Oddly enough, we don't have any UI tests showing this off in types, only `mir-opt` tests.
However, the pretty form should show up in the test output diff of rust-lang#71018, if this PR is merged first.

<hr/>

Examples of before/after:
|`Option<bool>`|
|:-:|
|`{transmute(0x01): std::option::Option<bool>}`|
| :sparkles: ↓↓↓ :sparkles: |
|`std::option::Option::<bool>::Some(true)`|

| `RawVec<u32>` |
|:-:|
| `ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), undef_mask: UndefMask { blocks: [65535], len: Size { raw: 16 } }, size: Size { raw: 16 }, align: Align { pow2: 3 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }: alloc::raw_vec::RawVec::<u32>`|
| :sparkles: ↓↓↓ :sparkles: |
|`alloc::raw_vec::RawVec::<u32> { ptr: std::ptr::Unique::<u32> { pointer: {0x4 as *const u32}, _marker: std::marker::PhantomData::<u32> }, cap: 0usize, alloc: std::alloc::Global }`|

<hr/>

This PR is a prerequisite for rust-lang#61486, *sort of*, in that we need to be able to pretty-print values in order to even consider how we might mangle them.
We still don't have pretty-printing for constants of reference types, @oli-obk has the necessary support logic in a PR but I didn't want to interfere with that.

<hr/>

Each commit should be reviewed separately, as I've fixed a couple deficiencies along the way.

r? @oli-obk cc @rust-lang/wg-mir-opt @varkor @yodaldevoid
  • Loading branch information
bors committed Apr 20, 2020
2 parents 9b2f8db + eccb28e commit 4ca5fd2
Show file tree
Hide file tree
Showing 21 changed files with 128 additions and 103 deletions.
32 changes: 17 additions & 15 deletions src/librustc_middle/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2242,39 +2242,41 @@ impl<'tcx> Debug for Rvalue<'tcx> {
}

Aggregate(ref kind, ref places) => {
fn fmt_tuple(fmt: &mut Formatter<'_>, places: &[Operand<'_>]) -> fmt::Result {
let mut tuple_fmt = fmt.debug_tuple("");
let fmt_tuple = |fmt: &mut Formatter<'_>, name: &str| {
let mut tuple_fmt = fmt.debug_tuple(name);
for place in places {
tuple_fmt.field(place);
}
tuple_fmt.finish()
}
};

match **kind {
AggregateKind::Array(_) => write!(fmt, "{:?}", places),

AggregateKind::Tuple => match places.len() {
0 => write!(fmt, "()"),
1 => write!(fmt, "({:?},)", places[0]),
_ => fmt_tuple(fmt, places),
},
AggregateKind::Tuple => {
if places.is_empty() {
write!(fmt, "()")
} else {
fmt_tuple(fmt, "")
}
}

AggregateKind::Adt(adt_def, variant, substs, _user_ty, _) => {
let variant_def = &adt_def.variants[variant];

let f = &mut *fmt;
ty::tls::with(|tcx| {
let name = ty::tls::with(|tcx| {
let mut name = String::new();
let substs = tcx.lift(&substs).expect("could not lift for printing");
FmtPrinter::new(tcx, f, Namespace::ValueNS)
FmtPrinter::new(tcx, &mut name, Namespace::ValueNS)
.print_def_path(variant_def.def_id, substs)?;
Ok(())
Ok(name)
})?;

match variant_def.ctor_kind {
CtorKind::Const => Ok(()),
CtorKind::Fn => fmt_tuple(fmt, places),
CtorKind::Const => fmt.write_str(&name),
CtorKind::Fn => fmt_tuple(fmt, &name),
CtorKind::Fictive => {
let mut struct_fmt = fmt.debug_struct("");
let mut struct_fmt = fmt.debug_struct(&name);
for (field, place) in variant_def.fields.iter().zip(places) {
struct_fmt.field(&field.ident.as_str(), place);
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_middle/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@ rustc_queries! {
desc { "extract field of const" }
}

/// Destructure a constant ADT or array into its variant indent and its
/// Destructure a constant ADT or array into its variant index and its
/// field values.
query destructure_const(
key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>>
Expand Down
127 changes: 75 additions & 52 deletions src/librustc_middle/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use rustc_apfloat::Float;
use rustc_ast::ast;
use rustc_attr::{SignedInt, UnsignedInt};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Namespace};
use rustc_hir::def::{CtorKind, DefKind, Namespace};
use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
use rustc_span::symbol::{kw, Symbol};
Expand Down Expand Up @@ -498,16 +498,9 @@ pub trait PrettyPrinter<'tcx>:
}
ty::Never => p!(write("!")),
ty::Tuple(ref tys) => {
p!(write("("));
let mut tys = tys.iter();
if let Some(&ty) = tys.next() {
p!(print(ty), write(","));
if let Some(&ty) = tys.next() {
p!(write(" "), print(ty));
for &ty in tys {
p!(write(", "), print(ty));
}
}
p!(write("("), comma_sep(tys.iter().copied()));
if tys.len() == 1 {
p!(write(","));
}
p!(write(")"))
}
Expand Down Expand Up @@ -570,15 +563,10 @@ pub trait PrettyPrinter<'tcx>:
let def_key = self.tcx().def_key(def_id);
if let Some(name) = def_key.disambiguated_data.data.get_opt_name() {
p!(write("{}", name));
let mut substs = substs.iter();
// FIXME(eddyb) print this with `print_def_path`.
if let Some(first) = substs.next() {
p!(write("::<"));
p!(print(first));
for subst in substs {
p!(write(", "), print(subst));
}
p!(write(">"));
if !substs.is_empty() {
p!(write("::"));
p!(generic_delimiters(|cx| cx.comma_sep(substs.iter().copied())));
}
return Ok(self);
}
Expand Down Expand Up @@ -850,16 +838,12 @@ pub trait PrettyPrinter<'tcx>:
) -> Result<Self, Self::Error> {
define_scoped_cx!(self);

p!(write("("));
let mut inputs = inputs.iter();
if let Some(&ty) = inputs.next() {
p!(print(ty));
for &ty in inputs {
p!(write(", "), print(ty));
}
if c_variadic {
p!(write(", ..."));
p!(write("("), comma_sep(inputs.iter().copied()));
if c_variadic {
if !inputs.is_empty() {
p!(write(", "));
}
p!(write("..."));
}
p!(write(")"));
if !output.is_unit() {
Expand Down Expand Up @@ -1050,19 +1034,6 @@ pub trait PrettyPrinter<'tcx>:
}
// For function type zsts just printing the path is enough
(Scalar::Raw { size: 0, .. }, ty::FnDef(d, s)) => p!(print_value_path(*d, s)),
// Empty tuples are frequently occurring, so don't print the fallback.
(Scalar::Raw { size: 0, .. }, ty::Tuple(ts)) if ts.is_empty() => p!(write("()")),
// Zero element arrays have a trivial representation.
(
Scalar::Raw { size: 0, .. },
ty::Array(
_,
ty::Const {
val: ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data: 0, .. })),
..
},
),
) => p!(write("[]")),
// Nontrivial types with scalar bit representation
(Scalar::Raw { data, size }, _) => {
let print = |mut this: Self| {
Expand Down Expand Up @@ -1131,14 +1102,14 @@ pub trait PrettyPrinter<'tcx>:
define_scoped_cx!(self);

if self.tcx().sess.verbose() {
p!(write("ConstValue({:?}: {:?})", ct, ty));
p!(write("ConstValue({:?}: ", ct), print(ty), write(")"));
return Ok(self);
}

let u8_type = self.tcx().types.u8;

match (ct, &ty.kind) {
(ConstValue::Scalar(scalar), _) => self.pretty_print_const_scalar(scalar, ty, print_ty),
// Byte/string slices, printed as (byte) string literals.
(
ConstValue::Slice { data, start, end },
ty::Ref(_, ty::TyS { kind: ty::Slice(t), .. }, _),
Expand Down Expand Up @@ -1172,6 +1143,66 @@ pub trait PrettyPrinter<'tcx>:
p!(pretty_print_byte_str(byte_str));
Ok(self)
}

// Aggregates, printed as array/tuple/struct/variant construction syntax.
//
// NB: the `has_param_types_or_consts` check ensures that we can use
// the `destructure_const` query with an empty `ty::ParamEnv` without
// 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_param_types_or_consts() => {
let contents = self.tcx().destructure_const(
ty::ParamEnv::reveal_all()
.and(self.tcx().mk_const(ty::Const { val: ty::ConstKind::Value(ct), ty })),
);
let fields = contents.fields.iter().copied();

match ty.kind {
ty::Array(..) => {
p!(write("["), comma_sep(fields), write("]"));
}
ty::Tuple(..) => {
p!(write("("), comma_sep(fields));
if contents.fields.len() == 1 {
p!(write(","));
}
p!(write(")"));
}
ty::Adt(def, substs) => {
let variant_def = &def.variants[contents.variant];
p!(print_value_path(variant_def.def_id, substs));

match variant_def.ctor_kind {
CtorKind::Const => {}
CtorKind::Fn => {
p!(write("("), comma_sep(fields), write(")"));
}
CtorKind::Fictive => {
p!(write(" {{ "));
let mut first = true;
for (field_def, field) in variant_def.fields.iter().zip(fields) {
if !first {
p!(write(", "));
}
p!(write("{}: ", field_def.ident), print(field));
first = false;
}
p!(write(" }}"));
}
}
}
_ => unreachable!(),
}

Ok(self)
}

(ConstValue::Scalar(scalar), _) => self.pretty_print_const_scalar(scalar, ty, print_ty),

// FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading
// their fields instead of just dumping the memory.
_ => {
Expand Down Expand Up @@ -1910,15 +1941,7 @@ define_print_and_forward_display! {
(self, cx):

&'tcx ty::List<Ty<'tcx>> {
p!(write("{{"));
let mut tys = self.iter();
if let Some(&ty) = tys.next() {
p!(print(ty));
for &ty in tys {
p!(write(", "), print(ty));
}
}
p!(write("}}"))
p!(write("{{"), comma_sep(self.iter().copied()), write("}}"))
}

ty::TypeAndMut<'tcx> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
StorageLive(_1); // bb0[0]: scope 0 at $DIR/discriminant.rs:6:9: 6:10
StorageLive(_2); // bb0[1]: scope 0 at $DIR/discriminant.rs:6:13: 6:64
StorageLive(_3); // bb0[2]: scope 0 at $DIR/discriminant.rs:6:34: 6:44
- _3 = std::option::Option::<bool>::Some(const true,); // bb0[3]: scope 0 at $DIR/discriminant.rs:6:34: 6:44
+ _3 = const {transmute(0x01): std::option::Option<bool>}; // bb0[3]: scope 0 at $DIR/discriminant.rs:6:34: 6:44
- _3 = std::option::Option::<bool>::Some(const true); // bb0[3]: scope 0 at $DIR/discriminant.rs:6:34: 6:44
+ _3 = const std::option::Option::<bool>::Some(true); // bb0[3]: scope 0 at $DIR/discriminant.rs:6:34: 6:44
// ty::Const
- // + ty: bool
+ // + ty: std::option::Option<bool>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
StorageLive(_1); // bb0[0]: scope 0 at $DIR/discriminant.rs:6:9: 6:10
StorageLive(_2); // bb0[1]: scope 0 at $DIR/discriminant.rs:6:13: 6:64
StorageLive(_3); // bb0[2]: scope 0 at $DIR/discriminant.rs:6:34: 6:44
- _3 = std::option::Option::<bool>::Some(const true,); // bb0[3]: scope 0 at $DIR/discriminant.rs:6:34: 6:44
+ _3 = const {transmute(0x01): std::option::Option<bool>}; // bb0[3]: scope 0 at $DIR/discriminant.rs:6:34: 6:44
- _3 = std::option::Option::<bool>::Some(const true); // bb0[3]: scope 0 at $DIR/discriminant.rs:6:34: 6:44
+ _3 = const std::option::Option::<bool>::Some(true); // bb0[3]: scope 0 at $DIR/discriminant.rs:6:34: 6:44
// ty::Const
- // + ty: bool
+ // + ty: std::option::Option<bool>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
bb1: {
StorageLive(_5); // bb1[0]: scope 0 at $DIR/deaggregator_test_enum_2.rs:13:16: 13:17
_5 = _2; // bb1[1]: scope 0 at $DIR/deaggregator_test_enum_2.rs:13:16: 13:17
- _0 = Foo::B(move _5,); // bb1[2]: scope 0 at $DIR/deaggregator_test_enum_2.rs:13:9: 13:18
- _0 = Foo::B(move _5); // bb1[2]: scope 0 at $DIR/deaggregator_test_enum_2.rs:13:9: 13:18
- StorageDead(_5); // bb1[3]: scope 0 at $DIR/deaggregator_test_enum_2.rs:13:17: 13:18
- goto -> bb3; // bb1[4]: scope 0 at $DIR/deaggregator_test_enum_2.rs:10:5: 14:6
+ ((_0 as B).0: i32) = move _5; // bb1[2]: scope 0 at $DIR/deaggregator_test_enum_2.rs:13:9: 13:18
Expand All @@ -30,7 +30,7 @@
bb2: {
StorageLive(_4); // bb2[0]: scope 0 at $DIR/deaggregator_test_enum_2.rs:11:16: 11:17
_4 = _2; // bb2[1]: scope 0 at $DIR/deaggregator_test_enum_2.rs:11:16: 11:17
- _0 = Foo::A(move _4,); // bb2[2]: scope 0 at $DIR/deaggregator_test_enum_2.rs:11:9: 11:18
- _0 = Foo::A(move _4); // bb2[2]: scope 0 at $DIR/deaggregator_test_enum_2.rs:11:9: 11:18
- StorageDead(_4); // bb2[3]: scope 0 at $DIR/deaggregator_test_enum_2.rs:11:17: 11:18
- goto -> bb3; // bb2[4]: scope 0 at $DIR/deaggregator_test_enum_2.rs:10:5: 14:6
+ ((_0 as A).0: i32) = move _4; // bb2[2]: scope 0 at $DIR/deaggregator_test_enum_2.rs:11:9: 11:18
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
StorageLive(_2); // bb0[0]: scope 0 at $DIR/deaggregator_test_multiple.rs:10:6: 10:15
StorageLive(_3); // bb0[1]: scope 0 at $DIR/deaggregator_test_multiple.rs:10:13: 10:14
_3 = _1; // bb0[2]: scope 0 at $DIR/deaggregator_test_multiple.rs:10:13: 10:14
- _2 = Foo::A(move _3,); // bb0[3]: scope 0 at $DIR/deaggregator_test_multiple.rs:10:6: 10:15
- _2 = Foo::A(move _3); // bb0[3]: scope 0 at $DIR/deaggregator_test_multiple.rs:10:6: 10:15
- StorageDead(_3); // bb0[4]: scope 0 at $DIR/deaggregator_test_multiple.rs:10:14: 10:15
- StorageLive(_4); // bb0[5]: scope 0 at $DIR/deaggregator_test_multiple.rs:10:17: 10:26
- StorageLive(_5); // bb0[6]: scope 0 at $DIR/deaggregator_test_multiple.rs:10:24: 10:25
- _5 = _1; // bb0[7]: scope 0 at $DIR/deaggregator_test_multiple.rs:10:24: 10:25
- _4 = Foo::A(move _5,); // bb0[8]: scope 0 at $DIR/deaggregator_test_multiple.rs:10:17: 10:26
- _4 = Foo::A(move _5); // bb0[8]: scope 0 at $DIR/deaggregator_test_multiple.rs:10:17: 10:26
- StorageDead(_5); // bb0[9]: scope 0 at $DIR/deaggregator_test_multiple.rs:10:25: 10:26
- _0 = [move _2, move _4]; // bb0[10]: scope 0 at $DIR/deaggregator_test_multiple.rs:10:5: 10:27
- StorageDead(_4); // bb0[11]: scope 0 at $DIR/deaggregator_test_multiple.rs:10:26: 10:27
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ yields ()

bb0: {
StorageLive(_3); // bb0[0]: scope 0 at $DIR/generator-storage-dead-unwind.rs:23:13: 23:14
_3 = Foo(const 5i32,); // bb0[1]: scope 0 at $DIR/generator-storage-dead-unwind.rs:23:17: 23:23
_3 = Foo(const 5i32); // bb0[1]: scope 0 at $DIR/generator-storage-dead-unwind.rs:23:17: 23:23
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000005))
// mir::Constant
// + span: $DIR/generator-storage-dead-unwind.rs:23:21: 23:22
// + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
StorageLive(_4); // bb0[2]: scope 1 at $DIR/generator-storage-dead-unwind.rs:24:13: 24:14
_4 = Bar(const 6i32,); // bb0[3]: scope 1 at $DIR/generator-storage-dead-unwind.rs:24:17: 24:23
_4 = Bar(const 6i32); // bb0[3]: scope 1 at $DIR/generator-storage-dead-unwind.rs:24:17: 24:23
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000006))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fn main::{{closure}}#0(_1: std::pin::Pin<&mut [generator@$DIR/generator-tiny.rs:
StorageLive(_6); // bb2[0]: scope 1 at $DIR/generator-tiny.rs:21:13: 21:18
StorageLive(_7); // bb2[1]: scope 1 at $DIR/generator-tiny.rs:21:13: 21:18
_7 = (); // bb2[2]: scope 1 at $DIR/generator-tiny.rs:21:13: 21:18
_0 = std::ops::GeneratorState::<(), ()>::Yielded(move _7,); // bb2[3]: scope 1 at $DIR/generator-tiny.rs:21:13: 21:18
_0 = std::ops::GeneratorState::<(), ()>::Yielded(move _7); // bb2[3]: scope 1 at $DIR/generator-tiny.rs:21:13: 21:18
discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:18:16: 24:6 {u8, HasDrop, ()}]))) = 3; // bb2[4]: scope 1 at $DIR/generator-tiny.rs:21:13: 21:18
return; // bb2[5]: scope 1 at $DIR/generator-tiny.rs:21:13: 21:18
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
_2 = Box(std::vec::Vec<u32>); // bb0[2]: scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
- (*_2) = const std::vec::Vec::<u32>::new() -> [return: bb2, unwind: bb4]; // bb0[3]: scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
+ _4 = &mut (*_2); // bb0[3]: scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
+ ((*_4).0: alloc::raw_vec::RawVec<u32>) = const ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), undef_mask: UndefMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }: alloc::raw_vec::RawVec::<u32>; // bb0[4]: scope 2 at $SRC_DIR/liballoc/vec.rs:LL:COL
+ ((*_4).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: std::ptr::Unique::<u32> { pointer: {0x4 as *const u32}, _marker: std::marker::PhantomData::<u32> }, cap: 0usize, alloc: std::alloc::Global }; // bb0[4]: scope 2 at $SRC_DIR/liballoc/vec.rs:LL:COL
// ty::Const
- // + ty: fn() -> std::vec::Vec<u32> {std::vec::Vec::<u32>::new}
- // + val: Value(Scalar(<ZST>))
Expand Down
Loading

0 comments on commit 4ca5fd2

Please sign in to comment.