1use itertools::Itertools;
2use rustc_middle::ty;
3use rustc_span::sym;
4
5use super::translate_ctx::*;
6use charon_lib::ast::*;
7use charon_lib::ids::{IndexMap, IndexVec};
8use hax::{HasOwnerId, HasParamEnv, Visibility};
9
10impl<'tcx, 'ctx> ItemTransCtx<'tcx, 'ctx> {
11 pub(crate) fn translate_erased_region(&mut self) -> Region {
14 if let Some(v) = &mut self.lifetime_freshener {
15 Region::Body(v.push(()))
16 } else {
17 Region::Erased
18 }
19 }
20
21 pub(crate) fn erase_region_binder<T: TyVisitable>(&mut self, b: RegionBinder<T>) -> T {
24 let regions = b
25 .regions
26 .map_ref_indexed(|_, _| self.translate_erased_region());
27 b.apply(regions)
28 }
29
30 pub(crate) fn translate_region(
32 &mut self,
33 span: Span,
34 region: &hax::Region,
35 ) -> Result<Region, Error> {
36 use hax::RegionKind::*;
37 match ®ion.kind {
38 ReErased => Ok(self.translate_erased_region()),
39 ReStatic => Ok(Region::Static),
40 ReBound(hax::BoundVarIndexKind::Bound(id), br) => {
41 Ok(match self.lookup_bound_region(span, *id, br.var) {
42 Ok(var) => Region::Var(var),
43 Err(_) => Region::Erased,
44 })
45 }
46 ReEarlyParam(region) => Ok(match self.lookup_early_region(span, region) {
47 Ok(var) => Region::Var(var),
48 Err(_) => Region::Erased,
49 }),
50 ReVar(..) | RePlaceholder(..) => {
51 raise_error!(
53 self,
54 span,
55 "Should not exist outside of type inference: {region:?}"
56 )
57 }
58 ReBound(..) | ReLateParam(..) | ReError(..) => {
59 raise_error!(self, span, "Unexpected region kind: {region:?}")
60 }
61 }
62 }
63
64 pub(crate) fn translate_hax_int_ty(int_ty: &hax::IntTy) -> IntTy {
65 match int_ty {
66 hax::IntTy::Isize => IntTy::Isize,
67 hax::IntTy::I8 => IntTy::I8,
68 hax::IntTy::I16 => IntTy::I16,
69 hax::IntTy::I32 => IntTy::I32,
70 hax::IntTy::I64 => IntTy::I64,
71 hax::IntTy::I128 => IntTy::I128,
72 }
73 }
74
75 pub(crate) fn translate_hax_uint_ty(uint_ty: &hax::UintTy) -> UIntTy {
76 use hax::UintTy;
77 match uint_ty {
78 UintTy::Usize => UIntTy::Usize,
79 UintTy::U8 => UIntTy::U8,
80 UintTy::U16 => UIntTy::U16,
81 UintTy::U32 => UIntTy::U32,
82 UintTy::U64 => UIntTy::U64,
83 UintTy::U128 => UIntTy::U128,
84 }
85 }
86
87 #[tracing::instrument(skip(self, span))]
96 pub(crate) fn translate_ty(&mut self, span: Span, hax_ty: &hax::Ty) -> Result<Ty, Error> {
97 if let Some(ty) = self
98 .innermost_binder()
99 .type_trans_cache
100 .get(&hax_ty)
101 .cloned()
102 {
103 return Ok(ty);
104 }
105 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 Ok(ty)
113 }
114
115 fn translate_ty_inner(&mut self, span: Span, ty: &hax::Ty) -> Result<Ty, Error> {
116 trace!("{:?}", ty);
117 let kind = match ty.kind() {
118 hax::TyKind::Bool => TyKind::Literal(LiteralTy::Bool),
119 hax::TyKind::Char => TyKind::Literal(LiteralTy::Char),
120 hax::TyKind::Int(int_ty) => {
121 TyKind::Literal(LiteralTy::Int(Self::translate_hax_int_ty(int_ty)))
122 }
123 hax::TyKind::Uint(uint_ty) => {
124 TyKind::Literal(LiteralTy::UInt(Self::translate_hax_uint_ty(uint_ty)))
125 }
126 hax::TyKind::Float(float_ty) => {
127 use hax::FloatTy;
128 TyKind::Literal(LiteralTy::Float(match float_ty {
129 FloatTy::F16 => types::FloatTy::F16,
130 FloatTy::F32 => types::FloatTy::F32,
131 FloatTy::F64 => types::FloatTy::F64,
132 FloatTy::F128 => types::FloatTy::F128,
133 }))
134 }
135 hax::TyKind::Never => TyKind::Never,
136
137 hax::TyKind::Alias(alias) => match &alias.kind {
138 hax::AliasKind::Projection {
139 impl_expr,
140 assoc_item,
141 } => {
142 let trait_ref = self.translate_trait_impl_expr(span, impl_expr)?;
143 let name = self.t_ctx.translate_trait_item_name(&assoc_item.def_id)?;
144 TyKind::TraitType(trait_ref, name)
145 }
146 hax::AliasKind::Opaque { hidden_ty, .. } => {
147 return self.translate_ty(span, hidden_ty);
148 }
149 _ => {
150 raise_error!(self, span, "Unsupported alias type: {:?}", alias.kind)
151 }
152 },
153
154 hax::TyKind::Adt(item) => {
155 let tref = self.translate_type_decl_ref(span, item)?;
156 TyKind::Adt(tref)
157 }
158 hax::TyKind::Str => {
159 let tref = TypeDeclRef::new(TypeId::Builtin(BuiltinTy::Str), GenericArgs::empty());
160 TyKind::Adt(tref)
161 }
162 hax::TyKind::Array(item_ref) => {
163 let mut args = self.translate_generic_args(span, &item_ref.generic_args, &[])?;
164 assert!(args.types.elem_count() == 1 && args.const_generics.elem_count() == 1);
165 TyKind::Array(
166 args.types.pop().unwrap(),
167 Box::new(args.const_generics.pop().unwrap()),
168 )
169 }
170 hax::TyKind::Slice(item_ref) => {
171 let mut args = self.translate_generic_args(span, &item_ref.generic_args, &[])?;
172 assert!(args.types.elem_count() == 1);
173 TyKind::Slice(args.types.pop().unwrap())
174 }
175 hax::TyKind::Tuple(item_ref) => {
176 let args = self.translate_generic_args(span, &item_ref.generic_args, &[])?;
177 let tref = TypeDeclRef::new(TypeId::Tuple, args);
178 TyKind::Adt(tref)
179 }
180 hax::TyKind::Ref(region, ty, mutability) => {
181 trace!("Ref");
182
183 let region = self.translate_region(span, region)?;
184 let ty = self.translate_ty(span, ty)?;
185 let kind = if mutability.is_mut() {
186 RefKind::Mut
187 } else {
188 RefKind::Shared
189 };
190 TyKind::Ref(region, ty, kind)
191 }
192 hax::TyKind::RawPtr(ty, mutbl) => {
193 trace!("RawPtr: {:?}", (ty, mutbl));
194 let ty = self.translate_ty(span, ty)?;
195 let kind = if mutbl.is_mut() {
196 RefKind::Mut
197 } else {
198 RefKind::Shared
199 };
200 TyKind::RawPtr(ty, kind)
201 }
202
203 hax::TyKind::Param(param) => {
204 match self.lookup_type_var(span, param) {
212 Ok(var) => TyKind::TypeVar(var),
213 Err(err) => TyKind::Error(err.msg),
214 }
215 }
216
217 hax::TyKind::Foreign(item) => {
218 let tref = self.translate_type_decl_ref(span, item)?;
219 TyKind::Adt(tref)
220 }
221
222 hax::TyKind::Arrow(sig) => {
223 trace!("Arrow");
224 trace!("bound vars: {:?}", sig.bound_vars);
225 let sig = self.translate_poly_fun_sig(span, sig)?;
226 TyKind::FnPtr(sig)
227 }
228 hax::TyKind::FnDef { item, .. } => {
229 let fnref = self.translate_bound_fn_ptr(span, item, TransItemSourceKind::Fun)?;
230 TyKind::FnDef(fnref)
231 }
232 hax::TyKind::Closure(args) => {
233 let tref = self.translate_closure_type_ref(span, args)?;
234 TyKind::Adt(tref)
235 }
236
237 hax::TyKind::Dynamic(dyn_binder, region) => {
238 self.check_no_monomorphize(span)?;
239 let region = self.translate_region(span, region)?;
241
242 let binder = self.translate_dyn_binder(span, dyn_binder, |ctx, ty, ()| {
243 let region = region.move_under_binder();
244 ctx.innermost_binder_mut()
245 .params
246 .types_outlive
247 .push(RegionBinder::empty(OutlivesPred(ty.clone(), region)));
248 Ok(ty)
249 })?;
250
251 if let hax::ClauseKind::Trait(trait_predicate) = dyn_binder.predicates.predicates[0]
252 .0
253 .kind
254 .hax_skip_binder_ref()
255 {
256 if self.trait_is_dyn_compatible(&trait_predicate.trait_ref.def_id)? {
260 let _: TypeDeclId = self.register_item(
263 span,
264 &trait_predicate.trait_ref,
265 TransItemSourceKind::VTable,
266 );
267 }
268 }
269 TyKind::DynTrait(DynPredicate { binder })
270 }
271
272 hax::TyKind::Infer(_) => {
273 raise_error!(self, span, "Unsupported type: infer type")
274 }
275 hax::TyKind::Coroutine(..) => {
276 raise_error!(self, span, "Coroutine types are not supported yet")
277 }
278 hax::TyKind::Bound(_, _) => {
279 raise_error!(self, span, "Unexpected type kind: bound")
280 }
281 hax::TyKind::Placeholder(_) => {
282 raise_error!(self, span, "Unsupported type: placeholder")
283 }
284
285 hax::TyKind::Error => {
286 raise_error!(self, span, "Type checking error")
287 }
288 hax::TyKind::Todo(s) => {
289 raise_error!(self, span, "Unsupported type: {:?}", s)
290 }
291 };
292 Ok(kind.into_ty())
293 }
294
295 pub(crate) fn translate_rustc_ty(
296 &mut self,
297 span: Span,
298 ty: &ty::Ty<'tcx>,
299 ) -> Result<Ty, Error> {
300 let ty = self.t_ctx.catch_sinto(&self.hax_state, span, ty)?;
301 self.translate_ty(span, &ty)
302 }
303
304 pub fn translate_poly_fun_sig(
305 &mut self,
306 span: Span,
307 sig: &hax::Binder<hax::TyFnSig>,
308 ) -> Result<RegionBinder<FunSig>, Error> {
309 self.translate_region_binder(span, sig, |ctx, sig| ctx.translate_fun_sig(span, sig))
310 }
311 pub fn translate_fun_sig(&mut self, span: Span, sig: &hax::TyFnSig) -> Result<FunSig, Error> {
312 let inputs = sig
313 .inputs
314 .iter()
315 .map(|x| self.translate_ty(span, x))
316 .try_collect()?;
317 let output = self.translate_ty(span, &sig.output)?;
318 Ok(FunSig {
319 is_unsafe: sig.safety == hax::Safety::Unsafe,
320 inputs,
321 output,
322 })
323 }
324
325 pub fn translate_generic_args(
327 &mut self,
328 span: Span,
329 substs: &[hax::GenericArg],
330 trait_refs: &[hax::ImplExpr],
331 ) -> Result<GenericArgs, Error> {
332 use hax::GenericArg::*;
333 trace!("{:?}", substs);
334
335 let mut regions = IndexMap::new();
336 let mut types = IndexMap::new();
337 let mut const_generics = IndexMap::new();
338 for param in substs {
339 match param {
340 Type(param_ty) => {
341 types.push(self.translate_ty(span, param_ty)?);
342 }
343 Lifetime(region) => {
344 regions.push(self.translate_region(span, region)?);
345 }
346 Const(c) => {
347 const_generics.push(self.translate_constant_expr(span, c)?);
348 }
349 }
350 }
351 let trait_refs = self.translate_trait_impl_exprs(span, trait_refs)?;
352
353 Ok(GenericArgs {
354 regions,
355 types,
356 const_generics,
357 trait_refs,
358 })
359 }
360
361 pub(crate) fn recognize_builtin_type(
363 &mut self,
364 item: &hax::ItemRef,
365 ) -> Result<Option<BuiltinTy>, Error> {
366 let def = self.hax_def(item)?;
367 let ty = if def.lang_item == Some(sym::owned_box) && self.t_ctx.options.treat_box_as_builtin
368 {
369 Some(BuiltinTy::Box)
370 } else {
371 None
372 };
373 Ok(ty)
374 }
375
376 pub fn translate_ptr_metadata(
380 &mut self,
381 span: Span,
382 item: &hax::ItemRef,
383 ) -> Result<PtrMetadata, Error> {
384 use rustc_middle::ty;
386 let tcx = self.t_ctx.tcx;
387 let rdefid = item.def_id.as_rust_def_id().unwrap();
388 let hax_state = &self.hax_state;
389 let ty_env = hax_state.typing_env();
390 let ty = tcx
391 .type_of(rdefid)
392 .instantiate(tcx, item.rustc_args(hax_state));
393
394 let tail_ty = tcx.struct_tail_raw(
396 ty,
397 &rustc_middle::traits::ObligationCause::dummy(),
398 |ty| tcx.try_normalize_erasing_regions(ty_env, ty).unwrap_or(ty),
399 || {},
400 );
401 let hax_ty: hax::Ty = self.t_ctx.catch_sinto(hax_state, span, &tail_ty)?;
402
403 let everything_is_sized = self.t_ctx.options.hide_marker_traits;
405 let ret = match tail_ty.kind() {
406 _ if everything_is_sized || tail_ty.is_sized(tcx, ty_env) => PtrMetadata::None,
407 ty::Str | ty::Slice(..) => PtrMetadata::Length,
408 ty::Dynamic(..) => match hax_ty.kind() {
409 hax::TyKind::Dynamic(dyn_binder, _) => {
410 let vtable = self.translate_region_binder(
411 span,
412 &dyn_binder.predicates.predicates[0].0.kind,
413 |ctx, kind: &hax::ClauseKind| {
414 let hax::ClauseKind::Trait(trait_predicate) = kind else {
415 unreachable!()
416 };
417 Ok(ctx
418 .translate_vtable_struct_ref(span, &trait_predicate.trait_ref)?
419 .unwrap())
420 },
421 )?;
422 let vtable = self.erase_region_binder(vtable);
423 PtrMetadata::VTable(vtable)
424 }
425 _ => unreachable!("Unexpected hax type {hax_ty:?} for dynamic type: {ty:?}"),
426 },
427 ty::Param(..) => PtrMetadata::InheritFrom(self.translate_ty(span, &hax_ty)?),
428 ty::Placeholder(..) | ty::Infer(..) | ty::Bound(..) => {
429 panic!(
430 "We should never encounter a placeholder, infer, or bound type from ptr_metadata translation. Got: {tail_ty:?}"
431 )
432 }
433 _ => PtrMetadata::None,
434 };
435
436 Ok(ret)
437 }
438
439 #[tracing::instrument(skip(self))]
444 pub fn translate_layout(&self, item: &hax::ItemRef) -> Option<Layout> {
445 use rustc_abi as r_abi;
446
447 fn translate_variant_layout(
448 variant_layout: &r_abi::LayoutData<r_abi::FieldIdx, r_abi::VariantIdx>,
449 tag: Option<ScalarValue>,
450 ) -> VariantLayout {
451 let field_offsets = match &variant_layout.fields {
452 r_abi::FieldsShape::Arbitrary { offsets, .. } => {
453 offsets.iter().map(|o| o.bytes()).collect()
454 }
455 r_abi::FieldsShape::Primitive | r_abi::FieldsShape::Union(_) => IndexVec::default(),
456 r_abi::FieldsShape::Array { .. } => panic!("Unexpected layout shape"),
457 };
458 VariantLayout {
459 field_offsets,
460 uninhabited: variant_layout.is_uninhabited(),
461 tag,
462 }
463 }
464
465 fn translate_primitive_int(int_ty: r_abi::Integer, signed: bool) -> IntegerTy {
466 if signed {
467 IntegerTy::Signed(match int_ty {
468 r_abi::Integer::I8 => IntTy::I8,
469 r_abi::Integer::I16 => IntTy::I16,
470 r_abi::Integer::I32 => IntTy::I32,
471 r_abi::Integer::I64 => IntTy::I64,
472 r_abi::Integer::I128 => IntTy::I128,
473 })
474 } else {
475 IntegerTy::Unsigned(match int_ty {
476 r_abi::Integer::I8 => UIntTy::U8,
477 r_abi::Integer::I16 => UIntTy::U16,
478 r_abi::Integer::I32 => UIntTy::U32,
479 r_abi::Integer::I64 => UIntTy::U64,
480 r_abi::Integer::I128 => UIntTy::U128,
481 })
482 }
483 }
484
485 let tcx = self.t_ctx.tcx;
486 let rdefid = item.def_id.as_rust_def_id().unwrap();
487 let hax_state = self.hax_state_with_id();
488 assert_eq!(hax_state.owner_id(), rdefid);
489 let ty_env = hax_state.typing_env();
490 let ty = tcx
491 .type_of(rdefid)
492 .instantiate(tcx, item.rustc_args(hax_state));
493 let pseudo_input = ty_env.as_query_input(ty);
494
495 let layout = tcx.layout_of(pseudo_input).ok()?.layout;
497 let (size, align) = if layout.is_sized() {
498 (
499 Some(layout.size().bytes()),
500 Some(layout.align().abi.bytes()),
501 )
502 } else {
503 (None, None)
504 };
505
506 let discriminant_layout = match layout.variants() {
508 r_abi::Variants::Multiple {
509 tag,
510 tag_encoding,
511 tag_field,
512 ..
513 } => {
514 let r_abi::FieldsShape::Arbitrary { offsets, .. } = layout.fields() else {
516 unreachable!()
517 };
518
519 let tag_ty = match tag.primitive() {
520 r_abi::Primitive::Int(int_ty, signed) => {
521 translate_primitive_int(int_ty, signed)
522 }
523 r_abi::Primitive::Pointer(_) => IntegerTy::Signed(IntTy::Isize),
525 r_abi::Primitive::Float(_) => {
526 unreachable!()
527 }
528 };
529
530 let encoding = match tag_encoding {
531 r_abi::TagEncoding::Direct => TagEncoding::Direct,
532 r_abi::TagEncoding::Niche {
533 untagged_variant, ..
534 } => TagEncoding::Niche {
535 untagged_variant: VariantId::from_usize(r_abi::VariantIdx::as_usize(
536 *untagged_variant,
537 )),
538 },
539 };
540 offsets.get(*tag_field).map(|s| DiscriminantLayout {
541 offset: r_abi::Size::bytes(*s),
542 tag_ty,
543 encoding,
544 })
545 }
546 r_abi::Variants::Single { .. } | r_abi::Variants::Empty => None,
547 };
548
549 let mut variant_layouts: IndexVec<VariantId, VariantLayout> = IndexVec::new();
550
551 match layout.variants() {
552 r_abi::Variants::Multiple { variants, .. } => {
553 let tag_ty = discriminant_layout
554 .as_ref()
555 .expect("No discriminant layout for enum?")
556 .tag_ty;
557 let ptr_size = self.t_ctx.translated.target_information.target_pointer_size;
558 let tag_size = r_abi::Size::from_bytes(tag_ty.target_size(ptr_size));
559
560 for (id, variant_layout) in variants.iter_enumerated() {
561 let tag = if variant_layout.is_uninhabited() {
562 None
563 } else {
564 tcx.tag_for_variant(ty_env.as_query_input((ty, id)))
565 .map(|s| match tag_ty {
566 IntegerTy::Signed(int_ty) => {
567 ScalarValue::from_int(ptr_size, int_ty, s.to_int(tag_size))
568 .unwrap()
569 }
570 IntegerTy::Unsigned(uint_ty) => {
571 ScalarValue::from_uint(ptr_size, uint_ty, s.to_uint(tag_size))
572 .unwrap()
573 }
574 })
575 };
576 variant_layouts.push(translate_variant_layout(variant_layout, tag));
577 }
578 }
579 r_abi::Variants::Single { index } => {
580 if let r_abi::FieldsShape::Arbitrary { .. } = layout.fields() {
581 let n_variants = match ty.kind() {
582 _ if let Some(range) = ty.variant_range(tcx) => range.end.index(),
583 _ => 1,
584 };
585 variant_layouts = (0..n_variants)
587 .map(|_| VariantLayout {
588 field_offsets: IndexVec::default(),
589 uninhabited: true,
590 tag: None,
591 })
592 .collect();
593 variant_layouts[index.index()] = translate_variant_layout(&layout, None);
594 }
595 }
596 r_abi::Variants::Empty => {}
597 }
598
599 Some(Layout {
600 size,
601 align,
602 discriminant_layout,
603 uninhabited: layout.is_uninhabited(),
604 variant_layouts,
605 })
606 }
607
608 pub fn generate_naive_layout(&self, span: Span, ty: &TypeDeclKind) -> Result<Layout, Error> {
610 match ty {
611 TypeDeclKind::Struct(fields) => {
612 let mut size = 0;
613 let mut align = 0;
614 let ptr_size = self.t_ctx.translated.target_information.target_pointer_size;
615 let field_offsets = fields.map_ref(|field| {
616 let offset = size;
617 let size_of_ty = match field.ty.kind() {
618 TyKind::Literal(literal_ty) => literal_ty.target_size(ptr_size) as u64,
619 TyKind::Ref(..) | TyKind::RawPtr(..) | TyKind::FnPtr(..) => ptr_size,
621 _ => panic!("Unsupported type for `generate_naive_layout`: {ty:?}"),
622 };
623 size += size_of_ty;
624 align = std::cmp::max(align, size);
626 offset
627 });
628
629 Ok(Layout {
630 size: Some(size),
631 align: Some(align),
632 discriminant_layout: None,
633 uninhabited: false,
634 variant_layouts: IndexVec::from_array([VariantLayout {
635 field_offsets,
636 tag: None,
637 uninhabited: false,
638 }]),
639 })
640 }
641 _ => raise_error!(
642 self,
643 span,
644 "`generate_naive_layout` only supports structs at the moment"
645 ),
646 }
647 }
648
649 pub(crate) fn translate_adt_def(
655 &mut self,
656 trans_id: TypeDeclId,
657 def_span: Span,
658 item_meta: &ItemMeta,
659 def: &hax::FullDef,
660 ) -> Result<TypeDeclKind, Error> {
661 use hax::AdtKind;
662 let hax::FullDefKind::Adt {
663 adt_kind, variants, ..
664 } = def.kind()
665 else {
666 unreachable!()
667 };
668
669 if item_meta.opacity.is_opaque() {
670 return Ok(TypeDeclKind::Opaque);
671 }
672
673 trace!("{}", trans_id);
674
675 let contents_are_public = match adt_kind {
680 AdtKind::Enum => true,
681 AdtKind::Struct | AdtKind::Union => {
682 error_assert!(self, def_span, variants.len() == 1);
684 variants[hax::VariantIdx::from(0usize)]
685 .fields
686 .iter()
687 .all(|f| matches!(f.vis, Visibility::Public))
688 }
689 _ => unreachable!(),
691 };
692
693 if item_meta
694 .opacity
695 .with_content_visibility(contents_are_public)
696 .is_opaque()
697 {
698 return Ok(TypeDeclKind::Opaque);
699 }
700
701 let mut translated_variants: IndexVec<VariantId, Variant> = Default::default();
703 for (i, var_def) in variants.iter().enumerate() {
704 trace!("variant {i}: {var_def:?}");
705
706 let mut fields: IndexVec<FieldId, Field> = Default::default();
707 let mut have_names: Option<bool> = None;
710 for (j, field_def) in var_def.fields.iter().enumerate() {
711 trace!("variant {i}: field {j}: {field_def:?}");
712 let field_span = self.t_ctx.translate_span(&field_def.span);
713 let ty = self.translate_ty(field_span, &field_def.ty)?;
715 let field_full_def =
716 self.hax_def(&def.this().with_def_id(self.hax_state(), &field_def.did))?;
717 let field_attrs = self.t_ctx.translate_attr_info(&field_full_def);
718
719 let field_name = field_def.name.map(|s| s.to_string());
721 match &have_names {
723 None => {
724 have_names = match &field_name {
725 None => Some(false),
726 Some(_) => Some(true),
727 }
728 }
729 Some(b) => {
730 error_assert!(self, field_span, *b == field_name.is_some());
731 }
732 };
733
734 let field = Field {
736 span: field_span,
737 attr_info: field_attrs,
738 name: field_name,
739 ty,
740 };
741 fields.push(field);
742 }
743
744 let discriminant = self.translate_discriminant(def_span, &var_def.discr_val)?;
745 let variant_span = self.t_ctx.translate_span(&var_def.span);
746 let variant_name = var_def.name.to_string();
747 let variant_full_def =
748 self.hax_def(&def.this().with_def_id(self.hax_state(), &var_def.def_id))?;
749 let variant_attrs = self.t_ctx.translate_attr_info(&variant_full_def);
750
751 let mut variant = Variant {
752 span: variant_span,
753 attr_info: variant_attrs,
754 name: variant_name,
755 fields,
756 discriminant,
757 };
758 if variant.attr_info.rename.is_none() {
760 let prefix = item_meta
761 .attr_info
762 .attributes
763 .iter()
764 .filter_map(|a| a.as_variants_prefix())
765 .next()
766 .map(|attr| attr.as_str());
767 let suffix = item_meta
768 .attr_info
769 .attributes
770 .iter()
771 .filter_map(|a| a.as_variants_suffix())
772 .next()
773 .map(|attr| attr.as_str());
774 if prefix.is_some() || suffix.is_some() {
775 let prefix = prefix.unwrap_or_default();
776 let suffix = suffix.unwrap_or_default();
777 let name = &variant.name;
778 variant.attr_info.rename = Some(format!("{prefix}{name}{suffix}"));
779 }
780 }
781 translated_variants.push(variant);
782 }
783
784 let type_def_kind: TypeDeclKind = match adt_kind {
786 AdtKind::Struct => TypeDeclKind::Struct(translated_variants[0].fields.clone()),
787 AdtKind::Enum => TypeDeclKind::Enum(translated_variants),
788 AdtKind::Union => TypeDeclKind::Union(translated_variants[0].fields.clone()),
789 _ => unreachable!(),
791 };
792
793 Ok(type_def_kind)
794 }
795
796 fn translate_discriminant(
797 &mut self,
798 def_span: Span,
799 discr: &hax::DiscriminantValue,
800 ) -> Result<Literal, Error> {
801 let ty = self.translate_ty(def_span, &discr.ty)?;
802 let lit_ty = ty.kind().as_literal().unwrap();
803 match Literal::from_bits(lit_ty, discr.val) {
804 Some(lit) => Ok(lit),
805 None => raise_error!(self, def_span, "unexpected discriminant type: {ty:?}",),
806 }
807 }
808
809 pub fn translate_repr_options(&mut self, hax_repr_options: &hax::ReprOptions) -> ReprOptions {
810 let repr_algo = if hax_repr_options.flags.is_c {
811 ReprAlgorithm::C
812 } else {
813 ReprAlgorithm::Rust
814 };
815
816 let align_mod = if let Some(align) = &hax_repr_options.align {
817 Some(AlignmentModifier::Align(align.bytes))
818 } else if let Some(pack) = &hax_repr_options.pack {
819 Some(AlignmentModifier::Pack(pack.bytes))
820 } else {
821 None
822 };
823
824 ReprOptions {
825 transparent: hax_repr_options.flags.is_transparent,
826 explicit_discr_type: hax_repr_options.int_specified,
827 repr_algo,
828 align_modif: align_mod,
829 }
830 }
831}