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