Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion compiler/rustc_const_eval/src/const_eval/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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;
Expand Down
63 changes: 5 additions & 58 deletions compiler/rustc_const_eval/src/const_eval/type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -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>,
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_hir_analysis/src/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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())
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
16 changes: 16 additions & 0 deletions library/core/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<crate::any::TypeId>;

/// Gets the size of the type represented by this `TypeId`.
///
/// The more user-friendly version of this intrinsic is [`core::any::TypeId::size`].
Expand Down
62 changes: 40 additions & 22 deletions library/core/src/mem/type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ pub enum TypeKind {
/// Tuples.
Tuple,
/// Arrays.
Array(Array),
Array,
/// Slices.
Slice(Slice),
Slice,
/// Dynamic Traits.
DynTrait(DynTrait),
/// Structs.
Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -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::<u32>()));
/// assert_eq!(const { TypeId::of::<u8>().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<TypeId> {
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::<u8>().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
Expand Down
28 changes: 13 additions & 15 deletions library/coretests/tests/mem/type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<u16>());
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::<u16>()));
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::<bool>());
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::<bool>()));
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::<usize>()),
_ => unreachable!(),
assert!(matches!(Type::of::<[usize]>().kind, TypeKind::Slice));
const {
assert!(TypeId::of::<[usize]>().element_ty() == Some(TypeId::of::<usize>()));
}
}

Expand Down
Loading