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