diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index ce4c8497463c8..4251c74eb1ffb 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -12,7 +12,7 @@ use rustc_lint_defs::builtin::LONG_RUNNING_CONST_EVAL; use rustc_middle::mir::AssertMessage; use rustc_middle::mir::interpret::ReportedErrorInfo; use rustc_middle::query::TyCtxtAt; -use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout, ValidityRequirement}; +use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, TyAndLayout, ValidityRequirement}; use rustc_middle::ty::{self, FieldInfo, ScalarInt, Ty, TyCtxt}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::{Span, Symbol, sym}; @@ -638,6 +638,30 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { ecx.write_discriminant(variant_index, dest)?; } + sym::type_id_element_ty => { + let ty = ecx.read_type_id(&args[0])?; + let variant_index = if let ty::Array(ty, _) | ty::Slice(ty) = ty.kind() { + let (variant_idx, variant_place) = + ecx.project_downcast_named(dest, sym::Some)?; + let type_id_field_place = ecx.project_field(&variant_place, FieldIdx::ZERO)?; + ecx.write_type_id(*ty, &type_id_field_place)?; + variant_idx + } else { + ecx.project_downcast_named(dest, sym::None)?.0 + }; + ecx.write_discriminant(variant_index, dest)?; + } + + sym::type_id_array_len => { + let ty = ecx.read_type_id(&args[0])?; + let len = if let ty::Array(_, len) = ty.kind() { + len.to_leaf().to_target_usize(ecx.tcx.tcx()) + } else { + 0 + }; + ecx.write_scalar(Scalar::from_target_usize(len, ecx), dest)?; + } + sym::type_id_fields => { let ty = ecx.read_type_id(&args[0])?; let variant_idx = ecx.read_target_usize(&args[1])? as usize; 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 8d93aee57a518..f9bd6ec1b4aad 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -6,7 +6,7 @@ use rustc_abi::{ExternAbi, FieldIdx}; use rustc_hir::attrs::lang_items::LangItem; use rustc_middle::span_bug; use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{self, Const, FnHeader, FnSigKind, FnSigTys, ScalarInt, Ty, TyCtxt}; +use rustc_middle::ty::{self, FnHeader, FnSigKind, FnSigTys, ScalarInt, Ty, TyCtxt}; use rustc_span::{Symbol, sym}; use crate::const_eval::CompileTimeMachine; @@ -82,22 +82,14 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { self.write_tuple_type_info(tuple_place, fields, ty)?; variant } - ty::Array(ty, len) => { - let (variant, variant_place) = + ty::Array(_, _) => { + let (variant, _variant_place) = self.project_downcast_named(&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::Slice(ty) => { - let (variant, variant_place) = + ty::Slice(_) => { + let (variant, _variant_place) = self.project_downcast_named(&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) => { @@ -239,51 +231,6 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { ) } - 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(()) - } - - pub(crate) fn write_slice_type_info( - &mut self, - place: impl Writeable<'tcx, CtfeProvenance>, - ty: Ty<'tcx>, - ) -> InterpResult<'tcx> { - // Iterate over all fields of `type_info::Slice`. - 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 slice's elements to the `element_ty` field. - sym::element_ty => self.write_type_id(ty, &field_place)?, - other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"), - } - } - - interp_ok(()) - } - pub(crate) fn write_type_id_generics( &mut self, place: &impl Writeable<'tcx, CtfeProvenance>, diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 61f72ee4b5de1..cca93e8aef0ec 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -199,6 +199,8 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::truncf64 | sym::truncf128 | sym::type_id + | sym::type_id_array_len + | sym::type_id_element_ty | sym::type_id_eq | sym::type_id_field_representing_type | sym::type_id_fields @@ -315,6 +317,8 @@ pub(crate) fn check_intrinsic_type( sym::type_name => (1, 0, vec![], Ty::new_static_str(tcx)), sym::type_id => (1, 0, vec![], type_id_ty()), + sym::type_id_array_len => (0, 0, vec![type_id_ty()], tcx.types.usize), + sym::type_id_element_ty => (0, 0, vec![type_id_ty()], Ty::new_option(tcx, type_id_ty())), sym::type_id_eq => (0, 0, vec![type_id_ty(), type_id_ty()], tcx.types.bool), sym::type_id_field_representing_type => { (0, 0, vec![type_id_ty(), tcx.types.usize, tcx.types.usize], type_id_ty()) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 68d28f9227dbe..c8fa04e08f768 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2168,6 +2168,8 @@ symbols! { type_ascription, type_changing_struct_update, type_id, + type_id_array_len, + type_id_element_ty, type_id_eq, type_id_field_representing_type, type_id_fields, diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index f8cc81228b27b..9b55d70fecb9a 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -3009,6 +3009,22 @@ pub const fn type_id_eq(a: crate::any::TypeId, b: crate::any::TypeId) -> bool { #[rustc_comptime] pub fn type_id_is_signed(_id: crate::any::TypeId) -> bool; +/// Gets the length of the array represented by this `TypeId`. +/// +/// The more user-friendly version of this intrinsic is [`core::any::TypeId::array_len`]. +#[rustc_intrinsic] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_comptime] +pub fn type_id_array_len(_id: crate::any::TypeId) -> usize; + +/// Gets the type of each element of the array or slice represented by this `TypeId`. +/// +/// The more user-friendly version of this intrinsic is [`core::any::TypeId::element_ty`]. +#[rustc_intrinsic] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_comptime] +pub fn type_id_element_ty(_id: crate::any::TypeId) -> Option; + /// Gets the size of the type represented by this `TypeId`. /// /// The more user-friendly version of this intrinsic is [`core::any::TypeId::size`]. diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index 1f38339a7421b..a11d1f1d0dc18 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -78,9 +78,9 @@ pub enum TypeKind { /// Tuples. Tuple, /// Arrays. - Array(Array), + Array, /// Slices. - Slice(Slice), + Slice, /// Dynamic Traits. DynTrait(DynTrait), /// Structs. @@ -111,26 +111,6 @@ pub enum TypeKind { Other, } -/// 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, -} - -/// Compile-time type information about slices. -#[derive(Debug)] -#[non_exhaustive] -#[unstable(feature = "type_info", issue = "146922")] -pub struct Slice { - /// The type of each element in the slice. - pub element_ty: TypeId, -} - /// Compile-time type information about dynamic traits. /// FIXME(#146922): Add super traits and generics #[derive(Debug)] @@ -295,6 +275,44 @@ impl TypeId { intrinsics::type_id_is_signed(self) } + /// When called on a `TypeId` representing an array or slice this returns the type of each + /// element otherwise this returns `None`. + /// + /// # Examples + /// + /// ``` + /// #![feature(type_info)] + /// use std::any::TypeId; + /// + /// assert_eq!(const { TypeId::of::<[u32; 16]>().element_ty() }, Some(TypeId::of::())); + /// assert_eq!(const { TypeId::of::().element_ty() }, None); // not an array or slice + /// ``` + #[unstable(feature = "type_info", issue = "146922")] + #[rustc_const_unstable(feature = "type_info", issue = "146922")] + #[rustc_comptime] + pub fn element_ty(self) -> Option { + intrinsics::type_id_element_ty(self) + } + + /// When called on a `TypeId` representing an array this returns the length of the array in + /// all other cases this returns zero. + /// + /// # Examples + /// + /// ``` + /// #![feature(type_info)] + /// use std::any::TypeId; + /// + /// assert_eq!(const { TypeId::of::<[u32; 16]>().array_len() }, 16); + /// assert_eq!(const { TypeId::of::().array_len() }, 0); // not an array + /// ``` + #[unstable(feature = "type_info", issue = "146922")] + #[rustc_const_unstable(feature = "type_info", issue = "146922")] + #[rustc_comptime] + pub fn array_len(self) -> usize { + intrinsics::type_id_array_len(self) + } + /// Returns the size of the type represented by this `TypeId`. `None` if it is unsized. /// /// # Examples diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs index 7fe592496f1a7..865b6a269afff 100644 --- a/library/coretests/tests/mem/type_info.rs +++ b/library/coretests/tests/mem/type_info.rs @@ -7,29 +7,27 @@ use std::mem::type_info::{Const, Generic, GenericType, 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!(), + assert!(matches!(Type::of::<[u16; 4]>().kind, TypeKind::Array)); + const { + let ty_id = TypeId::of::<[u16; 4]>(); + assert!(ty_id.element_ty() == Some(TypeId::of::())); + assert!(ty_id.array_len() == 4); } // 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!(), + assert!(matches!(Type::of::<[bool; 0]>().kind, TypeKind::Array)); + const { + let ty_id = TypeId::of::<[bool; 0]>(); + assert!(ty_id.element_ty() == Some(TypeId::of::())); + assert!(ty_id.array_len() == 0); } } #[test] fn test_slices() { - match const { Type::of::<[usize]>() }.kind { - TypeKind::Slice(slice) => assert_eq!(slice.element_ty, TypeId::of::()), - _ => unreachable!(), + assert!(matches!(Type::of::<[usize]>().kind, TypeKind::Slice)); + const { + assert!(TypeId::of::<[usize]>().element_ty() == Some(TypeId::of::())); } }