1- use rustc_abi:: FieldIdx ;
1+ use rustc_abi:: { FieldIdx , VariantIdx } ;
22use rustc_hir:: LangItem ;
33use rustc_middle:: mir:: interpret:: CtfeProvenance ;
44use rustc_middle:: span_bug;
55use rustc_middle:: ty:: layout:: TyAndLayout ;
6- use rustc_middle:: ty:: { self , Const , ScalarInt , Ty } ;
6+ use rustc_middle:: ty:: { self , AdtDef , AdtKind , Const , GenericArgs , ScalarInt , Ty , VariantDef } ;
77use rustc_span:: { Symbol , sym} ;
88
99use crate :: const_eval:: CompileTimeMachine ;
1010use crate :: interpret:: {
11- Immediate , InterpCx , InterpResult , MPlaceTy , MemoryKind , Writeable , interp_ok,
11+ Immediate , InterpCx , InterpResult , MPlaceTy , MemoryKind , Projectable , Scalar , Writeable ,
12+ interp_ok,
1213} ;
1314
1415impl < ' tcx > InterpCx < ' tcx , CompileTimeMachine < ' tcx > > {
16+ fn downcast (
17+ & self ,
18+ place : & ( impl Writeable < ' tcx , CtfeProvenance > + ' tcx ) ,
19+ name : Symbol ,
20+ ) -> InterpResult < ' tcx , ( VariantIdx , impl Writeable < ' tcx , CtfeProvenance > + ' tcx ) > {
21+ let variants = place. layout ( ) . ty . ty_adt_def ( ) . unwrap ( ) . variants ( ) ;
22+ let variant_id = variants
23+ . iter_enumerated ( )
24+ . find ( |( _idx, var) | var. name == name)
25+ . unwrap_or_else ( || panic ! ( "got {name} but expected one of {variants:#?}" ) )
26+ . 0 ;
27+
28+ interp_ok ( ( variant_id, self . project_downcast ( place, variant_id) ?) )
29+ }
30+
1531 /// Writes a `core::mem::type_info::TypeInfo` for a given type, `ty` to the given place.
1632 pub ( crate ) fn write_type_info (
1733 & mut self ,
1834 ty : Ty < ' tcx > ,
19- dest : & impl Writeable < ' tcx , CtfeProvenance > ,
35+ dest : & ( impl Writeable < ' tcx , CtfeProvenance > + ' tcx ) ,
2036 ) -> InterpResult < ' tcx > {
2137 let ty_struct = self . tcx . require_lang_item ( LangItem :: Type , self . tcx . span ) ;
2238 let ty_struct = self . tcx . type_of ( ty_struct) . no_bound_vars ( ) . unwrap ( ) ;
@@ -25,22 +41,13 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
2541 // Fill all fields of the `TypeInfo` struct.
2642 for ( idx, field) in ty_struct. fields . iter_enumerated ( ) {
2743 let field_dest = self . project_field ( dest, idx) ?;
28- let downcast = |name : Symbol | {
29- let variants = field_dest. layout ( ) . ty . ty_adt_def ( ) . unwrap ( ) . variants ( ) ;
30- let variant_id = variants
31- . iter_enumerated ( )
32- . find ( |( _idx, var) | var. name == name)
33- . unwrap_or_else ( || panic ! ( "got {name} but expected one of {variants:#?}" ) )
34- . 0 ;
35-
36- interp_ok ( ( variant_id, self . project_downcast ( & field_dest, variant_id) ?) )
37- } ;
3844 let ptr_bit_width = || self . tcx . data_layout . pointer_size ( ) . bits ( ) ;
3945 match field. name {
4046 sym:: kind => {
4147 let variant_index = match ty. kind ( ) {
4248 ty:: Tuple ( fields) => {
43- let ( variant, variant_place) = downcast ( sym:: Tuple ) ?;
49+ let ( variant, variant_place) =
50+ self . downcast ( & field_dest, sym:: Tuple ) ?;
4451 // project to the single tuple variant field of `type_info::Tuple` struct type
4552 let tuple_place = self . project_field ( & variant_place, FieldIdx :: ZERO ) ?;
4653 assert_eq ! (
@@ -58,27 +65,40 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
5865 variant
5966 }
6067 ty:: Array ( ty, len) => {
61- let ( variant, variant_place) = downcast ( sym:: Array ) ?;
68+ let ( variant, variant_place) =
69+ self . downcast ( & field_dest, sym:: Array ) ?;
6270 let array_place = self . project_field ( & variant_place, FieldIdx :: ZERO ) ?;
6371
6472 self . write_array_type_info ( array_place, * ty, * len) ?;
6573
6674 variant
6775 }
76+ ty:: Adt ( adt_def, generics) => {
77+ // TODO(type_info): Handle enum and union
78+ if !adt_def. is_struct ( ) {
79+ self . downcast ( & field_dest, sym:: Other ) ?. 0
80+ } else {
81+ let ( variant, variant_place) =
82+ self . downcast ( & field_dest, sym:: Struct ) ?;
83+ let place = self . project_field ( & variant_place, FieldIdx :: ZERO ) ?;
84+ self . write_adt_type_info ( place, ( ty, * adt_def) , generics) ?;
85+ variant
86+ }
87+ }
6888 ty:: Bool => {
69- let ( variant, variant_place) = downcast ( sym:: Bool ) ?;
89+ let ( variant, variant_place) = self . downcast ( & field_dest , sym:: Bool ) ?;
7090 let place = self . project_field ( & variant_place, FieldIdx :: ZERO ) ?;
7191 self . write_primitive_type_info ( place, ty, None ) ?;
7292 variant
7393 }
7494 ty:: Char => {
75- let ( variant, variant_place) = downcast ( sym:: Char ) ?;
95+ let ( variant, variant_place) = self . downcast ( & field_dest , sym:: Char ) ?;
7696 let place = self . project_field ( & variant_place, FieldIdx :: ZERO ) ?;
7797 self . write_primitive_type_info ( place, ty, None ) ?;
7898 variant
7999 }
80100 ty:: Int ( int_ty) => {
81- let ( variant, variant_place) = downcast ( sym:: Int ) ?;
101+ let ( variant, variant_place) = self . downcast ( & field_dest , sym:: Int ) ?;
82102 let place = self . project_field ( & variant_place, FieldIdx :: ZERO ) ?;
83103 self . write_primitive_type_info (
84104 place,
@@ -92,7 +112,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
92112 variant
93113 }
94114 ty:: Uint ( uint_ty) => {
95- let ( variant, variant_place) = downcast ( sym:: Uint ) ?;
115+ let ( variant, variant_place) = self . downcast ( & field_dest , sym:: Uint ) ?;
96116 let place = self . project_field ( & variant_place, FieldIdx :: ZERO ) ?;
97117 self . write_primitive_type_info (
98118 place,
@@ -106,19 +126,19 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
106126 variant
107127 }
108128 ty:: Float ( float_ty) => {
109- let ( variant, variant_place) = downcast ( sym:: Float ) ?;
129+ let ( variant, variant_place) =
130+ self . downcast ( & field_dest, sym:: Float ) ?;
110131 let place = self . project_field ( & variant_place, FieldIdx :: ZERO ) ?;
111132 self . write_primitive_type_info ( place, ty, Some ( float_ty. bit_width ( ) ) ) ?;
112133 variant
113134 }
114135 ty:: Str => {
115- let ( variant, variant_place) = downcast ( sym:: Str ) ?;
136+ let ( variant, variant_place) = self . downcast ( & field_dest , sym:: Str ) ?;
116137 let place = self . project_field ( & variant_place, FieldIdx :: ZERO ) ?;
117138 self . write_primitive_type_info ( place, ty, None ) ?;
118139 variant
119140 }
120- ty:: Adt ( _, _)
121- | ty:: Foreign ( _)
141+ ty:: Foreign ( _)
122142 | ty:: Pat ( _, _)
123143 | ty:: Slice ( _)
124144 | ty:: RawPtr ( ..)
@@ -137,14 +157,14 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
137157 | ty:: Bound ( ..)
138158 | ty:: Placeholder ( _)
139159 | ty:: Infer ( ..)
140- | ty:: Error ( _) => downcast ( sym:: Other ) ?. 0 ,
160+ | ty:: Error ( _) => self . downcast ( & field_dest , sym:: Other ) ?. 0 ,
141161 } ;
142162 self . write_discriminant ( variant_index, & field_dest) ?
143163 }
144164 sym:: size => {
145165 let layout = self . layout_of ( ty) ?;
146166 let variant_index = if layout. is_sized ( ) {
147- let ( variant, variant_place) = downcast ( sym:: Some ) ?;
167+ let ( variant, variant_place) = self . downcast ( & field_dest , sym:: Some ) ?;
148168 let size_field_place =
149169 self . project_field ( & variant_place, FieldIdx :: ZERO ) ?;
150170 self . write_scalar (
@@ -154,7 +174,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
154174 ) ?;
155175 variant
156176 } else {
157- downcast ( sym:: None ) ?. 0
177+ self . downcast ( & field_dest , sym:: None ) ?. 0
158178 } ;
159179 self . write_discriminant ( variant_index, & field_dest) ?;
160180 }
@@ -190,7 +210,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
190210
191211 while let Some ( ( i, place) ) = fields_places. next ( self ) ? {
192212 let field_ty = fields[ i as usize ] ;
193- self . write_field ( field_ty, place, tuple_layout, i) ?;
213+ self . write_field ( field_ty, place, tuple_layout, None , i) ?;
194214 }
195215
196216 let fields_place = fields_place. map_provenance ( CtfeProvenance :: as_immutable) ;
@@ -205,13 +225,24 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
205225 field_ty : Ty < ' tcx > ,
206226 place : MPlaceTy < ' tcx > ,
207227 layout : TyAndLayout < ' tcx > ,
228+ name : Option < Symbol > ,
208229 idx : u64 ,
209230 ) -> InterpResult < ' tcx > {
210231 for ( field_idx, field_ty_field) in
211232 place. layout . ty . ty_adt_def ( ) . unwrap ( ) . non_enum_variant ( ) . fields . iter_enumerated ( )
212233 {
213234 let field_place = self . project_field ( & place, field_idx) ?;
214235 match field_ty_field. name {
236+ sym:: name => {
237+ if let Some ( name) = name {
238+ let name_place = self . allocate_str_dedup ( name. as_str ( ) ) ?;
239+ let ptr = self . mplace_to_ref ( & name_place) ?;
240+ self . write_immediate ( * ptr, & field_place) ?
241+ } else {
242+ let ( variant, _) = self . downcast ( & field_place, sym:: None ) ?;
243+ self . write_discriminant ( variant, & field_place) ?;
244+ }
245+ }
215246 sym:: ty => self . write_type_id ( field_ty, & field_place) ?,
216247 sym:: offset => {
217248 let offset = layout. fields . offset ( idx as usize ) ;
@@ -252,6 +283,82 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
252283 interp_ok ( ( ) )
253284 }
254285
286+ // FIXME(type_info): No semver considerations for now
287+ pub ( crate ) fn write_adt_type_info (
288+ & mut self ,
289+ place : impl Writeable < ' tcx , CtfeProvenance > ,
290+ adt : ( Ty < ' tcx > , AdtDef < ' tcx > ) ,
291+ generics : & ' tcx GenericArgs < ' tcx > ,
292+ ) -> InterpResult < ' tcx > {
293+ let ( adt_ty, adt_def) = adt;
294+ match adt_def. adt_kind ( ) {
295+ AdtKind :: Struct => self . write_struct_type_info (
296+ place,
297+ ( adt_ty, adt_def. variant ( VariantIdx :: ZERO ) ) ,
298+ generics,
299+ ) ,
300+ AdtKind :: Union => todo ! ( ) ,
301+ AdtKind :: Enum => todo ! ( ) ,
302+ }
303+ }
304+
305+ pub ( crate ) fn write_struct_type_info (
306+ & mut self ,
307+ place : impl Writeable < ' tcx , CtfeProvenance > ,
308+ struct_ : ( Ty < ' tcx > , & ' tcx VariantDef ) ,
309+ generics : & ' tcx GenericArgs < ' tcx > ,
310+ ) -> InterpResult < ' tcx > {
311+ let ( struct_ty, struct_def) = struct_;
312+ let struct_layout = self . layout_of ( struct_ty) ?;
313+
314+ for ( field_idx, field) in
315+ place. layout ( ) . ty . ty_adt_def ( ) . unwrap ( ) . non_enum_variant ( ) . fields . iter_enumerated ( )
316+ {
317+ let field_place = self . project_field ( & place, field_idx) ?;
318+
319+ match field. name {
320+ sym:: fields => {
321+ let fields_slice_place = field_place;
322+ let field_type = fields_slice_place
323+ . layout ( )
324+ . ty
325+ . builtin_deref ( false )
326+ . unwrap ( )
327+ . sequence_element_type ( self . tcx . tcx ) ;
328+ let fields_layout = self . layout_of ( Ty :: new_array (
329+ self . tcx . tcx ,
330+ field_type,
331+ struct_def. fields . len ( ) as u64 ,
332+ ) ) ?;
333+ let fields_place = self . allocate ( fields_layout, MemoryKind :: Stack ) ?;
334+ let mut fields_places = self . project_array_fields ( & fields_place) ?;
335+
336+ for field_def in & struct_def. fields {
337+ let ( i, place) = fields_places. next ( self ) ?. unwrap ( ) ;
338+ let field_ty = field_def. ty ( * self . tcx , generics) ;
339+ self . write_field ( field_ty, place, struct_layout, Some ( field_def. name ) , i) ?;
340+ }
341+
342+ let fields_place = fields_place. map_provenance ( CtfeProvenance :: as_immutable) ;
343+ let ptr = Immediate :: new_slice (
344+ fields_place. ptr ( ) ,
345+ struct_def. fields . len ( ) as u64 ,
346+ self ,
347+ ) ;
348+ self . write_immediate ( ptr, & fields_slice_place) ?
349+ }
350+ sym:: non_exhaustive => {
351+ let is_non_exhaustive = struct_def. is_field_list_non_exhaustive ( ) ;
352+ self . write_scalar ( Scalar :: from_bool ( is_non_exhaustive) , & field_place) ?
353+ }
354+ // TODO(type_info): Write more info
355+ other => span_bug ! ( self . tcx. def_span( field. did) , "unimplemented field {other}" ) ,
356+ }
357+ }
358+
359+ interp_ok ( ( ) )
360+ }
361+
255362 // This method always writes to field `ty`.
256363 // If field `bit_width` is present, it also writes to it (in which case parameter `write_bit_width` must be `Some`).
257364 fn write_primitive_type_info (
0 commit comments