diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs index b68c73a46425e..b64f184c24e23 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -1,23 +1,74 @@ -use rustc_abi::FieldIdx; +use std::borrow::Cow; + +use rustc_abi::{FieldIdx, VariantIdx}; use rustc_ast::Mutability; use rustc_hir::LangItem; use rustc_middle::mir::interpret::{CtfeProvenance, Scalar}; -use rustc_middle::span_bug; use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{self, Const, ScalarInt, Ty}; +use rustc_middle::ty::{ + self, AdtDef, AdtKind, Const, ConstKind, GenericArgKind, GenericArgs, Region, ScalarInt, Ty, + VariantDef, +}; +use rustc_middle::{bug, span_bug}; use rustc_span::{Symbol, sym}; use crate::const_eval::CompileTimeMachine; use crate::interpret::{ - Immediate, InterpCx, InterpResult, MPlaceTy, MemoryKind, Writeable, interp_ok, + Immediate, InterpCx, InterpResult, MPlaceTy, MemoryKind, Projectable, Writeable, interp_ok, }; impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { + fn downcast( + &self, + place: &(impl Writeable<'tcx, CtfeProvenance> + 'tcx), + name: Symbol, + ) -> InterpResult<'tcx, (VariantIdx, impl Writeable<'tcx, CtfeProvenance> + 'tcx)> { + let variants = place.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(place, variant_id)?)) + } + + // A general method to write an array to a static slice place. + fn project_write_array( + &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, ty: Ty<'tcx>, - dest: &impl Writeable<'tcx, CtfeProvenance>, + dest: &(impl Writeable<'tcx, CtfeProvenance> + 'tcx), ) -> InterpResult<'tcx> { let ty_struct = self.tcx.require_lang_item(LangItem::Type, self.tcx.span); let ty_struct = self.tcx.type_of(ty_struct).no_bound_vars().unwrap(); @@ -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!( @@ -59,23 +101,34 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { 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)?; variant } + ty::Adt(adt_def, generics) => { + // TODO(type_info): Handle union + if !adt_def.is_struct() && !adt_def.is_enum() { + self.downcast(&field_dest, sym::Other)?.0 + } else { + 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, @@ -85,7 +138,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, @@ -95,25 +148,26 @@ 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)?; variant } - ty::Adt(_, _) - | ty::Foreign(_) + ty::Foreign(_) | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(..) @@ -131,14 +185,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( @@ -148,7 +202,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)?; } @@ -159,6 +213,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { interp_ok(()) } + // TODO(type_info): Remove this method, use `project_write_array` as it's more general. pub(crate) fn write_tuple_fields( &mut self, tuple_place: impl Writeable<'tcx, CtfeProvenance>, @@ -184,7 +239,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { 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)?; + self.write_field(field_ty, place, tuple_layout, None, i)?; } let fields_place = fields_place.map_provenance(CtfeProvenance::as_immutable); @@ -194,11 +249,27 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { self.write_immediate(ptr, &fields_slice_place) } + // 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.project_write_array(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_field( &mut self, field_ty: Ty<'tcx>, place: MPlaceTy<'tcx>, layout: TyAndLayout<'tcx>, + name: Option, idx: u64, ) -> InterpResult<'tcx> { for (field_idx, field_ty_field) in @@ -206,6 +277,15 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { { let field_place = self.project_field(&place, field_idx)?; match field_ty_field.name { + 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 => self.write_type_id(field_ty, &field_place)?, sym::offset => { let offset = layout.fields.offset(idx as usize); @@ -246,6 +326,212 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { interp_ok(()) } + // FIXME(type_info): No semver considerations for now + pub(crate) fn write_adt_type_info( + &mut self, + place: &(impl Writeable<'tcx, CtfeProvenance> + 'tcx), + 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::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 + } + AdtKind::Union => todo!(), + }; + 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)? + } + // TODO(type_info): Write more info + 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.project_write_array( + 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); + // TODO(type_info): Is it correct to use enum_ty here? If yes, leave some explanation. + 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(()) + } + + fn write_generics( + &mut self, + place: impl Writeable<'tcx, CtfeProvenance>, + generics: &'tcx GenericArgs<'tcx>, + ) -> InterpResult<'tcx> { + self.project_write_array(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(()) + } + fn write_int_type_info( &mut self, place: impl Writeable<'tcx, CtfeProvenance>, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d21580c16db20..d1bd752ac4805 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -211,6 +211,7 @@ symbols! { CoercePointeeValidated, CoerceUnsized, Command, + Const, ConstParamTy, ConstParamTy_, Context, @@ -233,6 +234,7 @@ symbols! { Duration, Encodable, Encoder, + Enum, Enumerate, Eq, Equal, @@ -290,6 +292,7 @@ symbols! { IteratorMap, Layout, Left, + Lifetime, LinkedList, LintDiagnostic, LintPass, @@ -369,6 +372,7 @@ symbols! { Stdin, Str, String, + Struct, StructuralPartialEq, SubdiagMessage, Subdiagnostic, @@ -392,6 +396,7 @@ symbols! { Ty, TyCtxt, TyKind, + Type, Unknown, Unsize, UnsizedConstParamTy, @@ -1080,6 +1085,7 @@ symbols! { ffi_returns_twice, field, field_init_shorthand, + fields, file, file_options, flags, @@ -1168,6 +1174,7 @@ symbols! { generic_const_parameter_types, generic_param_attrs, generic_pattern_types, + generics, get_context, global_alloc_ty, global_allocator, @@ -2463,6 +2470,7 @@ symbols! { values, var, variant_count, + variants, vec, vec_as_mut_slice, vec_as_slice, diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index 1d6cc034dbac8..a80f2aef80521 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -45,6 +45,10 @@ pub enum TypeKind { Tuple(Tuple), /// Arrays. Array(Array), + /// Structs. + Struct(Struct), + /// Enums. + Enum(Enum), /// Primitive boolean type. Bool(Bool), /// Primitive character type. @@ -75,6 +79,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 @@ -92,6 +98,84 @@ pub struct Array { pub len: usize, } +/// 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 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 const's type. + 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] diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs index 1e15446967b97..4c4401d6e8679 100644 --- a/library/coretests/tests/mem/type_info.rs +++ b/library/coretests/tests/mem/type_info.rs @@ -1,5 +1,7 @@ +#![allow(dead_code)] + use std::any::{Any, TypeId}; -use std::mem::type_info::{Type, TypeKind}; +use std::mem::type_info::{Const, Generic, GenericType, Type, TypeKind}; #[test] fn test_arrays() { @@ -58,6 +60,107 @@ fn test_tuples() { } } +#[test] +fn test_structs() { + use TypeKind::*; + + const { + struct TestStruct { + first: u8, + second: u16, + } + + let Type { kind: Struct(ty), size, .. } = Type::of::() else { panic!() }; + assert!(size == Some(size_of::())); + assert!(!ty.non_exhaustive); + assert!(ty.fields.len() == 2); + assert!(ty.fields[0].name == "first"); + assert!(ty.fields[1].name == "second"); + } + + const { + #[non_exhaustive] + struct NonExhaustive { + a: u8, + } + + let Type { kind: Struct(ty), .. } = Type::of::() else { panic!() }; + assert!(ty.non_exhaustive); + } + + const { + struct TupleStruct(u8, u16); + + let Type { kind: Struct(ty), .. } = Type::of::() else { panic!() }; + assert!(ty.fields.len() == 2); + assert!(ty.fields[0].name == "0"); + assert!(ty.fields[0].ty == TypeId::of::()); + assert!(ty.fields[1].name == "1"); + assert!(ty.fields[1].ty == TypeId::of::()); + } + + const { + struct Generics<'a, T, const C: u64> { + a: T, + z: &'a (), // FIXME(type_info): offset of this field is dumped as 0, which may not be correct + } + + let Type { kind: Struct(ty), .. } = Type::of::>() else { + panic!() + }; + assert!(ty.fields.len() == 2); + 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::()); + let Generic::Const(Const { ty: const_ty, .. }) = ty.generics[2] else { panic!() }; + assert!(const_ty == TypeId::of::()); + } +} + +#[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::() else { panic!() }; + assert!(size == Some(size_of::())); + 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::>() else { panic!() }; + assert!(size == Some(size_of::>())); + 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::()); + } +} + #[test] fn test_primitives() { use TypeKind::*; diff --git a/tests/ui/generics/wrong-number-of-args.rs b/tests/ui/generics/wrong-number-of-args.rs index 8bc384a3d817d..9af16567cd75a 100644 --- a/tests/ui/generics/wrong-number-of-args.rs +++ b/tests/ui/generics/wrong-number-of-args.rs @@ -127,7 +127,7 @@ mod r#trait { //~| HELP remove type D = Box; - //~^ ERROR missing generics for trait `GenericType` + //~^ ERROR missing generics for trait `r#trait::GenericType` //~| HELP add missing type E = Box>; diff --git a/tests/ui/generics/wrong-number-of-args.stderr b/tests/ui/generics/wrong-number-of-args.stderr index bedeeb812fc99..554d017d67e33 100644 --- a/tests/ui/generics/wrong-number-of-args.stderr +++ b/tests/ui/generics/wrong-number-of-args.stderr @@ -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; diff --git a/tests/ui/missing-trait-bounds/issue-69725.stderr b/tests/ui/missing-trait-bounds/issue-69725.stderr index f483ea849b0ef..20d2213f4f5fe 100644 --- a/tests/ui/missing-trait-bounds/issue-69725.stderr +++ b/tests/ui/missing-trait-bounds/issue-69725.stderr @@ -1,17 +1,17 @@ -error[E0599]: the method `clone` exists for struct `Struct`, but its trait bounds were not satisfied +error[E0599]: the method `clone` exists for struct `issue_69725::Struct`, but its trait bounds were not satisfied --> $DIR/issue-69725.rs:9:32 | LL | let _ = Struct::::new().clone(); - | ^^^^^ method cannot be called on `Struct` due to unsatisfied trait bounds + | ^^^^^ method cannot be called on `issue_69725::Struct` due to unsatisfied trait bounds | ::: $DIR/auxiliary/issue-69725.rs:2:1 | LL | pub struct Struct(A); - | -------------------- doesn't satisfy `Struct: Clone` + | -------------------- doesn't satisfy `issue_69725::Struct: Clone` | = note: the following trait bounds were not satisfied: `A: Clone` - which is required by `Struct: Clone` + which is required by `issue_69725::Struct: Clone` help: consider restricting the type parameter to satisfy the trait bound | LL | fn crash() where A: Clone { diff --git a/tests/ui/privacy/issue-79593.rs b/tests/ui/privacy/issue-79593.rs index 39c222f7c3414..663dd67fcdb14 100644 --- a/tests/ui/privacy/issue-79593.rs +++ b/tests/ui/privacy/issue-79593.rs @@ -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() {} diff --git a/tests/ui/privacy/issue-79593.stderr b/tests/ui/privacy/issue-79593.stderr index 5bb69836f609f..74fea1a3ab76c 100644 --- a/tests/ui/privacy/issue-79593.stderr +++ b/tests/ui/privacy/issue-79593.stderr @@ -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 { }; diff --git a/tests/ui/reflection/dump.bit32.run.stdout b/tests/ui/reflection/dump.bit32.run.stdout index 0c8a835923be7..9fabd95e6aeac 100644 --- a/tests/ui/reflection/dump.bit32.run.stdout +++ b/tests/ui/reflection/dump.bit32.run.stdout @@ -3,14 +3,17 @@ Type { Tuple { fields: [ Field { + name: "0", ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), offset: 0, }, Field { + name: "1", ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), offset: 1, }, Field { + name: "2", ty: TypeId(0x41223169ff28813ba79b7268a2a968d9), offset: 2, }, @@ -143,13 +146,152 @@ Type { ), } Type { - kind: Other, + kind: Struct( + Struct { + generics: [], + fields: [ + Field { + name: "a", + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + offset: 0, + }, + ], + non_exhaustive: false, + }, + ), size: Some( 4, ), } Type { - kind: Other, + kind: Enum( + Enum { + generics: [], + variants: [ + Variant { + name: "Some", + fields: [ + Field { + name: "0", + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + offset: 4, + }, + ], + non_exhaustive: false, + }, + Variant { + name: "None", + fields: [], + non_exhaustive: false, + }, + Variant { + name: "Foomp", + fields: [ + Field { + name: "a", + ty: TypeId(0x41223169ff28813ba79b7268a2a968d9), + offset: 4, + }, + Field { + name: "b", + ty: TypeId(0xb98b1b7157a6417863eb502cd6cb5d6d), + offset: 4, + }, + ], + non_exhaustive: true, + }, + ], + non_exhaustive: false, + }, + ), + size: Some( + 12, + ), +} +Type { + kind: Struct( + Struct { + generics: [], + fields: [ + Field { + name: "a", + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + offset: 0, + }, + ], + non_exhaustive: true, + }, + ), + size: Some( + 4, + ), +} +Type { + kind: Struct( + Struct { + generics: [], + fields: [ + Field { + name: "0", + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + offset: 8, + }, + Field { + name: "1", + ty: TypeId(0x9ed91be891e304132cb86891e578f4a5), + offset: 0, + }, + ], + non_exhaustive: false, + }, + ), + size: Some( + 12, + ), +} +Type { + kind: Struct( + Struct { + generics: [ + Lifetime( + Lifetime, + ), + Type( + GenericType { + ty: TypeId(0x56ced5e4a15bd89050bb9674fa2df013), + }, + ), + Type( + GenericType { + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + }, + ), + Const( + Const { + ty: TypeId(0x9ed91be891e304132cb86891e578f4a5), + }, + ), + ], + fields: [ + Field { + name: "a", + ty: TypeId(0x56ced5e4a15bd89050bb9674fa2df013), + offset: 4, + }, + Field { + name: "b", + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + offset: 8, + }, + Field { + name: "l", + ty: TypeId(0x5d686ae9be5f6232dca1f88c0b941fd9), + offset: 0, + }, + ], + non_exhaustive: false, + }, + ), size: Some( 12, ), diff --git a/tests/ui/reflection/dump.bit64.run.stdout b/tests/ui/reflection/dump.bit64.run.stdout index 20af4deb4e416..34ba7fb3ec6a7 100644 --- a/tests/ui/reflection/dump.bit64.run.stdout +++ b/tests/ui/reflection/dump.bit64.run.stdout @@ -3,14 +3,17 @@ Type { Tuple { fields: [ Field { + name: "0", ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), offset: 0, }, Field { + name: "1", ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), offset: 1, }, Field { + name: "2", ty: TypeId(0x41223169ff28813ba79b7268a2a968d9), offset: 2, }, @@ -143,17 +146,156 @@ Type { ), } Type { - kind: Other, + kind: Struct( + Struct { + generics: [], + fields: [ + Field { + name: "a", + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + offset: 0, + }, + ], + non_exhaustive: false, + }, + ), size: Some( 4, ), } Type { - kind: Other, + kind: Enum( + Enum { + generics: [], + variants: [ + Variant { + name: "Some", + fields: [ + Field { + name: "0", + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + offset: 4, + }, + ], + non_exhaustive: false, + }, + Variant { + name: "None", + fields: [], + non_exhaustive: false, + }, + Variant { + name: "Foomp", + fields: [ + Field { + name: "a", + ty: TypeId(0x41223169ff28813ba79b7268a2a968d9), + offset: 4, + }, + Field { + name: "b", + ty: TypeId(0xb98b1b7157a6417863eb502cd6cb5d6d), + offset: 8, + }, + ], + non_exhaustive: true, + }, + ], + non_exhaustive: false, + }, + ), size: Some( 24, ), } +Type { + kind: Struct( + Struct { + generics: [], + fields: [ + Field { + name: "a", + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + offset: 0, + }, + ], + non_exhaustive: true, + }, + ), + size: Some( + 4, + ), +} +Type { + kind: Struct( + Struct { + generics: [], + fields: [ + Field { + name: "0", + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + offset: 8, + }, + Field { + name: "1", + ty: TypeId(0x9ed91be891e304132cb86891e578f4a5), + offset: 0, + }, + ], + non_exhaustive: false, + }, + ), + size: Some( + 16, + ), +} +Type { + kind: Struct( + Struct { + generics: [ + Lifetime( + Lifetime, + ), + Type( + GenericType { + ty: TypeId(0x56ced5e4a15bd89050bb9674fa2df013), + }, + ), + Type( + GenericType { + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + }, + ), + Const( + Const { + ty: TypeId(0x9ed91be891e304132cb86891e578f4a5), + }, + ), + ], + fields: [ + Field { + name: "a", + ty: TypeId(0x56ced5e4a15bd89050bb9674fa2df013), + offset: 8, + }, + Field { + name: "b", + ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7), + offset: 12, + }, + Field { + name: "l", + ty: TypeId(0x5d686ae9be5f6232dca1f88c0b941fd9), + offset: 0, + }, + ], + non_exhaustive: false, + }, + ), + size: Some( + 16, + ), +} Type { kind: Reference( Reference { diff --git a/tests/ui/reflection/dump.rs b/tests/ui/reflection/dump.rs index d42216a62fdc8..755f0c900e33d 100644 --- a/tests/ui/reflection/dump.rs +++ b/tests/ui/reflection/dump.rs @@ -14,10 +14,27 @@ struct Foo { a: u32, } +#[non_exhaustive] +struct NonExhaustiveStruct { + a: u32, +} + +struct TupleStruct(u32, u64); + enum Bar { Some(u32), None, - Foomp { a: (), b: &'static str }, + #[non_exhaustive] + Foomp { + a: (), + b: &'static str, + }, +} + +struct Generics<'a, A, B, const C: u64> { + a: A, + b: B, + l: &'a (), } struct Unsized { @@ -37,7 +54,7 @@ fn main() { [u8; 2], i8, i32, i64, i128, isize, u8, u32, u64, u128, usize, - Foo, Bar, + Foo, Bar, NonExhaustiveStruct, TupleStruct, Generics, &Unsized, &str, &[u8], str, [u8], &u8, &mut u8, diff --git a/tests/ui/resolve/resolve-assoc-suggestions.stderr b/tests/ui/resolve/resolve-assoc-suggestions.stderr index 7d94fb5ca35f4..e6311962884f1 100644 --- a/tests/ui/resolve/resolve-assoc-suggestions.stderr +++ b/tests/ui/resolve/resolve-assoc-suggestions.stderr @@ -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