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 f932b198b4260..814c81278a104 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -3,7 +3,7 @@ use rustc_hir::LangItem; use rustc_middle::mir::interpret::CtfeProvenance; use rustc_middle::span_bug; use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{self, ScalarInt, Ty}; +use rustc_middle::ty::{self, Const, ScalarInt, Ty}; use rustc_span::{Symbol, sym}; use crate::const_eval::CompileTimeMachine; @@ -56,6 +56,14 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { self.write_tuple_fields(tuple_place, fields, ty)?; variant } + ty::Array(ty, len) => { + let (variant, variant_place) = downcast(sym::Array)?; + let array_place = self.project_field(&variant_place, FieldIdx::ZERO)?; + + self.write_array_type_info(array_place, *ty, *len)?; + + variant + } // For now just merge all primitives into one `Leaf` variant with no data ty::Uint(_) | ty::Int(_) | ty::Float(_) | ty::Char | ty::Bool => { downcast(sym::Leaf)?.0 @@ -63,7 +71,6 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { ty::Adt(_, _) | ty::Foreign(_) | ty::Str - | ty::Array(_, _) | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(..) @@ -172,4 +179,28 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { } interp_ok(()) } + + pub(crate) fn write_array_type_info( + &mut self, + place: impl Writeable<'tcx, CtfeProvenance>, + ty: Ty<'tcx>, + len: Const<'tcx>, + ) -> InterpResult<'tcx> { + // Iterate over all fields of `type_info::Array`. + 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 { + // Write the `TypeId` of the array's elements to the `element_ty` field. + sym::element_ty => self.write_type_id(ty, &field_place)?, + // Write the length of the array to the `len` field. + sym::len => self.write_scalar(len.to_leaf(), &field_place)?, + other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), + } + } + + interp_ok(()) + } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index f56c3421ce0f5..34804160ed398 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -162,6 +162,7 @@ symbols! { Arc, ArcWeak, Argument, + Array, ArrayIntoIter, AsMut, AsRef, @@ -939,6 +940,7 @@ symbols! { eii_impl, eii_internals, eii_shared_macro, + element_ty, emit, emit_enum, emit_enum_variant, diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index 7938e2b52ed02..208cbc299aae5 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -43,6 +43,8 @@ impl Type { pub enum TypeKind { /// Tuples. Tuple(Tuple), + /// Arrays. + Array(Array), /// Primitives /// FIXME(#146922): disambiguate further Leaf, @@ -69,3 +71,14 @@ pub struct Field { /// Offset in bytes from the parent type pub offset: usize, } + +/// Compile-time type information about arrays. +#[derive(Debug)] +#[non_exhaustive] +#[unstable(feature = "type_info", issue = "146922")] +pub struct Array { + /// The type of each element in the array. + pub element_ty: TypeId, + /// The length of the array. + pub len: usize, +} diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index ff4fc4c892afe..caa130be1483e 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -115,6 +115,7 @@ #![feature(try_blocks)] #![feature(try_find)] #![feature(try_trait_v2)] +#![feature(type_info)] #![feature(uint_bit_width)] #![feature(uint_gather_scatter_bits)] #![feature(unsize)] diff --git a/library/coretests/tests/mem.rs b/library/coretests/tests/mem.rs index 5247e01fba01b..193d5416b06a7 100644 --- a/library/coretests/tests/mem.rs +++ b/library/coretests/tests/mem.rs @@ -1,3 +1,5 @@ +mod type_info; + use core::mem::*; use core::{array, ptr}; use std::cell::Cell; diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs new file mode 100644 index 0000000000000..b3b8d96d49b00 --- /dev/null +++ b/library/coretests/tests/mem/type_info.rs @@ -0,0 +1,56 @@ +use std::any::TypeId; +use std::mem::type_info::{Type, TypeKind}; + +#[test] +fn test_arrays() { + // Normal array. + match const { Type::of::<[u16; 4]>() }.kind { + TypeKind::Array(array) => { + assert_eq!(array.element_ty, TypeId::of::()); + assert_eq!(array.len, 4); + } + _ => unreachable!(), + } + + // Zero-length array. + match const { Type::of::<[bool; 0]>() }.kind { + TypeKind::Array(array) => { + assert_eq!(array.element_ty, TypeId::of::()); + assert_eq!(array.len, 0); + } + _ => unreachable!(), + } +} + +#[test] +fn test_tuples() { + fn assert_tuple_arity() { + match const { Type::of::() }.kind { + TypeKind::Tuple(tup) => { + assert_eq!(tup.fields.len(), N); + } + _ => unreachable!(), + } + } + + assert_tuple_arity::<(), 0>(); + assert_tuple_arity::<(u8,), 1>(); + assert_tuple_arity::<(u8, u8), 2>(); + + const { + match Type::of::<(u8, u8)>().kind { + TypeKind::Tuple(tup) => { + let [a, b] = tup.fields else { unreachable!() }; + + assert!(a.offset == 0); + assert!(b.offset == 1); + + match (a.ty.info().kind, b.ty.info().kind) { + (TypeKind::Leaf, TypeKind::Leaf) => {} + _ => unreachable!(), + } + } + _ => unreachable!(), + } + } +} diff --git a/tests/ui/reflection/dump.rs b/tests/ui/reflection/dump.rs index 3bf4f32b6641d..cc3bcb8b9faf7 100644 --- a/tests/ui/reflection/dump.rs +++ b/tests/ui/reflection/dump.rs @@ -22,6 +22,7 @@ struct Unsized { fn main() { println!("{:#?}", const { Type::of::<(u8, u8, ())>() }.kind); + println!("{:#?}", const { Type::of::<[u8; 2]>() }.kind); println!("{:#?}", const { Type::of::() }.kind); println!("{:#?}", const { Type::of::() }.kind); println!("{:#?}", const { Type::of::<&Unsized>() }.kind); diff --git a/tests/ui/reflection/dump.run.stdout b/tests/ui/reflection/dump.run.stdout index 71fd80b466580..7a0bb9592a3cd 100644 --- a/tests/ui/reflection/dump.run.stdout +++ b/tests/ui/reflection/dump.run.stdout @@ -16,6 +16,12 @@ Tuple( ], }, ) +Array( + Array { + element_ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), + len: 2, + }, +) Other Other Other diff --git a/tests/ui/reflection/tuples.rs b/tests/ui/reflection/tuples.rs deleted file mode 100644 index eab25a691efe2..0000000000000 --- a/tests/ui/reflection/tuples.rs +++ /dev/null @@ -1,36 +0,0 @@ -#![feature(type_info)] - -//@ run-pass - -use std::mem::type_info::{Type, TypeKind}; - -fn assert_tuple_arity() { - const { - match &Type::of::().kind { - TypeKind::Tuple(tup) => { - assert!(tup.fields.len() == N); - } - _ => unreachable!(), - } - } -} - -fn main() { - assert_tuple_arity::<(), 0>(); - assert_tuple_arity::<(u8,), 1>(); - assert_tuple_arity::<(u8, u8), 2>(); - const { - match &Type::of::<(u8, u8)>().kind { - TypeKind::Tuple(tup) => { - let [a, b] = tup.fields else { unreachable!() }; - assert!(a.offset == 0); - assert!(b.offset == 1); - match (&a.ty.info().kind, &b.ty.info().kind) { - (TypeKind::Leaf, TypeKind::Leaf) => {} - _ => unreachable!(), - } - } - _ => unreachable!(), - } - } -}