Skip to content

Commit 921e311

Browse files
authored
Rollup merge of #98643 - voidc:valtree-ref-pretty, r=lcnr
Improve pretty printing of valtrees for references This implements the changes outlined in #66451 (comment). r? `@lcnr` Fixes #66451
2 parents 05c0b2e + d048b15 commit 921e311

File tree

9 files changed

+138
-102
lines changed

9 files changed

+138
-102
lines changed

compiler/rustc_const_eval/src/const_eval/mod.rs

-78
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use rustc_middle::mir;
55
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId};
66
use rustc_middle::ty::{self, TyCtxt};
77
use rustc_span::{source_map::DUMMY_SP, symbol::Symbol};
8-
use rustc_target::abi::VariantIdx;
98

109
use crate::interpret::{
1110
intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MemPlaceMeta,
@@ -91,83 +90,6 @@ pub(crate) fn eval_to_valtree<'tcx>(
9190
}
9291
}
9392

94-
/// Tries to destructure constants of type Array or Adt into the constants
95-
/// of its fields.
96-
pub(crate) fn try_destructure_const<'tcx>(
97-
tcx: TyCtxt<'tcx>,
98-
const_: ty::Const<'tcx>,
99-
) -> Option<ty::DestructuredConst<'tcx>> {
100-
if let ty::ConstKind::Value(valtree) = const_.kind() {
101-
let branches = match valtree {
102-
ty::ValTree::Branch(b) => b,
103-
_ => return None,
104-
};
105-
106-
let (fields, variant) = match const_.ty().kind() {
107-
ty::Array(inner_ty, _) | ty::Slice(inner_ty) => {
108-
// construct the consts for the elements of the array/slice
109-
let field_consts = branches
110-
.iter()
111-
.map(|b| {
112-
tcx.mk_const(ty::ConstS { kind: ty::ConstKind::Value(*b), ty: *inner_ty })
113-
})
114-
.collect::<Vec<_>>();
115-
debug!(?field_consts);
116-
117-
(field_consts, None)
118-
}
119-
ty::Adt(def, _) if def.variants().is_empty() => bug!("unreachable"),
120-
ty::Adt(def, substs) => {
121-
let variant_idx = if def.is_enum() {
122-
VariantIdx::from_u32(branches[0].unwrap_leaf().try_to_u32().ok()?)
123-
} else {
124-
VariantIdx::from_u32(0)
125-
};
126-
let fields = &def.variant(variant_idx).fields;
127-
let mut field_consts = Vec::with_capacity(fields.len());
128-
129-
// Note: First element inValTree corresponds to variant of enum
130-
let mut valtree_idx = if def.is_enum() { 1 } else { 0 };
131-
for field in fields {
132-
let field_ty = field.ty(tcx, substs);
133-
let field_valtree = branches[valtree_idx]; // first element of branches is variant
134-
let field_const = tcx.mk_const(ty::ConstS {
135-
kind: ty::ConstKind::Value(field_valtree),
136-
ty: field_ty,
137-
});
138-
field_consts.push(field_const);
139-
valtree_idx += 1;
140-
}
141-
debug!(?field_consts);
142-
143-
(field_consts, Some(variant_idx))
144-
}
145-
ty::Tuple(elem_tys) => {
146-
let fields = elem_tys
147-
.iter()
148-
.enumerate()
149-
.map(|(i, elem_ty)| {
150-
let elem_valtree = branches[i];
151-
tcx.mk_const(ty::ConstS {
152-
kind: ty::ConstKind::Value(elem_valtree),
153-
ty: elem_ty,
154-
})
155-
})
156-
.collect::<Vec<_>>();
157-
158-
(fields, None)
159-
}
160-
_ => bug!("cannot destructure constant {:?}", const_),
161-
};
162-
163-
let fields = tcx.arena.alloc_from_iter(fields.into_iter());
164-
165-
Some(ty::DestructuredConst { variant, fields })
166-
} else {
167-
None
168-
}
169-
}
170-
17193
#[instrument(skip(tcx), level = "debug")]
17294
pub(crate) fn try_destructure_mir_constant<'tcx>(
17395
tcx: TyCtxt<'tcx>,

compiler/rustc_const_eval/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ pub fn provide(providers: &mut Providers) {
4242
providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider;
4343
providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider;
4444
providers.const_caller_location = const_eval::const_caller_location;
45-
providers.try_destructure_const = |tcx, val| const_eval::try_destructure_const(tcx, val);
4645
providers.eval_to_valtree = |tcx, param_env_and_value| {
4746
let (param_env, raw) = param_env_and_value.into_parts();
4847
const_eval::eval_to_valtree(tcx, param_env, raw)

compiler/rustc_middle/src/mir/interpret/queries.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -205,14 +205,8 @@ impl<'tcx> TyCtxtEnsure<'tcx> {
205205
}
206206

207207
impl<'tcx> TyCtxt<'tcx> {
208-
/// Destructure a type-level constant ADT or array into its variant index and its field values.
209-
/// Panics if the destructuring fails, use `try_destructure_const` for fallible version.
210-
pub fn destructure_const(self, const_: ty::Const<'tcx>) -> ty::DestructuredConst<'tcx> {
211-
self.try_destructure_const(const_).unwrap()
212-
}
213-
214208
/// Destructure a mir constant ADT or array into its variant index and its field values.
215-
/// Panics if the destructuring fails, use `try_destructure_const` for fallible version.
209+
/// Panics if the destructuring fails, use `try_destructure_mir_constant` for fallible version.
216210
pub fn destructure_mir_constant(
217211
self,
218212
param_env: ty::ParamEnv<'tcx>,

compiler/rustc_middle/src/query/mod.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -978,11 +978,9 @@ rustc_queries! {
978978
desc { "converting type-level constant value to mir constant value"}
979979
}
980980

981-
/// Destructure a constant ADT or array into its variant index and its
982-
/// field values or return `None` if constant is invalid.
983-
///
984-
/// Use infallible `TyCtxt::destructure_const` when you know that constant is valid.
985-
query try_destructure_const(key: ty::Const<'tcx>) -> Option<ty::DestructuredConst<'tcx>> {
981+
/// Destructures array, ADT or tuple constants into the constants
982+
/// of their fields.
983+
query destructure_const(key: ty::Const<'tcx>) -> ty::DestructuredConst<'tcx> {
986984
desc { "destructuring type level constant"}
987985
}
988986

compiler/rustc_middle/src/ty/print/pretty.rs

+7-11
Original file line numberDiff line numberDiff line change
@@ -1447,7 +1447,11 @@ pub trait PrettyPrinter<'tcx>:
14471447
p!(write("{:?}", String::from_utf8_lossy(bytes)));
14481448
return Ok(self);
14491449
}
1450-
_ => {}
1450+
_ => {
1451+
p!("&");
1452+
p!(pretty_print_const_valtree(valtree, *inner_ty, print_ty));
1453+
return Ok(self);
1454+
}
14511455
},
14521456
(ty::ValTree::Branch(_), ty::Array(t, _)) if *t == u8_type => {
14531457
let bytes = valtree.try_to_raw_bytes(self.tcx(), *t).unwrap_or_else(|| {
@@ -1459,16 +1463,8 @@ pub trait PrettyPrinter<'tcx>:
14591463
}
14601464
// Aggregates, printed as array/tuple/struct/variant construction syntax.
14611465
(ty::ValTree::Branch(_), ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) => {
1462-
let Some(contents) = self.tcx().try_destructure_const(
1463-
ty::Const::from_value(self.tcx(), valtree, ty)
1464-
) else {
1465-
// Fall back to debug pretty printing for invalid constants.
1466-
p!(write("{:?}", valtree));
1467-
if print_ty {
1468-
p!(": ", print(ty));
1469-
}
1470-
return Ok(self);
1471-
};
1466+
let contents =
1467+
self.tcx().destructure_const(ty::Const::from_value(self.tcx(), valtree, ty));
14721468
let fields = contents.fields.iter().copied();
14731469
match *ty.kind() {
14741470
ty::Array(..) => {

compiler/rustc_ty_utils/src/consts.rs

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
use rustc_middle::ty::{self, TyCtxt};
2+
use rustc_target::abi::VariantIdx;
3+
4+
use std::iter;
5+
6+
/// Destructures array, ADT or tuple constants into the constants
7+
/// of their fields.
8+
pub(crate) fn destructure_const<'tcx>(
9+
tcx: TyCtxt<'tcx>,
10+
const_: ty::Const<'tcx>,
11+
) -> ty::DestructuredConst<'tcx> {
12+
let ty::ConstKind::Value(valtree) = const_.kind() else {
13+
bug!("cannot destructure constant {:?}", const_)
14+
};
15+
16+
let branches = match valtree {
17+
ty::ValTree::Branch(b) => b,
18+
_ => bug!("cannot destructure constant {:?}", const_),
19+
};
20+
21+
let (fields, variant) = match const_.ty().kind() {
22+
ty::Array(inner_ty, _) | ty::Slice(inner_ty) => {
23+
// construct the consts for the elements of the array/slice
24+
let field_consts = branches
25+
.iter()
26+
.map(|b| tcx.mk_const(ty::ConstS { kind: ty::ConstKind::Value(*b), ty: *inner_ty }))
27+
.collect::<Vec<_>>();
28+
debug!(?field_consts);
29+
30+
(field_consts, None)
31+
}
32+
ty::Adt(def, _) if def.variants().is_empty() => bug!("unreachable"),
33+
ty::Adt(def, substs) => {
34+
let (variant_idx, branches) = if def.is_enum() {
35+
let (head, rest) = branches.split_first().unwrap();
36+
(VariantIdx::from_u32(head.unwrap_leaf().try_to_u32().unwrap()), rest)
37+
} else {
38+
(VariantIdx::from_u32(0), branches)
39+
};
40+
let fields = &def.variant(variant_idx).fields;
41+
let mut field_consts = Vec::with_capacity(fields.len());
42+
43+
for (field, field_valtree) in iter::zip(fields, branches) {
44+
let field_ty = field.ty(tcx, substs);
45+
let field_const = tcx.mk_const(ty::ConstS {
46+
kind: ty::ConstKind::Value(*field_valtree),
47+
ty: field_ty,
48+
});
49+
field_consts.push(field_const);
50+
}
51+
debug!(?field_consts);
52+
53+
(field_consts, Some(variant_idx))
54+
}
55+
ty::Tuple(elem_tys) => {
56+
let fields = iter::zip(*elem_tys, branches)
57+
.map(|(elem_ty, elem_valtree)| {
58+
tcx.mk_const(ty::ConstS {
59+
kind: ty::ConstKind::Value(*elem_valtree),
60+
ty: elem_ty,
61+
})
62+
})
63+
.collect::<Vec<_>>();
64+
65+
(fields, None)
66+
}
67+
_ => bug!("cannot destructure constant {:?}", const_),
68+
};
69+
70+
let fields = tcx.arena.alloc_from_iter(fields.into_iter());
71+
72+
ty::DestructuredConst { variant, fields }
73+
}
74+
75+
pub fn provide(providers: &mut ty::query::Providers) {
76+
*providers = ty::query::Providers { destructure_const, ..*providers };
77+
}

compiler/rustc_ty_utils/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use rustc_middle::ty::query::Providers;
1818

1919
mod assoc;
2020
mod common_traits;
21+
mod consts;
2122
pub mod instance;
2223
mod needs_drop;
2324
pub mod representability;
@@ -26,6 +27,7 @@ mod ty;
2627
pub fn provide(providers: &mut Providers) {
2728
assoc::provide(providers);
2829
common_traits::provide(providers);
30+
consts::provide(providers);
2931
needs_drop::provide(providers);
3032
ty::provide(providers);
3133
instance::provide(providers);
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#![feature(adt_const_params)]
2+
#![allow(incomplete_features)]
3+
4+
#[derive(Debug, PartialEq, Eq)]
5+
struct Foo {
6+
value: i32,
7+
nested: &'static Bar<i32>,
8+
}
9+
10+
#[derive(Debug, PartialEq, Eq)]
11+
struct Bar<T>(T);
12+
13+
struct Test<const F: Foo>;
14+
15+
fn main() {
16+
let x: Test<{
17+
Foo {
18+
value: 3,
19+
nested: &Bar(4),
20+
}
21+
}> = Test;
22+
let y: Test<{
23+
Foo {
24+
value: 3,
25+
nested: &Bar(5),
26+
}
27+
}> = x; //~ ERROR mismatched types
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-66451.rs:27:10
3+
|
4+
LL | let y: Test<{
5+
| ____________-
6+
LL | | Foo {
7+
LL | | value: 3,
8+
LL | | nested: &Bar(5),
9+
LL | | }
10+
LL | | }> = x;
11+
| | - ^ expected `Foo { value: 3_i32, nested: &Bar::<i32>(5_i32) }`, found `Foo { value: 3_i32, nested: &Bar::<i32>(4_i32) }`
12+
| |______|
13+
| expected due to this
14+
|
15+
= note: expected struct `Test<Foo { value: 3_i32, nested: &Bar::<i32>(5_i32) }>`
16+
found struct `Test<Foo { value: 3_i32, nested: &Bar::<i32>(4_i32) }>`
17+
18+
error: aborting due to previous error
19+
20+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)