1use itertools::Itertools;
2use rustc_middle::ty;
3use rustc_span::sym;
4
5use super::translate_ctx::*;
6use crate::hax::{self, UnderOwnerState};
7use crate::hax::{HasOwner, Visibility};
8use charon_lib::ast::*;
9use charon_lib::ids::IndexVec;
10
11impl<'tcx, 'ctx> ItemTransCtx<'tcx, 'ctx> {
12 pub(crate) fn translate_erased_region(&mut self) -> Region {
15 if let Some(v) = &mut self.lifetime_freshener {
16 Region::Body(v.push(()))
17 } else {
18 Region::Erased
19 }
20 }
21
22 pub(crate) fn erase_region_binder<T: TyVisitable>(&mut self, b: RegionBinder<T>) -> T {
25 let regions = b
26 .regions
27 .map_ref_indexed(|_, _| self.translate_erased_region());
28 b.apply(regions)
29 }
30
31 pub(crate) fn translate_region(
33 &mut self,
34 span: Span,
35 region: &hax::Region,
36 ) -> Result<Region, Error> {
37 use crate::hax::RegionKind::*;
38 match ®ion.kind {
39 ReErased => Ok(self.translate_erased_region()),
40 ReStatic => Ok(Region::Static),
41 ReBound(hax::BoundVarIndexKind::Bound(id), br) => {
42 Ok(match self.lookup_bound_region(span, *id, br.var) {
43 Ok(var) => Region::Var(var),
44 Err(_) => Region::Erased,
45 })
46 }
47 ReEarlyParam(region) => Ok(match self.lookup_early_region(span, region) {
48 Ok(var) => Region::Var(var),
49 Err(_) => Region::Erased,
50 }),
51 ReVar(..) | RePlaceholder(..) => {
52 raise_error!(
54 self,
55 span,
56 "Should not exist outside of type inference: {region:?}"
57 )
58 }
59 ReBound(..) | ReLateParam(..) | ReError(..) => {
60 raise_error!(self, span, "Unexpected region kind: {region:?}")
61 }
62 }
63 }
64
65 pub(crate) fn translate_hax_int_ty(int_ty: &hax::IntTy) -> IntTy {
66 match int_ty {
67 hax::IntTy::Isize => IntTy::Isize,
68 hax::IntTy::I8 => IntTy::I8,
69 hax::IntTy::I16 => IntTy::I16,
70 hax::IntTy::I32 => IntTy::I32,
71 hax::IntTy::I64 => IntTy::I64,
72 hax::IntTy::I128 => IntTy::I128,
73 }
74 }
75
76 pub(crate) fn translate_hax_uint_ty(uint_ty: &hax::UintTy) -> UIntTy {
77 use crate::hax::UintTy;
78 match uint_ty {
79 UintTy::Usize => UIntTy::Usize,
80 UintTy::U8 => UIntTy::U8,
81 UintTy::U16 => UIntTy::U16,
82 UintTy::U32 => UIntTy::U32,
83 UintTy::U64 => UIntTy::U64,
84 UintTy::U128 => UIntTy::U128,
85 }
86 }
87
88 #[tracing::instrument(skip(self, span))]
97 pub(crate) fn translate_ty(&mut self, span: Span, hax_ty: &hax::Ty) -> Result<Ty, Error> {
98 let mut ty = if let Some(ty) = self
99 .innermost_binder()
100 .type_trans_cache
101 .get(hax_ty)
102 .cloned()
103 {
104 ty
105 } else {
106 let ty = self
107 .translate_ty_inner(span, hax_ty)
108 .unwrap_or_else(|e| TyKind::Error(e.msg).into_ty());
109 self.innermost_binder_mut()
110 .type_trans_cache
111 .insert(hax_ty.clone(), ty.clone());
112 ty
113 };
114 if let Some(v) = &mut self.lifetime_freshener {
115 ty = ty.replace_erased_regions(|| Region::Body(v.push(())));
117 }
118 Ok(ty)
119 }
120
121 fn translate_ty_inner(&mut self, span: Span, ty: &hax::Ty) -> Result<Ty, Error> {
122 trace!("{:?}", ty);
123 let kind = match ty.kind() {
124 hax::TyKind::Bool => TyKind::Literal(LiteralTy::Bool),
125 hax::TyKind::Char => TyKind::Literal(LiteralTy::Char),
126 hax::TyKind::Int(int_ty) => {
127 TyKind::Literal(LiteralTy::Int(Self::translate_hax_int_ty(int_ty)))
128 }
129 hax::TyKind::Uint(uint_ty) => {
130 TyKind::Literal(LiteralTy::UInt(Self::translate_hax_uint_ty(uint_ty)))
131 }
132 hax::TyKind::Float(float_ty) => {
133 use crate::hax::FloatTy;
134 TyKind::Literal(LiteralTy::Float(match float_ty {
135 FloatTy::F16 => types::FloatTy::F16,
136 FloatTy::F32 => types::FloatTy::F32,
137 FloatTy::F64 => types::FloatTy::F64,
138 FloatTy::F128 => types::FloatTy::F128,
139 }))
140 }
141 hax::TyKind::Never => TyKind::Never,
142
143 hax::TyKind::Alias(alias) => match &alias.kind {
144 hax::AliasKind::Projection(item) => {
145 let trait_ref = self.translate_trait_proof(
146 span,
147 item.in_trait
148 .as_ref()
149 .expect("projection without a trait_ref?"),
150 )?;
151 let assoc_type_id =
152 self.translate_assoc_type_id(trait_ref.trait_id(), &item.def_id)?;
153 let generics =
154 self.translate_generic_args(span, &item.generic_args, &item.trait_proofs)?;
155 TyKind::TraitType(trait_ref, assoc_type_id, generics)
156 }
157 hax::AliasKind::Opaque { hidden_ty, .. } => {
158 return self.translate_ty(span, hidden_ty);
159 }
160 _ => {
161 raise_error!(self, span, "Unsupported alias type: {:?}", alias.kind)
162 }
163 },
164
165 hax::TyKind::Adt(item) => {
166 let tref = self.translate_type_decl_ref(span, item)?;
167 TyKind::Adt(tref)
168 }
169 hax::TyKind::Str => {
170 let tref = TypeDeclRef::new(TypeId::Builtin(BuiltinTy::Str), GenericArgs::empty());
171 TyKind::Adt(tref)
172 }
173 hax::TyKind::Array(item_ref) => {
174 let mut args = self.translate_generic_args(span, &item_ref.generic_args, &[])?;
175 assert!(args.types.len() == 1 && args.const_generics.len() == 1);
176 TyKind::Array(
177 args.types.pop().unwrap(),
178 Box::new(args.const_generics.pop().unwrap()),
179 )
180 }
181 hax::TyKind::Pat(ty, pat) => {
182 let ty = self.translate_ty(span, ty)?;
183 let pat = self.translate_pattern(span, pat)?;
184 TyKind::Pattern(ty, pat)
185 }
186 hax::TyKind::Slice(item_ref) => {
187 let mut args = self.translate_generic_args(span, &item_ref.generic_args, &[])?;
188 assert!(args.types.len() == 1);
189 TyKind::Slice(args.types.pop().unwrap())
190 }
191 hax::TyKind::Tuple(item_ref) => {
192 let args = self.translate_generic_args(span, &item_ref.generic_args, &[])?;
193 let tref = TypeDeclRef::new(TypeId::Tuple, args);
194 TyKind::Adt(tref)
195 }
196 hax::TyKind::Ref(region, ty, mutability) => {
197 trace!("Ref");
198
199 let region = self.translate_region(span, region)?;
200 let ty = self.translate_ty(span, ty)?;
201 let kind = if mutability.is_mut() {
202 RefKind::Mut
203 } else {
204 RefKind::Shared
205 };
206 TyKind::Ref(region, ty, kind)
207 }
208 hax::TyKind::RawPtr(ty, mutbl) => {
209 trace!("RawPtr: {:?}", (ty, mutbl));
210 let ty = self.translate_ty(span, ty)?;
211 let kind = if mutbl.is_mut() {
212 RefKind::Mut
213 } else {
214 RefKind::Shared
215 };
216 TyKind::RawPtr(ty, kind)
217 }
218
219 hax::TyKind::Param(param) => {
220 match self.lookup_type_var(span, param) {
228 Ok(var) => TyKind::TypeVar(var),
229 Err(err) => TyKind::Error(err.msg),
230 }
231 }
232
233 hax::TyKind::Foreign(item) => {
234 let tref = self.translate_type_decl_ref(span, item)?;
235 TyKind::Adt(tref)
236 }
237
238 hax::TyKind::Arrow(sig) => {
239 trace!("Arrow");
240 trace!("bound vars: {:?}", sig.bound_vars);
241 let sig = self.translate_poly_fun_sig(span, sig)?;
242 TyKind::FnPtr(sig)
243 }
244 hax::TyKind::FnDef { item, .. } => {
245 let fnref = self.translate_bound_fn_ptr(span, item, TransItemSourceKind::Fun)?;
246 TyKind::FnDef(fnref)
247 }
248 hax::TyKind::Closure(args) => {
249 let tref = self.translate_closure_type_ref(span, args)?;
250 TyKind::Adt(tref)
251 }
252
253 hax::TyKind::Dynamic(dyn_binder, region) => {
254 let region = self.translate_region(span, region)?;
257
258 let binder = self.translate_dyn_binder(span, dyn_binder, |ctx, ty, ()| {
259 let region = region.move_under_binder();
260 ctx.innermost_binder_mut()
261 .params
262 .types_outlive
263 .push(RegionBinder::empty(OutlivesPred(ty.clone(), region)));
264 Ok(ty)
265 })?;
266
267 if let hax::ClauseKind::Trait(trait_predicate) = dyn_binder.predicates.predicates[0]
268 .clause
269 .kind
270 .hax_skip_binder_ref()
271 {
272 if self.trait_is_dyn_compatible(&trait_predicate.trait_ref.def_id)? {
276 if self.monomorphize() {
279 let item_src = TransItemSource::monomorphic_trait(
280 &trait_predicate.trait_ref.def_id,
281 TransItemSourceKind::VTable,
282 );
283 let _: TypeDeclId = self.register_and_enqueue(span, item_src);
284 } else {
285 let _: TypeDeclId = self.register_item(
286 span,
287 &trait_predicate.trait_ref,
288 TransItemSourceKind::VTable,
289 );
290 }
291 }
292 }
293 TyKind::DynTrait(DynPredicate { binder })
294 }
295
296 hax::TyKind::Infer(_) => {
297 raise_error!(self, span, "Unsupported type: infer type")
298 }
299 hax::TyKind::Coroutine(..) => {
300 raise_error!(self, span, "Coroutine types are not supported yet")
301 }
302 hax::TyKind::Bound(_, _) => {
303 raise_error!(self, span, "Unexpected type kind: bound")
304 }
305 hax::TyKind::Placeholder(_) => {
306 raise_error!(self, span, "Unsupported type: placeholder")
307 }
308
309 hax::TyKind::Error => {
310 raise_error!(self, span, "Type checking error")
311 }
312 hax::TyKind::Todo(s) => {
313 raise_error!(self, span, "Unsupported type: {:?}", s)
314 }
315 };
316 Ok(kind.into_ty())
317 }
318
319 pub fn translate_pattern(
320 &mut self,
321 span: Span,
322 pat: &hax::Pattern,
323 ) -> Result<TypePattern, Error> {
324 Ok(match pat {
325 hax::Pattern::Range { start, end } => TypePattern::Range(
326 Box::new(self.translate_constant_expr(span, start)?),
327 Box::new(self.translate_constant_expr(span, end)?),
328 ),
329 hax::Pattern::Or(patterns) => TypePattern::OrPattern(
330 patterns
331 .iter()
332 .map(|pat| self.translate_pattern(span, pat))
333 .try_collect()?,
334 ),
335 hax::Pattern::NotNull => TypePattern::NotNull,
336 })
337 }
338
339 pub(crate) fn translate_rustc_ty(
340 &mut self,
341 span: Span,
342 ty: &ty::Ty<'tcx>,
343 ) -> Result<Ty, Error> {
344 let ty = self.t_ctx.catch_sinto(&self.hax_state, span, ty)?;
345 self.translate_ty(span, &ty)
346 }
347
348 pub fn translate_poly_fun_sig(
349 &mut self,
350 span: Span,
351 sig: &hax::Binder<hax::TyFnSig>,
352 ) -> Result<RegionBinder<FunSig>, Error> {
353 self.translate_region_binder(span, sig, |ctx, sig| ctx.translate_fun_sig(span, sig))
354 }
355 pub fn translate_fun_sig(&mut self, span: Span, sig: &hax::TyFnSig) -> Result<FunSig, Error> {
356 let inputs = sig
357 .inputs
358 .iter()
359 .map(|x| self.translate_ty(span, x))
360 .try_collect()?;
361 let output = self.translate_ty(span, &sig.output)?;
362 Ok(FunSig {
363 is_unsafe: sig.safety == hax::Safety::Unsafe,
364 abi: Self::translate_abi(&sig.abi),
365 inputs,
366 output,
367 })
368 }
369
370 pub fn translate_abi(abi: &hax::ExternAbi) -> Abi {
371 match abi {
372 hax::ExternAbi::Rust => Abi::Rust,
373 hax::ExternAbi::C { unwind: false } => Abi::C,
374 _ => Abi::Other(abi.as_str().into()),
375 }
376 }
377
378 pub fn translate_generic_args(
380 &mut self,
381 span: Span,
382 substs: &[hax::GenericArg],
383 trait_refs: &[hax::TraitProof],
384 ) -> Result<GenericArgs, Error> {
385 use crate::hax::GenericArg::*;
386 trace!("{:?}", substs);
387
388 let mut regions = IndexVec::new();
389 let mut types = IndexVec::new();
390 let mut const_generics = IndexVec::new();
391 for param in substs {
392 match param {
393 Type(param_ty) => {
394 types.push(self.translate_ty(span, param_ty)?);
395 }
396 Lifetime(region) => {
397 regions.push(self.translate_region(span, region)?);
398 }
399 Const(c) => {
400 const_generics.push(self.translate_constant_expr(span, c)?);
401 }
402 }
403 }
404 let trait_refs = self.translate_trait_proofs(span, trait_refs)?;
405
406 Ok(GenericArgs {
407 regions,
408 types,
409 const_generics,
410 trait_refs,
411 })
412 }
413
414 pub(crate) fn recognize_builtin_type(
416 &mut self,
417 item: &hax::ItemRef,
418 ) -> Result<Option<BuiltinTy>, Error> {
419 let def = self.hax_def(item)?;
420 let ty = if def.lang_item == Some(sym::owned_box) && self.t_ctx.options.treat_box_as_builtin
421 {
422 Some(BuiltinTy::Box)
423 } else {
424 None
425 };
426 Ok(ty)
427 }
428
429 pub fn translate_ptr_metadata(
433 &mut self,
434 span: Span,
435 item: &hax::ItemRef,
436 ) -> Result<PtrMetadata, Error> {
437 use rustc_middle::ty;
439 let tcx = self.t_ctx.tcx;
440 let hax_state = &self.hax_state;
441 let ty_env = hax_state.typing_env();
442 let ty = item
443 .def_id
444 .type_of(hax_state)
445 .instantiate(tcx, item.rustc_args(hax_state));
446 let ty = hax::normalize(tcx, ty_env, ty);
447
448 let tail_ty = tcx.struct_tail_raw(
450 ty,
451 &rustc_middle::traits::ObligationCause::dummy(),
452 |ty| hax::normalize(tcx, ty_env, ty),
453 || {},
454 );
455 let hax_ty: hax::Ty = self.t_ctx.catch_sinto(hax_state, span, &tail_ty)?;
456
457 let everything_is_sized = self.t_ctx.options.hide_marker_traits;
459 let ret = match tail_ty.kind() {
460 _ if everything_is_sized || tail_ty.is_sized(tcx, ty_env) => PtrMetadata::None,
461 ty::Str | ty::Slice(..) => PtrMetadata::Length,
462 ty::Dynamic(..) => match hax_ty.kind() {
463 hax::TyKind::Dynamic(dyn_binder, _) => {
464 let vtable = self.translate_dyn_binder(span, dyn_binder, |ctx, _, _| {
465 ctx.translate_region_binder(
466 span,
467 &dyn_binder.predicates.predicates[0].clause.kind,
468 |ctx, kind: &hax::ClauseKind| {
469 let hax::ClauseKind::Trait(trait_predicate) = kind else {
470 unreachable!()
471 };
472 ctx.translate_vtable_struct_ref(span, &trait_predicate.trait_ref)
473 },
474 )
475 })?;
476 let vtable = vtable
477 .skip_binder
478 .try_substitute(&GenericArgs::empty())
479 .expect("vtable struct should not depend on self type");
480 let vtable = self.erase_region_binder(vtable);
481 PtrMetadata::VTable(vtable)
482 }
483 _ => unreachable!("Unexpected hax type {hax_ty:?} for dynamic type: {ty:?}"),
484 },
485 ty::Param(..) => PtrMetadata::InheritFrom(self.translate_ty(span, &hax_ty)?),
486 ty::Placeholder(..) | ty::Infer(..) | ty::Bound(..) => {
487 panic!(
488 "We should never encounter a placeholder, infer, or bound type from ptr_metadata translation. Got: {tail_ty:?}"
489 )
490 }
491 _ => PtrMetadata::None,
492 };
493
494 Ok(ret)
495 }
496
497 #[tracing::instrument(skip(self))]
502 pub fn translate_layout(&mut self, def: &hax::FullDef<'tcx>) -> Option<Layout> {
503 let item = def.this();
504 use rustc_abi as r_abi;
505
506 fn translate_variant_layout(
507 variant_layout: &r_abi::VariantLayout<r_abi::FieldIdx>,
508 tagger: Vec<(ByteCount, ScalarValue)>,
509 ) -> Option<VariantLayout> {
510 let field_offsets = variant_layout
511 .field_offsets
512 .iter()
513 .map(|o| o.bytes())
514 .collect();
515 Some(VariantLayout {
516 field_offsets,
517 uninhabited: variant_layout.is_uninhabited(),
518 tagger,
519 })
520 }
521
522 fn translate_layout_data(
523 layout_data: &r_abi::LayoutData<r_abi::FieldIdx, r_abi::VariantIdx>,
524 tagger: Vec<(ByteCount, ScalarValue)>,
525 ) -> Option<VariantLayout> {
526 let field_offsets = match &layout_data.fields {
527 r_abi::FieldsShape::Arbitrary { offsets, .. } => {
528 offsets.iter().map(|o| o.bytes()).collect()
529 }
530 r_abi::FieldsShape::Union(n) => vec![0; n.get()].into(),
531 r_abi::FieldsShape::Primitive => IndexVec::default(),
532 r_abi::FieldsShape::Array { .. } => panic!("Unexpected layout shape"),
533 };
534 Some(VariantLayout {
535 field_offsets,
536 uninhabited: layout_data.is_uninhabited(),
537 tagger,
538 })
539 }
540
541 fn translate_primitive_int(int_ty: r_abi::Integer, signed: bool) -> IntegerTy {
542 if signed {
543 IntegerTy::Signed(match int_ty {
544 r_abi::Integer::I8 => IntTy::I8,
545 r_abi::Integer::I16 => IntTy::I16,
546 r_abi::Integer::I32 => IntTy::I32,
547 r_abi::Integer::I64 => IntTy::I64,
548 r_abi::Integer::I128 => IntTy::I128,
549 })
550 } else {
551 IntegerTy::Unsigned(match int_ty {
552 r_abi::Integer::I8 => UIntTy::U8,
553 r_abi::Integer::I16 => UIntTy::U16,
554 r_abi::Integer::I32 => UIntTy::U32,
555 r_abi::Integer::I64 => UIntTy::U64,
556 r_abi::Integer::I128 => UIntTy::U128,
557 })
558 }
559 }
560
561 let tcx = self.t_ctx.tcx;
562 let hax_state = self.hax_state_with_id();
563 assert_eq!(hax_state.owner(), item.def_id);
564 let ty_env = hax_state.typing_env();
565 let ty = item
566 .def_id
567 .type_of(hax_state)
568 .instantiate(tcx, item.rustc_args(hax_state));
569 let ty = hax::normalize(tcx, ty_env, ty);
570 let pseudo_input = ty_env.as_query_input(ty);
571 let ptr_size = self.translated.the_target_information().target_pointer_size;
572
573 let layout = tcx.layout_of(pseudo_input).ok()?.layout;
575 let (size, align) = if layout.is_sized() {
576 (
577 Some(layout.size().bytes()),
578 Some(layout.align().abi.bytes()),
579 )
580 } else {
581 (None, None)
582 };
583
584 let (discriminator, variant_layouts) = match layout.variants() {
586 r_abi::Variants::Multiple {
587 tag,
588 tag_encoding,
589 tag_field,
590 variants,
591 ..
592 } => {
593 let r_abi::FieldsShape::Arbitrary { offsets, .. } = layout.fields() else {
595 unreachable!()
596 };
597 let tag_offset = offsets
598 .get(*tag_field)
599 .map(|s| r_abi::Size::bytes(*s))
600 .expect("No tag field offset for enum?");
601
602 let tag_ty = match tag.primitive() {
603 r_abi::Primitive::Int(int_ty, signed) => {
604 translate_primitive_int(int_ty, signed)
605 }
606 r_abi::Primitive::Pointer(_) => IntegerTy::Signed(IntTy::Isize),
607 r_abi::Primitive::Float(_) => unreachable!(),
608 };
609 let tag_size = r_abi::Size::from_bytes(tag_ty.target_size(ptr_size));
610 let tag_for_variant = |id: rustc_abi::VariantIdx| {
611 tcx.tag_for_variant(ty_env.as_query_input((ty, id)))
612 .map(|s| match tag_ty {
613 IntegerTy::Signed(int_ty) => {
614 ScalarValue::from_int(ptr_size, int_ty, s.to_int(tag_size)).unwrap()
615 }
616 IntegerTy::Unsigned(uint_ty) => {
617 ScalarValue::from_uint(ptr_size, uint_ty, s.to_uint(tag_size))
618 .unwrap()
619 }
620 })
621 };
622
623 let mut variant_layouts: IndexVec<VariantId, Option<VariantLayout>> =
625 IndexVec::new();
626 let mut children = Vec::new();
627
628 for (id, variant_layout) in variants.iter_enumerated() {
629 let variant_id = self.translate_variant_id(id);
630 let tagger = if variant_layout.is_uninhabited() {
631 vec![]
632 } else if let Some(val) = tag_for_variant(id) {
633 children.push((val..=val, Discriminator::Known(variant_id)));
634 vec![(tag_offset, val)]
635 } else {
636 vec![]
638 };
639 variant_layouts.push(translate_variant_layout(variant_layout, tagger));
640 }
641
642 let fallback = match tag_encoding {
643 r_abi::TagEncoding::Direct => Discriminator::Invalid,
644 r_abi::TagEncoding::Niche {
645 untagged_variant,
646 niche_variants,
647 ..
648 } => {
649 if niche_variants.contains(untagged_variant)
650 && let Some(start) = tag_for_variant(niche_variants.start)
651 && let Some(end) = tag_for_variant(niche_variants.last)
652 {
653 let discriminator = Discriminator::Branch {
659 offset: tag_offset,
660 int_ty: tag_ty,
661 fallback: Box::new(Discriminator::Invalid),
662 children,
663 };
664 children = vec![(start..=end, discriminator)];
665 }
666 Discriminator::Known(self.translate_variant_id(*untagged_variant))
667 }
668 };
669
670 let discriminator = Discriminator::Branch {
671 offset: tag_offset,
672 int_ty: tag_ty,
673 fallback: Box::new(fallback),
674 children,
675 };
676
677 (Some(discriminator), variant_layouts)
678 }
679 r_abi::Variants::Single { index } => {
680 let variant_id = self.translate_variant_id(*index);
681 let variant_layouts = match layout.fields() {
682 r_abi::FieldsShape::Arbitrary { .. } => {
683 let n_variants = if let Some(range) = ty.variant_range(self.t_ctx.tcx) {
684 range.end.index()
685 } else {
686 1
687 };
688 let mut variant_layouts: IndexVec<VariantId, Option<VariantLayout>> =
689 (0..n_variants).map(|_| None).collect();
690 variant_layouts[variant_id] = translate_layout_data(&layout, vec![]);
691 variant_layouts
692 }
693 r_abi::FieldsShape::Union(_) => {
694 vec![translate_layout_data(&layout, vec![])].into()
695 }
696 r_abi::FieldsShape::Primitive | r_abi::FieldsShape::Array { .. } => {
697 vec![].into()
698 }
699 };
700 (Some(Discriminator::trivial(variant_id)), variant_layouts)
701 }
702 r_abi::Variants::Empty => (None, IndexVec::new()),
703 };
704
705 let repr = match &def.kind {
706 hax::FullDefKind::Adt { repr: hax_repr, .. } => self.translate_repr_options(hax_repr),
707 _ => ReprOptions::default(),
708 };
709
710 Some(Layout {
711 size,
712 align,
713 discriminator,
714 uninhabited: layout.is_uninhabited(),
715 variant_layouts,
716 repr,
717 })
718 }
719
720 pub fn generate_naive_layout(&self, span: Span, ty: &TypeDeclKind) -> Result<Layout, Error> {
722 match ty {
723 TypeDeclKind::Struct(fields) => {
724 let mut size = 0;
725 let mut align = 0;
726 let ptr_size = self.translated.the_target_information().target_pointer_size;
727 let field_offsets = fields.map_ref(|field| {
728 let offset = size;
729 let size_of_ty = match field.ty.kind() {
730 TyKind::Literal(literal_ty) => literal_ty.target_size(ptr_size) as u64,
731 TyKind::Ref(..) | TyKind::RawPtr(..) | TyKind::FnPtr(..) => ptr_size,
733 _ => panic!("Unsupported type for `generate_naive_layout`: {ty:?}"),
734 };
735 size += size_of_ty;
736 align = std::cmp::max(align, size);
738 offset
739 });
740
741 Ok(Layout {
742 size: Some(size),
743 align: Some(align),
744 discriminator: None,
745 uninhabited: false,
746 variant_layouts: IndexVec::from([Some(VariantLayout {
747 field_offsets,
748 tagger: vec![],
749 uninhabited: false,
750 })]),
751 repr: ReprOptions::default(),
752 })
753 }
754 _ => raise_error!(
755 self,
756 span,
757 "`generate_naive_layout` only supports structs at the moment"
758 ),
759 }
760 }
761
762 pub(crate) fn translate_adt_def(
768 &mut self,
769 trans_id: TypeDeclId,
770 def_span: Span,
771 item_meta: &ItemMeta,
772 def: &hax::FullDef<'tcx>,
773 ) -> Result<TypeDeclKind, Error> {
774 use crate::hax::AdtKind;
775 let hax::FullDefKind::Adt {
776 adt_kind, variants, ..
777 } = def.kind()
778 else {
779 unreachable!()
780 };
781
782 if item_meta.opacity.is_opaque() {
783 return Ok(TypeDeclKind::Opaque);
784 }
785
786 trace!("{}", trans_id);
787
788 let contents_are_public = match adt_kind {
793 AdtKind::Enum => true,
794 AdtKind::Struct | AdtKind::Union => {
795 error_assert!(self, def_span, variants.len() == 1);
797 variants[hax::VariantIdx::from(0usize)]
798 .fields
799 .iter()
800 .all(|f| matches!(f.vis, Visibility::Public))
801 }
802 _ => unreachable!(),
804 };
805
806 if item_meta
807 .opacity
808 .with_content_visibility(contents_are_public)
809 .is_opaque()
810 {
811 return Ok(TypeDeclKind::Opaque);
812 }
813
814 let mut translated_variants: IndexVec<VariantId, Variant> = Default::default();
816 for (i, var_def) in variants.iter().enumerate() {
817 trace!("variant {i}: {var_def:?}");
818
819 let mut fields: IndexVec<FieldId, Field> = Default::default();
820 let mut have_names: Option<bool> = None;
823 for (j, field_def) in var_def.fields.iter().enumerate() {
824 trace!("variant {i}: field {j}: {field_def:?}");
825 let field_span = self.t_ctx.translate_span(&field_def.span);
826 let ty = self.translate_ty(field_span, &field_def.ty)?;
828 let field_full_def =
829 self.hax_def(&def.this().with_def_id(self.hax_state(), &field_def.did))?;
830 let field_attrs = self.t_ctx.translate_attr_info(&field_full_def);
831
832 let field_name = field_def.name.map(|s| s.to_string());
834 match &have_names {
836 None => {
837 have_names = match &field_name {
838 None => Some(false),
839 Some(_) => Some(true),
840 }
841 }
842 Some(b) => {
843 error_assert!(self, field_span, *b == field_name.is_some());
844 }
845 };
846
847 let field = Field {
849 span: field_span,
850 attr_info: field_attrs,
851 name: field_name,
852 ty,
853 };
854 fields.push(field);
855 }
856
857 let discriminant = self.translate_discriminant(def_span, &var_def.discr_val)?;
858 let variant_span = self.t_ctx.translate_span(&var_def.span);
859 let variant_name = var_def.name.to_string();
860 let variant_full_def =
861 self.hax_def(&def.this().with_def_id(self.hax_state(), &var_def.def_id))?;
862
863 let mut variant_attrs = self.t_ctx.translate_attr_info(&variant_full_def);
864 if variant_attrs.rename.is_none() {
866 let prefix = item_meta
867 .attr_info
868 .attributes
869 .iter()
870 .filter_map(|a| a.as_variants_prefix())
871 .next()
872 .map(|attr| attr.as_str());
873 let suffix = item_meta
874 .attr_info
875 .attributes
876 .iter()
877 .filter_map(|a| a.as_variants_suffix())
878 .next()
879 .map(|attr| attr.as_str());
880 if prefix.is_some() || suffix.is_some() {
881 let prefix = prefix.unwrap_or_default();
882 let suffix = suffix.unwrap_or_default();
883 variant_attrs.rename = Some(format!("{prefix}{variant_name}{suffix}"));
884 }
885 }
886
887 translated_variants.push_with(|id| Variant {
888 id,
889 span: variant_span,
890 attr_info: variant_attrs,
891 name: variant_name,
892 fields,
893 discriminant,
894 });
895 }
896
897 let type_def_kind: TypeDeclKind = match adt_kind {
899 AdtKind::Struct => TypeDeclKind::Struct(translated_variants[0].fields.clone()),
900 AdtKind::Enum => TypeDeclKind::Enum(translated_variants),
901 AdtKind::Union => TypeDeclKind::Union(translated_variants[0].fields.clone()),
902 _ => unreachable!(),
904 };
905
906 Ok(type_def_kind)
907 }
908
909 fn translate_discriminant(
910 &mut self,
911 def_span: Span,
912 discr: &hax::DiscriminantValue,
913 ) -> Result<Literal, Error> {
914 let ty = self.translate_ty(def_span, &discr.ty)?;
915 let lit_ty = ty.kind().as_literal().unwrap();
916 match Literal::from_bits(lit_ty, discr.val) {
917 Some(lit) => Ok(lit),
918 None => raise_error!(self, def_span, "unexpected discriminant type: {ty:?}",),
919 }
920 }
921
922 pub fn translate_repr_options(&mut self, hax_repr_options: &hax::ReprOptions) -> ReprOptions {
923 let repr_algo = if hax_repr_options.flags.is_c {
924 ReprAlgorithm::C
925 } else {
926 ReprAlgorithm::Rust
927 };
928
929 let align_mod = if let Some(align) = &hax_repr_options.align {
930 Some(AlignmentModifier::Align(align.bytes))
931 } else if let Some(pack) = &hax_repr_options.pack {
932 Some(AlignmentModifier::Pack(pack.bytes))
933 } else {
934 None
935 };
936
937 ReprOptions {
938 transparent: hax_repr_options.flags.is_transparent,
939 explicit_discr_type: hax_repr_options.int_specified,
940 repr_algo,
941 align_modif: align_mod,
942 }
943 }
944}