Skip to content

Commit e50e5d9

Browse files
committed
Add generics info for structs in type info
1 parent b7b56a9 commit e50e5d9

File tree

11 files changed

+297
-10
lines changed

11 files changed

+297
-10
lines changed

compiler/rustc_const_eval/src/const_eval/type_info.rs

Lines changed: 109 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ use rustc_abi::{FieldIdx, VariantIdx};
44
use rustc_ast::Mutability;
55
use rustc_hir::LangItem;
66
use rustc_middle::mir::interpret::{CtfeProvenance, Scalar};
7-
use rustc_middle::span_bug;
87
use rustc_middle::ty::layout::TyAndLayout;
9-
use rustc_middle::ty::{self, AdtDef, AdtKind, Const, GenericArgs, ScalarInt, Ty, VariantDef};
8+
use rustc_middle::ty::{
9+
self, AdtDef, AdtKind, Const, ConstKind, GenericArgKind, GenericArgs, Region, ScalarInt, Ty,
10+
VariantDef,
11+
};
12+
use rustc_middle::{bug, span_bug};
1013
use rustc_span::{Symbol, sym};
1114

1215
use crate::const_eval::CompileTimeMachine;
@@ -30,6 +33,37 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
3033
interp_ok((variant_id, self.project_downcast(place, variant_id)?))
3134
}
3235

36+
// A general method to write an array to a static slice place.
37+
fn project_write_array(
38+
&mut self,
39+
slice_place: impl Writeable<'tcx, CtfeProvenance>,
40+
len: usize,
41+
writer: impl Fn(&mut Self, /* index */ usize, MPlaceTy<'tcx>) -> InterpResult<'tcx>,
42+
) -> InterpResult<'tcx> {
43+
// Array element type
44+
let field_ty = slice_place
45+
.layout()
46+
.ty
47+
.builtin_deref(false)
48+
.unwrap()
49+
.sequence_element_type(self.tcx.tcx);
50+
51+
// Allocate an array
52+
let array_layout = self.layout_of(Ty::new_array(self.tcx.tcx, field_ty, len as u64))?;
53+
let array_place = self.allocate(array_layout, MemoryKind::Stack)?;
54+
55+
// Fill the array fields
56+
let mut field_places = self.project_array_fields(&array_place)?;
57+
while let Some((i, place)) = field_places.next(self)? {
58+
writer(self, i as usize, place)?;
59+
}
60+
61+
// Write the slice pointing to the array
62+
let array_place = array_place.map_provenance(CtfeProvenance::as_immutable);
63+
let ptr = Immediate::new_slice(array_place.ptr(), len as u64, self);
64+
self.write_immediate(ptr, &slice_place)
65+
}
66+
3367
/// Writes a `core::mem::type_info::TypeInfo` for a given type, `ty` to the given place.
3468
pub(crate) fn write_type_info(
3569
&mut self,
@@ -183,6 +217,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
183217
interp_ok(())
184218
}
185219

220+
// TODO(type_info): Remove this method, use `project_write_array` as it's more general.
186221
pub(crate) fn write_tuple_fields(
187222
&mut self,
188223
tuple_place: impl Writeable<'tcx, CtfeProvenance>,
@@ -314,6 +349,18 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
314349
let field_place = self.project_field(&place, field_idx)?;
315350

316351
match field.name {
352+
sym::generics => {
353+
self.project_write_array(field_place, generics.len(), |this, i, place| {
354+
match generics[i].kind() {
355+
GenericArgKind::Lifetime(region) => {
356+
this.write_generic_lifetime(region, place)
357+
}
358+
GenericArgKind::Type(ty) => this.write_generic_type(ty, place),
359+
GenericArgKind::Const(c) => this.write_generic_const(c, place),
360+
}
361+
})?;
362+
}
363+
// TODO(type_info): Use method `project_write_array` as it's more general.
317364
sym::fields => {
318365
let fields_slice_place = field_place;
319366
let field_type = fields_slice_place
@@ -356,6 +403,66 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
356403
interp_ok(())
357404
}
358405

406+
fn write_generic_lifetime(
407+
&mut self,
408+
_region: Region<'tcx>,
409+
place: MPlaceTy<'tcx>,
410+
) -> InterpResult<'tcx> {
411+
let (variant_idx, _) = self.downcast(&place, sym::Lifetime)?;
412+
self.write_discriminant(variant_idx, &place)?;
413+
interp_ok(())
414+
}
415+
416+
fn write_generic_type(&mut self, ty: Ty<'tcx>, place: MPlaceTy<'tcx>) -> InterpResult<'tcx> {
417+
let (variant_idx, variant_place) = self.downcast(&place, sym::Type)?;
418+
let generic_type_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
419+
420+
for (field_idx, field_def) in generic_type_place
421+
.layout()
422+
.ty
423+
.ty_adt_def()
424+
.unwrap()
425+
.non_enum_variant()
426+
.fields
427+
.iter_enumerated()
428+
{
429+
let field_place = self.project_field(&generic_type_place, field_idx)?;
430+
match field_def.name {
431+
sym::ty => self.write_type_id(ty, &field_place)?,
432+
other => span_bug!(self.tcx.def_span(field_def.did), "unimplemented field {other}"),
433+
}
434+
}
435+
436+
self.write_discriminant(variant_idx, &place)?;
437+
interp_ok(())
438+
}
439+
440+
fn write_generic_const(&mut self, c: Const<'tcx>, place: MPlaceTy<'tcx>) -> InterpResult<'tcx> {
441+
let ConstKind::Value(c) = c.kind() else { bug!("expected a computed const, got {c:?}") };
442+
443+
let (variant_idx, variant_place) = self.downcast(&place, sym::Const)?;
444+
let const_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
445+
446+
for (field_idx, field_def) in const_place
447+
.layout()
448+
.ty
449+
.ty_adt_def()
450+
.unwrap()
451+
.non_enum_variant()
452+
.fields
453+
.iter_enumerated()
454+
{
455+
let field_place = self.project_field(&const_place, field_idx)?;
456+
match field_def.name {
457+
sym::ty => self.write_type_id(c.ty, &field_place)?,
458+
other => span_bug!(self.tcx.def_span(field_def.did), "unimplemented field {other}"),
459+
}
460+
}
461+
462+
self.write_discriminant(variant_idx, &place)?;
463+
interp_ok(())
464+
}
465+
359466
fn write_int_type_info(
360467
&mut self,
361468
place: impl Writeable<'tcx, CtfeProvenance>,

compiler/rustc_span/src/symbol.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ symbols! {
211211
CoercePointeeValidated,
212212
CoerceUnsized,
213213
Command,
214+
Const,
214215
ConstParamTy,
215216
ConstParamTy_,
216217
Context,
@@ -290,6 +291,7 @@ symbols! {
290291
IteratorMap,
291292
Layout,
292293
Left,
294+
Lifetime,
293295
LinkedList,
294296
LintDiagnostic,
295297
LintPass,
@@ -393,6 +395,7 @@ symbols! {
393395
Ty,
394396
TyCtxt,
395397
TyKind,
398+
Type,
396399
Unknown,
397400
Unsize,
398401
UnsizedConstParamTy,
@@ -1080,8 +1083,8 @@ symbols! {
10801083
ffi_pure,
10811084
ffi_returns_twice,
10821085
field,
1083-
fields,
10841086
field_init_shorthand,
1087+
fields,
10851088
file,
10861089
file_options,
10871090
flags,
@@ -1170,6 +1173,7 @@ symbols! {
11701173
generic_const_parameter_types,
11711174
generic_param_attrs,
11721175
generic_pattern_types,
1176+
generics,
11731177
get_context,
11741178
global_alloc_ty,
11751179
global_allocator,

library/core/src/mem/type_info.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,53 @@ pub struct Array {
101101
#[non_exhaustive]
102102
#[unstable(feature = "type_info", issue = "146922")]
103103
pub struct Struct {
104+
/// Instantiated generics of the struct.
105+
pub generics: &'static [Generic],
104106
/// All fields of the struct.
105107
pub fields: &'static [Field],
106108
/// Whether the struct is non-exhaustive.
107109
pub non_exhaustive: bool,
108110
}
109111

112+
/// Compile-time type information about instantiated generics of structs, enum and union variants.
113+
#[derive(Debug)]
114+
#[non_exhaustive]
115+
#[unstable(feature = "type_info", issue = "146922")]
116+
pub enum Generic {
117+
/// Lifetimes.
118+
Lifetime(Lifetime),
119+
/// Types.
120+
Type(GenericType),
121+
/// Const parameters.
122+
Const(Const),
123+
}
124+
125+
/// Compile-time type information about generic lifetimes.
126+
#[derive(Debug)]
127+
#[non_exhaustive]
128+
#[unstable(feature = "type_info", issue = "146922")]
129+
pub struct Lifetime {
130+
// No additional information to provide for now.
131+
}
132+
133+
/// Compile-time type information about instantiated generic types.
134+
#[derive(Debug)]
135+
#[non_exhaustive]
136+
#[unstable(feature = "type_info", issue = "146922")]
137+
pub struct GenericType {
138+
/// The const's type.
139+
pub ty: TypeId,
140+
}
141+
142+
/// Compile-time type information about generic const parameters.
143+
#[derive(Debug)]
144+
#[non_exhaustive]
145+
#[unstable(feature = "type_info", issue = "146922")]
146+
pub struct Const {
147+
/// The const's type.
148+
pub ty: TypeId,
149+
}
150+
110151
/// Compile-time type information about `bool`.
111152
#[derive(Debug)]
112153
#[non_exhaustive]

library/coretests/tests/mem/type_info.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ fn test_structs() {
7171
a: u8,
7272
}
7373
struct TupleStruct(u8, u16);
74+
struct Generics<'a, A, B, const C: u64> {
75+
a: A,
76+
b: B,
77+
l: &'a (), // FIXME(type_info): offset of this field is dumped as 0, which may not be correct
78+
}
7479

7580
let Type { kind: Struct(ty), size, .. } = (const { Type::of::<TestStruct>() }) else {
7681
panic!()
@@ -93,6 +98,20 @@ fn test_structs() {
9398
assert_eq!(ty.fields.len(), 2);
9499
assert_eq!(ty.fields[0].name, "0");
95100
assert_eq!(ty.fields[1].name, "1");
101+
102+
let Type { kind: Struct(ty), size, .. } =
103+
(const { Type::of::<Generics<'static, i32, u32, 1>>() })
104+
else {
105+
panic!()
106+
};
107+
assert_eq!(ty.fields.len(), 3);
108+
let Generic::Lifetime(_) = ty.generics[0] else { panic!() };
109+
let Generic::Type(GenericType { ty: generic_ty }) = ty.generics[1] else { panic!() };
110+
let TypeKind::Int(generic_ty) = generic_ty.info().kind else { panic!() };
111+
assert_eq!(generic_ty.bits, 32);
112+
let Generic::Type(GenericType { ty: generic_ty }) = ty.generics[2] else { panic!() };
113+
let TypeKind::Int(generic_ty) = generic_ty.info().kind else { panic!() };
114+
assert_eq!(generic_ty.bits, 32);
96115
}
97116

98117
#[test]

tests/ui/generics/wrong-number-of-args.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ mod r#trait {
127127
//~| HELP remove
128128

129129
type D = Box<dyn GenericType>;
130-
//~^ ERROR missing generics for trait `GenericType`
130+
//~^ ERROR missing generics for trait `r#trait::GenericType`
131131
//~| HELP add missing
132132

133133
type E = Box<dyn GenericType<String, usize>>;

tests/ui/generics/wrong-number-of-args.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ note: trait defined here, with 1 lifetime parameter: `'a`
469469
LL | trait GenericLifetime<'a> {
470470
| ^^^^^^^^^^^^^^^ --
471471

472-
error[E0107]: missing generics for trait `GenericType`
472+
error[E0107]: missing generics for trait `r#trait::GenericType`
473473
--> $DIR/wrong-number-of-args.rs:129:22
474474
|
475475
LL | type D = Box<dyn GenericType>;

tests/ui/missing-trait-bounds/issue-69725.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
error[E0599]: the method `clone` exists for struct `Struct<A>`, but its trait bounds were not satisfied
1+
error[E0599]: the method `clone` exists for struct `issue_69725::Struct<A>`, but its trait bounds were not satisfied
22
--> $DIR/issue-69725.rs:9:32
33
|
44
LL | let _ = Struct::<A>::new().clone();
5-
| ^^^^^ method cannot be called on `Struct<A>` due to unsatisfied trait bounds
5+
| ^^^^^ method cannot be called on `issue_69725::Struct<A>` due to unsatisfied trait bounds
66
|
77
::: $DIR/auxiliary/issue-69725.rs:2:1
88
|
99
LL | pub struct Struct<A>(A);
10-
| -------------------- doesn't satisfy `Struct<A>: Clone`
10+
| -------------------- doesn't satisfy `issue_69725::Struct<A>: Clone`
1111
|
1212
= note: the following trait bounds were not satisfied:
1313
`A: Clone`
14-
which is required by `Struct<A>: Clone`
14+
which is required by `issue_69725::Struct<A>: Clone`
1515
help: consider restricting the type parameter to satisfy the trait bound
1616
|
1717
LL | fn crash<A>() where A: Clone {

tests/ui/reflection/dump.bit32.run.stdout

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ Type {
148148
Type {
149149
kind: Struct(
150150
Struct {
151+
generics: [],
151152
fields: [
152153
Field {
153154
name: "a",
@@ -171,6 +172,7 @@ Type {
171172
Type {
172173
kind: Struct(
173174
Struct {
175+
generics: [],
174176
fields: [
175177
Field {
176178
name: "a",
@@ -188,6 +190,7 @@ Type {
188190
Type {
189191
kind: Struct(
190192
Struct {
193+
generics: [],
191194
fields: [
192195
Field {
193196
name: "0",
@@ -207,6 +210,53 @@ Type {
207210
12,
208211
),
209212
}
213+
Type {
214+
kind: Struct(
215+
Struct {
216+
generics: [
217+
Lifetime(
218+
Lifetime,
219+
),
220+
Type(
221+
GenericType {
222+
ty: TypeId(0x56ced5e4a15bd89050bb9674fa2df013),
223+
},
224+
),
225+
Type(
226+
GenericType {
227+
ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7),
228+
},
229+
),
230+
Const(
231+
Const {
232+
ty: TypeId(0x9ed91be891e304132cb86891e578f4a5),
233+
},
234+
),
235+
],
236+
fields: [
237+
Field {
238+
name: "a",
239+
ty: TypeId(0x56ced5e4a15bd89050bb9674fa2df013),
240+
offset: 4,
241+
},
242+
Field {
243+
name: "b",
244+
ty: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7),
245+
offset: 8,
246+
},
247+
Field {
248+
name: "l",
249+
ty: TypeId(0x5d686ae9be5f6232dca1f88c0b941fd9),
250+
offset: 0,
251+
},
252+
],
253+
non_exhaustive: false,
254+
},
255+
),
256+
size: Some(
257+
12,
258+
),
259+
}
210260
Type {
211261
kind: Reference(
212262
Reference {

0 commit comments

Comments
 (0)