|
| 1 | +use rustc_abi::FieldIdx; |
| 2 | +use rustc_hir::LangItem; |
| 3 | +use rustc_middle::mir::interpret::CtfeProvenance; |
| 4 | +use rustc_middle::span_bug; |
| 5 | +use rustc_middle::ty::layout::TyAndLayout; |
| 6 | +use rustc_middle::ty::{self, ScalarInt, Ty}; |
| 7 | +use rustc_span::{Symbol, sym}; |
| 8 | + |
| 9 | +use crate::const_eval::CompileTimeMachine; |
| 10 | +use crate::interpret::{ |
| 11 | + Immediate, InterpCx, InterpResult, MPlaceTy, MemoryKind, Writeable, interp_ok, |
| 12 | +}; |
| 13 | + |
| 14 | +impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { |
| 15 | + /// Writes a `core::mem::type_info::TypeInfo` for a given type, `ty` to the given place. |
| 16 | + pub(crate) fn write_type_info( |
| 17 | + &mut self, |
| 18 | + ty: Ty<'tcx>, |
| 19 | + dest: &impl Writeable<'tcx, CtfeProvenance>, |
| 20 | + ) -> InterpResult<'tcx> { |
| 21 | + let ty_struct = self.tcx.require_lang_item(LangItem::Type, self.tcx.span); |
| 22 | + let ty_struct = self.tcx.type_of(ty_struct).instantiate_identity(); |
| 23 | + assert_eq!(ty_struct, dest.layout().ty); |
| 24 | + let ty_struct = ty_struct.ty_adt_def().unwrap().non_enum_variant(); |
| 25 | + // Fill all fields of the `TypeInfo` struct. |
| 26 | + for (idx, field) in ty_struct.fields.iter_enumerated() { |
| 27 | + 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 | + }; |
| 38 | + match field.name { |
| 39 | + sym::kind => { |
| 40 | + let variant_index = match ty.kind() { |
| 41 | + ty::Tuple(fields) => { |
| 42 | + let (variant, variant_place) = downcast(sym::Tuple)?; |
| 43 | + // project to the single tuple variant field of `type_info::Tuple` struct type |
| 44 | + let tuple_place = self.project_field(&variant_place, FieldIdx::ZERO)?; |
| 45 | + assert_eq!( |
| 46 | + 1, |
| 47 | + tuple_place |
| 48 | + .layout() |
| 49 | + .ty |
| 50 | + .ty_adt_def() |
| 51 | + .unwrap() |
| 52 | + .non_enum_variant() |
| 53 | + .fields |
| 54 | + .len() |
| 55 | + ); |
| 56 | + self.write_tuple_fields(tuple_place, fields, ty)?; |
| 57 | + variant |
| 58 | + } |
| 59 | + // For now just merge all primitives into one `Leaf` variant with no data |
| 60 | + ty::Uint(_) | ty::Int(_) | ty::Float(_) | ty::Char | ty::Bool => { |
| 61 | + downcast(sym::Leaf)?.0 |
| 62 | + } |
| 63 | + ty::Adt(_, _) |
| 64 | + | ty::Foreign(_) |
| 65 | + | ty::Str |
| 66 | + | ty::Array(_, _) |
| 67 | + | ty::Pat(_, _) |
| 68 | + | ty::Slice(_) |
| 69 | + | ty::RawPtr(..) |
| 70 | + | ty::Ref(..) |
| 71 | + | ty::FnDef(..) |
| 72 | + | ty::FnPtr(..) |
| 73 | + | ty::UnsafeBinder(..) |
| 74 | + | ty::Dynamic(..) |
| 75 | + | ty::Closure(..) |
| 76 | + | ty::CoroutineClosure(..) |
| 77 | + | ty::Coroutine(..) |
| 78 | + | ty::CoroutineWitness(..) |
| 79 | + | ty::Never |
| 80 | + | ty::Alias(..) |
| 81 | + | ty::Param(_) |
| 82 | + | ty::Bound(..) |
| 83 | + | ty::Placeholder(_) |
| 84 | + | ty::Infer(..) |
| 85 | + | ty::Error(_) => downcast(sym::Other)?.0, |
| 86 | + }; |
| 87 | + self.write_discriminant(variant_index, &field_dest)? |
| 88 | + } |
| 89 | + other => span_bug!(self.tcx.span, "unknown `Type` field {other}"), |
| 90 | + } |
| 91 | + } |
| 92 | + |
| 93 | + interp_ok(()) |
| 94 | + } |
| 95 | + |
| 96 | + pub(crate) fn write_tuple_fields( |
| 97 | + &mut self, |
| 98 | + tuple_place: impl Writeable<'tcx, CtfeProvenance>, |
| 99 | + fields: &[Ty<'tcx>], |
| 100 | + tuple_ty: Ty<'tcx>, |
| 101 | + ) -> InterpResult<'tcx> { |
| 102 | + // project into the `type_info::Tuple::fields` field |
| 103 | + let fields_slice_place = self.project_field(&tuple_place, FieldIdx::ZERO)?; |
| 104 | + // get the `type_info::Field` type from `fields: &[Field]` |
| 105 | + let field_type = fields_slice_place |
| 106 | + .layout() |
| 107 | + .ty |
| 108 | + .builtin_deref(false) |
| 109 | + .unwrap() |
| 110 | + .sequence_element_type(self.tcx.tcx); |
| 111 | + // Create an array with as many elements as the number of fields in the inspected tuple |
| 112 | + let fields_layout = |
| 113 | + self.layout_of(Ty::new_array(self.tcx.tcx, field_type, fields.len() as u64))?; |
| 114 | + let fields_place = self.allocate(fields_layout, MemoryKind::Stack)?; |
| 115 | + let mut fields_places = self.project_array_fields(&fields_place)?; |
| 116 | + |
| 117 | + let tuple_layout = self.layout_of(tuple_ty)?; |
| 118 | + |
| 119 | + while let Some((i, place)) = fields_places.next(self)? { |
| 120 | + let field_ty = fields[i as usize]; |
| 121 | + self.write_field(field_ty, place, tuple_layout, i)?; |
| 122 | + } |
| 123 | + |
| 124 | + let fields_place = fields_place.map_provenance(CtfeProvenance::as_immutable); |
| 125 | + |
| 126 | + let ptr = Immediate::new_slice(fields_place.ptr(), fields.len() as u64, self); |
| 127 | + |
| 128 | + self.write_immediate(ptr, &fields_slice_place) |
| 129 | + } |
| 130 | + |
| 131 | + fn write_field( |
| 132 | + &mut self, |
| 133 | + field_ty: Ty<'tcx>, |
| 134 | + place: MPlaceTy<'tcx>, |
| 135 | + layout: TyAndLayout<'tcx>, |
| 136 | + idx: u64, |
| 137 | + ) -> InterpResult<'tcx> { |
| 138 | + for (field_idx, field_ty_field) in |
| 139 | + place.layout.ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated() |
| 140 | + { |
| 141 | + let field_place = self.project_field(&place, field_idx)?; |
| 142 | + match field_ty_field.name { |
| 143 | + sym::ty => self.write_type_id(field_ty, &field_place)?, |
| 144 | + sym::offset => { |
| 145 | + let offset = layout.fields.offset(idx as usize); |
| 146 | + self.write_scalar( |
| 147 | + ScalarInt::try_from_target_usize(offset.bytes(), self.tcx.tcx).unwrap(), |
| 148 | + &field_place, |
| 149 | + )?; |
| 150 | + } |
| 151 | + other => { |
| 152 | + span_bug!(self.tcx.def_span(field_ty_field.did), "unimplemented field {other}") |
| 153 | + } |
| 154 | + } |
| 155 | + } |
| 156 | + interp_ok(()) |
| 157 | + } |
| 158 | +} |
0 commit comments