Skip to content

Commit e8b0f6c

Browse files
committed
Add support for trait object types in type_info reflection
1 parent 63f4513 commit e8b0f6c

25 files changed

Lines changed: 389 additions & 41 deletions

compiler/rustc_const_eval/src/const_eval/type_info.rs

Lines changed: 177 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ use rustc_ast::Mutability;
33
use rustc_hir::LangItem;
44
use rustc_middle::span_bug;
55
use rustc_middle::ty::layout::TyAndLayout;
6-
use rustc_middle::ty::{self, Const, ScalarInt, Ty};
6+
use rustc_middle::ty::{self, Const, Region, ScalarInt, Ty};
7+
use rustc_span::def_id::DefId;
78
use rustc_span::{Symbol, sym};
89

910
use crate::const_eval::CompileTimeMachine;
@@ -121,14 +122,19 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
121122

122123
variant
123124
}
125+
ty::Dynamic(predicates, region) => {
126+
let (variant, variant_place) = downcast(sym::DynTrait)?;
127+
let dyn_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
128+
self.write_dyn_trait_type_info(dyn_place, *predicates, *region)?;
129+
variant
130+
}
124131
ty::Adt(_, _)
125132
| ty::Foreign(_)
126133
| ty::Pat(_, _)
127134
| ty::Slice(_)
128135
| ty::FnDef(..)
129136
| ty::FnPtr(..)
130137
| ty::UnsafeBinder(..)
131-
| ty::Dynamic(..)
132138
| ty::Closure(..)
133139
| ty::CoroutineClosure(..)
134140
| ty::Coroutine(..)
@@ -167,6 +173,175 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
167173
interp_ok(())
168174
}
169175

176+
fn write_dyn_trait_type_info(
177+
&mut self,
178+
dyn_place: impl Writeable<'tcx, CtfeProvenance>,
179+
data: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
180+
region: Region<'tcx>,
181+
) -> InterpResult<'tcx> {
182+
let tcx = self.tcx.tcx;
183+
184+
// Find the principal trait ref (for super trait collection), collect auto traits,
185+
// and collect all projection predicates (used when computing TypeId for each supertrait).
186+
let mut principal: Option<ty::Binder<'tcx, ty::ExistentialTraitRef<'tcx>>> = None;
187+
let mut auto_traits_def_ids: Vec<ty::Binder<'tcx, DefId>> = Vec::new();
188+
let mut projections: Vec<ty::Binder<'tcx, ty::ExistentialProjection<'tcx>>> = Vec::new();
189+
190+
for b in data.iter() {
191+
match b.skip_binder() {
192+
ty::ExistentialPredicate::Trait(tr) => principal = Some(b.rebind(tr)),
193+
ty::ExistentialPredicate::AutoTrait(did) => auto_traits_def_ids.push(b.rebind(did)),
194+
ty::ExistentialPredicate::Projection(p) => projections.push(b.rebind(p)),
195+
}
196+
}
197+
198+
// This is to make principal dyn type include Trait and projection predicates, excluding auto traits.
199+
let principal_ty: Option<Ty<'tcx>> = principal.map(|_tr| {
200+
let preds = tcx
201+
.mk_poly_existential_predicates_from_iter(data.iter().filter(|b| {
202+
!matches!(b.skip_binder(), ty::ExistentialPredicate::AutoTrait(_))
203+
}));
204+
Ty::new_dynamic(tcx, preds, region)
205+
});
206+
207+
// DynTrait { predicates: &'static [Trait] }
208+
for (field_idx, field) in
209+
dyn_place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
210+
{
211+
let field_place = self.project_field(&dyn_place, field_idx)?;
212+
match field.name {
213+
sym::predicates => {
214+
self.write_dyn_trait_predicates_slice(
215+
&field_place,
216+
principal_ty,
217+
&auto_traits_def_ids,
218+
region,
219+
)?;
220+
}
221+
other => {
222+
span_bug!(self.tcx.def_span(field.did), "unimplemented DynTrait field {other}")
223+
}
224+
}
225+
}
226+
227+
interp_ok(())
228+
}
229+
230+
fn mk_dyn_principal_auto_trait_ty(
231+
&self,
232+
auto_trait_def_id: ty::Binder<'tcx, DefId>,
233+
region: Region<'tcx>,
234+
) -> Ty<'tcx> {
235+
let tcx = self.tcx.tcx;
236+
237+
// Preserve the binder vars from the original auto-trait predicate.
238+
let pred_inner = ty::ExistentialPredicate::AutoTrait(auto_trait_def_id.skip_binder());
239+
let pred = ty::Binder::bind_with_vars(pred_inner, auto_trait_def_id.bound_vars());
240+
241+
let preds = tcx.mk_poly_existential_predicates_from_iter([pred].into_iter());
242+
Ty::new_dynamic(tcx, preds, region)
243+
}
244+
245+
fn write_dyn_trait_predicates_slice(
246+
&mut self,
247+
slice_place: &impl Writeable<'tcx, CtfeProvenance>,
248+
principal_ty: Option<Ty<'tcx>>,
249+
auto_trait_def_ids: &[ty::Binder<'tcx, DefId>],
250+
region: Region<'tcx>,
251+
) -> InterpResult<'tcx> {
252+
let tcx = self.tcx.tcx;
253+
254+
// total entries in DynTrait predicates
255+
let total_len = principal_ty.map(|_| 1).unwrap_or(0) + auto_trait_def_ids.len();
256+
257+
// element type = DynTraitPredicate
258+
let slice_ty = slice_place.layout().ty.builtin_deref(false).unwrap(); // [DynTraitPredicate]
259+
let elem_ty = slice_ty.sequence_element_type(tcx); // DynTraitPredicate
260+
261+
let arr_layout = self.layout_of(Ty::new_array(tcx, elem_ty, total_len as u64))?;
262+
let arr_place = self.allocate(arr_layout, MemoryKind::Stack)?;
263+
let mut elems = self.project_array_fields(&arr_place)?;
264+
265+
// principal entry (if any) - NOT an auto trait
266+
if let Some(principal_ty) = principal_ty {
267+
let Some((_i, elem_place)) = elems.next(self)? else {
268+
span_bug!(self.tcx.span, "DynTrait.predicates length computed wrong (principal)");
269+
};
270+
self.write_dyn_trait_predicate(elem_place, principal_ty, false)?;
271+
}
272+
273+
// auto trait entries - these ARE auto traits
274+
for auto in auto_trait_def_ids {
275+
let Some((_i, elem_place)) = elems.next(self)? else {
276+
span_bug!(self.tcx.span, "DynTrait.predicates length computed wrong (auto)");
277+
};
278+
let auto_ty = self.mk_dyn_principal_auto_trait_ty(*auto, region);
279+
self.write_dyn_trait_predicate(elem_place, auto_ty, true)?;
280+
}
281+
282+
let arr_place = arr_place.map_provenance(CtfeProvenance::as_immutable);
283+
let imm = Immediate::new_slice(arr_place.ptr(), total_len as u64, self);
284+
self.write_immediate(imm, slice_place)
285+
}
286+
287+
fn write_dyn_trait_predicate(
288+
&mut self,
289+
predicate_place: MPlaceTy<'tcx>,
290+
trait_ty: Ty<'tcx>,
291+
is_auto: bool,
292+
) -> InterpResult<'tcx> {
293+
// DynTraitPredicate { trait_ty: Trait }
294+
for (field_idx, field) in predicate_place
295+
.layout
296+
.ty
297+
.ty_adt_def()
298+
.unwrap()
299+
.non_enum_variant()
300+
.fields
301+
.iter_enumerated()
302+
{
303+
let field_place = self.project_field(&predicate_place, field_idx)?;
304+
match field.name {
305+
sym::trait_ty => {
306+
// Now write the Trait struct
307+
self.write_trait(field_place, trait_ty, is_auto)?;
308+
}
309+
other => {
310+
span_bug!(
311+
self.tcx.def_span(field.did),
312+
"unimplemented DynTraitPredicate field {other}"
313+
)
314+
}
315+
}
316+
}
317+
interp_ok(())
318+
}
319+
fn write_trait(
320+
&mut self,
321+
trait_place: MPlaceTy<'tcx>,
322+
trait_ty: Ty<'tcx>,
323+
is_auto: bool,
324+
) -> InterpResult<'tcx> {
325+
// Trait { ty: TypeId, is_auto: bool }
326+
for (field_idx, field) in
327+
trait_place.layout.ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
328+
{
329+
let field_place = self.project_field(&trait_place, field_idx)?;
330+
match field.name {
331+
sym::ty => {
332+
self.write_type_id(trait_ty, &field_place)?;
333+
}
334+
sym::is_auto => {
335+
self.write_scalar(Scalar::from_bool(is_auto), &field_place)?;
336+
}
337+
other => {
338+
span_bug!(self.tcx.def_span(field.did), "unimplemented Trait field {other}")
339+
}
340+
}
341+
}
342+
interp_ok(())
343+
}
344+
170345
pub(crate) fn write_tuple_fields(
171346
&mut self,
172347
tuple_place: impl Writeable<'tcx, CtfeProvenance>,

compiler/rustc_span/src/symbol.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ symbols! {
186186
AtomicU64,
187187
AtomicU128,
188188
AtomicUsize,
189+
AutoTrait,
189190
BTreeEntry,
190191
BTreeMap,
191192
BTreeSet,
@@ -231,6 +232,7 @@ symbols! {
231232
Display,
232233
DoubleEndedIterator,
233234
Duration,
235+
DynTrait,
234236
Encodable,
235237
Encoder,
236238
Enumerate,
@@ -1294,6 +1296,7 @@ symbols! {
12941296
io_stdout,
12951297
irrefutable_let_patterns,
12961298
is,
1299+
is_auto,
12971300
is_val_statically_known,
12981301
isa_attribute,
12991302
isize,
@@ -1747,6 +1750,7 @@ symbols! {
17471750
precise_capturing_in_traits,
17481751
precise_pointer_size_matching,
17491752
precision,
1753+
predicates,
17501754
pref_align_of,
17511755
prefetch_read_data,
17521756
prefetch_read_instruction,
@@ -2292,6 +2296,7 @@ symbols! {
22922296
trace_macros,
22932297
track_caller,
22942298
trait_alias,
2299+
trait_ty,
22952300
trait_upcasting,
22962301
transmute,
22972302
transmute_generic_consts,

library/core/src/mem/type_info.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ pub enum TypeKind {
4545
Tuple(Tuple),
4646
/// Arrays.
4747
Array(Array),
48+
/// Dynamic Traits.
49+
DynTrait(DynTrait),
4850
/// Primitive boolean type.
4951
Bool(Bool),
5052
/// Primitive character type.
@@ -94,6 +96,36 @@ pub struct Array {
9496
pub len: usize,
9597
}
9698

99+
/// Compile-time type information about dynamic traits.
100+
/// FIXME(#146922): Add super traits and generics
101+
#[derive(Debug)]
102+
#[non_exhaustive]
103+
#[unstable(feature = "type_info", issue = "146922")]
104+
pub struct DynTrait {
105+
/// The predicates of a dynamic trait.
106+
pub predicates: &'static [DynTraitPredicate],
107+
}
108+
109+
/// Compile-time type information about a dynamic trait predicate.
110+
#[derive(Debug)]
111+
#[non_exhaustive]
112+
#[unstable(feature = "type_info", issue = "146922")]
113+
pub struct DynTraitPredicate {
114+
/// The type of the trait as a dynamic trait type.
115+
pub trait_ty: Trait,
116+
}
117+
118+
/// Compile-time type information about a trait.
119+
#[derive(Debug)]
120+
#[non_exhaustive]
121+
#[unstable(feature = "type_info", issue = "146922")]
122+
pub struct Trait {
123+
/// The TypeId of the trait as a dynamic type
124+
pub ty: TypeId,
125+
/// Whether the trait is an auto trait
126+
pub is_auto: bool,
127+
}
128+
97129
/// Compile-time type information about `bool`.
98130
#[derive(Debug)]
99131
#[non_exhaustive]

0 commit comments

Comments
 (0)