1mod adt;
2
3use std::borrow::Cow;
4
5use rustc_abi::{ExternAbi, FieldIdx};
6use rustc_ast::Mutability;
7use rustc_hir::LangItem;
8use rustc_middle::span_bug;
9use rustc_middle::ty::layout::TyAndLayout;
10use rustc_middle::ty::{self, Const, FnHeader, FnSigTys, ScalarInt, Ty, TyCtxt};
11use rustc_span::{Symbol, sym};
12
13use crate::const_eval::CompileTimeMachine;
14use crate::interpret::{
15 CtfeProvenance, Immediate, InterpCx, InterpResult, MPlaceTy, MemoryKind, Scalar, Writeable,
16 interp_ok,
17};
18
19impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
20 fn allocate_fill_and_write_slice_ptr(
22 &mut self,
23 slice_place: impl Writeable<'tcx, CtfeProvenance>,
24 len: u64,
25 writer: impl Fn(&mut Self, u64, MPlaceTy<'tcx>) -> InterpResult<'tcx>,
26 ) -> InterpResult<'tcx> {
27 let field_ty = slice_place
29 .layout()
30 .ty
31 .builtin_deref(false)
32 .unwrap()
33 .sequence_element_type(self.tcx.tcx);
34
35 let array_layout = self.layout_of(Ty::new_array(self.tcx.tcx, field_ty, len))?;
37 let array_place = self.allocate(array_layout, MemoryKind::Stack)?;
38
39 let mut field_places = self.project_array_fields(&array_place)?;
41 while let Some((i, place)) = field_places.next(self)? {
42 writer(self, i, place)?;
43 }
44
45 let array_place = array_place.map_provenance(CtfeProvenance::as_immutable);
47 let ptr = Immediate::new_slice(array_place.ptr(), len, self);
48 self.write_immediate(ptr, &slice_place)
49 }
50
51 pub(crate) fn write_type_info(
53 &mut self,
54 ty: Ty<'tcx>,
55 dest: &impl Writeable<'tcx, CtfeProvenance>,
56 ) -> InterpResult<'tcx> {
57 let ty_struct = self.tcx.require_lang_item(LangItem::Type, self.tcx.span);
58 let ty_struct = self.tcx.type_of(ty_struct).no_bound_vars().unwrap();
59 match (&ty_struct, &dest.layout().ty) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val, &*right_val,
::core::option::Option::None);
}
}
};assert_eq!(ty_struct, dest.layout().ty);
60 let ty_struct = ty_struct.ty_adt_def().unwrap().non_enum_variant();
61 for (idx, field) in ty_struct.fields.iter_enumerated() {
63 let field_dest = self.project_field(dest, idx)?;
64 let ptr_bit_width = || self.tcx.data_layout.pointer_size().bits();
65 match field.name {
66 sym::kind => {
67 let variant_index = match ty.kind() {
68 ty::Tuple(fields) => {
69 let (variant, variant_place) =
70 self.project_downcast_named(&field_dest, sym::Tuple)?;
71 let tuple_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
73 match (&1,
&tuple_place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.len())
{
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val, &*right_val,
::core::option::Option::None);
}
}
};assert_eq!(
74 1,
75 tuple_place
76 .layout()
77 .ty
78 .ty_adt_def()
79 .unwrap()
80 .non_enum_variant()
81 .fields
82 .len()
83 );
84 self.write_tuple_type_info(tuple_place, fields, ty)?;
85 variant
86 }
87 ty::Array(ty, len) => {
88 let (variant, variant_place) =
89 self.project_downcast_named(&field_dest, sym::Array)?;
90 let array_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
91
92 self.write_array_type_info(array_place, *ty, *len)?;
93
94 variant
95 }
96 ty::Slice(ty) => {
97 let (variant, variant_place) =
98 self.project_downcast_named(&field_dest, sym::Slice)?;
99 let slice_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
100
101 self.write_slice_type_info(slice_place, *ty)?;
102
103 variant
104 }
105 ty::Adt(adt_def, generics) => {
106 self.write_adt_type_info(&field_dest, (ty, *adt_def), generics)?
107 }
108 ty::Bool => {
109 let (variant, _variant_place) =
110 self.project_downcast_named(&field_dest, sym::Bool)?;
111 variant
112 }
113 ty::Char => {
114 let (variant, _variant_place) =
115 self.project_downcast_named(&field_dest, sym::Char)?;
116 variant
117 }
118 ty::Int(int_ty) => {
119 let (variant, variant_place) =
120 self.project_downcast_named(&field_dest, sym::Int)?;
121 let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
122 self.write_int_type_info(
123 place,
124 int_ty.bit_width().unwrap_or_else(ptr_bit_width),
125 true,
126 )?;
127 variant
128 }
129 ty::Uint(uint_ty) => {
130 let (variant, variant_place) =
131 self.project_downcast_named(&field_dest, sym::Int)?;
132 let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
133 self.write_int_type_info(
134 place,
135 uint_ty.bit_width().unwrap_or_else(ptr_bit_width),
136 false,
137 )?;
138 variant
139 }
140 ty::Float(float_ty) => {
141 let (variant, variant_place) =
142 self.project_downcast_named(&field_dest, sym::Float)?;
143 let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
144 self.write_float_type_info(place, float_ty.bit_width())?;
145 variant
146 }
147 ty::Str => {
148 let (variant, _variant_place) =
149 self.project_downcast_named(&field_dest, sym::Str)?;
150 variant
151 }
152 ty::Ref(_, ty, mutability) => {
153 let (variant, variant_place) =
154 self.project_downcast_named(&field_dest, sym::Reference)?;
155 let reference_place =
156 self.project_field(&variant_place, FieldIdx::ZERO)?;
157 self.write_reference_type_info(reference_place, *ty, *mutability)?;
158
159 variant
160 }
161 ty::RawPtr(ty, mutability) => {
162 let (variant, variant_place) =
163 self.project_downcast_named(&field_dest, sym::Pointer)?;
164 let pointer_place =
165 self.project_field(&variant_place, FieldIdx::ZERO)?;
166
167 self.write_pointer_type_info(pointer_place, *ty, *mutability)?;
168
169 variant
170 }
171 ty::Dynamic(predicates, region) => {
172 let (variant, variant_place) =
173 self.project_downcast_named(&field_dest, sym::DynTrait)?;
174 let dyn_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
175 self.write_dyn_trait_type_info(dyn_place, *predicates, *region)?;
176 variant
177 }
178 ty::FnPtr(sig, fn_header) => {
179 let (variant, variant_place) =
180 self.project_downcast_named(&field_dest, sym::FnPtr)?;
181 let fn_ptr_place =
182 self.project_field(&variant_place, FieldIdx::ZERO)?;
183
184 let sig = sig.skip_binder();
186
187 self.write_fn_ptr_type_info(fn_ptr_place, &sig, fn_header)?;
188 variant
189 }
190 ty::Foreign(_)
191 | ty::Pat(_, _)
192 | ty::FnDef(..)
193 | ty::UnsafeBinder(..)
194 | ty::Closure(..)
195 | ty::CoroutineClosure(..)
196 | ty::Coroutine(..)
197 | ty::CoroutineWitness(..)
198 | ty::Never
199 | ty::Alias(..)
200 | ty::Param(_)
201 | ty::Bound(..)
202 | ty::Placeholder(_)
203 | ty::Infer(..)
204 | ty::Error(_) => self.project_downcast_named(&field_dest, sym::Other)?.0,
205 };
206 self.write_discriminant(variant_index, &field_dest)?
207 }
208 other => ::rustc_middle::util::bug::span_bug_fmt(self.tcx.span,
format_args!("unknown `Type` field {0}", other))span_bug!(self.tcx.span, "unknown `Type` field {other}"),
209 }
210 }
211
212 interp_ok(())
213 }
214
215 fn write_field(
216 &mut self,
217 field_ty: Ty<'tcx>,
218 place: MPlaceTy<'tcx>,
219 layout: TyAndLayout<'tcx>,
220 name: Option<Symbol>,
221 idx: u64,
222 ) -> InterpResult<'tcx> {
223 for (field_idx, field_ty_field) in
224 place.layout.ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
225 {
226 let field_place = self.project_field(&place, field_idx)?;
227 match field_ty_field.name {
228 sym::name => {
229 let name = match name.as_ref() {
230 Some(name) => Cow::Borrowed(name.as_str()),
231 None => Cow::Owned(idx.to_string()), };
233 let name_place = self.allocate_str_dedup(&name)?;
234 let ptr = self.mplace_to_imm_ptr(&name_place, None)?;
235 self.write_immediate(*ptr, &field_place)?
236 }
237 sym::ty => {
238 let field_ty = self.tcx.erase_and_anonymize_regions(field_ty);
239 self.write_type_id(field_ty, &field_place)?
240 }
241 sym::offset => {
242 let offset = layout.fields.offset(idx as usize);
243 self.write_scalar(
244 ScalarInt::try_from_target_usize(offset.bytes(), self.tcx.tcx).unwrap(),
245 &field_place,
246 )?;
247 }
248 other => {
249 ::rustc_middle::util::bug::span_bug_fmt(self.tcx.def_span(field_ty_field.did),
format_args!("unimplemented field {0}", other))span_bug!(self.tcx.def_span(field_ty_field.did), "unimplemented field {other}")
250 }
251 }
252 }
253 interp_ok(())
254 }
255
256 pub(crate) fn write_tuple_type_info(
257 &mut self,
258 tuple_place: impl Writeable<'tcx, CtfeProvenance>,
259 fields: &[Ty<'tcx>],
260 tuple_ty: Ty<'tcx>,
261 ) -> InterpResult<'tcx> {
262 let tuple_layout = self.layout_of(tuple_ty)?;
263 let fields_slice_place = self.project_field(&tuple_place, FieldIdx::ZERO)?;
264 self.allocate_fill_and_write_slice_ptr(
265 fields_slice_place,
266 fields.len() as u64,
267 |this, i, place| {
268 let field_ty = fields[i as usize];
269 this.write_field(field_ty, place, tuple_layout, None, i)
270 },
271 )
272 }
273
274 pub(crate) fn write_array_type_info(
275 &mut self,
276 place: impl Writeable<'tcx, CtfeProvenance>,
277 ty: Ty<'tcx>,
278 len: Const<'tcx>,
279 ) -> InterpResult<'tcx> {
280 for (field_idx, field) in
282 place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
283 {
284 let field_place = self.project_field(&place, field_idx)?;
285
286 match field.name {
287 sym::element_ty => self.write_type_id(ty, &field_place)?,
289 sym::len => self.write_scalar(len.to_leaf(), &field_place)?,
291 other => ::rustc_middle::util::bug::span_bug_fmt(self.tcx.def_span(field.did),
format_args!("unimplemented field {0}", other))span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
292 }
293 }
294
295 interp_ok(())
296 }
297
298 pub(crate) fn write_slice_type_info(
299 &mut self,
300 place: impl Writeable<'tcx, CtfeProvenance>,
301 ty: Ty<'tcx>,
302 ) -> InterpResult<'tcx> {
303 for (field_idx, field) in
305 place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
306 {
307 let field_place = self.project_field(&place, field_idx)?;
308
309 match field.name {
310 sym::element_ty => self.write_type_id(ty, &field_place)?,
312 other => ::rustc_middle::util::bug::span_bug_fmt(self.tcx.def_span(field.did),
format_args!("unimplemented field {0}", other))span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
313 }
314 }
315
316 interp_ok(())
317 }
318
319 fn write_int_type_info(
320 &mut self,
321 place: impl Writeable<'tcx, CtfeProvenance>,
322 bit_width: u64,
323 signed: bool,
324 ) -> InterpResult<'tcx> {
325 for (field_idx, field) in
326 place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
327 {
328 let field_place = self.project_field(&place, field_idx)?;
329 match field.name {
330 sym::bits => self.write_scalar(
331 Scalar::from_u32(bit_width.try_into().expect("bit_width overflowed")),
332 &field_place,
333 )?,
334 sym::signed => self.write_scalar(Scalar::from_bool(signed), &field_place)?,
335 other => ::rustc_middle::util::bug::span_bug_fmt(self.tcx.def_span(field.did),
format_args!("unimplemented field {0}", other))span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
336 }
337 }
338 interp_ok(())
339 }
340
341 fn write_float_type_info(
342 &mut self,
343 place: impl Writeable<'tcx, CtfeProvenance>,
344 bit_width: u64,
345 ) -> InterpResult<'tcx> {
346 for (field_idx, field) in
347 place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
348 {
349 let field_place = self.project_field(&place, field_idx)?;
350 match field.name {
351 sym::bits => self.write_scalar(
352 Scalar::from_u32(bit_width.try_into().expect("bit_width overflowed")),
353 &field_place,
354 )?,
355 other => ::rustc_middle::util::bug::span_bug_fmt(self.tcx.def_span(field.did),
format_args!("unimplemented field {0}", other))span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
356 }
357 }
358 interp_ok(())
359 }
360
361 pub(crate) fn write_reference_type_info(
362 &mut self,
363 place: impl Writeable<'tcx, CtfeProvenance>,
364 ty: Ty<'tcx>,
365 mutability: Mutability,
366 ) -> InterpResult<'tcx> {
367 for (field_idx, field) in
369 place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
370 {
371 let field_place = self.project_field(&place, field_idx)?;
372
373 match field.name {
374 sym::pointee => self.write_type_id(ty, &field_place)?,
376 sym::mutable => {
378 self.write_scalar(Scalar::from_bool(mutability.is_mut()), &field_place)?
379 }
380 other => ::rustc_middle::util::bug::span_bug_fmt(self.tcx.def_span(field.did),
format_args!("unimplemented field {0}", other))span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
381 }
382 }
383 interp_ok(())
384 }
385
386 pub(crate) fn write_fn_ptr_type_info(
387 &mut self,
388 place: impl Writeable<'tcx, CtfeProvenance>,
389 sig: &FnSigTys<TyCtxt<'tcx>>,
390 fn_header: &FnHeader<TyCtxt<'tcx>>,
391 ) -> InterpResult<'tcx> {
392 let FnHeader { fn_sig_kind } = fn_header;
393
394 for (field_idx, field) in
395 place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
396 {
397 let field_place = self.project_field(&place, field_idx)?;
398
399 match field.name {
400 sym::unsafety => {
401 self.write_scalar(Scalar::from_bool(!fn_sig_kind.is_safe()), &field_place)?;
402 }
403 sym::abi => match fn_sig_kind.abi() {
404 ExternAbi::C { .. } => {
405 let (rust_variant, _rust_place) =
406 self.project_downcast_named(&field_place, sym::ExternC)?;
407 self.write_discriminant(rust_variant, &field_place)?;
408 }
409 ExternAbi::Rust => {
410 let (rust_variant, _rust_place) =
411 self.project_downcast_named(&field_place, sym::ExternRust)?;
412 self.write_discriminant(rust_variant, &field_place)?;
413 }
414 other_abi => {
415 let (variant, variant_place) =
416 self.project_downcast_named(&field_place, sym::Named)?;
417 let str_place = self.allocate_str_dedup(other_abi.as_str())?;
418 let str_ref = self.mplace_to_imm_ptr(&str_place, None)?;
419 let payload = self.project_field(&variant_place, FieldIdx::ZERO)?;
420 self.write_immediate(*str_ref, &payload)?;
421 self.write_discriminant(variant, &field_place)?;
422 }
423 },
424 sym::inputs => {
425 let inputs = sig.inputs();
426 self.allocate_fill_and_write_slice_ptr(
427 field_place,
428 inputs.len() as _,
429 |this, i, place| this.write_type_id(inputs[i as usize], &place),
430 )?;
431 }
432 sym::output => {
433 let output = sig.output();
434 self.write_type_id(output, &field_place)?;
435 }
436 sym::variadic => {
437 self.write_scalar(Scalar::from_bool(fn_sig_kind.c_variadic()), &field_place)?;
438 }
439 other => ::rustc_middle::util::bug::span_bug_fmt(self.tcx.def_span(field.did),
format_args!("unimplemented field {0}", other))span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
440 }
441 }
442
443 interp_ok(())
444 }
445
446 pub(crate) fn write_pointer_type_info(
447 &mut self,
448 place: impl Writeable<'tcx, CtfeProvenance>,
449 ty: Ty<'tcx>,
450 mutability: Mutability,
451 ) -> InterpResult<'tcx> {
452 for (field_idx, field) in
454 place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
455 {
456 let field_place = self.project_field(&place, field_idx)?;
457
458 match field.name {
459 sym::pointee => self.write_type_id(ty, &field_place)?,
461 sym::mutable => {
463 self.write_scalar(Scalar::from_bool(mutability.is_mut()), &field_place)?
464 }
465 other => ::rustc_middle::util::bug::span_bug_fmt(self.tcx.def_span(field.did),
format_args!("unimplemented field {0}", other))span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
466 }
467 }
468
469 interp_ok(())
470 }
471}