Skip to content

Commit f488671

Browse files
authored
Rollup merge of #151239 - izagawd:comptime-reflection-dyn-trait-variant, r=oli-obk
Support trait objects in type info reflection Tracking issue: #146922 Adds type_info support for trait object types by introducing a DynTrait variant ~~I can't seem to get it to work correctly with `dyn for<'a> Foo<'a>`, though it works fine for normal `dyn Foo` trait objects~~ r? @oli-obk
2 parents e96bb7e + a1893d3 commit f488671

29 files changed

Lines changed: 399 additions & 42 deletions
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
use rustc_middle::mir::interpret::{CtfeProvenance, InterpResult, Scalar, interp_ok};
2+
use rustc_middle::ty::{Region, Ty};
3+
use rustc_middle::{span_bug, ty};
4+
use rustc_span::def_id::DefId;
5+
use rustc_span::sym;
6+
7+
use crate::const_eval::CompileTimeMachine;
8+
use crate::interpret::{Immediate, InterpCx, MPlaceTy, MemoryKind, Writeable};
9+
impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
10+
pub(crate) fn write_dyn_trait_type_info(
11+
&mut self,
12+
dyn_place: impl Writeable<'tcx, CtfeProvenance>,
13+
data: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
14+
region: Region<'tcx>,
15+
) -> InterpResult<'tcx> {
16+
let tcx = self.tcx.tcx;
17+
18+
// Find the principal trait ref (for super trait collection), collect auto traits,
19+
// and collect all projection predicates (used when computing TypeId for each supertrait).
20+
let mut principal: Option<ty::Binder<'tcx, ty::ExistentialTraitRef<'tcx>>> = None;
21+
let mut auto_traits_def_ids: Vec<ty::Binder<'tcx, DefId>> = Vec::new();
22+
let mut projections: Vec<ty::Binder<'tcx, ty::ExistentialProjection<'tcx>>> = Vec::new();
23+
24+
for b in data.iter() {
25+
match b.skip_binder() {
26+
ty::ExistentialPredicate::Trait(tr) => principal = Some(b.rebind(tr)),
27+
ty::ExistentialPredicate::AutoTrait(did) => auto_traits_def_ids.push(b.rebind(did)),
28+
ty::ExistentialPredicate::Projection(p) => projections.push(b.rebind(p)),
29+
}
30+
}
31+
32+
// This is to make principal dyn type include Trait and projection predicates, excluding auto traits.
33+
let principal_ty: Option<Ty<'tcx>> = principal.map(|_tr| {
34+
let preds = tcx
35+
.mk_poly_existential_predicates_from_iter(data.iter().filter(|b| {
36+
!matches!(b.skip_binder(), ty::ExistentialPredicate::AutoTrait(_))
37+
}));
38+
Ty::new_dynamic(tcx, preds, region)
39+
});
40+
41+
// DynTrait { predicates: &'static [Trait] }
42+
for (field_idx, field) in
43+
dyn_place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
44+
{
45+
let field_place = self.project_field(&dyn_place, field_idx)?;
46+
match field.name {
47+
sym::predicates => {
48+
self.write_dyn_trait_predicates_slice(
49+
&field_place,
50+
principal_ty,
51+
&auto_traits_def_ids,
52+
region,
53+
)?;
54+
}
55+
other => {
56+
span_bug!(self.tcx.def_span(field.did), "unimplemented DynTrait field {other}")
57+
}
58+
}
59+
}
60+
61+
interp_ok(())
62+
}
63+
64+
fn mk_dyn_principal_auto_trait_ty(
65+
&self,
66+
auto_trait_def_id: ty::Binder<'tcx, DefId>,
67+
region: Region<'tcx>,
68+
) -> Ty<'tcx> {
69+
let tcx = self.tcx.tcx;
70+
71+
// Preserve the binder vars from the original auto-trait predicate.
72+
let pred_inner = ty::ExistentialPredicate::AutoTrait(auto_trait_def_id.skip_binder());
73+
let pred = ty::Binder::bind_with_vars(pred_inner, auto_trait_def_id.bound_vars());
74+
75+
let preds = tcx.mk_poly_existential_predicates_from_iter([pred].into_iter());
76+
Ty::new_dynamic(tcx, preds, region)
77+
}
78+
79+
fn write_dyn_trait_predicates_slice(
80+
&mut self,
81+
slice_place: &impl Writeable<'tcx, CtfeProvenance>,
82+
principal_ty: Option<Ty<'tcx>>,
83+
auto_trait_def_ids: &[ty::Binder<'tcx, DefId>],
84+
region: Region<'tcx>,
85+
) -> InterpResult<'tcx> {
86+
let tcx = self.tcx.tcx;
87+
88+
// total entries in DynTrait predicates
89+
let total_len = principal_ty.map(|_| 1).unwrap_or(0) + auto_trait_def_ids.len();
90+
91+
// element type = DynTraitPredicate
92+
let slice_ty = slice_place.layout().ty.builtin_deref(false).unwrap(); // [DynTraitPredicate]
93+
let elem_ty = slice_ty.sequence_element_type(tcx); // DynTraitPredicate
94+
95+
let arr_layout = self.layout_of(Ty::new_array(tcx, elem_ty, total_len as u64))?;
96+
let arr_place = self.allocate(arr_layout, MemoryKind::Stack)?;
97+
let mut elems = self.project_array_fields(&arr_place)?;
98+
99+
// principal entry (if any) - NOT an auto trait
100+
if let Some(principal_ty) = principal_ty {
101+
let Some((_i, elem_place)) = elems.next(self)? else {
102+
span_bug!(self.tcx.span, "DynTrait.predicates length computed wrong (principal)");
103+
};
104+
self.write_dyn_trait_predicate(elem_place, principal_ty, false)?;
105+
}
106+
107+
// auto trait entries - these ARE auto traits
108+
for auto in auto_trait_def_ids {
109+
let Some((_i, elem_place)) = elems.next(self)? else {
110+
span_bug!(self.tcx.span, "DynTrait.predicates length computed wrong (auto)");
111+
};
112+
let auto_ty = self.mk_dyn_principal_auto_trait_ty(*auto, region);
113+
self.write_dyn_trait_predicate(elem_place, auto_ty, true)?;
114+
}
115+
116+
let arr_place = arr_place.map_provenance(CtfeProvenance::as_immutable);
117+
let imm = Immediate::new_slice(arr_place.ptr(), total_len as u64, self);
118+
self.write_immediate(imm, slice_place)
119+
}
120+
121+
fn write_dyn_trait_predicate(
122+
&mut self,
123+
predicate_place: MPlaceTy<'tcx>,
124+
trait_ty: Ty<'tcx>,
125+
is_auto: bool,
126+
) -> InterpResult<'tcx> {
127+
// DynTraitPredicate { trait_ty: Trait }
128+
for (field_idx, field) in predicate_place
129+
.layout
130+
.ty
131+
.ty_adt_def()
132+
.unwrap()
133+
.non_enum_variant()
134+
.fields
135+
.iter_enumerated()
136+
{
137+
let field_place = self.project_field(&predicate_place, field_idx)?;
138+
match field.name {
139+
sym::trait_ty => {
140+
// Now write the Trait struct
141+
self.write_trait(field_place, trait_ty, is_auto)?;
142+
}
143+
other => {
144+
span_bug!(
145+
self.tcx.def_span(field.did),
146+
"unimplemented DynTraitPredicate field {other}"
147+
)
148+
}
149+
}
150+
}
151+
interp_ok(())
152+
}
153+
fn write_trait(
154+
&mut self,
155+
trait_place: MPlaceTy<'tcx>,
156+
trait_ty: Ty<'tcx>,
157+
is_auto: bool,
158+
) -> InterpResult<'tcx> {
159+
// Trait { ty: TypeId, is_auto: bool }
160+
for (field_idx, field) in
161+
trait_place.layout.ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
162+
{
163+
let field_place = self.project_field(&trait_place, field_idx)?;
164+
match field.name {
165+
sym::ty => {
166+
self.write_type_id(trait_ty, &field_place)?;
167+
}
168+
sym::is_auto => {
169+
self.write_scalar(Scalar::from_bool(is_auto), &field_place)?;
170+
}
171+
other => {
172+
span_bug!(self.tcx.def_span(field.did), "unimplemented Trait field {other}")
173+
}
174+
}
175+
}
176+
interp_ok(())
177+
}
178+
}

compiler/rustc_const_eval/src/const_eval/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use tracing::instrument;
99
use crate::interpret::InterpCx;
1010

1111
mod dummy_machine;
12+
mod dyn_trait;
1213
mod error;
1314
mod eval_queries;
1415
mod fn_queries;

compiler/rustc_const_eval/src/const_eval/type_info.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,18 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
129129

130130
variant
131131
}
132+
ty::Dynamic(predicates, region) => {
133+
let (variant, variant_place) = downcast(sym::DynTrait)?;
134+
let dyn_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
135+
self.write_dyn_trait_type_info(dyn_place, *predicates, *region)?;
136+
variant
137+
}
132138
ty::Adt(_, _)
133139
| ty::Foreign(_)
134140
| ty::Pat(_, _)
135141
| ty::FnDef(..)
136142
| ty::FnPtr(..)
137143
| ty::UnsafeBinder(..)
138-
| ty::Dynamic(..)
139144
| ty::Closure(..)
140145
| ty::CoroutineClosure(..)
141146
| ty::Coroutine(..)

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)