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