Skip to content

Commit 6a60888

Browse files
Rollup merge of rust-lang#151142 - SpriteOvO:type-info-adt, r=oli-obk
Support ADT types in type info reflection Tracking issue: rust-lang#146922 `#![feature(type_info)]` This PR supports ADT types for feature `type_info` reflection. (It's still a draft PR, with implementation in progress) Note that this PR does not take SemVer into consideration (I left a FIXME comment). As discussed earlier ([comment](rust-lang#146923 (comment))), this requires further discussion. However, I hope we could get an initial implementation to land first, so we can start playing with it. ### Progress / Checklist - [x] Struct support. - [x] Enum - [x] Union - [x] Generics - [ ] ~Methods~ Implemented and to be implemented in other PRs - [ ] ~Traits~ Implemented and to be implemented in other PRs - [x] Rebasing PR to `main` branch ~~(It's currently based on PR rust-lang#151123, so here's an extra commit)~~ - [x] Cleanup and Rebase. - [x] Fix field info for references. (see [comment](rust-lang#151142 (comment))) r? @oli-obk
2 parents 12f3a94 + 6ab6734 commit 6a60888

File tree

15 files changed

+1034
-87
lines changed

15 files changed

+1034
-87
lines changed

compiler/rustc_const_eval/src/const_eval/type_info.rs

Lines changed: 115 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
use rustc_abi::FieldIdx;
1+
mod adt;
2+
3+
use std::borrow::Cow;
4+
5+
use rustc_abi::{FieldIdx, VariantIdx};
26
use rustc_ast::Mutability;
37
use rustc_hir::LangItem;
48
use rustc_middle::span_bug;
@@ -8,11 +12,58 @@ use rustc_span::{Symbol, sym};
812

913
use crate::const_eval::CompileTimeMachine;
1014
use crate::interpret::{
11-
CtfeProvenance, Immediate, InterpCx, InterpResult, MPlaceTy, MemoryKind, Scalar, Writeable,
12-
interp_ok,
15+
CtfeProvenance, Immediate, InterpCx, InterpResult, MPlaceTy, MemoryKind, Projectable, Scalar,
16+
Writeable, interp_ok,
1317
};
1418

1519
impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
20+
/// Equivalent to `project_downcast`, but identifies the variant by name instead of index.
21+
fn downcast<'a>(
22+
&self,
23+
place: &(impl Writeable<'tcx, CtfeProvenance> + 'a),
24+
name: Symbol,
25+
) -> InterpResult<'tcx, (VariantIdx, impl Writeable<'tcx, CtfeProvenance> + 'a)> {
26+
let variants = place.layout().ty.ty_adt_def().unwrap().variants();
27+
let variant_idx = variants
28+
.iter_enumerated()
29+
.find(|(_idx, var)| var.name == name)
30+
.unwrap_or_else(|| panic!("got {name} but expected one of {variants:#?}"))
31+
.0;
32+
33+
interp_ok((variant_idx, self.project_downcast(place, variant_idx)?))
34+
}
35+
36+
// A general method to write an array to a static slice place.
37+
fn allocate_fill_and_write_slice_ptr(
38+
&mut self,
39+
slice_place: impl Writeable<'tcx, CtfeProvenance>,
40+
len: u64,
41+
writer: impl Fn(&mut Self, /* index */ u64, 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))?;
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, 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, self);
64+
self.write_immediate(ptr, &slice_place)
65+
}
66+
1667
/// Writes a `core::mem::type_info::TypeInfo` for a given type, `ty` to the given place.
1768
pub(crate) fn write_type_info(
1869
&mut self,
@@ -26,22 +77,13 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
2677
// Fill all fields of the `TypeInfo` struct.
2778
for (idx, field) in ty_struct.fields.iter_enumerated() {
2879
let field_dest = self.project_field(dest, idx)?;
29-
let downcast = |name: Symbol| {
30-
let variants = field_dest.layout().ty.ty_adt_def().unwrap().variants();
31-
let variant_id = variants
32-
.iter_enumerated()
33-
.find(|(_idx, var)| var.name == name)
34-
.unwrap_or_else(|| panic!("got {name} but expected one of {variants:#?}"))
35-
.0;
36-
37-
interp_ok((variant_id, self.project_downcast(&field_dest, variant_id)?))
38-
};
3980
let ptr_bit_width = || self.tcx.data_layout.pointer_size().bits();
4081
match field.name {
4182
sym::kind => {
4283
let variant_index = match ty.kind() {
4384
ty::Tuple(fields) => {
44-
let (variant, variant_place) = downcast(sym::Tuple)?;
85+
let (variant, variant_place) =
86+
self.downcast(&field_dest, sym::Tuple)?;
4587
// project to the single tuple variant field of `type_info::Tuple` struct type
4688
let tuple_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
4789
assert_eq!(
@@ -55,35 +97,42 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
5597
.fields
5698
.len()
5799
);
58-
self.write_tuple_fields(tuple_place, fields, ty)?;
100+
self.write_tuple_type_info(tuple_place, fields, ty)?;
59101
variant
60102
}
61103
ty::Array(ty, len) => {
62-
let (variant, variant_place) = downcast(sym::Array)?;
104+
let (variant, variant_place) =
105+
self.downcast(&field_dest, sym::Array)?;
63106
let array_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
64107

65108
self.write_array_type_info(array_place, *ty, *len)?;
66109

67110
variant
68111
}
69112
ty::Slice(ty) => {
70-
let (variant, variant_place) = downcast(sym::Slice)?;
113+
let (variant, variant_place) =
114+
self.downcast(&field_dest, sym::Slice)?;
71115
let slice_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
72116

73117
self.write_slice_type_info(slice_place, *ty)?;
74118

75119
variant
76120
}
121+
ty::Adt(adt_def, generics) => {
122+
self.write_adt_type_info(&field_dest, (ty, *adt_def), generics)?
123+
}
77124
ty::Bool => {
78-
let (variant, _variant_place) = downcast(sym::Bool)?;
125+
let (variant, _variant_place) =
126+
self.downcast(&field_dest, sym::Bool)?;
79127
variant
80128
}
81129
ty::Char => {
82-
let (variant, _variant_place) = downcast(sym::Char)?;
130+
let (variant, _variant_place) =
131+
self.downcast(&field_dest, sym::Char)?;
83132
variant
84133
}
85134
ty::Int(int_ty) => {
86-
let (variant, variant_place) = downcast(sym::Int)?;
135+
let (variant, variant_place) = self.downcast(&field_dest, sym::Int)?;
87136
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
88137
self.write_int_type_info(
89138
place,
@@ -93,7 +142,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
93142
variant
94143
}
95144
ty::Uint(uint_ty) => {
96-
let (variant, variant_place) = downcast(sym::Int)?;
145+
let (variant, variant_place) = self.downcast(&field_dest, sym::Int)?;
97146
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
98147
self.write_int_type_info(
99148
place,
@@ -103,25 +152,28 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
103152
variant
104153
}
105154
ty::Float(float_ty) => {
106-
let (variant, variant_place) = downcast(sym::Float)?;
155+
let (variant, variant_place) =
156+
self.downcast(&field_dest, sym::Float)?;
107157
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
108158
self.write_float_type_info(place, float_ty.bit_width())?;
109159
variant
110160
}
111161
ty::Str => {
112-
let (variant, _variant_place) = downcast(sym::Str)?;
162+
let (variant, _variant_place) = self.downcast(&field_dest, sym::Str)?;
113163
variant
114164
}
115165
ty::Ref(_, ty, mutability) => {
116-
let (variant, variant_place) = downcast(sym::Reference)?;
166+
let (variant, variant_place) =
167+
self.downcast(&field_dest, sym::Reference)?;
117168
let reference_place =
118169
self.project_field(&variant_place, FieldIdx::ZERO)?;
119170
self.write_reference_type_info(reference_place, *ty, *mutability)?;
120171

121172
variant
122173
}
123174
ty::RawPtr(ty, mutability) => {
124-
let (variant, variant_place) = downcast(sym::Pointer)?;
175+
let (variant, variant_place) =
176+
self.downcast(&field_dest, sym::Pointer)?;
125177
let pointer_place =
126178
self.project_field(&variant_place, FieldIdx::ZERO)?;
127179

@@ -130,13 +182,13 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
130182
variant
131183
}
132184
ty::Dynamic(predicates, region) => {
133-
let (variant, variant_place) = downcast(sym::DynTrait)?;
185+
let (variant, variant_place) =
186+
self.downcast(&field_dest, sym::DynTrait)?;
134187
let dyn_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
135188
self.write_dyn_trait_type_info(dyn_place, *predicates, *region)?;
136189
variant
137190
}
138-
ty::Adt(_, _)
139-
| ty::Foreign(_)
191+
ty::Foreign(_)
140192
| ty::Pat(_, _)
141193
| ty::FnDef(..)
142194
| ty::FnPtr(..)
@@ -151,14 +203,14 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
151203
| ty::Bound(..)
152204
| ty::Placeholder(_)
153205
| ty::Infer(..)
154-
| ty::Error(_) => downcast(sym::Other)?.0,
206+
| ty::Error(_) => self.downcast(&field_dest, sym::Other)?.0,
155207
};
156208
self.write_discriminant(variant_index, &field_dest)?
157209
}
158210
sym::size => {
159211
let layout = self.layout_of(ty)?;
160212
let variant_index = if layout.is_sized() {
161-
let (variant, variant_place) = downcast(sym::Some)?;
213+
let (variant, variant_place) = self.downcast(&field_dest, sym::Some)?;
162214
let size_field_place =
163215
self.project_field(&variant_place, FieldIdx::ZERO)?;
164216
self.write_scalar(
@@ -168,7 +220,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
168220
)?;
169221
variant
170222
} else {
171-
downcast(sym::None)?.0
223+
self.downcast(&field_dest, sym::None)?.0
172224
};
173225
self.write_discriminant(variant_index, &field_dest)?;
174226
}
@@ -179,54 +231,32 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
179231
interp_ok(())
180232
}
181233

182-
pub(crate) fn write_tuple_fields(
183-
&mut self,
184-
tuple_place: impl Writeable<'tcx, CtfeProvenance>,
185-
fields: &[Ty<'tcx>],
186-
tuple_ty: Ty<'tcx>,
187-
) -> InterpResult<'tcx> {
188-
// project into the `type_info::Tuple::fields` field
189-
let fields_slice_place = self.project_field(&tuple_place, FieldIdx::ZERO)?;
190-
// get the `type_info::Field` type from `fields: &[Field]`
191-
let field_type = fields_slice_place
192-
.layout()
193-
.ty
194-
.builtin_deref(false)
195-
.unwrap()
196-
.sequence_element_type(self.tcx.tcx);
197-
// Create an array with as many elements as the number of fields in the inspected tuple
198-
let fields_layout =
199-
self.layout_of(Ty::new_array(self.tcx.tcx, field_type, fields.len() as u64))?;
200-
let fields_place = self.allocate(fields_layout, MemoryKind::Stack)?;
201-
let mut fields_places = self.project_array_fields(&fields_place)?;
202-
203-
let tuple_layout = self.layout_of(tuple_ty)?;
204-
205-
while let Some((i, place)) = fields_places.next(self)? {
206-
let field_ty = fields[i as usize];
207-
self.write_field(field_ty, place, tuple_layout, i)?;
208-
}
209-
210-
let fields_place = fields_place.map_provenance(CtfeProvenance::as_immutable);
211-
212-
let ptr = Immediate::new_slice(fields_place.ptr(), fields.len() as u64, self);
213-
214-
self.write_immediate(ptr, &fields_slice_place)
215-
}
216-
217234
fn write_field(
218235
&mut self,
219236
field_ty: Ty<'tcx>,
220237
place: MPlaceTy<'tcx>,
221238
layout: TyAndLayout<'tcx>,
239+
name: Option<Symbol>,
222240
idx: u64,
223241
) -> InterpResult<'tcx> {
224242
for (field_idx, field_ty_field) in
225243
place.layout.ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
226244
{
227245
let field_place = self.project_field(&place, field_idx)?;
228246
match field_ty_field.name {
229-
sym::ty => self.write_type_id(field_ty, &field_place)?,
247+
sym::name => {
248+
let name = match name.as_ref() {
249+
Some(name) => Cow::Borrowed(name.as_str()),
250+
None => Cow::Owned(idx.to_string()), // For tuples
251+
};
252+
let name_place = self.allocate_str_dedup(&name)?;
253+
let ptr = self.mplace_to_ref(&name_place)?;
254+
self.write_immediate(*ptr, &field_place)?
255+
}
256+
sym::ty => {
257+
let field_ty = self.tcx.erase_and_anonymize_regions(field_ty);
258+
self.write_type_id(field_ty, &field_place)?
259+
}
230260
sym::offset => {
231261
let offset = layout.fields.offset(idx as usize);
232262
self.write_scalar(
@@ -242,6 +272,24 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
242272
interp_ok(())
243273
}
244274

275+
pub(crate) fn write_tuple_type_info(
276+
&mut self,
277+
tuple_place: impl Writeable<'tcx, CtfeProvenance>,
278+
fields: &[Ty<'tcx>],
279+
tuple_ty: Ty<'tcx>,
280+
) -> InterpResult<'tcx> {
281+
let tuple_layout = self.layout_of(tuple_ty)?;
282+
let fields_slice_place = self.project_field(&tuple_place, FieldIdx::ZERO)?;
283+
self.allocate_fill_and_write_slice_ptr(
284+
fields_slice_place,
285+
fields.len() as u64,
286+
|this, i, place| {
287+
let field_ty = fields[i as usize];
288+
this.write_field(field_ty, place, tuple_layout, None, i)
289+
},
290+
)
291+
}
292+
245293
pub(crate) fn write_array_type_info(
246294
&mut self,
247295
place: impl Writeable<'tcx, CtfeProvenance>,

0 commit comments

Comments
 (0)