Skip to content

Commit 79ec275

Browse files
committed
Support primitives in type info reflection
Support {bool,char,int,uint,float,str} primitive types for feature `type_info` reflection.
1 parent 2fd6efc commit 79ec275

15 files changed

Lines changed: 611 additions & 65 deletions

File tree

compiler/rustc_const_eval/src/const_eval/type_info.rs

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
3535

3636
interp_ok((variant_id, self.project_downcast(&field_dest, variant_id)?))
3737
};
38+
let ptr_bit_width = || self.tcx.data_layout.pointer_size().bits();
3839
match field.name {
3940
sym::kind => {
4041
let variant_index = match ty.kind() {
@@ -64,13 +65,60 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
6465

6566
variant
6667
}
67-
// For now just merge all primitives into one `Leaf` variant with no data
68-
ty::Uint(_) | ty::Int(_) | ty::Float(_) | ty::Char | ty::Bool => {
69-
downcast(sym::Leaf)?.0
68+
ty::Bool => {
69+
let (variant, variant_place) = downcast(sym::Bool)?;
70+
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
71+
self.write_primitive_type_info(place, ty, None)?;
72+
variant
73+
}
74+
ty::Char => {
75+
let (variant, variant_place) = downcast(sym::Char)?;
76+
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
77+
self.write_primitive_type_info(place, ty, None)?;
78+
variant
79+
}
80+
ty::Int(int_ty) => {
81+
let (variant, variant_place) = downcast(sym::Int)?;
82+
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
83+
self.write_primitive_type_info(
84+
place,
85+
ty,
86+
Some(
87+
int_ty
88+
.bit_width()
89+
.unwrap_or_else(/* isize */ ptr_bit_width),
90+
),
91+
)?;
92+
variant
93+
}
94+
ty::Uint(uint_ty) => {
95+
let (variant, variant_place) = downcast(sym::Uint)?;
96+
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
97+
self.write_primitive_type_info(
98+
place,
99+
ty,
100+
Some(
101+
uint_ty
102+
.bit_width()
103+
.unwrap_or_else(/* usize */ ptr_bit_width),
104+
),
105+
)?;
106+
variant
107+
}
108+
ty::Float(float_ty) => {
109+
let (variant, variant_place) = downcast(sym::Float)?;
110+
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
111+
self.write_primitive_type_info(place, ty, Some(float_ty.bit_width()))?;
112+
variant
113+
}
114+
ty::Str => {
115+
let (variant, variant_place) = downcast(sym::Str)?;
116+
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
117+
self.write_primitive_type_info(place, ty, None)?;
118+
variant
70119
}
71120
ty::Adt(_, _)
72121
| ty::Foreign(_)
73-
| ty::Str
74122
| ty::Pat(_, _)
75123
| ty::Slice(_)
76124
| ty::RawPtr(..)
@@ -203,4 +251,32 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
203251

204252
interp_ok(())
205253
}
254+
255+
// This method always writes to field `ty`.
256+
// If field `bit_width` is present, it also writes to it (in which case parameter `write_bit_width` must be `Some`).
257+
fn write_primitive_type_info(
258+
&mut self,
259+
place: impl Writeable<'tcx, CtfeProvenance>,
260+
ty: Ty<'tcx>,
261+
write_bit_width: Option<u64>,
262+
) -> InterpResult<'tcx> {
263+
for (field_idx, field) in
264+
place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
265+
{
266+
let field_place = self.project_field(&place, field_idx)?;
267+
match field.name {
268+
sym::ty => self.write_type_id(ty, &field_place)?,
269+
sym::bit_width => {
270+
let bit_width = write_bit_width
271+
.expect("type info struct needs a `bit_width` but none was provided");
272+
self.write_scalar(
273+
ScalarInt::try_from_target_usize(bit_width, self.tcx.tcx).unwrap(),
274+
&field_place,
275+
)?
276+
}
277+
other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
278+
}
279+
}
280+
interp_ok(())
281+
}
206282
}

compiler/rustc_span/src/symbol.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ symbols! {
190190
BTreeMap,
191191
BTreeSet,
192192
BinaryHeap,
193+
Bool,
193194
Borrow,
194195
BorrowMut,
195196
Break,
@@ -202,6 +203,7 @@ symbols! {
202203
Capture,
203204
Cell,
204205
Center,
206+
Char,
205207
Child,
206208
Cleanup,
207209
Clone,
@@ -238,6 +240,7 @@ symbols! {
238240
Error,
239241
File,
240242
FileType,
243+
Float,
241244
FmtArgumentsNew,
242245
FmtWrite,
243246
Fn,
@@ -263,6 +266,7 @@ symbols! {
263266
IndexOutput,
264267
Input,
265268
Instant,
269+
Int,
266270
Into,
267271
IntoFuture,
268272
IntoIterator,
@@ -285,7 +289,6 @@ symbols! {
285289
IteratorItem,
286290
IteratorMap,
287291
Layout,
288-
Leaf,
289292
Left,
290293
LinkedList,
291294
LintDiagnostic,
@@ -363,6 +366,7 @@ symbols! {
363366
Some,
364367
SpanCtxt,
365368
Stdin,
369+
Str,
366370
String,
367371
StructuralPartialEq,
368372
SubdiagMessage,
@@ -387,6 +391,7 @@ symbols! {
387391
Ty,
388392
TyCtxt,
389393
TyKind,
394+
Uint,
390395
Unknown,
391396
Unsize,
392397
UnsizedConstParamTy,
@@ -584,6 +589,7 @@ symbols! {
584589
binaryheap_iter,
585590
bind_by_move_pattern_guards,
586591
bindings_after_at,
592+
bit_width,
587593
bitand,
588594
bitand_assign,
589595
bitor,

library/core/src/mem/type_info.rs

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,18 @@ pub enum TypeKind {
4545
Tuple(Tuple),
4646
/// Arrays.
4747
Array(Array),
48-
/// Primitives
49-
/// FIXME(#146922): disambiguate further
50-
Leaf,
48+
/// Primitive boolean type.
49+
Bool(Bool),
50+
/// Primitive character type.
51+
Char(Char),
52+
/// Primitive signed integer type.
53+
Int(Int),
54+
/// Primitive unsigned integer type.
55+
Uint(Uint),
56+
/// Primitive floating-point type.
57+
Float(Float),
58+
/// String slice type.
59+
Str(Str),
5160
/// FIXME(#146922): add all the common types
5261
Other,
5362
}
@@ -82,3 +91,63 @@ pub struct Array {
8291
/// The length of the array.
8392
pub len: usize,
8493
}
94+
95+
/// Compile-time type information about `bool`.
96+
#[derive(Debug)]
97+
#[non_exhaustive]
98+
#[unstable(feature = "type_info", issue = "146922")]
99+
pub struct Bool {
100+
/// The type id of `bool`.
101+
pub ty: TypeId,
102+
}
103+
104+
/// Compile-time type information about `char`.
105+
#[derive(Debug)]
106+
#[non_exhaustive]
107+
#[unstable(feature = "type_info", issue = "146922")]
108+
pub struct Char {
109+
/// The type id of `char`.
110+
pub ty: TypeId,
111+
}
112+
113+
/// Compile-time type information about signed integer types.
114+
#[derive(Debug)]
115+
#[non_exhaustive]
116+
#[unstable(feature = "type_info", issue = "146922")]
117+
pub struct Int {
118+
/// The type id of signed integer type.
119+
pub ty: TypeId,
120+
/// The bit width of the signed integer type.
121+
pub bit_width: usize,
122+
}
123+
124+
/// Compile-time type information about unsigned integer types.
125+
#[derive(Debug)]
126+
#[non_exhaustive]
127+
#[unstable(feature = "type_info", issue = "146922")]
128+
pub struct Uint {
129+
/// The type id of unsigned integer type.
130+
pub ty: TypeId,
131+
/// The bit width of the unsigned integer type.
132+
pub bit_width: usize,
133+
}
134+
135+
/// Compile-time type information about floating-point types.
136+
#[derive(Debug)]
137+
#[non_exhaustive]
138+
#[unstable(feature = "type_info", issue = "146922")]
139+
pub struct Float {
140+
/// The type id of floating-point type.
141+
pub ty: TypeId,
142+
/// The bit width of the floating-point type.
143+
pub bit_width: usize,
144+
}
145+
146+
/// Compile-time type information about string slice types.
147+
#[derive(Debug)]
148+
#[non_exhaustive]
149+
#[unstable(feature = "type_info", issue = "146922")]
150+
pub struct Str {
151+
/// The type id of `str`.
152+
pub ty: TypeId,
153+
}

library/coretests/tests/mem/type_info.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,48 @@ fn test_tuples() {
4646
assert!(b.offset == 1);
4747

4848
match (a.ty.info().kind, b.ty.info().kind) {
49-
(TypeKind::Leaf, TypeKind::Leaf) => {}
49+
(TypeKind::Uint(a), TypeKind::Uint(b)) => {
50+
assert!(a.bit_width == 8);
51+
assert!(b.bit_width == 8);
52+
}
5053
_ => unreachable!(),
5154
}
5255
}
5356
_ => unreachable!(),
5457
}
5558
}
5659
}
60+
61+
#[test]
62+
fn test_primitives() {
63+
use TypeKind::*;
64+
65+
let Type { kind: Bool(_ty), size, .. } = (const { Type::of::<bool>() }) else { panic!() };
66+
assert_eq!(size, Some(1));
67+
68+
let Type { kind: Char(_ty), size, .. } = (const { Type::of::<char>() }) else { panic!() };
69+
assert_eq!(size, Some(4));
70+
71+
let Type { kind: Int(ty), size, .. } = (const { Type::of::<i32>() }) else { panic!() };
72+
assert_eq!(size, Some(4));
73+
assert_eq!(ty.bit_width, 32);
74+
75+
let Type { kind: Int(ty), size, .. } = (const { Type::of::<isize>() }) else { panic!() };
76+
assert_eq!(size, Some(size_of::<isize>()));
77+
assert_eq!(ty.bit_width, size_of::<isize>() * 8);
78+
79+
let Type { kind: Uint(ty), size, .. } = (const { Type::of::<u32>() }) else { panic!() };
80+
assert_eq!(size, Some(4));
81+
assert_eq!(ty.bit_width, 32);
82+
83+
let Type { kind: Uint(ty), size, .. } = (const { Type::of::<usize>() }) else { panic!() };
84+
assert_eq!(size, Some(size_of::<usize>()));
85+
assert_eq!(ty.bit_width, size_of::<usize>() * 8);
86+
87+
let Type { kind: Float(ty), size, .. } = (const { Type::of::<f32>() }) else { panic!() };
88+
assert_eq!(size, Some(4));
89+
assert_eq!(ty.bit_width, 32);
90+
91+
let Type { kind: Str(_ty), size, .. } = (const { Type::of::<str>() }) else { panic!() };
92+
assert_eq!(size, None);
93+
}

tests/mir-opt/const_prop/invalid_constant.main.GVN.diff

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
debug _enum_without_variants => const [ZeroSized: Empty];
2020
let _9: main::Str<"���">;
2121
scope 4 {
22-
debug _non_utf8_str => const Str::<"���">;
22+
debug _non_utf8_str => const main::Str::<"���">;
2323
}
2424
}
2525
}

tests/mir-opt/const_prop/invalid_constant.main.RemoveZsts.diff

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
let _9: main::Str<"���">;
2222
scope 4 {
2323
- debug _non_utf8_str => _9;
24-
+ debug _non_utf8_str => const Str::<"���">;
24+
+ debug _non_utf8_str => const main::Str::<"���">;
2525
}
2626
}
2727
}

tests/ui/lint/recommend-literal.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//~vv HELP consider importing this struct
2+
13
type Real = double;
24
//~^ ERROR cannot find type `double` in this scope
35
//~| HELP perhaps you intended to use this type

0 commit comments

Comments
 (0)