refactor destructure_const
This commit is contained in:
parent
7eadf834b5
commit
b29cc9860b
11 changed files with 174 additions and 159 deletions
|
|
@ -1896,7 +1896,8 @@ fn pretty_print_const_value_tcx<'tcx>(
|
|||
// Aggregates, printed as array/tuple/struct/variant construction syntax.
|
||||
//
|
||||
// NB: the `has_non_region_param` check ensures that we can use
|
||||
// the `destructure_const` query with an empty `ty::ParamEnv` without
|
||||
// the `try_destructure_mir_constant_for_user_output ` query with
|
||||
// an empty `TypingEnv::fully_monomorphized` 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)`
|
||||
|
|
|
|||
|
|
@ -402,7 +402,7 @@ tcx_lifetime! {
|
|||
rustc_middle::ty::ClauseKind,
|
||||
rustc_middle::ty::ClosureTypeInfo,
|
||||
rustc_middle::ty::Const,
|
||||
rustc_middle::ty::DestructuredConst,
|
||||
rustc_middle::ty::DestructuredAdtConst,
|
||||
rustc_middle::ty::ExistentialTraitRef,
|
||||
rustc_middle::ty::FnSig,
|
||||
rustc_middle::ty::GenericArg,
|
||||
|
|
|
|||
|
|
@ -1408,12 +1408,6 @@ rustc_queries! {
|
|||
desc { "converting type-level constant value to MIR constant value"}
|
||||
}
|
||||
|
||||
/// 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"}
|
||||
}
|
||||
|
||||
// FIXME get rid of this with valtrees
|
||||
query lit_to_const(
|
||||
key: LitToConstInput<'tcx>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::fmt;
|
||||
use std::ops::Deref;
|
||||
|
||||
use rustc_abi::{FIRST_VARIANT, VariantIdx};
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_hir::def::Namespace;
|
||||
use rustc_macros::{
|
||||
|
|
@ -189,6 +190,26 @@ impl<'tcx> Value<'tcx> {
|
|||
ValTreeKind::Leaf(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Destructures array, ADT or tuple constants into the constants
|
||||
/// of their fields.
|
||||
pub fn destructure_adt_const(&self) -> ty::DestructuredAdtConst<'tcx> {
|
||||
let fields = self.to_branch();
|
||||
|
||||
let (variant, fields) = match self.ty.kind() {
|
||||
ty::Adt(def, _) if def.variants().is_empty() => {
|
||||
bug!("unreachable")
|
||||
}
|
||||
ty::Adt(def, _) if def.is_enum() => {
|
||||
let (head, rest) = fields.split_first().unwrap();
|
||||
(VariantIdx::from_u32(head.to_leaf().to_u32()), rest)
|
||||
}
|
||||
ty::Adt(_, _) => (FIRST_VARIANT, fields),
|
||||
_ => bug!("destructure_adt_const called on non-ADT type: {:?}", self.ty),
|
||||
};
|
||||
|
||||
ty::DestructuredAdtConst { variant, fields }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::ValueConst<TyCtxt<'tcx>> for Value<'tcx> {
|
||||
|
|
|
|||
|
|
@ -2331,8 +2331,8 @@ impl<'tcx> fmt::Debug for SymbolName<'tcx> {
|
|||
|
||||
/// The constituent parts of a type level constant of kind ADT or array.
|
||||
#[derive(Copy, Clone, Debug, HashStable)]
|
||||
pub struct DestructuredConst<'tcx> {
|
||||
pub variant: Option<VariantIdx>,
|
||||
pub struct DestructuredAdtConst<'tcx> {
|
||||
pub variant: VariantIdx,
|
||||
pub fields: &'tcx [ty::Const<'tcx>],
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1919,66 +1919,65 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
|||
self.pretty_print_byte_str(bytes)?;
|
||||
return Ok(());
|
||||
}
|
||||
// Aggregates, printed as array/tuple/struct/variant construction syntax.
|
||||
(ty::ValTreeKind::Branch(_), ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) => {
|
||||
let contents = self.tcx().destructure_const(ty::Const::new_value(
|
||||
self.tcx(),
|
||||
cv.valtree,
|
||||
cv.ty,
|
||||
));
|
||||
let fields = contents.fields.iter().copied();
|
||||
(ty::ValTreeKind::Branch(fields), ty::Array(..) | ty::Tuple(..)) => {
|
||||
let fields_iter = fields.iter().copied();
|
||||
|
||||
match *cv.ty.kind() {
|
||||
ty::Array(..) => {
|
||||
write!(self, "[")?;
|
||||
self.comma_sep(fields)?;
|
||||
self.comma_sep(fields_iter)?;
|
||||
write!(self, "]")?;
|
||||
}
|
||||
ty::Tuple(..) => {
|
||||
write!(self, "(")?;
|
||||
self.comma_sep(fields)?;
|
||||
if contents.fields.len() == 1 {
|
||||
self.comma_sep(fields_iter)?;
|
||||
if fields.len() == 1 {
|
||||
write!(self, ",")?;
|
||||
}
|
||||
write!(self, ")")?;
|
||||
}
|
||||
ty::Adt(def, _) if def.variants().is_empty() => {
|
||||
self.typed_value(
|
||||
|this| {
|
||||
write!(this, "unreachable()")?;
|
||||
Ok(())
|
||||
},
|
||||
|this| this.print_type(cv.ty),
|
||||
": ",
|
||||
)?;
|
||||
}
|
||||
ty::Adt(def, args) => {
|
||||
let variant_idx =
|
||||
contents.variant.expect("destructed const of adt without variant idx");
|
||||
let variant_def = &def.variant(variant_idx);
|
||||
self.pretty_print_value_path(variant_def.def_id, args)?;
|
||||
match variant_def.ctor_kind() {
|
||||
Some(CtorKind::Const) => {}
|
||||
Some(CtorKind::Fn) => {
|
||||
write!(self, "(")?;
|
||||
self.comma_sep(fields)?;
|
||||
write!(self, ")")?;
|
||||
}
|
||||
None => {
|
||||
write!(self, " {{ ")?;
|
||||
let mut first = true;
|
||||
for (field_def, field) in iter::zip(&variant_def.fields, fields) {
|
||||
if !first {
|
||||
write!(self, ", ")?;
|
||||
}
|
||||
write!(self, "{}: ", field_def.name)?;
|
||||
field.print(self)?;
|
||||
first = false;
|
||||
_ => unreachable!(),
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
(ty::ValTreeKind::Branch(_), ty::Adt(def, args)) => {
|
||||
let contents = cv.destructure_adt_const();
|
||||
let fields = contents.fields.iter().copied();
|
||||
|
||||
if def.variants().is_empty() {
|
||||
self.typed_value(
|
||||
|this| {
|
||||
write!(this, "unreachable()")?;
|
||||
Ok(())
|
||||
},
|
||||
|this| this.print_type(cv.ty),
|
||||
": ",
|
||||
)?;
|
||||
} else {
|
||||
let variant_idx = contents.variant;
|
||||
let variant_def = &def.variant(variant_idx);
|
||||
self.pretty_print_value_path(variant_def.def_id, args)?;
|
||||
match variant_def.ctor_kind() {
|
||||
Some(CtorKind::Const) => {}
|
||||
Some(CtorKind::Fn) => {
|
||||
write!(self, "(")?;
|
||||
self.comma_sep(fields)?;
|
||||
write!(self, ")")?;
|
||||
}
|
||||
None => {
|
||||
write!(self, " {{ ")?;
|
||||
let mut first = true;
|
||||
for (field_def, field) in iter::zip(&variant_def.fields, fields) {
|
||||
if !first {
|
||||
write!(self, ", ")?;
|
||||
}
|
||||
write!(self, " }}")?;
|
||||
write!(self, "{}: ", field_def.name)?;
|
||||
field.print(self)?;
|
||||
first = false;
|
||||
}
|
||||
write!(self, " }}")?;
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -755,9 +755,8 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> {
|
|||
dereferenced_const.print(self)?;
|
||||
}
|
||||
|
||||
ty::Array(..) | ty::Tuple(..) | ty::Adt(..) | ty::Slice(_) => {
|
||||
let contents = self.tcx.destructure_const(ct);
|
||||
let fields = contents.fields.iter().copied();
|
||||
ty::Array(..) | ty::Tuple(..) | ty::Slice(_) => {
|
||||
let fields = cv.to_branch().iter().copied();
|
||||
|
||||
let print_field_list = |this: &mut Self| {
|
||||
for field in fields.clone() {
|
||||
|
|
@ -776,45 +775,53 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> {
|
|||
self.push("T");
|
||||
print_field_list(self)?;
|
||||
}
|
||||
ty::Adt(def, args) => {
|
||||
let variant_idx =
|
||||
contents.variant.expect("destructed const of adt without variant idx");
|
||||
let variant_def = &def.variant(variant_idx);
|
||||
|
||||
self.push("V");
|
||||
self.print_def_path(variant_def.def_id, args)?;
|
||||
|
||||
match variant_def.ctor_kind() {
|
||||
Some(CtorKind::Const) => {
|
||||
self.push("U");
|
||||
}
|
||||
Some(CtorKind::Fn) => {
|
||||
self.push("T");
|
||||
print_field_list(self)?;
|
||||
}
|
||||
None => {
|
||||
self.push("S");
|
||||
for (field_def, field) in iter::zip(&variant_def.fields, fields) {
|
||||
// HACK(eddyb) this mimics `print_path_with_simple`,
|
||||
// instead of simply using `field_def.ident`,
|
||||
// just to be able to handle disambiguators.
|
||||
let disambiguated_field =
|
||||
self.tcx.def_key(field_def.did).disambiguated_data;
|
||||
let field_name = disambiguated_field.data.get_opt_name();
|
||||
self.push_disambiguator(
|
||||
disambiguated_field.disambiguator as u64,
|
||||
);
|
||||
self.push_ident(field_name.unwrap().as_str());
|
||||
|
||||
field.print(self)?;
|
||||
}
|
||||
self.push("E");
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
ty::Adt(def, args) => {
|
||||
let contents = cv.destructure_adt_const();
|
||||
let fields = contents.fields.iter().copied();
|
||||
|
||||
let print_field_list = |this: &mut Self| {
|
||||
for field in fields.clone() {
|
||||
field.print(this)?;
|
||||
}
|
||||
this.push("E");
|
||||
Ok(())
|
||||
};
|
||||
|
||||
let variant_idx = contents.variant;
|
||||
let variant_def = &def.variant(variant_idx);
|
||||
|
||||
self.push("V");
|
||||
self.print_def_path(variant_def.def_id, args)?;
|
||||
|
||||
match variant_def.ctor_kind() {
|
||||
Some(CtorKind::Const) => {
|
||||
self.push("U");
|
||||
}
|
||||
Some(CtorKind::Fn) => {
|
||||
self.push("T");
|
||||
print_field_list(self)?;
|
||||
}
|
||||
None => {
|
||||
self.push("S");
|
||||
for (field_def, field) in iter::zip(&variant_def.fields, fields) {
|
||||
// HACK(eddyb) this mimics `print_path_with_simple`,
|
||||
// instead of simply using `field_def.ident`,
|
||||
// just to be able to handle disambiguators.
|
||||
let disambiguated_field =
|
||||
self.tcx.def_key(field_def.did).disambiguated_data;
|
||||
let field_name = disambiguated_field.data.get_opt_name();
|
||||
self.push_disambiguator(disambiguated_field.disambiguator as u64);
|
||||
self.push_ident(field_name.unwrap().as_str());
|
||||
|
||||
field.print(self)?;
|
||||
}
|
||||
self.push("E");
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct_ty, ct);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
use std::iter;
|
||||
|
||||
use rustc_abi::{FIRST_VARIANT, VariantIdx};
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
|
|
@ -10,63 +7,12 @@ use rustc_middle::thir::visit;
|
|||
use rustc_middle::thir::visit::Visitor;
|
||||
use rustc_middle::ty::abstract_const::CastKind;
|
||||
use rustc_middle::ty::{self, Expr, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::{bug, mir, thir};
|
||||
use rustc_middle::{mir, thir};
|
||||
use rustc_span::Span;
|
||||
use tracing::{debug, instrument};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::errors::{GenericConstantTooComplex, GenericConstantTooComplexSub};
|
||||
|
||||
/// Destructures array, ADT or tuple constants into the constants
|
||||
/// of their fields.
|
||||
fn destructure_const<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
const_: ty::Const<'tcx>,
|
||||
) -> ty::DestructuredConst<'tcx> {
|
||||
let ty::ConstKind::Value(cv) = const_.kind() else {
|
||||
bug!("cannot destructure constant {:?}", const_)
|
||||
};
|
||||
let branches = cv.to_branch();
|
||||
|
||||
let (fields, variant) = match cv.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| ty::Const::new_value(tcx, b.to_value().valtree, *inner_ty))
|
||||
.collect::<Vec<_>>();
|
||||
debug!(?field_consts);
|
||||
|
||||
(field_consts, None)
|
||||
}
|
||||
ty::Adt(def, _) if def.variants().is_empty() => bug!("unreachable"),
|
||||
ty::Adt(def, _) => {
|
||||
let (variant_idx, field_consts) = if def.is_enum() {
|
||||
let (head, rest) = branches.split_first().unwrap();
|
||||
(VariantIdx::from_u32(head.to_leaf().to_u32()), rest)
|
||||
} else {
|
||||
(FIRST_VARIANT, branches)
|
||||
};
|
||||
debug!(?field_consts);
|
||||
|
||||
(field_consts.to_vec(), Some(variant_idx))
|
||||
}
|
||||
ty::Tuple(elem_tys) => {
|
||||
let fields = iter::zip(*elem_tys, branches)
|
||||
.map(|(elem_ty, elem_valtree)| {
|
||||
ty::Const::new_value(tcx, elem_valtree.to_value().valtree, elem_ty)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
(fields, None)
|
||||
}
|
||||
_ => bug!("cannot destructure constant {:?}", const_),
|
||||
};
|
||||
|
||||
let fields = tcx.arena.alloc_from_iter(fields);
|
||||
|
||||
ty::DestructuredConst { variant, fields }
|
||||
}
|
||||
|
||||
/// We do not allow all binary operations in abstract consts, so filter disallowed ones.
|
||||
fn check_binop(op: mir::BinOp) -> bool {
|
||||
use mir::BinOp::*;
|
||||
|
|
@ -432,5 +378,5 @@ fn thir_abstract_const<'tcx>(
|
|||
}
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
*providers = Providers { destructure_const, thir_abstract_const, ..*providers };
|
||||
*providers = Providers { thir_abstract_const, ..*providers };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
//@ known-bug: #131052
|
||||
#![feature(adt_const_params)]
|
||||
|
||||
struct ConstBytes<const T: &'static [*mut u8; 3]>;
|
||||
|
||||
pub fn main() {
|
||||
let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">;
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
//! Regression test for <https://github.com/rust-lang/rust/issues/131052>
|
||||
|
||||
#![feature(adt_const_params)]
|
||||
|
||||
struct ConstBytes<const T: &'static [*mut u8; 3]>;
|
||||
//~^ ERROR `&'static [*mut u8; 3]` can't be used as a const parameter type
|
||||
|
||||
pub fn main() {
|
||||
let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">;
|
||||
//~^ ERROR mismatched types
|
||||
//~| ERROR mismatched types
|
||||
//~| ERROR mismatched types
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
error[E0741]: `&'static [*mut u8; 3]` can't be used as a const parameter type
|
||||
--> $DIR/mismatch-raw-ptr-in-adt.rs:5:28
|
||||
|
|
||||
LL | struct ConstBytes<const T: &'static [*mut u8; 3]>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `*mut u8` must implement `ConstParamTy_`, but it does not
|
||||
= note: `[*mut u8; 3]` must implement `ConstParamTy_`, but it does not
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/mismatch-raw-ptr-in-adt.rs:9:33
|
||||
|
|
||||
LL | let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">;
|
||||
| ------------------ ^^^^^^^^^^^^^^^^^^^^ expected `&[65, 65, 65]`, found `&[66, 66, 66]`
|
||||
| |
|
||||
| expected due to this
|
||||
|
|
||||
= note: expected struct `ConstBytes<&[65, 65, 65]>`
|
||||
found struct `ConstBytes<&[66, 66, 66]>`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/mismatch-raw-ptr-in-adt.rs:9:46
|
||||
|
|
||||
LL | let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">;
|
||||
| ^^^^^^ expected `&[*mut u8; 3]`, found `&[u8; 3]`
|
||||
|
|
||||
= note: expected reference `&'static [*mut u8; 3]`
|
||||
found reference `&'static [u8; 3]`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/mismatch-raw-ptr-in-adt.rs:9:23
|
||||
|
|
||||
LL | let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">;
|
||||
| ^^^^^^ expected `&[*mut u8; 3]`, found `&[u8; 3]`
|
||||
|
|
||||
= note: expected reference `&'static [*mut u8; 3]`
|
||||
found reference `&'static [u8; 3]`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0308, E0741.
|
||||
For more information about an error, try `rustc --explain E0308`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue