Rollup merge of #151142 - SpriteOvO:type-info-adt, r=oli-obk
Support ADT types in type info reflection Tracking issue: rust-lang/rust#146922 `#![feature(type_info)]` This PR supports ADT types for feature `type_info` reflection. (It's still a draft PR, with implementation in progress) Note that this PR does not take SemVer into consideration (I left a FIXME comment). As discussed earlier ([comment](https://github.com/rust-lang/rust/pull/146923#discussion_r2372249477)), this requires further discussion. However, I hope we could get an initial implementation to land first, so we can start playing with it. ### Progress / Checklist - [x] Struct support. - [x] Enum - [x] Union - [x] Generics - [ ] ~Methods~ Implemented and to be implemented in other PRs - [ ] ~Traits~ Implemented and to be implemented in other PRs - [x] Rebasing PR to `main` branch ~~(It's currently based on PR rust-lang/rust#151123, so here's an extra commit)~~ - [x] Cleanup and Rebase. - [x] Fix field info for references. (see [comment](https://github.com/rust-lang/rust/pull/151142#discussion_r2777920512)) r? @oli-obk
This commit is contained in:
commit
c87a89ed14
15 changed files with 678 additions and 576 deletions
|
|
@ -1,4 +1,8 @@
|
|||
use rustc_abi::FieldIdx;
|
||||
mod adt;
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use rustc_abi::{FieldIdx, VariantIdx};
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_middle::span_bug;
|
||||
|
|
@ -8,11 +12,58 @@ use rustc_span::{Symbol, sym};
|
|||
|
||||
use crate::const_eval::CompileTimeMachine;
|
||||
use crate::interpret::{
|
||||
CtfeProvenance, Immediate, InterpCx, InterpResult, MPlaceTy, MemoryKind, Scalar, Writeable,
|
||||
interp_ok,
|
||||
CtfeProvenance, Immediate, InterpCx, InterpResult, MPlaceTy, MemoryKind, Projectable, Scalar,
|
||||
Writeable, interp_ok,
|
||||
};
|
||||
|
||||
impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
|
||||
/// Equivalent to `project_downcast`, but identifies the variant by name instead of index.
|
||||
fn downcast<'a>(
|
||||
&self,
|
||||
place: &(impl Writeable<'tcx, CtfeProvenance> + 'a),
|
||||
name: Symbol,
|
||||
) -> InterpResult<'tcx, (VariantIdx, impl Writeable<'tcx, CtfeProvenance> + 'a)> {
|
||||
let variants = place.layout().ty.ty_adt_def().unwrap().variants();
|
||||
let variant_idx = variants
|
||||
.iter_enumerated()
|
||||
.find(|(_idx, var)| var.name == name)
|
||||
.unwrap_or_else(|| panic!("got {name} but expected one of {variants:#?}"))
|
||||
.0;
|
||||
|
||||
interp_ok((variant_idx, self.project_downcast(place, variant_idx)?))
|
||||
}
|
||||
|
||||
// A general method to write an array to a static slice place.
|
||||
fn allocate_fill_and_write_slice_ptr(
|
||||
&mut self,
|
||||
slice_place: impl Writeable<'tcx, CtfeProvenance>,
|
||||
len: u64,
|
||||
writer: impl Fn(&mut Self, /* index */ u64, MPlaceTy<'tcx>) -> InterpResult<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
// Array element type
|
||||
let field_ty = slice_place
|
||||
.layout()
|
||||
.ty
|
||||
.builtin_deref(false)
|
||||
.unwrap()
|
||||
.sequence_element_type(self.tcx.tcx);
|
||||
|
||||
// Allocate an array
|
||||
let array_layout = self.layout_of(Ty::new_array(self.tcx.tcx, field_ty, len))?;
|
||||
let array_place = self.allocate(array_layout, MemoryKind::Stack)?;
|
||||
|
||||
// Fill the array fields
|
||||
let mut field_places = self.project_array_fields(&array_place)?;
|
||||
while let Some((i, place)) = field_places.next(self)? {
|
||||
writer(self, i, place)?;
|
||||
}
|
||||
|
||||
// Write the slice pointing to the array
|
||||
let array_place = array_place.map_provenance(CtfeProvenance::as_immutable);
|
||||
let ptr = Immediate::new_slice(array_place.ptr(), len, self);
|
||||
self.write_immediate(ptr, &slice_place)
|
||||
}
|
||||
|
||||
/// Writes a `core::mem::type_info::TypeInfo` for a given type, `ty` to the given place.
|
||||
pub(crate) fn write_type_info(
|
||||
&mut self,
|
||||
|
|
@ -26,22 +77,13 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
|
|||
// Fill all fields of the `TypeInfo` struct.
|
||||
for (idx, field) in ty_struct.fields.iter_enumerated() {
|
||||
let field_dest = self.project_field(dest, idx)?;
|
||||
let downcast = |name: Symbol| {
|
||||
let variants = field_dest.layout().ty.ty_adt_def().unwrap().variants();
|
||||
let variant_id = variants
|
||||
.iter_enumerated()
|
||||
.find(|(_idx, var)| var.name == name)
|
||||
.unwrap_or_else(|| panic!("got {name} but expected one of {variants:#?}"))
|
||||
.0;
|
||||
|
||||
interp_ok((variant_id, self.project_downcast(&field_dest, variant_id)?))
|
||||
};
|
||||
let ptr_bit_width = || self.tcx.data_layout.pointer_size().bits();
|
||||
match field.name {
|
||||
sym::kind => {
|
||||
let variant_index = match ty.kind() {
|
||||
ty::Tuple(fields) => {
|
||||
let (variant, variant_place) = downcast(sym::Tuple)?;
|
||||
let (variant, variant_place) =
|
||||
self.downcast(&field_dest, sym::Tuple)?;
|
||||
// project to the single tuple variant field of `type_info::Tuple` struct type
|
||||
let tuple_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
|
||||
assert_eq!(
|
||||
|
|
@ -55,11 +97,12 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
|
|||
.fields
|
||||
.len()
|
||||
);
|
||||
self.write_tuple_fields(tuple_place, fields, ty)?;
|
||||
self.write_tuple_type_info(tuple_place, fields, ty)?;
|
||||
variant
|
||||
}
|
||||
ty::Array(ty, len) => {
|
||||
let (variant, variant_place) = downcast(sym::Array)?;
|
||||
let (variant, variant_place) =
|
||||
self.downcast(&field_dest, sym::Array)?;
|
||||
let array_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
|
||||
|
||||
self.write_array_type_info(array_place, *ty, *len)?;
|
||||
|
|
@ -67,23 +110,29 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
|
|||
variant
|
||||
}
|
||||
ty::Slice(ty) => {
|
||||
let (variant, variant_place) = downcast(sym::Slice)?;
|
||||
let (variant, variant_place) =
|
||||
self.downcast(&field_dest, sym::Slice)?;
|
||||
let slice_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
|
||||
|
||||
self.write_slice_type_info(slice_place, *ty)?;
|
||||
|
||||
variant
|
||||
}
|
||||
ty::Adt(adt_def, generics) => {
|
||||
self.write_adt_type_info(&field_dest, (ty, *adt_def), generics)?
|
||||
}
|
||||
ty::Bool => {
|
||||
let (variant, _variant_place) = downcast(sym::Bool)?;
|
||||
let (variant, _variant_place) =
|
||||
self.downcast(&field_dest, sym::Bool)?;
|
||||
variant
|
||||
}
|
||||
ty::Char => {
|
||||
let (variant, _variant_place) = downcast(sym::Char)?;
|
||||
let (variant, _variant_place) =
|
||||
self.downcast(&field_dest, sym::Char)?;
|
||||
variant
|
||||
}
|
||||
ty::Int(int_ty) => {
|
||||
let (variant, variant_place) = downcast(sym::Int)?;
|
||||
let (variant, variant_place) = self.downcast(&field_dest, sym::Int)?;
|
||||
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
|
||||
self.write_int_type_info(
|
||||
place,
|
||||
|
|
@ -93,7 +142,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
|
|||
variant
|
||||
}
|
||||
ty::Uint(uint_ty) => {
|
||||
let (variant, variant_place) = downcast(sym::Int)?;
|
||||
let (variant, variant_place) = self.downcast(&field_dest, sym::Int)?;
|
||||
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
|
||||
self.write_int_type_info(
|
||||
place,
|
||||
|
|
@ -103,17 +152,19 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
|
|||
variant
|
||||
}
|
||||
ty::Float(float_ty) => {
|
||||
let (variant, variant_place) = downcast(sym::Float)?;
|
||||
let (variant, variant_place) =
|
||||
self.downcast(&field_dest, sym::Float)?;
|
||||
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
|
||||
self.write_float_type_info(place, float_ty.bit_width())?;
|
||||
variant
|
||||
}
|
||||
ty::Str => {
|
||||
let (variant, _variant_place) = downcast(sym::Str)?;
|
||||
let (variant, _variant_place) = self.downcast(&field_dest, sym::Str)?;
|
||||
variant
|
||||
}
|
||||
ty::Ref(_, ty, mutability) => {
|
||||
let (variant, variant_place) = downcast(sym::Reference)?;
|
||||
let (variant, variant_place) =
|
||||
self.downcast(&field_dest, sym::Reference)?;
|
||||
let reference_place =
|
||||
self.project_field(&variant_place, FieldIdx::ZERO)?;
|
||||
self.write_reference_type_info(reference_place, *ty, *mutability)?;
|
||||
|
|
@ -121,7 +172,8 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
|
|||
variant
|
||||
}
|
||||
ty::RawPtr(ty, mutability) => {
|
||||
let (variant, variant_place) = downcast(sym::Pointer)?;
|
||||
let (variant, variant_place) =
|
||||
self.downcast(&field_dest, sym::Pointer)?;
|
||||
let pointer_place =
|
||||
self.project_field(&variant_place, FieldIdx::ZERO)?;
|
||||
|
||||
|
|
@ -130,13 +182,13 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
|
|||
variant
|
||||
}
|
||||
ty::Dynamic(predicates, region) => {
|
||||
let (variant, variant_place) = downcast(sym::DynTrait)?;
|
||||
let (variant, variant_place) =
|
||||
self.downcast(&field_dest, sym::DynTrait)?;
|
||||
let dyn_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
|
||||
self.write_dyn_trait_type_info(dyn_place, *predicates, *region)?;
|
||||
variant
|
||||
}
|
||||
ty::Adt(_, _)
|
||||
| ty::Foreign(_)
|
||||
ty::Foreign(_)
|
||||
| ty::Pat(_, _)
|
||||
| ty::FnDef(..)
|
||||
| ty::FnPtr(..)
|
||||
|
|
@ -151,14 +203,14 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
|
|||
| ty::Bound(..)
|
||||
| ty::Placeholder(_)
|
||||
| ty::Infer(..)
|
||||
| ty::Error(_) => downcast(sym::Other)?.0,
|
||||
| ty::Error(_) => self.downcast(&field_dest, sym::Other)?.0,
|
||||
};
|
||||
self.write_discriminant(variant_index, &field_dest)?
|
||||
}
|
||||
sym::size => {
|
||||
let layout = self.layout_of(ty)?;
|
||||
let variant_index = if layout.is_sized() {
|
||||
let (variant, variant_place) = downcast(sym::Some)?;
|
||||
let (variant, variant_place) = self.downcast(&field_dest, sym::Some)?;
|
||||
let size_field_place =
|
||||
self.project_field(&variant_place, FieldIdx::ZERO)?;
|
||||
self.write_scalar(
|
||||
|
|
@ -168,7 +220,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
|
|||
)?;
|
||||
variant
|
||||
} else {
|
||||
downcast(sym::None)?.0
|
||||
self.downcast(&field_dest, sym::None)?.0
|
||||
};
|
||||
self.write_discriminant(variant_index, &field_dest)?;
|
||||
}
|
||||
|
|
@ -179,46 +231,12 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
|
|||
interp_ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn write_tuple_fields(
|
||||
&mut self,
|
||||
tuple_place: impl Writeable<'tcx, CtfeProvenance>,
|
||||
fields: &[Ty<'tcx>],
|
||||
tuple_ty: Ty<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
// project into the `type_info::Tuple::fields` field
|
||||
let fields_slice_place = self.project_field(&tuple_place, FieldIdx::ZERO)?;
|
||||
// get the `type_info::Field` type from `fields: &[Field]`
|
||||
let field_type = fields_slice_place
|
||||
.layout()
|
||||
.ty
|
||||
.builtin_deref(false)
|
||||
.unwrap()
|
||||
.sequence_element_type(self.tcx.tcx);
|
||||
// Create an array with as many elements as the number of fields in the inspected tuple
|
||||
let fields_layout =
|
||||
self.layout_of(Ty::new_array(self.tcx.tcx, field_type, fields.len() as u64))?;
|
||||
let fields_place = self.allocate(fields_layout, MemoryKind::Stack)?;
|
||||
let mut fields_places = self.project_array_fields(&fields_place)?;
|
||||
|
||||
let tuple_layout = self.layout_of(tuple_ty)?;
|
||||
|
||||
while let Some((i, place)) = fields_places.next(self)? {
|
||||
let field_ty = fields[i as usize];
|
||||
self.write_field(field_ty, place, tuple_layout, i)?;
|
||||
}
|
||||
|
||||
let fields_place = fields_place.map_provenance(CtfeProvenance::as_immutable);
|
||||
|
||||
let ptr = Immediate::new_slice(fields_place.ptr(), fields.len() as u64, self);
|
||||
|
||||
self.write_immediate(ptr, &fields_slice_place)
|
||||
}
|
||||
|
||||
fn write_field(
|
||||
&mut self,
|
||||
field_ty: Ty<'tcx>,
|
||||
place: MPlaceTy<'tcx>,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
name: Option<Symbol>,
|
||||
idx: u64,
|
||||
) -> InterpResult<'tcx> {
|
||||
for (field_idx, field_ty_field) in
|
||||
|
|
@ -226,7 +244,19 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
|
|||
{
|
||||
let field_place = self.project_field(&place, field_idx)?;
|
||||
match field_ty_field.name {
|
||||
sym::ty => self.write_type_id(field_ty, &field_place)?,
|
||||
sym::name => {
|
||||
let name = match name.as_ref() {
|
||||
Some(name) => Cow::Borrowed(name.as_str()),
|
||||
None => Cow::Owned(idx.to_string()), // For tuples
|
||||
};
|
||||
let name_place = self.allocate_str_dedup(&name)?;
|
||||
let ptr = self.mplace_to_ref(&name_place)?;
|
||||
self.write_immediate(*ptr, &field_place)?
|
||||
}
|
||||
sym::ty => {
|
||||
let field_ty = self.tcx.erase_and_anonymize_regions(field_ty);
|
||||
self.write_type_id(field_ty, &field_place)?
|
||||
}
|
||||
sym::offset => {
|
||||
let offset = layout.fields.offset(idx as usize);
|
||||
self.write_scalar(
|
||||
|
|
@ -242,6 +272,24 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
|
|||
interp_ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn write_tuple_type_info(
|
||||
&mut self,
|
||||
tuple_place: impl Writeable<'tcx, CtfeProvenance>,
|
||||
fields: &[Ty<'tcx>],
|
||||
tuple_ty: Ty<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let tuple_layout = self.layout_of(tuple_ty)?;
|
||||
let fields_slice_place = self.project_field(&tuple_place, FieldIdx::ZERO)?;
|
||||
self.allocate_fill_and_write_slice_ptr(
|
||||
fields_slice_place,
|
||||
fields.len() as u64,
|
||||
|this, i, place| {
|
||||
let field_ty = fields[i as usize];
|
||||
this.write_field(field_ty, place, tuple_layout, None, i)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn write_array_type_info(
|
||||
&mut self,
|
||||
place: impl Writeable<'tcx, CtfeProvenance>,
|
||||
|
|
|
|||
276
compiler/rustc_const_eval/src/const_eval/type_info/adt.rs
Normal file
276
compiler/rustc_const_eval/src/const_eval/type_info/adt.rs
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
use rustc_abi::{FieldIdx, VariantIdx};
|
||||
use rustc_middle::ty::layout::TyAndLayout;
|
||||
use rustc_middle::ty::{
|
||||
AdtDef, AdtKind, Const, ConstKind, GenericArgKind, GenericArgs, Region, Ty, VariantDef,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::sym;
|
||||
|
||||
use crate::const_eval::CompileTimeMachine;
|
||||
use crate::interpret::{
|
||||
CtfeProvenance, InterpCx, InterpResult, MPlaceTy, Projectable, Scalar, Writeable, interp_ok,
|
||||
};
|
||||
|
||||
impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
|
||||
// FIXME(type_info): No semver considerations for now
|
||||
pub(crate) fn write_adt_type_info(
|
||||
&mut self,
|
||||
place: &impl Writeable<'tcx, CtfeProvenance>,
|
||||
adt: (Ty<'tcx>, AdtDef<'tcx>),
|
||||
generics: &'tcx GenericArgs<'tcx>,
|
||||
) -> InterpResult<'tcx, VariantIdx> {
|
||||
let (adt_ty, adt_def) = adt;
|
||||
let variant_idx = match adt_def.adt_kind() {
|
||||
AdtKind::Struct => {
|
||||
let (variant, variant_place) = self.downcast(place, sym::Struct)?;
|
||||
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
|
||||
self.write_struct_type_info(
|
||||
place,
|
||||
(adt_ty, adt_def.variant(VariantIdx::ZERO)),
|
||||
generics,
|
||||
)?;
|
||||
variant
|
||||
}
|
||||
AdtKind::Union => {
|
||||
let (variant, variant_place) = self.downcast(place, sym::Union)?;
|
||||
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
|
||||
self.write_union_type_info(
|
||||
place,
|
||||
(adt_ty, adt_def.variant(VariantIdx::ZERO)),
|
||||
generics,
|
||||
)?;
|
||||
variant
|
||||
}
|
||||
AdtKind::Enum => {
|
||||
let (variant, variant_place) = self.downcast(place, sym::Enum)?;
|
||||
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
|
||||
self.write_enum_type_info(place, adt, generics)?;
|
||||
variant
|
||||
}
|
||||
};
|
||||
interp_ok(variant_idx)
|
||||
}
|
||||
|
||||
pub(crate) fn write_struct_type_info(
|
||||
&mut self,
|
||||
place: impl Writeable<'tcx, CtfeProvenance>,
|
||||
struct_: (Ty<'tcx>, &'tcx VariantDef),
|
||||
generics: &'tcx GenericArgs<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let (struct_ty, struct_def) = struct_;
|
||||
let struct_layout = self.layout_of(struct_ty)?;
|
||||
|
||||
for (field_idx, field) in
|
||||
place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
|
||||
{
|
||||
let field_place = self.project_field(&place, field_idx)?;
|
||||
|
||||
match field.name {
|
||||
sym::generics => self.write_generics(field_place, generics)?,
|
||||
sym::fields => {
|
||||
self.write_variant_fields(field_place, struct_def, struct_layout, generics)?
|
||||
}
|
||||
sym::non_exhaustive => {
|
||||
let is_non_exhaustive = struct_def.is_field_list_non_exhaustive();
|
||||
self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)?
|
||||
}
|
||||
other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
|
||||
}
|
||||
}
|
||||
|
||||
interp_ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn write_union_type_info(
|
||||
&mut self,
|
||||
place: impl Writeable<'tcx, CtfeProvenance>,
|
||||
union_: (Ty<'tcx>, &'tcx VariantDef),
|
||||
generics: &'tcx GenericArgs<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let (union_ty, union_def) = union_;
|
||||
let union_layout = self.layout_of(union_ty)?;
|
||||
|
||||
for (field_idx, field) in
|
||||
place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
|
||||
{
|
||||
let field_place = self.project_field(&place, field_idx)?;
|
||||
|
||||
match field.name {
|
||||
sym::generics => self.write_generics(field_place, generics)?,
|
||||
sym::fields => {
|
||||
self.write_variant_fields(field_place, union_def, union_layout, generics)?
|
||||
}
|
||||
sym::non_exhaustive => {
|
||||
let is_non_exhaustive = union_def.is_field_list_non_exhaustive();
|
||||
self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)?
|
||||
}
|
||||
other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
|
||||
}
|
||||
}
|
||||
|
||||
interp_ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn write_enum_type_info(
|
||||
&mut self,
|
||||
place: impl Writeable<'tcx, CtfeProvenance>,
|
||||
enum_: (Ty<'tcx>, AdtDef<'tcx>),
|
||||
generics: &'tcx GenericArgs<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let (enum_ty, enum_def) = enum_;
|
||||
let enum_layout = self.layout_of(enum_ty)?;
|
||||
|
||||
for (field_idx, field) in
|
||||
place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
|
||||
{
|
||||
let field_place = self.project_field(&place, field_idx)?;
|
||||
|
||||
match field.name {
|
||||
sym::generics => self.write_generics(field_place, generics)?,
|
||||
sym::variants => {
|
||||
self.allocate_fill_and_write_slice_ptr(
|
||||
field_place,
|
||||
enum_def.variants().len() as u64,
|
||||
|this, i, place| {
|
||||
let variant_idx = VariantIdx::from_usize(i as usize);
|
||||
let variant_def = &enum_def.variants()[variant_idx];
|
||||
let variant_layout = enum_layout.for_variant(this, variant_idx);
|
||||
this.write_enum_variant(place, (variant_layout, &variant_def), generics)
|
||||
},
|
||||
)?;
|
||||
}
|
||||
sym::non_exhaustive => {
|
||||
let is_non_exhaustive = enum_def.is_variant_list_non_exhaustive();
|
||||
self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)?
|
||||
}
|
||||
other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
|
||||
}
|
||||
}
|
||||
|
||||
interp_ok(())
|
||||
}
|
||||
|
||||
fn write_enum_variant(
|
||||
&mut self,
|
||||
place: impl Writeable<'tcx, CtfeProvenance>,
|
||||
variant: (TyAndLayout<'tcx>, &'tcx VariantDef),
|
||||
generics: &'tcx GenericArgs<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let (variant_layout, variant_def) = variant;
|
||||
|
||||
for (field_idx, field_def) in
|
||||
place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
|
||||
{
|
||||
let field_place = self.project_field(&place, field_idx)?;
|
||||
match field_def.name {
|
||||
sym::name => {
|
||||
let name_place = self.allocate_str_dedup(variant_def.name.as_str())?;
|
||||
let ptr = self.mplace_to_ref(&name_place)?;
|
||||
self.write_immediate(*ptr, &field_place)?
|
||||
}
|
||||
sym::fields => {
|
||||
self.write_variant_fields(field_place, &variant_def, variant_layout, generics)?
|
||||
}
|
||||
sym::non_exhaustive => {
|
||||
let is_non_exhaustive = variant_def.is_field_list_non_exhaustive();
|
||||
self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)?
|
||||
}
|
||||
other => span_bug!(self.tcx.def_span(field_def.did), "unimplemented field {other}"),
|
||||
}
|
||||
}
|
||||
interp_ok(())
|
||||
}
|
||||
|
||||
// Write fields for struct, enum variants
|
||||
fn write_variant_fields(
|
||||
&mut self,
|
||||
place: impl Writeable<'tcx, CtfeProvenance>,
|
||||
variant_def: &'tcx VariantDef,
|
||||
variant_layout: TyAndLayout<'tcx>,
|
||||
generics: &'tcx GenericArgs<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
self.allocate_fill_and_write_slice_ptr(
|
||||
place,
|
||||
variant_def.fields.len() as u64,
|
||||
|this, i, place| {
|
||||
let field_def = &variant_def.fields[FieldIdx::from_usize(i as usize)];
|
||||
let field_ty = field_def.ty(*this.tcx, generics);
|
||||
this.write_field(field_ty, place, variant_layout, Some(field_def.name), i)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn write_generics(
|
||||
&mut self,
|
||||
place: impl Writeable<'tcx, CtfeProvenance>,
|
||||
generics: &'tcx GenericArgs<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
self.allocate_fill_and_write_slice_ptr(place, generics.len() as u64, |this, i, place| {
|
||||
match generics[i as usize].kind() {
|
||||
GenericArgKind::Lifetime(region) => this.write_generic_lifetime(region, place),
|
||||
GenericArgKind::Type(ty) => this.write_generic_type(ty, place),
|
||||
GenericArgKind::Const(c) => this.write_generic_const(c, place),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn write_generic_lifetime(
|
||||
&mut self,
|
||||
_region: Region<'tcx>,
|
||||
place: MPlaceTy<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let (variant_idx, _) = self.downcast(&place, sym::Lifetime)?;
|
||||
self.write_discriminant(variant_idx, &place)?;
|
||||
interp_ok(())
|
||||
}
|
||||
|
||||
fn write_generic_type(&mut self, ty: Ty<'tcx>, place: MPlaceTy<'tcx>) -> InterpResult<'tcx> {
|
||||
let (variant_idx, variant_place) = self.downcast(&place, sym::Type)?;
|
||||
let generic_type_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
|
||||
|
||||
for (field_idx, field_def) in generic_type_place
|
||||
.layout()
|
||||
.ty
|
||||
.ty_adt_def()
|
||||
.unwrap()
|
||||
.non_enum_variant()
|
||||
.fields
|
||||
.iter_enumerated()
|
||||
{
|
||||
let field_place = self.project_field(&generic_type_place, field_idx)?;
|
||||
match field_def.name {
|
||||
sym::ty => self.write_type_id(ty, &field_place)?,
|
||||
other => span_bug!(self.tcx.def_span(field_def.did), "unimplemented field {other}"),
|
||||
}
|
||||
}
|
||||
|
||||
self.write_discriminant(variant_idx, &place)?;
|
||||
interp_ok(())
|
||||
}
|
||||
|
||||
fn write_generic_const(&mut self, c: Const<'tcx>, place: MPlaceTy<'tcx>) -> InterpResult<'tcx> {
|
||||
let ConstKind::Value(c) = c.kind() else { bug!("expected a computed const, got {c:?}") };
|
||||
|
||||
let (variant_idx, variant_place) = self.downcast(&place, sym::Const)?;
|
||||
let const_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
|
||||
|
||||
for (field_idx, field_def) in const_place
|
||||
.layout()
|
||||
.ty
|
||||
.ty_adt_def()
|
||||
.unwrap()
|
||||
.non_enum_variant()
|
||||
.fields
|
||||
.iter_enumerated()
|
||||
{
|
||||
let field_place = self.project_field(&const_place, field_idx)?;
|
||||
match field_def.name {
|
||||
sym::ty => self.write_type_id(c.ty, &field_place)?,
|
||||
other => span_bug!(self.tcx.def_span(field_def.did), "unimplemented field {other}"),
|
||||
}
|
||||
}
|
||||
|
||||
self.write_discriminant(variant_idx, &place)?;
|
||||
interp_ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ use rustc_infer::infer::TyCtxtInferExt;
|
|||
use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, read_target_uint, write_target_uint};
|
||||
use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic};
|
||||
use rustc_middle::ty::layout::TyAndLayout;
|
||||
use rustc_middle::ty::{FloatTy, PolyExistentialPredicate, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{FloatTy, PolyExistentialPredicate, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::{bug, span_bug, ty};
|
||||
use rustc_span::{Symbol, sym};
|
||||
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
|
||||
|
|
@ -73,6 +73,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
ty: Ty<'tcx>,
|
||||
dest: &impl Writeable<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx, ()> {
|
||||
debug_assert!(
|
||||
!ty.has_erasable_regions(),
|
||||
"type {ty:?} has regions that need erasing before writing a TypeId",
|
||||
);
|
||||
|
||||
let tcx = self.tcx;
|
||||
let type_id_hash = tcx.type_id_hash(ty).as_u128();
|
||||
let op = self.const_val_to_op(
|
||||
|
|
|
|||
|
|
@ -211,6 +211,7 @@ symbols! {
|
|||
CoercePointeeValidated,
|
||||
CoerceUnsized,
|
||||
Command,
|
||||
Const,
|
||||
ConstParamTy,
|
||||
ConstParamTy_,
|
||||
Context,
|
||||
|
|
@ -234,6 +235,7 @@ symbols! {
|
|||
DynTrait,
|
||||
Encodable,
|
||||
Encoder,
|
||||
Enum,
|
||||
Enumerate,
|
||||
Eq,
|
||||
Equal,
|
||||
|
|
@ -292,6 +294,7 @@ symbols! {
|
|||
IteratorMap,
|
||||
Layout,
|
||||
Left,
|
||||
Lifetime,
|
||||
LinkedList,
|
||||
LintDiagnostic,
|
||||
LintPass,
|
||||
|
|
@ -372,6 +375,7 @@ symbols! {
|
|||
Stdin,
|
||||
Str,
|
||||
String,
|
||||
Struct,
|
||||
StructuralPartialEq,
|
||||
Subdiagnostic,
|
||||
SymbolIntern,
|
||||
|
|
@ -394,6 +398,8 @@ symbols! {
|
|||
Ty,
|
||||
TyCtxt,
|
||||
TyKind,
|
||||
Type,
|
||||
Union,
|
||||
Unknown,
|
||||
Unsize,
|
||||
UnsizedConstParamTy,
|
||||
|
|
@ -1085,6 +1091,7 @@ symbols! {
|
|||
ffi_returns_twice,
|
||||
field,
|
||||
field_init_shorthand,
|
||||
fields,
|
||||
file,
|
||||
file_options,
|
||||
flags,
|
||||
|
|
@ -1173,6 +1180,7 @@ symbols! {
|
|||
generic_const_parameter_types,
|
||||
generic_param_attrs,
|
||||
generic_pattern_types,
|
||||
generics,
|
||||
get_context,
|
||||
global_alloc_ty,
|
||||
global_allocator,
|
||||
|
|
@ -2473,6 +2481,7 @@ symbols! {
|
|||
values,
|
||||
var,
|
||||
variant_count,
|
||||
variants,
|
||||
vec,
|
||||
vec_as_mut_slice,
|
||||
vec_as_slice,
|
||||
|
|
|
|||
|
|
@ -49,6 +49,12 @@ pub enum TypeKind {
|
|||
Slice(Slice),
|
||||
/// Dynamic Traits.
|
||||
DynTrait(DynTrait),
|
||||
/// Structs.
|
||||
Struct(Struct),
|
||||
/// Enums.
|
||||
Enum(Enum),
|
||||
/// Unions.
|
||||
Union(Union),
|
||||
/// Primitive boolean type.
|
||||
Bool(Bool),
|
||||
/// Primitive character type.
|
||||
|
|
@ -81,6 +87,8 @@ pub struct Tuple {
|
|||
#[non_exhaustive]
|
||||
#[unstable(feature = "type_info", issue = "146922")]
|
||||
pub struct Field {
|
||||
/// The name of the field.
|
||||
pub name: &'static str,
|
||||
/// The field's type.
|
||||
pub ty: TypeId,
|
||||
/// Offset in bytes from the parent type
|
||||
|
|
@ -137,6 +145,95 @@ pub struct Trait {
|
|||
pub is_auto: bool,
|
||||
}
|
||||
|
||||
/// Compile-time type information about arrays.
|
||||
#[derive(Debug)]
|
||||
#[non_exhaustive]
|
||||
#[unstable(feature = "type_info", issue = "146922")]
|
||||
pub struct Struct {
|
||||
/// Instantiated generics of the struct.
|
||||
pub generics: &'static [Generic],
|
||||
/// All fields of the struct.
|
||||
pub fields: &'static [Field],
|
||||
/// Whether the struct field list is non-exhaustive.
|
||||
pub non_exhaustive: bool,
|
||||
}
|
||||
|
||||
/// Compile-time type information about unions.
|
||||
#[derive(Debug)]
|
||||
#[non_exhaustive]
|
||||
#[unstable(feature = "type_info", issue = "146922")]
|
||||
pub struct Union {
|
||||
/// Instantiated generics of the union.
|
||||
pub generics: &'static [Generic],
|
||||
/// All fields of the union.
|
||||
pub fields: &'static [Field],
|
||||
}
|
||||
|
||||
/// Compile-time type information about enums.
|
||||
#[derive(Debug)]
|
||||
#[non_exhaustive]
|
||||
#[unstable(feature = "type_info", issue = "146922")]
|
||||
pub struct Enum {
|
||||
/// Instantiated generics of the enum.
|
||||
pub generics: &'static [Generic],
|
||||
/// All variants of the enum.
|
||||
pub variants: &'static [Variant],
|
||||
/// Whether the enum variant list is non-exhaustive.
|
||||
pub non_exhaustive: bool,
|
||||
}
|
||||
|
||||
/// Compile-time type information about variants of enums.
|
||||
#[derive(Debug)]
|
||||
#[non_exhaustive]
|
||||
#[unstable(feature = "type_info", issue = "146922")]
|
||||
pub struct Variant {
|
||||
/// The name of the variant.
|
||||
pub name: &'static str,
|
||||
/// All fields of the variant.
|
||||
pub fields: &'static [Field],
|
||||
/// Whether the enum variant fields is non-exhaustive.
|
||||
pub non_exhaustive: bool,
|
||||
}
|
||||
|
||||
/// Compile-time type information about instantiated generics of structs, enum and union variants.
|
||||
#[derive(Debug)]
|
||||
#[non_exhaustive]
|
||||
#[unstable(feature = "type_info", issue = "146922")]
|
||||
pub enum Generic {
|
||||
/// Lifetimes.
|
||||
Lifetime(Lifetime),
|
||||
/// Types.
|
||||
Type(GenericType),
|
||||
/// Const parameters.
|
||||
Const(Const),
|
||||
}
|
||||
|
||||
/// Compile-time type information about generic lifetimes.
|
||||
#[derive(Debug)]
|
||||
#[non_exhaustive]
|
||||
#[unstable(feature = "type_info", issue = "146922")]
|
||||
pub struct Lifetime {
|
||||
// No additional information to provide for now.
|
||||
}
|
||||
|
||||
/// Compile-time type information about instantiated generic types.
|
||||
#[derive(Debug)]
|
||||
#[non_exhaustive]
|
||||
#[unstable(feature = "type_info", issue = "146922")]
|
||||
pub struct GenericType {
|
||||
/// The type itself.
|
||||
pub ty: TypeId,
|
||||
}
|
||||
|
||||
/// Compile-time type information about generic const parameters.
|
||||
#[derive(Debug)]
|
||||
#[non_exhaustive]
|
||||
#[unstable(feature = "type_info", issue = "146922")]
|
||||
pub struct Const {
|
||||
/// The const's type.
|
||||
pub ty: TypeId,
|
||||
}
|
||||
|
||||
/// Compile-time type information about `bool`.
|
||||
#[derive(Debug)]
|
||||
#[non_exhaustive]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use std::any::{Any, TypeId};
|
||||
use std::mem::type_info::{Type, TypeKind};
|
||||
use std::mem::offset_of;
|
||||
use std::mem::type_info::{Const, Generic, GenericType, Type, TypeKind};
|
||||
|
||||
#[test]
|
||||
fn test_arrays() {
|
||||
|
|
@ -66,6 +69,155 @@ fn test_tuples() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_structs() {
|
||||
use TypeKind::*;
|
||||
|
||||
const {
|
||||
struct TestStruct {
|
||||
first: u8,
|
||||
second: u16,
|
||||
reference: &'static u16,
|
||||
}
|
||||
|
||||
let Type { kind: Struct(ty), size, .. } = Type::of::<TestStruct>() else { panic!() };
|
||||
assert!(size == Some(size_of::<TestStruct>()));
|
||||
assert!(!ty.non_exhaustive);
|
||||
assert!(ty.fields.len() == 3);
|
||||
assert!(ty.fields[0].name == "first");
|
||||
assert!(ty.fields[0].ty == TypeId::of::<u8>());
|
||||
assert!(ty.fields[0].offset == offset_of!(TestStruct, first));
|
||||
assert!(ty.fields[1].name == "second");
|
||||
assert!(ty.fields[1].ty == TypeId::of::<u16>());
|
||||
assert!(ty.fields[1].offset == offset_of!(TestStruct, second));
|
||||
assert!(ty.fields[2].name == "reference");
|
||||
assert!(ty.fields[2].ty == TypeId::of::<&'static u16>());
|
||||
assert!(ty.fields[2].offset == offset_of!(TestStruct, reference));
|
||||
}
|
||||
|
||||
const {
|
||||
#[non_exhaustive]
|
||||
struct NonExhaustive {
|
||||
a: u8,
|
||||
}
|
||||
|
||||
let Type { kind: Struct(ty), .. } = Type::of::<NonExhaustive>() else { panic!() };
|
||||
assert!(ty.non_exhaustive);
|
||||
}
|
||||
|
||||
const {
|
||||
struct TupleStruct(u8, u16);
|
||||
|
||||
let Type { kind: Struct(ty), .. } = Type::of::<TupleStruct>() else { panic!() };
|
||||
assert!(ty.fields.len() == 2);
|
||||
assert!(ty.fields[0].name == "0");
|
||||
assert!(ty.fields[0].ty == TypeId::of::<u8>());
|
||||
assert!(ty.fields[1].name == "1");
|
||||
assert!(ty.fields[1].ty == TypeId::of::<u16>());
|
||||
}
|
||||
|
||||
const {
|
||||
struct Generics<'a, T, const C: u64> {
|
||||
a: &'a T,
|
||||
}
|
||||
|
||||
let Type { kind: Struct(ty), .. } = Type::of::<Generics<'static, i32, 1_u64>>() else {
|
||||
panic!()
|
||||
};
|
||||
assert!(ty.fields.len() == 1);
|
||||
assert!(ty.generics.len() == 3);
|
||||
|
||||
let Generic::Lifetime(_) = ty.generics[0] else { panic!() };
|
||||
let Generic::Type(GenericType { ty: generic_ty, .. }) = ty.generics[1] else { panic!() };
|
||||
assert!(generic_ty == TypeId::of::<i32>());
|
||||
let Generic::Const(Const { ty: const_ty, .. }) = ty.generics[2] else { panic!() };
|
||||
assert!(const_ty == TypeId::of::<u64>());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unions() {
|
||||
use TypeKind::*;
|
||||
|
||||
const {
|
||||
union TestUnion {
|
||||
first: i16,
|
||||
second: u16,
|
||||
}
|
||||
|
||||
let Type { kind: Union(ty), size, .. } = Type::of::<TestUnion>() else { panic!() };
|
||||
assert!(size == Some(size_of::<TestUnion>()));
|
||||
assert!(ty.fields.len() == 2);
|
||||
assert!(ty.fields[0].name == "first");
|
||||
assert!(ty.fields[0].offset == offset_of!(TestUnion, first));
|
||||
assert!(ty.fields[1].name == "second");
|
||||
assert!(ty.fields[1].offset == offset_of!(TestUnion, second));
|
||||
}
|
||||
|
||||
const {
|
||||
union Generics<'a, T: Copy, const C: u64> {
|
||||
a: T,
|
||||
z: &'a (),
|
||||
}
|
||||
|
||||
let Type { kind: Union(ty), .. } = Type::of::<Generics<'static, i32, 1_u64>>() else {
|
||||
panic!()
|
||||
};
|
||||
assert!(ty.fields.len() == 2);
|
||||
assert!(ty.fields[0].offset == offset_of!(Generics<'static, i32, 1_u64>, a));
|
||||
assert!(ty.fields[1].offset == offset_of!(Generics<'static, i32, 1_u64>, z));
|
||||
|
||||
assert!(ty.generics.len() == 3);
|
||||
let Generic::Lifetime(_) = ty.generics[0] else { panic!() };
|
||||
let Generic::Type(GenericType { ty: generic_ty, .. }) = ty.generics[1] else { panic!() };
|
||||
assert!(generic_ty == TypeId::of::<i32>());
|
||||
let Generic::Const(Const { ty: const_ty, .. }) = ty.generics[2] else { panic!() };
|
||||
assert!(const_ty == TypeId::of::<u64>());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_enums() {
|
||||
use TypeKind::*;
|
||||
|
||||
const {
|
||||
enum E {
|
||||
Some(u32),
|
||||
None,
|
||||
#[non_exhaustive]
|
||||
Foomp {
|
||||
a: (),
|
||||
b: &'static str,
|
||||
},
|
||||
}
|
||||
|
||||
let Type { kind: Enum(ty), size, .. } = Type::of::<E>() else { panic!() };
|
||||
assert!(size == Some(size_of::<E>()));
|
||||
assert!(ty.variants.len() == 3);
|
||||
|
||||
assert!(ty.variants[0].name == "Some");
|
||||
assert!(!ty.variants[0].non_exhaustive);
|
||||
assert!(ty.variants[0].fields.len() == 1);
|
||||
|
||||
assert!(ty.variants[1].name == "None");
|
||||
assert!(!ty.variants[1].non_exhaustive);
|
||||
assert!(ty.variants[1].fields.len() == 0);
|
||||
|
||||
assert!(ty.variants[2].name == "Foomp");
|
||||
assert!(ty.variants[2].non_exhaustive);
|
||||
assert!(ty.variants[2].fields.len() == 2);
|
||||
}
|
||||
|
||||
const {
|
||||
let Type { kind: Enum(ty), size, .. } = Type::of::<Option<i32>>() else { panic!() };
|
||||
assert!(size == Some(size_of::<Option<i32>>()));
|
||||
assert!(ty.variants.len() == 2);
|
||||
assert!(ty.generics.len() == 1);
|
||||
let Generic::Type(GenericType { ty: generic_ty, .. }) = ty.generics[0] else { panic!() };
|
||||
assert!(generic_ty == TypeId::of::<i32>());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_primitives() {
|
||||
use TypeKind::*;
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ mod r#trait {
|
|||
//~| HELP remove
|
||||
|
||||
type D = Box<dyn GenericType>;
|
||||
//~^ ERROR missing generics for trait `GenericType`
|
||||
//~^ ERROR missing generics for trait `r#trait::GenericType`
|
||||
//~| HELP add missing
|
||||
|
||||
type E = Box<dyn GenericType<String, usize>>;
|
||||
|
|
|
|||
|
|
@ -469,7 +469,7 @@ note: trait defined here, with 1 lifetime parameter: `'a`
|
|||
LL | trait GenericLifetime<'a> {
|
||||
| ^^^^^^^^^^^^^^^ --
|
||||
|
||||
error[E0107]: missing generics for trait `GenericType`
|
||||
error[E0107]: missing generics for trait `r#trait::GenericType`
|
||||
--> $DIR/wrong-number-of-args.rs:129:22
|
||||
|
|
||||
LL | type D = Box<dyn GenericType>;
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
error[E0599]: the method `clone` exists for struct `Struct<A>`, but its trait bounds were not satisfied
|
||||
error[E0599]: the method `clone` exists for struct `issue_69725::Struct<A>`, but its trait bounds were not satisfied
|
||||
--> $DIR/issue-69725.rs:9:32
|
||||
|
|
||||
LL | let _ = Struct::<A>::new().clone();
|
||||
| ^^^^^ method cannot be called on `Struct<A>` due to unsatisfied trait bounds
|
||||
| ^^^^^ method cannot be called on `issue_69725::Struct<A>` due to unsatisfied trait bounds
|
||||
|
|
||||
::: $DIR/auxiliary/issue-69725.rs:2:1
|
||||
|
|
||||
LL | pub struct Struct<A>(A);
|
||||
| -------------------- doesn't satisfy `Struct<A>: Clone`
|
||||
| -------------------- doesn't satisfy `issue_69725::Struct<A>: Clone`
|
||||
|
|
||||
= note: the following trait bounds were not satisfied:
|
||||
`A: Clone`
|
||||
which is required by `Struct<A>: Clone`
|
||||
which is required by `issue_69725::Struct<A>: Clone`
|
||||
help: consider restricting the type parameter to satisfy the trait bound
|
||||
|
|
||||
LL | fn crash<A>() where A: Clone {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ mod foo {
|
|||
Pub {};
|
||||
//~^ ERROR missing field `private` in initializer of `Pub`
|
||||
Enum::Variant { x: () };
|
||||
//~^ ERROR missing field `y` in initializer of `Enum`
|
||||
//~^ ERROR missing field `y` in initializer of `foo::Enum`
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -21,9 +21,9 @@ fn correct() {
|
|||
|
||||
fn wrong() {
|
||||
foo::Enum::Variant { x: () };
|
||||
//~^ ERROR missing field `y` in initializer of `Enum`
|
||||
//~^ ERROR missing field `y` in initializer of `foo::Enum`
|
||||
foo::Enum::Variant { };
|
||||
//~^ ERROR missing fields `x` and `y` in initializer of `Enum`
|
||||
//~^ ERROR missing fields `x` and `y` in initializer of `foo::Enum`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ error[E0063]: missing field `private` in initializer of `Pub`
|
|||
LL | Pub {};
|
||||
| ^^^ missing `private`
|
||||
|
||||
error[E0063]: missing field `y` in initializer of `Enum`
|
||||
error[E0063]: missing field `y` in initializer of `foo::Enum`
|
||||
--> $DIR/issue-79593.rs:12:9
|
||||
|
|
||||
LL | Enum::Variant { x: () };
|
||||
|
|
@ -18,13 +18,13 @@ LL | foo::Pub {};
|
|||
|
|
||||
= note: private field `private` that was not provided
|
||||
|
||||
error[E0063]: missing field `y` in initializer of `Enum`
|
||||
error[E0063]: missing field `y` in initializer of `foo::Enum`
|
||||
--> $DIR/issue-79593.rs:23:5
|
||||
|
|
||||
LL | foo::Enum::Variant { x: () };
|
||||
| ^^^^^^^^^^^^^^^^^^ missing `y`
|
||||
|
||||
error[E0063]: missing fields `x` and `y` in initializer of `Enum`
|
||||
error[E0063]: missing fields `x` and `y` in initializer of `foo::Enum`
|
||||
--> $DIR/issue-79593.rs:25:5
|
||||
|
|
||||
LL | foo::Enum::Variant { };
|
||||
|
|
|
|||
|
|
@ -1,225 +0,0 @@
|
|||
Type {
|
||||
kind: Tuple(
|
||||
Tuple {
|
||||
fields: [
|
||||
Field {
|
||||
ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
|
||||
offset: 0,
|
||||
},
|
||||
Field {
|
||||
ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
|
||||
offset: 1,
|
||||
},
|
||||
Field {
|
||||
ty: TypeId(0x41223169ff28813ba79b7268a2a968d9),
|
||||
offset: 2,
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
2,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Array(
|
||||
Array {
|
||||
element_ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
|
||||
len: 2,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
2,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Int(
|
||||
Int {
|
||||
bits: 8,
|
||||
signed: true,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
1,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Int(
|
||||
Int {
|
||||
bits: 32,
|
||||
signed: true,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
4,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Int(
|
||||
Int {
|
||||
bits: 64,
|
||||
signed: true,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
8,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Int(
|
||||
Int {
|
||||
bits: 128,
|
||||
signed: true,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
16,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Int(
|
||||
Int {
|
||||
bits: 32,
|
||||
signed: true,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
4,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Int(
|
||||
Int {
|
||||
bits: 8,
|
||||
signed: false,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
1,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Int(
|
||||
Int {
|
||||
bits: 32,
|
||||
signed: false,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
4,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Int(
|
||||
Int {
|
||||
bits: 64,
|
||||
signed: false,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
8,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Int(
|
||||
Int {
|
||||
bits: 128,
|
||||
signed: false,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
16,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Int(
|
||||
Int {
|
||||
bits: 32,
|
||||
signed: false,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
4,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Other,
|
||||
size: Some(
|
||||
4,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Other,
|
||||
size: Some(
|
||||
12,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Reference(
|
||||
Reference {
|
||||
pointee: TypeId(0xda1b6da9bd297bb2900de9303aadea79),
|
||||
mutable: false,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
8,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Reference(
|
||||
Reference {
|
||||
pointee: TypeId(0x474ccf3b5db264ef53916706f7d7bb2c),
|
||||
mutable: false,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
8,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Reference(
|
||||
Reference {
|
||||
pointee: TypeId(0x641e3def269c37acc6dcb92bf8c5f196),
|
||||
mutable: false,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
8,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Str(
|
||||
Str,
|
||||
),
|
||||
size: None,
|
||||
}
|
||||
Type {
|
||||
kind: Slice(
|
||||
Slice {
|
||||
element_ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
|
||||
},
|
||||
),
|
||||
size: None,
|
||||
}
|
||||
Type {
|
||||
kind: Reference(
|
||||
Reference {
|
||||
pointee: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
|
||||
mutable: false,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
4,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Reference(
|
||||
Reference {
|
||||
pointee: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
|
||||
mutable: true,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
4,
|
||||
),
|
||||
}
|
||||
|
|
@ -1,225 +0,0 @@
|
|||
Type {
|
||||
kind: Tuple(
|
||||
Tuple {
|
||||
fields: [
|
||||
Field {
|
||||
ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
|
||||
offset: 0,
|
||||
},
|
||||
Field {
|
||||
ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
|
||||
offset: 1,
|
||||
},
|
||||
Field {
|
||||
ty: TypeId(0x41223169ff28813ba79b7268a2a968d9),
|
||||
offset: 2,
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
2,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Array(
|
||||
Array {
|
||||
element_ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
|
||||
len: 2,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
2,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Int(
|
||||
Int {
|
||||
bits: 8,
|
||||
signed: true,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
1,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Int(
|
||||
Int {
|
||||
bits: 32,
|
||||
signed: true,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
4,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Int(
|
||||
Int {
|
||||
bits: 64,
|
||||
signed: true,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
8,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Int(
|
||||
Int {
|
||||
bits: 128,
|
||||
signed: true,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
16,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Int(
|
||||
Int {
|
||||
bits: 64,
|
||||
signed: true,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
8,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Int(
|
||||
Int {
|
||||
bits: 8,
|
||||
signed: false,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
1,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Int(
|
||||
Int {
|
||||
bits: 32,
|
||||
signed: false,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
4,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Int(
|
||||
Int {
|
||||
bits: 64,
|
||||
signed: false,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
8,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Int(
|
||||
Int {
|
||||
bits: 128,
|
||||
signed: false,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
16,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Int(
|
||||
Int {
|
||||
bits: 64,
|
||||
signed: false,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
8,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Other,
|
||||
size: Some(
|
||||
4,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Other,
|
||||
size: Some(
|
||||
24,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Reference(
|
||||
Reference {
|
||||
pointee: TypeId(0xda1b6da9bd297bb2900de9303aadea79),
|
||||
mutable: false,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
16,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Reference(
|
||||
Reference {
|
||||
pointee: TypeId(0x474ccf3b5db264ef53916706f7d7bb2c),
|
||||
mutable: false,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
16,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Reference(
|
||||
Reference {
|
||||
pointee: TypeId(0x641e3def269c37acc6dcb92bf8c5f196),
|
||||
mutable: false,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
16,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Str(
|
||||
Str,
|
||||
),
|
||||
size: None,
|
||||
}
|
||||
Type {
|
||||
kind: Slice(
|
||||
Slice {
|
||||
element_ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
|
||||
},
|
||||
),
|
||||
size: None,
|
||||
}
|
||||
Type {
|
||||
kind: Reference(
|
||||
Reference {
|
||||
pointee: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
|
||||
mutable: false,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
8,
|
||||
),
|
||||
}
|
||||
Type {
|
||||
kind: Reference(
|
||||
Reference {
|
||||
pointee: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
|
||||
mutable: true,
|
||||
},
|
||||
),
|
||||
size: Some(
|
||||
8,
|
||||
),
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
// Some types whose length depends on the target pointer length will be dumped.
|
||||
//@ revisions: bit32 bit64
|
||||
//@[bit32] only-32bit
|
||||
//@[bit64] only-64bit
|
||||
//@ run-pass
|
||||
//@ check-run-results
|
||||
|
||||
#![feature(type_info)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::mem::type_info::Type;
|
||||
|
||||
struct Foo {
|
||||
a: u32,
|
||||
}
|
||||
|
||||
enum Bar {
|
||||
Some(u32),
|
||||
None,
|
||||
Foomp { a: (), b: &'static str },
|
||||
}
|
||||
|
||||
struct Unsized {
|
||||
x: u16,
|
||||
s: str,
|
||||
}
|
||||
|
||||
macro_rules! dump_types {
|
||||
($($ty:ty),+ $(,)?) => {
|
||||
$(println!("{:#?}", const { Type::of::<$ty>() });)+
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
dump_types! {
|
||||
(u8, u8, ()),
|
||||
[u8; 2],
|
||||
i8, i32, i64, i128, isize,
|
||||
u8, u32, u64, u128, usize,
|
||||
Foo, Bar,
|
||||
&Unsized, &str, &[u8],
|
||||
str, [u8],
|
||||
&u8, &mut u8,
|
||||
}
|
||||
}
|
||||
|
|
@ -41,12 +41,22 @@ error[E0531]: cannot find tuple struct or tuple variant `Type` in this scope
|
|||
|
|
||||
LL | let Type(..);
|
||||
| ^^^^ not found in this scope
|
||||
|
|
||||
help: consider importing this tuple variant
|
||||
|
|
||||
LL + use std::mem::type_info::Generic::Type;
|
||||
|
|
||||
|
||||
error[E0425]: cannot find value `Type` in this scope
|
||||
--> $DIR/resolve-assoc-suggestions.rs:27:9
|
||||
|
|
||||
LL | Type;
|
||||
| ^^^^ not found in this scope
|
||||
|
|
||||
help: consider importing this tuple variant
|
||||
|
|
||||
LL + use std::mem::type_info::Generic::Type;
|
||||
|
|
||||
|
||||
error[E0425]: cannot find type `method` in this scope
|
||||
--> $DIR/resolve-assoc-suggestions.rs:30:16
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue