Skip to content

Commit afe3fc1

Browse files
committed
Add support for trait object types in type_info reflection
1 parent e96bb7e commit afe3fc1

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;
@@ -129,13 +130,18 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
129130

130131
variant
131132
}
133+
ty::Dynamic(predicates, region) => {
134+
let (variant, variant_place) = downcast(sym::DynTrait)?;
135+
let dyn_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
136+
self.write_dyn_trait_type_info(dyn_place, *predicates, *region)?;
137+
variant
138+
}
132139
ty::Adt(_, _)
133140
| ty::Foreign(_)
134141
| ty::Pat(_, _)
135142
| ty::FnDef(..)
136143
| ty::FnPtr(..)
137144
| ty::UnsafeBinder(..)
138-
| ty::Dynamic(..)
139145
| ty::Closure(..)
140146
| ty::CoroutineClosure(..)
141147
| ty::Coroutine(..)
@@ -174,6 +180,175 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
174180
interp_ok(())
175181
}
176182

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

library/core/src/mem/type_info.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ pub enum TypeKind {
4747
Array(Array),
4848
/// Slices.
4949
Slice(Slice),
50+
/// Dynamic Traits.
51+
DynTrait(DynTrait),
5052
/// Primitive boolean type.
5153
Bool(Bool),
5254
/// Primitive character type.
@@ -105,6 +107,36 @@ pub struct Slice {
105107
pub element_ty: TypeId,
106108
}
107109

110+
/// Compile-time type information about dynamic traits.
111+
/// FIXME(#146922): Add super traits and generics
112+
#[derive(Debug)]
113+
#[non_exhaustive]
114+
#[unstable(feature = "type_info", issue = "146922")]
115+
pub struct DynTrait {
116+
/// The predicates of a dynamic trait.
117+
pub predicates: &'static [DynTraitPredicate],
118+
}
119+
120+
/// Compile-time type information about a dynamic trait predicate.
121+
#[derive(Debug)]
122+
#[non_exhaustive]
123+
#[unstable(feature = "type_info", issue = "146922")]
124+
pub struct DynTraitPredicate {
125+
/// The type of the trait as a dynamic trait type.
126+
pub trait_ty: Trait,
127+
}
128+
129+
/// Compile-time type information about a trait.
130+
#[derive(Debug)]
131+
#[non_exhaustive]
132+
#[unstable(feature = "type_info", issue = "146922")]
133+
pub struct Trait {
134+
/// The TypeId of the trait as a dynamic type
135+
pub ty: TypeId,
136+
/// Whether the trait is an auto trait
137+
pub is_auto: bool,
138+
}
139+
108140
/// Compile-time type information about `bool`.
109141
#[derive(Debug)]
110142
#[non_exhaustive]

0 commit comments

Comments
 (0)