Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve pretty printing of valtrees for references #98643

Merged
merged 4 commits into from
Jun 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 0 additions & 78 deletions compiler/rustc_const_eval/src/const_eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use rustc_middle::mir;
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId};
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::{source_map::DUMMY_SP, symbol::Symbol};
use rustc_target::abi::VariantIdx;

use crate::interpret::{
intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MemPlaceMeta,
Expand Down Expand Up @@ -91,83 +90,6 @@ pub(crate) fn eval_to_valtree<'tcx>(
}
}

/// Tries to destructure constants of type Array or Adt into the constants
/// of its fields.
pub(crate) fn try_destructure_const<'tcx>(
tcx: TyCtxt<'tcx>,
const_: ty::Const<'tcx>,
) -> Option<ty::DestructuredConst<'tcx>> {
if let ty::ConstKind::Value(valtree) = const_.kind() {
let branches = match valtree {
ty::ValTree::Branch(b) => b,
_ => return None,
};

let (fields, variant) = match const_.ty().kind() {
ty::Array(inner_ty, _) | ty::Slice(inner_ty) => {
// construct the consts for the elements of the array/slice
let field_consts = branches
.iter()
.map(|b| {
tcx.mk_const(ty::ConstS { kind: ty::ConstKind::Value(*b), ty: *inner_ty })
})
.collect::<Vec<_>>();
debug!(?field_consts);

(field_consts, None)
}
ty::Adt(def, _) if def.variants().is_empty() => bug!("unreachable"),
ty::Adt(def, substs) => {
let variant_idx = if def.is_enum() {
VariantIdx::from_u32(branches[0].unwrap_leaf().try_to_u32().ok()?)
} else {
VariantIdx::from_u32(0)
};
let fields = &def.variant(variant_idx).fields;
let mut field_consts = Vec::with_capacity(fields.len());

// Note: First element inValTree corresponds to variant of enum
let mut valtree_idx = if def.is_enum() { 1 } else { 0 };
for field in fields {
let field_ty = field.ty(tcx, substs);
let field_valtree = branches[valtree_idx]; // first element of branches is variant
let field_const = tcx.mk_const(ty::ConstS {
kind: ty::ConstKind::Value(field_valtree),
ty: field_ty,
});
field_consts.push(field_const);
valtree_idx += 1;
}
debug!(?field_consts);

(field_consts, Some(variant_idx))
}
ty::Tuple(elem_tys) => {
let fields = elem_tys
.iter()
.enumerate()
.map(|(i, elem_ty)| {
let elem_valtree = branches[i];
tcx.mk_const(ty::ConstS {
kind: ty::ConstKind::Value(elem_valtree),
ty: elem_ty,
})
})
.collect::<Vec<_>>();

(fields, None)
}
_ => bug!("cannot destructure constant {:?}", const_),
};

let fields = tcx.arena.alloc_from_iter(fields.into_iter());

Some(ty::DestructuredConst { variant, fields })
} else {
None
}
}

#[instrument(skip(tcx), level = "debug")]
pub(crate) fn try_destructure_mir_constant<'tcx>(
tcx: TyCtxt<'tcx>,
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_const_eval/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ pub fn provide(providers: &mut Providers) {
providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider;
providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider;
providers.const_caller_location = const_eval::const_caller_location;
providers.try_destructure_const = |tcx, val| const_eval::try_destructure_const(tcx, val);
providers.eval_to_valtree = |tcx, param_env_and_value| {
let (param_env, raw) = param_env_and_value.into_parts();
const_eval::eval_to_valtree(tcx, param_env, raw)
Expand Down
8 changes: 1 addition & 7 deletions compiler/rustc_middle/src/mir/interpret/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,14 +205,8 @@ impl<'tcx> TyCtxtEnsure<'tcx> {
}

impl<'tcx> TyCtxt<'tcx> {
/// Destructure a type-level constant ADT or array into its variant index and its field values.
/// Panics if the destructuring fails, use `try_destructure_const` for fallible version.
pub fn destructure_const(self, const_: ty::Const<'tcx>) -> ty::DestructuredConst<'tcx> {
self.try_destructure_const(const_).unwrap()
}

/// Destructure a mir constant ADT or array into its variant index and its field values.
/// Panics if the destructuring fails, use `try_destructure_const` for fallible version.
/// Panics if the destructuring fails, use `try_destructure_mir_constant` for fallible version.
pub fn destructure_mir_constant(
self,
param_env: ty::ParamEnv<'tcx>,
Expand Down
8 changes: 3 additions & 5 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -978,11 +978,9 @@ rustc_queries! {
desc { "converting type-level constant value to mir constant value"}
}

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

Expand Down
18 changes: 7 additions & 11 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1447,7 +1447,11 @@ pub trait PrettyPrinter<'tcx>:
p!(write("{:?}", String::from_utf8_lossy(bytes)));
return Ok(self);
}
_ => {}
_ => {
p!("&");
p!(pretty_print_const_valtree(valtree, *inner_ty, print_ty));
return Ok(self);
}
},
(ty::ValTree::Branch(_), ty::Array(t, _)) if *t == u8_type => {
let bytes = valtree.try_to_raw_bytes(self.tcx(), *t).unwrap_or_else(|| {
Expand All @@ -1459,16 +1463,8 @@ pub trait PrettyPrinter<'tcx>:
}
// Aggregates, printed as array/tuple/struct/variant construction syntax.
(ty::ValTree::Branch(_), ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) => {
let Some(contents) = self.tcx().try_destructure_const(
ty::Const::from_value(self.tcx(), valtree, ty)
) else {
// Fall back to debug pretty printing for invalid constants.
p!(write("{:?}", valtree));
if print_ty {
p!(": ", print(ty));
}
return Ok(self);
};
let contents =
self.tcx().destructure_const(ty::Const::from_value(self.tcx(), valtree, ty));
let fields = contents.fields.iter().copied();
match *ty.kind() {
ty::Array(..) => {
Expand Down
77 changes: 77 additions & 0 deletions compiler/rustc_ty_utils/src/consts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use rustc_middle::ty::{self, TyCtxt};
use rustc_target::abi::VariantIdx;

use std::iter;

/// Destructures array, ADT or tuple constants into the constants
/// of their fields.
pub(crate) fn destructure_const<'tcx>(
tcx: TyCtxt<'tcx>,
const_: ty::Const<'tcx>,
) -> ty::DestructuredConst<'tcx> {
let ty::ConstKind::Value(valtree) = const_.kind() else {
bug!("cannot destructure constant {:?}", const_)
};

let branches = match valtree {
ty::ValTree::Branch(b) => b,
_ => bug!("cannot destructure constant {:?}", const_),
};

let (fields, variant) = match const_.ty().kind() {
ty::Array(inner_ty, _) | ty::Slice(inner_ty) => {
// construct the consts for the elements of the array/slice
let field_consts = branches
.iter()
.map(|b| tcx.mk_const(ty::ConstS { kind: ty::ConstKind::Value(*b), ty: *inner_ty }))
.collect::<Vec<_>>();
debug!(?field_consts);

(field_consts, None)
}
ty::Adt(def, _) if def.variants().is_empty() => bug!("unreachable"),
ty::Adt(def, substs) => {
let (variant_idx, branches) = if def.is_enum() {
let (head, rest) = branches.split_first().unwrap();
(VariantIdx::from_u32(head.unwrap_leaf().try_to_u32().unwrap()), rest)
} else {
(VariantIdx::from_u32(0), branches)
};
let fields = &def.variant(variant_idx).fields;
let mut field_consts = Vec::with_capacity(fields.len());

for (field, field_valtree) in iter::zip(fields, branches) {
let field_ty = field.ty(tcx, substs);
let field_const = tcx.mk_const(ty::ConstS {
kind: ty::ConstKind::Value(*field_valtree),
ty: field_ty,
});
field_consts.push(field_const);
}
debug!(?field_consts);

(field_consts, Some(variant_idx))
}
ty::Tuple(elem_tys) => {
let fields = iter::zip(*elem_tys, branches)
.map(|(elem_ty, elem_valtree)| {
tcx.mk_const(ty::ConstS {
kind: ty::ConstKind::Value(*elem_valtree),
ty: elem_ty,
})
})
.collect::<Vec<_>>();

(fields, None)
}
_ => bug!("cannot destructure constant {:?}", const_),
};

let fields = tcx.arena.alloc_from_iter(fields.into_iter());

ty::DestructuredConst { variant, fields }
}

pub fn provide(providers: &mut ty::query::Providers) {
*providers = ty::query::Providers { destructure_const, ..*providers };
}
2 changes: 2 additions & 0 deletions compiler/rustc_ty_utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use rustc_middle::ty::query::Providers;

mod assoc;
mod common_traits;
mod consts;
pub mod instance;
mod needs_drop;
pub mod representability;
Expand All @@ -26,6 +27,7 @@ mod ty;
pub fn provide(providers: &mut Providers) {
assoc::provide(providers);
common_traits::provide(providers);
consts::provide(providers);
needs_drop::provide(providers);
ty::provide(providers);
instance::provide(providers);
Expand Down
28 changes: 28 additions & 0 deletions src/test/ui/const-generics/issue-66451.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#![feature(adt_const_params)]
#![allow(incomplete_features)]

#[derive(Debug, PartialEq, Eq)]
struct Foo {
value: i32,
nested: &'static Bar<i32>,
}

#[derive(Debug, PartialEq, Eq)]
struct Bar<T>(T);

struct Test<const F: Foo>;

fn main() {
let x: Test<{
Foo {
value: 3,
nested: &Bar(4),
}
}> = Test;
let y: Test<{
Foo {
value: 3,
nested: &Bar(5),
}
}> = x; //~ ERROR mismatched types
}
20 changes: 20 additions & 0 deletions src/test/ui/const-generics/issue-66451.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error[E0308]: mismatched types
--> $DIR/issue-66451.rs:27:10
|
LL | let y: Test<{
| ____________-
LL | | Foo {
LL | | value: 3,
LL | | nested: &Bar(5),
LL | | }
LL | | }> = x;
| | - ^ expected `Foo { value: 3_i32, nested: &Bar::<i32>(5_i32) }`, found `Foo { value: 3_i32, nested: &Bar::<i32>(4_i32) }`
| |______|
| expected due to this
|
= note: expected struct `Test<Foo { value: 3_i32, nested: &Bar::<i32>(5_i32) }>`
found struct `Test<Foo { value: 3_i32, nested: &Bar::<i32>(4_i32) }>`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.