Support primitives in type info reflection

Support {bool,char,int,uint,float,str} primitive types for feature
`type_info` reflection.
This commit is contained in:
Asuna 2026-01-14 17:00:22 +01:00
parent 2fd6efc327
commit 79ec275e2d
15 changed files with 612 additions and 66 deletions

View file

@ -35,6 +35,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
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() {
@ -64,13 +65,60 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
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
ty::Bool => {
let (variant, variant_place) = downcast(sym::Bool)?;
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_primitive_type_info(place, ty, None)?;
variant
}
ty::Char => {
let (variant, variant_place) = downcast(sym::Char)?;
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_primitive_type_info(place, ty, None)?;
variant
}
ty::Int(int_ty) => {
let (variant, variant_place) = downcast(sym::Int)?;
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_primitive_type_info(
place,
ty,
Some(
int_ty
.bit_width()
.unwrap_or_else(/* isize */ ptr_bit_width),
),
)?;
variant
}
ty::Uint(uint_ty) => {
let (variant, variant_place) = downcast(sym::Uint)?;
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_primitive_type_info(
place,
ty,
Some(
uint_ty
.bit_width()
.unwrap_or_else(/* usize */ ptr_bit_width),
),
)?;
variant
}
ty::Float(float_ty) => {
let (variant, variant_place) = downcast(sym::Float)?;
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_primitive_type_info(place, ty, Some(float_ty.bit_width()))?;
variant
}
ty::Str => {
let (variant, variant_place) = downcast(sym::Str)?;
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_primitive_type_info(place, ty, None)?;
variant
}
ty::Adt(_, _)
| ty::Foreign(_)
| ty::Str
| ty::Pat(_, _)
| ty::Slice(_)
| ty::RawPtr(..)
@ -203,4 +251,32 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
interp_ok(())
}
// This method always writes to field `ty`.
// If field `bit_width` is present, it also writes to it (in which case parameter `write_bit_width` must be `Some`).
fn write_primitive_type_info(
&mut self,
place: impl Writeable<'tcx, CtfeProvenance>,
ty: Ty<'tcx>,
write_bit_width: Option<u64>,
) -> InterpResult<'tcx> {
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::ty => self.write_type_id(ty, &field_place)?,
sym::bit_width => {
let bit_width = write_bit_width
.expect("type info struct needs a `bit_width` but none was provided");
self.write_scalar(
ScalarInt::try_from_target_usize(bit_width, self.tcx.tcx).unwrap(),
&field_place,
)?
}
other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
}
}
interp_ok(())
}
}

View file

@ -190,6 +190,7 @@ symbols! {
BTreeMap,
BTreeSet,
BinaryHeap,
Bool,
Borrow,
BorrowMut,
Break,
@ -202,6 +203,7 @@ symbols! {
Capture,
Cell,
Center,
Char,
Child,
Cleanup,
Clone,
@ -238,6 +240,7 @@ symbols! {
Error,
File,
FileType,
Float,
FmtArgumentsNew,
FmtWrite,
Fn,
@ -263,6 +266,7 @@ symbols! {
IndexOutput,
Input,
Instant,
Int,
Into,
IntoFuture,
IntoIterator,
@ -285,7 +289,6 @@ symbols! {
IteratorItem,
IteratorMap,
Layout,
Leaf,
Left,
LinkedList,
LintDiagnostic,
@ -363,6 +366,7 @@ symbols! {
Some,
SpanCtxt,
Stdin,
Str,
String,
StructuralPartialEq,
SubdiagMessage,
@ -387,6 +391,7 @@ symbols! {
Ty,
TyCtxt,
TyKind,
Uint,
Unknown,
Unsize,
UnsizedConstParamTy,
@ -584,6 +589,7 @@ symbols! {
binaryheap_iter,
bind_by_move_pattern_guards,
bindings_after_at,
bit_width,
bitand,
bitand_assign,
bitor,

View file

@ -45,9 +45,18 @@ pub enum TypeKind {
Tuple(Tuple),
/// Arrays.
Array(Array),
/// Primitives
/// FIXME(#146922): disambiguate further
Leaf,
/// Primitive boolean type.
Bool(Bool),
/// Primitive character type.
Char(Char),
/// Primitive signed integer type.
Int(Int),
/// Primitive unsigned integer type.
Uint(Uint),
/// Primitive floating-point type.
Float(Float),
/// String slice type.
Str(Str),
/// FIXME(#146922): add all the common types
Other,
}
@ -82,3 +91,63 @@ pub struct Array {
/// The length of the array.
pub len: usize,
}
/// Compile-time type information about `bool`.
#[derive(Debug)]
#[non_exhaustive]
#[unstable(feature = "type_info", issue = "146922")]
pub struct Bool {
/// The type id of `bool`.
pub ty: TypeId,
}
/// Compile-time type information about `char`.
#[derive(Debug)]
#[non_exhaustive]
#[unstable(feature = "type_info", issue = "146922")]
pub struct Char {
/// The type id of `char`.
pub ty: TypeId,
}
/// Compile-time type information about signed integer types.
#[derive(Debug)]
#[non_exhaustive]
#[unstable(feature = "type_info", issue = "146922")]
pub struct Int {
/// The type id of signed integer type.
pub ty: TypeId,
/// The bit width of the signed integer type.
pub bit_width: usize,
}
/// Compile-time type information about unsigned integer types.
#[derive(Debug)]
#[non_exhaustive]
#[unstable(feature = "type_info", issue = "146922")]
pub struct Uint {
/// The type id of unsigned integer type.
pub ty: TypeId,
/// The bit width of the unsigned integer type.
pub bit_width: usize,
}
/// Compile-time type information about floating-point types.
#[derive(Debug)]
#[non_exhaustive]
#[unstable(feature = "type_info", issue = "146922")]
pub struct Float {
/// The type id of floating-point type.
pub ty: TypeId,
/// The bit width of the floating-point type.
pub bit_width: usize,
}
/// Compile-time type information about string slice types.
#[derive(Debug)]
#[non_exhaustive]
#[unstable(feature = "type_info", issue = "146922")]
pub struct Str {
/// The type id of `str`.
pub ty: TypeId,
}

View file

@ -46,7 +46,10 @@ fn test_tuples() {
assert!(b.offset == 1);
match (a.ty.info().kind, b.ty.info().kind) {
(TypeKind::Leaf, TypeKind::Leaf) => {}
(TypeKind::Uint(a), TypeKind::Uint(b)) => {
assert!(a.bit_width == 8);
assert!(b.bit_width == 8);
}
_ => unreachable!(),
}
}
@ -54,3 +57,37 @@ fn test_tuples() {
}
}
}
#[test]
fn test_primitives() {
use TypeKind::*;
let Type { kind: Bool(_ty), size, .. } = (const { Type::of::<bool>() }) else { panic!() };
assert_eq!(size, Some(1));
let Type { kind: Char(_ty), size, .. } = (const { Type::of::<char>() }) else { panic!() };
assert_eq!(size, Some(4));
let Type { kind: Int(ty), size, .. } = (const { Type::of::<i32>() }) else { panic!() };
assert_eq!(size, Some(4));
assert_eq!(ty.bit_width, 32);
let Type { kind: Int(ty), size, .. } = (const { Type::of::<isize>() }) else { panic!() };
assert_eq!(size, Some(size_of::<isize>()));
assert_eq!(ty.bit_width, size_of::<isize>() * 8);
let Type { kind: Uint(ty), size, .. } = (const { Type::of::<u32>() }) else { panic!() };
assert_eq!(size, Some(4));
assert_eq!(ty.bit_width, 32);
let Type { kind: Uint(ty), size, .. } = (const { Type::of::<usize>() }) else { panic!() };
assert_eq!(size, Some(size_of::<usize>()));
assert_eq!(ty.bit_width, size_of::<usize>() * 8);
let Type { kind: Float(ty), size, .. } = (const { Type::of::<f32>() }) else { panic!() };
assert_eq!(size, Some(4));
assert_eq!(ty.bit_width, 32);
let Type { kind: Str(_ty), size, .. } = (const { Type::of::<str>() }) else { panic!() };
assert_eq!(size, None);
}

View file

@ -19,7 +19,7 @@
debug _enum_without_variants => const [ZeroSized: Empty];
let _9: main::Str<"<22><><EFBFBD>">;
scope 4 {
debug _non_utf8_str => const Str::<"<22><><EFBFBD>">;
debug _non_utf8_str => const main::Str::<"<22><><EFBFBD>">;
}
}
}

View file

@ -21,7 +21,7 @@
let _9: main::Str<"<22><><EFBFBD>">;
scope 4 {
- debug _non_utf8_str => _9;
+ debug _non_utf8_str => const Str::<"<22><><EFBFBD>">;
+ debug _non_utf8_str => const main::Str::<"<22><><EFBFBD>">;
}
}
}

View file

@ -1,3 +1,5 @@
//~vv HELP consider importing this struct
type Real = double;
//~^ ERROR cannot find type `double` in this scope
//~| HELP perhaps you intended to use this type

View file

@ -1,5 +1,5 @@
error[E0425]: cannot find type `double` in this scope
--> $DIR/recommend-literal.rs:1:13
--> $DIR/recommend-literal.rs:3:13
|
LL | type Real = double;
| ^^^^^^
@ -8,7 +8,7 @@ LL | type Real = double;
| help: perhaps you intended to use this type: `f64`
error[E0425]: cannot find type `long` in this scope
--> $DIR/recommend-literal.rs:7:12
--> $DIR/recommend-literal.rs:9:12
|
LL | let y: long = 74802374902374923;
| ^^^^
@ -17,7 +17,7 @@ LL | let y: long = 74802374902374923;
| help: perhaps you intended to use this type: `i64`
error[E0425]: cannot find type `Boolean` in this scope
--> $DIR/recommend-literal.rs:10:13
--> $DIR/recommend-literal.rs:12:13
|
LL | let v1: Boolean = true;
| ^^^^^^^
@ -26,7 +26,7 @@ LL | let v1: Boolean = true;
| help: perhaps you intended to use this type: `bool`
error[E0425]: cannot find type `Bool` in this scope
--> $DIR/recommend-literal.rs:13:13
--> $DIR/recommend-literal.rs:15:13
|
LL | let v2: Bool = true;
| ^^^^
@ -41,9 +41,13 @@ help: perhaps you intended to use this type
LL - let v2: Bool = true;
LL + let v2: bool = true;
|
help: consider importing this struct
|
LL + use std::mem::type_info::Bool;
|
error[E0425]: cannot find type `boolean` in this scope
--> $DIR/recommend-literal.rs:19:9
--> $DIR/recommend-literal.rs:21:9
|
LL | fn z(a: boolean) {
| ^^^^^^^
@ -52,7 +56,7 @@ LL | fn z(a: boolean) {
| help: perhaps you intended to use this type: `bool`
error[E0425]: cannot find type `byte` in this scope
--> $DIR/recommend-literal.rs:24:11
--> $DIR/recommend-literal.rs:26:11
|
LL | fn a() -> byte {
| ^^^^
@ -61,7 +65,7 @@ LL | fn a() -> byte {
| help: perhaps you intended to use this type: `u8`
error[E0425]: cannot find type `float` in this scope
--> $DIR/recommend-literal.rs:31:12
--> $DIR/recommend-literal.rs:33:12
|
LL | width: float,
| ^^^^^
@ -70,7 +74,7 @@ LL | width: float,
| help: perhaps you intended to use this type: `f32`
error[E0425]: cannot find type `int` in this scope
--> $DIR/recommend-literal.rs:34:19
--> $DIR/recommend-literal.rs:36:19
|
LL | depth: Option<int>,
| ^^^ not found in this scope
@ -86,7 +90,7 @@ LL | struct Data<int> {
| +++++
error[E0425]: cannot find type `short` in this scope
--> $DIR/recommend-literal.rs:40:16
--> $DIR/recommend-literal.rs:42:16
|
LL | impl Stuff for short {}
| ^^^^^

View file

@ -0,0 +1,186 @@
Type {
kind: Tuple(
Tuple {
fields: [
Field {
ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
offset: 0,
},
Field {
ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
offset: 1,
},
Field {
ty: TypeId(0x41223169ff28813ba79b7268a2a968d9),
offset: 2,
},
],
},
),
size: Some(
2,
),
}
Type {
kind: Array(
Array {
element_ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
len: 2,
},
),
size: Some(
2,
),
}
Type {
kind: Int(
Int {
ty: TypeId(0x12427c993eca190c841e0d92c5b7a45d),
bit_width: 8,
},
),
size: Some(
1,
),
}
Type {
kind: Int(
Int {
ty: TypeId(0x56ced5e4a15bd89050bb9674fa2df013),
bit_width: 32,
},
),
size: Some(
4,
),
}
Type {
kind: Int(
Int {
ty: TypeId(0xae6c4318bb07632e00428affbea41961),
bit_width: 64,
},
),
size: Some(
8,
),
}
Type {
kind: Int(
Int {
ty: TypeId(0xc7164498f3902dde0d8194a7b9733e79),
bit_width: 128,
},
),
size: Some(
16,
),
}
Type {
kind: Int(
Int {
ty: TypeId(0x1e5f92831c560aac8658b980a22e60b0),
bit_width: 32,
},
),
size: Some(
4,
),
}
Type {
kind: Uint(
Uint {
ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
bit_width: 8,
},
),
size: Some(
1,
),
}
Type {
kind: Uint(
Uint {
ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7),
bit_width: 32,
},
),
size: Some(
4,
),
}
Type {
kind: Uint(
Uint {
ty: TypeId(0x9ed91be891e304132cb86891e578f4a5),
bit_width: 64,
},
),
size: Some(
8,
),
}
Type {
kind: Uint(
Uint {
ty: TypeId(0x7bf7411d57d603e9fb393892a9c3f362),
bit_width: 128,
},
),
size: Some(
16,
),
}
Type {
kind: Uint(
Uint {
ty: TypeId(0x763d199bccd319899208909ed1a860c6),
bit_width: 32,
},
),
size: Some(
4,
),
}
Type {
kind: Other,
size: Some(
4,
),
}
Type {
kind: Other,
size: Some(
12,
),
}
Type {
kind: Other,
size: Some(
8,
),
}
Type {
kind: Other,
size: Some(
8,
),
}
Type {
kind: Other,
size: Some(
8,
),
}
Type {
kind: Str(
Str {
ty: TypeId(0x474ccf3b5db264ef53916706f7d7bb2c),
},
),
size: None,
}
Type {
kind: Other,
size: None,
}

View file

@ -0,0 +1,186 @@
Type {
kind: Tuple(
Tuple {
fields: [
Field {
ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
offset: 0,
},
Field {
ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
offset: 1,
},
Field {
ty: TypeId(0x41223169ff28813ba79b7268a2a968d9),
offset: 2,
},
],
},
),
size: Some(
2,
),
}
Type {
kind: Array(
Array {
element_ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
len: 2,
},
),
size: Some(
2,
),
}
Type {
kind: Int(
Int {
ty: TypeId(0x12427c993eca190c841e0d92c5b7a45d),
bit_width: 8,
},
),
size: Some(
1,
),
}
Type {
kind: Int(
Int {
ty: TypeId(0x56ced5e4a15bd89050bb9674fa2df013),
bit_width: 32,
},
),
size: Some(
4,
),
}
Type {
kind: Int(
Int {
ty: TypeId(0xae6c4318bb07632e00428affbea41961),
bit_width: 64,
},
),
size: Some(
8,
),
}
Type {
kind: Int(
Int {
ty: TypeId(0xc7164498f3902dde0d8194a7b9733e79),
bit_width: 128,
},
),
size: Some(
16,
),
}
Type {
kind: Int(
Int {
ty: TypeId(0x1e5f92831c560aac8658b980a22e60b0),
bit_width: 64,
},
),
size: Some(
8,
),
}
Type {
kind: Uint(
Uint {
ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
bit_width: 8,
},
),
size: Some(
1,
),
}
Type {
kind: Uint(
Uint {
ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7),
bit_width: 32,
},
),
size: Some(
4,
),
}
Type {
kind: Uint(
Uint {
ty: TypeId(0x9ed91be891e304132cb86891e578f4a5),
bit_width: 64,
},
),
size: Some(
8,
),
}
Type {
kind: Uint(
Uint {
ty: TypeId(0x7bf7411d57d603e9fb393892a9c3f362),
bit_width: 128,
},
),
size: Some(
16,
),
}
Type {
kind: Uint(
Uint {
ty: TypeId(0x763d199bccd319899208909ed1a860c6),
bit_width: 64,
},
),
size: Some(
8,
),
}
Type {
kind: Other,
size: Some(
4,
),
}
Type {
kind: Other,
size: Some(
24,
),
}
Type {
kind: Other,
size: Some(
16,
),
}
Type {
kind: Other,
size: Some(
16,
),
}
Type {
kind: Other,
size: Some(
16,
),
}
Type {
kind: Str(
Str {
ty: TypeId(0x474ccf3b5db264ef53916706f7d7bb2c),
},
),
size: None,
}
Type {
kind: Other,
size: None,
}

View file

@ -1,6 +1,11 @@
#![feature(type_info)]
// Some types whose length depends on the target pointer length will be dumped.
//@ revisions: bit32 bit64
//@[bit32] only-32bit
//@[bit64] only-64bit
//@ run-pass
//@ check-run-results
#![feature(type_info)]
#![allow(dead_code)]
use std::mem::type_info::Type;
@ -20,14 +25,20 @@ struct Unsized {
s: str,
}
fn main() {
println!("{:#?}", const { Type::of::<(u8, u8, ())>() }.kind);
println!("{:#?}", const { Type::of::<[u8; 2]>() }.kind);
println!("{:#?}", const { Type::of::<Foo>() }.kind);
println!("{:#?}", const { Type::of::<Bar>() }.kind);
println!("{:#?}", const { Type::of::<&Unsized>() }.kind);
println!("{:#?}", const { Type::of::<&str>() }.kind);
println!("{:#?}", const { Type::of::<&[u8]>() }.kind);
println!("{:#?}", const { Type::of::<str>() }.kind);
println!("{:#?}", const { Type::of::<[u8]>() }.kind);
macro_rules! dump_types {
($($ty:ty),+ $(,)?) => {
$(println!("{:#?}", const { Type::of::<$ty>() });)+
};
}
fn main() {
dump_types! {
(u8, u8, ()),
[u8; 2],
i8, i32, i64, i128, isize,
u8, u32, u64, u128, usize,
Foo, Bar,
&Unsized, &str, &[u8],
str, [u8],
}
}

View file

@ -1,31 +0,0 @@
Tuple(
Tuple {
fields: [
Field {
ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
offset: 0,
},
Field {
ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
offset: 1,
},
Field {
ty: TypeId(0x41223169ff28813ba79b7268a2a968d9),
offset: 2,
},
],
},
)
Array(
Array {
element_ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb),
len: 2,
},
)
Other
Other
Other
Other
Other
Other
Other

View file

@ -21,14 +21,14 @@ LL | .collect::<String>();
|
= help: the trait `FromIterator<()>` is not implemented for `String`
= help: the following other types implement trait `FromIterator<A>`:
`String` implements `FromIterator<&Char>`
`String` implements `FromIterator<&char>`
`String` implements `FromIterator<&std::ascii::Char>`
`String` implements `FromIterator<&str>`
`String` implements `FromIterator<Box<str, A>>`
`String` implements `FromIterator<Char>`
`String` implements `FromIterator<Cow<'_, str>>`
`String` implements `FromIterator<String>`
`String` implements `FromIterator<char>`
`String` implements `FromIterator<std::ascii::Char>`
note: the method call chain might not have had the expected associated types
--> $DIR/semi-suggestion-when-stmt-and-expr-span-equal.rs:20:10
|

View file

@ -44,10 +44,10 @@ LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect(
| type must be known at this point
|
= note: multiple `impl`s satisfying `u32: From<_>` found in the `core` crate:
- impl From<Char> for u32;
- impl From<Ipv4Addr> for u32;
- impl From<bool> for u32;
- impl From<char> for u32;
- impl From<std::ascii::Char> for u32;
- impl From<u16> for u32;
- impl From<u8> for u32;
help: try using a fully qualified path to specify the expected types

View file

@ -18,7 +18,7 @@ help: the following other types implement trait `From<T>`
= note: in this macro invocation
--> $SRC_DIR/core/src/ascii/ascii_char.rs:LL:COL
|
= note: `u8` implements `From<Char>`
= note: `u8` implements `From<std::ascii::Char>`
::: $SRC_DIR/core/src/ascii/ascii_char.rs:LL:COL
|
= note: in this macro invocation