Rollup merge of #151118 - BD103:reflect-slices, r=oli-obk

Support slices in type reflection

Tracking issue: rust-lang/rust#146922

This PR adds support for inspecting slices `[T]` through type reflection. It does so by adding the new `Slice` struct + variant, which is very similar to `Array` but without the `len` field:

```rust
pub struct Slice {
    pub element_ty: TypeId,
}
```

Here is an example reflecting a slice:

```rust
match const { Type::of::<[u8]>() }.kind {
    TypeKind::Slice(slice) => assert_eq!(slice.element_ty, TypeId::of::<u8>()),
    _ => unreachable!(),
}
```

In addition to this, I also re-arranged the type info unit tests.

r? @oli-obk
This commit is contained in:
Jacob Pratt 2026-01-22 00:37:42 -05:00 committed by GitHub
commit a4cf93bccc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 59 additions and 3 deletions

View file

@ -66,6 +66,14 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
variant
}
ty::Slice(ty) => {
let (variant, variant_place) = downcast(sym::Slice)?;
let slice_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_slice_type_info(slice_place, *ty)?;
variant
}
ty::Bool => {
let (variant, _variant_place) = downcast(sym::Bool)?;
variant
@ -124,7 +132,6 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
ty::Adt(_, _)
| ty::Foreign(_)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::FnDef(..)
| ty::FnPtr(..)
| ty::UnsafeBinder(..)
@ -254,6 +261,27 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
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(())
}
fn write_int_type_info(
&mut self,
place: impl Writeable<'tcx, CtfeProvenance>,

View file

@ -362,6 +362,7 @@ symbols! {
Send,
SeqCst,
Sized,
Slice,
SliceIndex,
SliceIter,
Some,

View file

@ -45,6 +45,8 @@ pub enum TypeKind {
Tuple(Tuple),
/// Arrays.
Array(Array),
/// Slices.
Slice(Slice),
/// Primitive boolean type.
Bool(Bool),
/// Primitive character type.
@ -94,6 +96,15 @@ pub struct 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 `bool`.
#[derive(Debug)]
#[non_exhaustive]

View file

@ -22,6 +22,14 @@ fn test_arrays() {
}
}
#[test]
fn test_slices() {
match const { Type::of::<[usize]>() }.kind {
TypeKind::Slice(slice) => assert_eq!(slice.element_ty, TypeId::of::<usize>()),
_ => unreachable!(),
}
}
#[test]
fn test_tuples() {
fn assert_tuple_arity<T: 'static, const N: usize>() {

View file

@ -194,7 +194,11 @@ Type {
size: None,
}
Type {
kind: Other,
kind: Slice(
Slice {
element_ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
},
),
size: None,
}
Type {

View file

@ -194,7 +194,11 @@ Type {
size: None,
}
Type {
kind: Other,
kind: Slice(
Slice {
element_ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
},
),
size: None,
}
Type {