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