1use super::translate_ctx::*;
2use charon_lib::ast::*;
3use charon_lib::common::hash_by_addr::HashByAddr;
4use charon_lib::ids::Vector;
5use core::convert::*;
6use hax::{HasParamEnv, Visibility};
7use hax_frontend_exporter as hax;
8use itertools::Itertools;
9
10impl<'tcx, 'ctx> ItemTransCtx<'tcx, 'ctx> {
11 pub(crate) fn translate_region(
13 &mut self,
14 span: Span,
15 region: &hax::Region,
16 ) -> Result<Region, Error> {
17 use hax::RegionKind::*;
18 match ®ion.kind {
19 ReErased => Ok(Region::Erased),
20 ReStatic => Ok(Region::Static),
21 ReBound(id, br) => {
22 let var = self.lookup_bound_region(span, *id, br.var)?;
23 Ok(Region::Var(var))
24 }
25 ReEarlyParam(region) => {
26 let var = self.lookup_early_region(span, region)?;
27 Ok(Region::Var(var))
28 }
29 ReVar(..) | RePlaceholder(..) => {
30 raise_error!(
32 self,
33 span,
34 "Should not exist outside of type inference: {region:?}"
35 )
36 }
37 ReLateParam(..) | ReError(..) => {
38 raise_error!(self, span, "Unexpected region kind: {region:?}")
39 }
40 }
41 }
42
43 pub(crate) fn translate_hax_int_ty(int_ty: &hax::IntTy) -> IntTy {
44 match int_ty {
45 hax::IntTy::Isize => IntTy::Isize,
46 hax::IntTy::I8 => IntTy::I8,
47 hax::IntTy::I16 => IntTy::I16,
48 hax::IntTy::I32 => IntTy::I32,
49 hax::IntTy::I64 => IntTy::I64,
50 hax::IntTy::I128 => IntTy::I128,
51 }
52 }
53
54 pub(crate) fn translate_hax_uint_ty(uint_ty: &hax::UintTy) -> UIntTy {
55 use hax::UintTy;
56 match uint_ty {
57 UintTy::Usize => UIntTy::Usize,
58 UintTy::U8 => UIntTy::U8,
59 UintTy::U16 => UIntTy::U16,
60 UintTy::U32 => UIntTy::U32,
61 UintTy::U64 => UIntTy::U64,
62 UintTy::U128 => UIntTy::U128,
63 }
64 }
65
66 #[tracing::instrument(skip(self, span))]
75 pub(crate) fn translate_ty(&mut self, span: Span, ty: &hax::Ty) -> Result<Ty, Error> {
76 let cache_key = HashByAddr(ty.inner().clone());
77 if let Some(ty) = self
78 .innermost_binder()
79 .type_trans_cache
80 .get(&cache_key)
81 .cloned()
82 {
83 return Ok(ty.clone());
84 }
85 let ty = self
87 .translate_ty_inner(span, ty)
88 .unwrap_or_else(|e| TyKind::Error(e.msg).into_ty());
89 self.innermost_binder_mut()
90 .type_trans_cache
91 .insert(cache_key, ty.clone());
92 Ok(ty)
93 }
94
95 fn translate_ty_inner(&mut self, span: Span, ty: &hax::Ty) -> Result<Ty, Error> {
96 trace!("{:?}", ty);
97 let kind = match ty.kind() {
98 hax::TyKind::Bool => TyKind::Literal(LiteralTy::Bool),
99 hax::TyKind::Char => TyKind::Literal(LiteralTy::Char),
100 hax::TyKind::Int(int_ty) => {
101 TyKind::Literal(LiteralTy::Int(Self::translate_hax_int_ty(int_ty)))
102 }
103 hax::TyKind::Uint(uint_ty) => {
104 TyKind::Literal(LiteralTy::UInt(Self::translate_hax_uint_ty(uint_ty)))
105 }
106 hax::TyKind::Float(float_ty) => {
107 use hax::FloatTy;
108 TyKind::Literal(LiteralTy::Float(match float_ty {
109 FloatTy::F16 => charon_lib::ast::types::FloatTy::F16,
110 FloatTy::F32 => charon_lib::ast::types::FloatTy::F32,
111 FloatTy::F64 => charon_lib::ast::types::FloatTy::F64,
112 FloatTy::F128 => charon_lib::ast::types::FloatTy::F128,
113 }))
114 }
115 hax::TyKind::Never => TyKind::Never,
116
117 hax::TyKind::Alias(alias) => match &alias.kind {
118 hax::AliasKind::Projection {
119 impl_expr,
120 assoc_item,
121 } => {
122 let trait_ref = self.translate_trait_impl_expr(span, impl_expr)?;
123 let name = self.t_ctx.translate_trait_item_name(&assoc_item.def_id)?;
124 TyKind::TraitType(trait_ref, name)
125 }
126 hax::AliasKind::Opaque { hidden_ty, .. } => {
127 return self.translate_ty(span, hidden_ty);
128 }
129 _ => {
130 raise_error!(self, span, "Unsupported alias type: {:?}", alias.kind)
131 }
132 },
133
134 hax::TyKind::Adt(item) => {
135 let tref = self.translate_type_decl_ref(span, item)?;
136 TyKind::Adt(tref)
137 }
138 hax::TyKind::Str => {
139 let tref = TypeDeclRef::new(TypeId::Builtin(BuiltinTy::Str), GenericArgs::empty());
140 TyKind::Adt(tref)
141 }
142 hax::TyKind::Array(ty, const_param) => {
143 let c = self.translate_constant_expr_to_const_generic(span, const_param)?;
144 let ty = self.translate_ty(span, ty)?;
145 let tref = TypeDeclRef::new(
146 TypeId::Builtin(BuiltinTy::Array),
147 GenericArgs::new(Vector::new(), [ty].into(), [c].into(), Vector::new()),
148 );
149 TyKind::Adt(tref)
150 }
151 hax::TyKind::Slice(ty) => {
152 let ty = self.translate_ty(span, ty)?;
153 let tref = TypeDeclRef::new(
154 TypeId::Builtin(BuiltinTy::Slice),
155 GenericArgs::new_for_builtin([ty].into()),
156 );
157 TyKind::Adt(tref)
158 }
159 hax::TyKind::Ref(region, ty, mutability) => {
160 trace!("Ref");
161
162 let region = self.translate_region(span, region)?;
163 let ty = self.translate_ty(span, ty)?;
164 let kind = if *mutability {
165 RefKind::Mut
166 } else {
167 RefKind::Shared
168 };
169 TyKind::Ref(region, ty, kind)
170 }
171 hax::TyKind::RawPtr(ty, mutbl) => {
172 trace!("RawPtr: {:?}", (ty, mutbl));
173 let ty = self.translate_ty(span, ty)?;
174 let kind = if *mutbl {
175 RefKind::Mut
176 } else {
177 RefKind::Shared
178 };
179 TyKind::RawPtr(ty, kind)
180 }
181 hax::TyKind::Tuple(substs) => {
182 let mut params = Vector::new();
183 for param in substs.iter() {
184 let param_ty = self.translate_ty(span, param)?;
185 params.push(param_ty);
186 }
187 let tref = TypeDeclRef::new(TypeId::Tuple, GenericArgs::new_for_builtin(params));
188 TyKind::Adt(tref)
189 }
190
191 hax::TyKind::Param(param) => {
192 trace!("Param");
200
201 let var = self.lookup_type_var(span, param)?;
203 TyKind::TypeVar(var)
204 }
205
206 hax::TyKind::Foreign(item) => {
207 let tref = self.translate_type_decl_ref(span, item)?;
208 TyKind::Adt(tref)
209 }
210
211 hax::TyKind::Arrow(sig) => {
212 trace!("Arrow");
213 trace!("bound vars: {:?}", sig.bound_vars);
214 let sig = self.translate_fun_sig(span, sig)?;
215 TyKind::FnPtr(sig)
216 }
217 hax::TyKind::FnDef { item, .. } => {
218 let fnref = self.translate_fn_ptr(span, item)?;
219 TyKind::FnDef(fnref)
220 }
221 hax::TyKind::Closure(args) => {
222 let tref = self.translate_closure_type_ref(span, args)?;
223 TyKind::Adt(tref)
224 }
225
226 hax::TyKind::Dynamic(self_ty, preds, region) => {
227 if self.monomorphize() {
228 raise_error!(
229 self,
230 span,
231 "`dyn Trait` is not yet supported with `--monomorphize`; \
232 use `--monomorphize-conservative` instead"
233 )
234 }
235 let pred = self.translate_existential_predicates(span, self_ty, preds, region)?;
236 if let hax::ClauseKind::Trait(trait_predicate) =
237 preds.predicates[0].0.kind.hax_skip_binder_ref()
238 {
239 if self.trait_is_dyn_compatible(&trait_predicate.trait_ref.def_id)? {
243 let _: TypeDeclId = self.register_item(
246 span,
247 &trait_predicate.trait_ref,
248 TransItemSourceKind::VTable,
249 );
250 }
251 }
252 TyKind::DynTrait(pred)
253 }
254
255 hax::TyKind::Infer(_) => {
256 raise_error!(self, span, "Unsupported type: infer type")
257 }
258 hax::TyKind::Coroutine(..) => {
259 raise_error!(self, span, "Coroutine types are not supported yet")
260 }
261 hax::TyKind::Bound(_, _) => {
262 raise_error!(self, span, "Unexpected type kind: bound")
263 }
264 hax::TyKind::Placeholder(_) => {
265 raise_error!(self, span, "Unsupported type: placeholder")
266 }
267
268 hax::TyKind::Error => {
269 raise_error!(self, span, "Type checking error")
270 }
271 hax::TyKind::Todo(s) => {
272 raise_error!(self, span, "Unsupported type: {:?}", s)
273 }
274 };
275 Ok(kind.into_ty())
276 }
277
278 pub fn translate_fun_sig(
279 &mut self,
280 span: Span,
281 sig: &hax::Binder<hax::TyFnSig>,
282 ) -> Result<RegionBinder<(Vec<Ty>, Ty)>, Error> {
283 self.translate_region_binder(span, sig, |ctx, sig| {
284 let inputs = sig
285 .inputs
286 .iter()
287 .map(|x| ctx.translate_ty(span, x))
288 .try_collect()?;
289 let output = ctx.translate_ty(span, &sig.output)?;
290 Ok((inputs, output))
291 })
292 }
293
294 pub fn translate_generic_args(
296 &mut self,
297 span: Span,
298 substs: &[hax::GenericArg],
299 trait_refs: &[hax::ImplExpr],
300 ) -> Result<GenericArgs, Error> {
301 use hax::GenericArg::*;
302 trace!("{:?}", substs);
303
304 let mut regions = Vector::new();
305 let mut types = Vector::new();
306 let mut const_generics = Vector::new();
307 for param in substs {
308 match param {
309 Type(param_ty) => {
310 types.push(self.translate_ty(span, param_ty)?);
311 }
312 Lifetime(region) => {
313 regions.push(self.translate_region(span, region)?);
314 }
315 Const(c) => {
316 const_generics.push(self.translate_constant_expr_to_const_generic(span, c)?);
317 }
318 }
319 }
320 let trait_refs = self.translate_trait_impl_exprs(span, trait_refs)?;
321
322 Ok(GenericArgs {
323 regions,
324 types,
325 const_generics,
326 trait_refs,
327 })
328 }
329
330 pub fn append_late_bound_to_generics(
332 &mut self,
333 span: Span,
334 generics: GenericArgs,
335 late_bound: Option<hax::Binder<()>>,
336 ) -> Result<RegionBinder<GenericArgs>, Error> {
337 let late_bound = late_bound.unwrap_or(hax::Binder {
338 value: (),
339 bound_vars: vec![],
340 });
341 self.translate_region_binder(span, &late_bound, |ctx, _| {
342 Ok(generics
343 .move_under_binder()
344 .concat(&ctx.innermost_binder().params.identity_args()))
345 })
346 }
347
348 pub(crate) fn recognize_builtin_type(
350 &mut self,
351 item: &hax::ItemRef,
352 ) -> Result<Option<BuiltinTy>, Error> {
353 let def = self.hax_def(item)?;
354 let ty = if def.lang_item.as_deref() == Some("owned_box") && !self.t_ctx.options.raw_boxes {
355 Some(BuiltinTy::Box)
356 } else {
357 None
358 };
359 Ok(ty)
360 }
361
362 pub fn translate_ptr_metadata(&self, item: &hax::ItemRef) -> Option<PtrMetadata> {
366 use rustc_middle::ty;
368 let tcx = self.t_ctx.tcx;
369 let rdefid = item.def_id.as_rust_def_id().unwrap();
370 let hax_state = &self.hax_state_with_id();
371 let ty_env = hax_state.typing_env();
372 let ty = tcx
373 .type_of(rdefid)
374 .instantiate(tcx, item.rustc_args(hax_state));
375
376 match tcx
378 .struct_tail_raw(
379 ty,
380 |ty| tcx.try_normalize_erasing_regions(ty_env, ty).unwrap_or(ty),
381 || {},
382 )
383 .kind()
384 {
385 ty::Foreign(..) => Some(PtrMetadata::None),
386 ty::Str | ty::Slice(..) => Some(PtrMetadata::Length),
387 ty::Dynamic(..) => Some(PtrMetadata::VTable(VTable)),
388 ty::Placeholder(..) | ty::Infer(..) | ty::Param(..) | ty::Bound(..) => None,
392 _ => Some(PtrMetadata::None),
393 }
394 }
395
396 #[tracing::instrument(skip(self))]
401 pub fn translate_layout(&self, item: &hax::ItemRef) -> Option<Layout> {
402 use rustc_abi as r_abi;
403 fn translate_variant_layout(
405 variant_layout: &r_abi::LayoutData<r_abi::FieldIdx, r_abi::VariantIdx>,
406 tag: Option<ScalarValue>,
407 ) -> VariantLayout {
408 match &variant_layout.fields {
409 r_abi::FieldsShape::Arbitrary { offsets, .. } => {
410 let mut v = Vector::with_capacity(offsets.len());
411 for o in offsets.iter() {
412 v.push(o.bytes());
413 }
414 VariantLayout {
415 field_offsets: v,
416 uninhabited: variant_layout.is_uninhabited(),
417 tag,
418 }
419 }
420 r_abi::FieldsShape::Primitive
421 | r_abi::FieldsShape::Union(_)
422 | r_abi::FieldsShape::Array { .. } => panic!("Unexpected layout shape"),
423 }
424 }
425
426 fn translate_primitive_int(int_ty: r_abi::Integer, signed: bool) -> IntegerTy {
427 if signed {
428 IntegerTy::Signed(match int_ty {
429 r_abi::Integer::I8 => IntTy::I8,
430 r_abi::Integer::I16 => IntTy::I16,
431 r_abi::Integer::I32 => IntTy::I32,
432 r_abi::Integer::I64 => IntTy::I64,
433 r_abi::Integer::I128 => IntTy::I128,
434 })
435 } else {
436 IntegerTy::Unsigned(match int_ty {
437 r_abi::Integer::I8 => UIntTy::U8,
438 r_abi::Integer::I16 => UIntTy::U16,
439 r_abi::Integer::I32 => UIntTy::U32,
440 r_abi::Integer::I64 => UIntTy::U64,
441 r_abi::Integer::I128 => UIntTy::U128,
442 })
443 }
444 }
445
446 let tcx = self.t_ctx.tcx;
447 let rdefid = item.def_id.as_rust_def_id().unwrap();
448 let hax_state = &self.hax_state_with_id();
449 let ty_env = hax_state.typing_env();
450 let ty = tcx
451 .type_of(rdefid)
452 .instantiate(tcx, item.rustc_args(hax_state));
453 let pseudo_input = ty_env.as_query_input(ty);
454
455 let layout = tcx.layout_of(pseudo_input).ok()?.layout;
457 let (size, align) = if layout.is_sized() {
458 (
459 Some(layout.size().bytes()),
460 Some(layout.align().abi.bytes()),
461 )
462 } else {
463 (None, None)
464 };
465
466 let discriminant_layout = match layout.variants() {
468 r_abi::Variants::Multiple {
469 tag,
470 tag_encoding,
471 tag_field,
472 ..
473 } => {
474 let r_abi::FieldsShape::Arbitrary { offsets, .. } = layout.fields() else {
476 unreachable!()
477 };
478
479 let tag_ty = match tag.primitive() {
480 r_abi::Primitive::Int(int_ty, signed) => {
481 translate_primitive_int(int_ty, signed)
482 }
483 r_abi::Primitive::Pointer(_) => IntegerTy::Signed(IntTy::Isize),
485 r_abi::Primitive::Float(_) => {
486 unreachable!()
487 }
488 };
489
490 let encoding = match tag_encoding {
491 r_abi::TagEncoding::Direct => TagEncoding::Direct,
492 r_abi::TagEncoding::Niche {
493 untagged_variant, ..
494 } => TagEncoding::Niche {
495 untagged_variant: VariantId::from_usize(r_abi::VariantIdx::as_usize(
496 *untagged_variant,
497 )),
498 },
499 };
500 offsets.get(*tag_field).map(|s| DiscriminantLayout {
501 offset: r_abi::Size::bytes(*s),
502 tag_ty,
503 encoding,
504 })
505 }
506 r_abi::Variants::Single { .. } | r_abi::Variants::Empty => None,
507 };
508
509 let mut variant_layouts = Vector::new();
510 match layout.variants() {
511 r_abi::Variants::Multiple { variants, .. } => {
512 let tag_ty = discriminant_layout
513 .as_ref()
514 .expect("No discriminant layout for enum?")
515 .tag_ty;
516 let ptr_size = self.t_ctx.translated.target_information.target_pointer_size;
517 let tag_size = r_abi::Size::from_bytes(tag_ty.target_size(ptr_size));
518
519 for (id, variant_layout) in variants.iter_enumerated() {
520 let tag = if variant_layout.is_uninhabited() {
521 None
522 } else {
523 tcx.tag_for_variant(ty_env.as_query_input((ty, id)))
524 .map(|s| match tag_ty {
525 IntegerTy::Signed(int_ty) => {
526 ScalarValue::from_int(ptr_size, int_ty, s.to_int(tag_size))
527 .unwrap()
528 }
529 IntegerTy::Unsigned(uint_ty) => {
530 ScalarValue::from_uint(ptr_size, uint_ty, s.to_uint(tag_size))
531 .unwrap()
532 }
533 })
534 };
535 variant_layouts.push(translate_variant_layout(variant_layout, tag));
536 }
537 }
538 r_abi::Variants::Single { index } => {
539 assert!(*index == r_abi::VariantIdx::ZERO);
540 if let r_abi::FieldsShape::Arbitrary { .. } = layout.fields() {
543 variant_layouts.push(translate_variant_layout(&layout, None));
544 }
545 }
546 r_abi::Variants::Empty => {}
547 }
548
549 Some(Layout {
550 size,
551 align,
552 discriminant_layout,
553 uninhabited: layout.is_uninhabited(),
554 variant_layouts,
555 })
556 }
557
558 pub fn generate_naive_layout(&self, span: Span, ty: &TypeDeclKind) -> Result<Layout, Error> {
560 match ty {
561 TypeDeclKind::Struct(fields) => {
562 let mut size = 0;
563 let mut align = 0;
564 let ptr_size = self.t_ctx.translated.target_information.target_pointer_size;
565 let field_offsets = fields.map_ref(|field| {
566 let offset = size;
567 let size_of_ty = match field.ty.kind() {
568 TyKind::Literal(literal_ty) => literal_ty.target_size(ptr_size) as u64,
569 TyKind::Ref(..) | TyKind::RawPtr(..) | TyKind::FnPtr(..) => ptr_size,
571 _ => panic!("Unsupported type for `generate_naive_layout`: {ty:?}"),
572 };
573 size += size_of_ty;
574 align = std::cmp::max(align, size);
576 offset
577 });
578
579 Ok(Layout {
580 size: Some(size),
581 align: Some(align),
582 discriminant_layout: None,
583 uninhabited: false,
584 variant_layouts: [VariantLayout {
585 field_offsets,
586 tag: None,
587 uninhabited: false,
588 }]
589 .into(),
590 })
591 }
592 _ => raise_error!(
593 self,
594 span,
595 "`generate_naive_layout` only supports structs at the moment"
596 ),
597 }
598 }
599
600 pub(crate) fn translate_adt_def(
606 &mut self,
607 trans_id: TypeDeclId,
608 def_span: Span,
609 item_meta: &ItemMeta,
610 def: &hax::FullDef,
611 ) -> Result<TypeDeclKind, Error> {
612 use hax::AdtKind;
613 let hax::FullDefKind::Adt {
614 adt_kind, variants, ..
615 } = def.kind()
616 else {
617 unreachable!()
618 };
619
620 if item_meta.opacity.is_opaque() {
621 return Ok(TypeDeclKind::Opaque);
622 }
623
624 trace!("{}", trans_id);
625
626 let contents_are_public = match adt_kind {
631 AdtKind::Enum => true,
632 AdtKind::Struct | AdtKind::Union => {
633 error_assert!(self, def_span, variants.len() == 1);
635 variants[0]
636 .fields
637 .iter()
638 .all(|f| matches!(f.vis, Visibility::Public))
639 }
640 };
641
642 if item_meta
643 .opacity
644 .with_content_visibility(contents_are_public)
645 .is_opaque()
646 {
647 return Ok(TypeDeclKind::Opaque);
648 }
649
650 let mut translated_variants: Vector<VariantId, Variant> = Default::default();
652 for (i, var_def) in variants.iter().enumerate() {
653 trace!("variant {i}: {var_def:?}");
654
655 let mut fields: Vector<FieldId, Field> = Default::default();
656 let mut have_names: Option<bool> = None;
659 for (j, field_def) in var_def.fields.iter().enumerate() {
660 trace!("variant {i}: field {j}: {field_def:?}");
661 let field_span = self.t_ctx.translate_span_from_hax(&field_def.span);
662 let ty = self.translate_ty(field_span, &field_def.ty)?;
664 let field_full_def =
665 self.hax_def(&def.this().with_def_id(self.hax_state(), &field_def.did))?;
666 let field_attrs = self.t_ctx.translate_attr_info(&field_full_def);
667
668 let field_name = field_def.name.clone();
670 match &have_names {
672 None => {
673 have_names = match &field_name {
674 None => Some(false),
675 Some(_) => Some(true),
676 }
677 }
678 Some(b) => {
679 error_assert!(self, field_span, *b == field_name.is_some());
680 }
681 };
682
683 let field = Field {
685 span: field_span,
686 attr_info: field_attrs,
687 name: field_name.clone(),
688 ty,
689 };
690 fields.push(field);
691 }
692
693 let discriminant = self.translate_discriminant(def_span, &var_def.discr_val)?;
694 let variant_span = self.t_ctx.translate_span_from_hax(&var_def.span);
695 let variant_name = var_def.name.clone();
696 let variant_full_def =
697 self.hax_def(&def.this().with_def_id(self.hax_state(), &var_def.def_id))?;
698 let variant_attrs = self.t_ctx.translate_attr_info(&variant_full_def);
699
700 let mut variant = Variant {
701 span: variant_span,
702 attr_info: variant_attrs,
703 name: variant_name,
704 fields,
705 discriminant,
706 };
707 if variant.attr_info.rename.is_none() {
709 let prefix = item_meta
710 .attr_info
711 .attributes
712 .iter()
713 .filter_map(|a| a.as_variants_prefix())
714 .next()
715 .map(|attr| attr.as_str());
716 let suffix = item_meta
717 .attr_info
718 .attributes
719 .iter()
720 .filter_map(|a| a.as_variants_suffix())
721 .next()
722 .map(|attr| attr.as_str());
723 if prefix.is_some() || suffix.is_some() {
724 let prefix = prefix.unwrap_or_default();
725 let suffix = suffix.unwrap_or_default();
726 let name = &variant.name;
727 variant.attr_info.rename = Some(format!("{prefix}{name}{suffix}"));
728 }
729 }
730 translated_variants.push(variant);
731 }
732
733 let type_def_kind: TypeDeclKind = match adt_kind {
735 AdtKind::Struct => TypeDeclKind::Struct(translated_variants[0].fields.clone()),
736 AdtKind::Enum => TypeDeclKind::Enum(translated_variants),
737 AdtKind::Union => TypeDeclKind::Union(translated_variants[0].fields.clone()),
738 };
739
740 Ok(type_def_kind)
741 }
742
743 fn translate_discriminant(
744 &mut self,
745 def_span: Span,
746 discr: &hax::DiscriminantValue,
747 ) -> Result<ScalarValue, Error> {
748 let ty = self.translate_ty(def_span, &discr.ty)?;
749 let int_ty = ty.kind().as_literal().unwrap().to_integer_ty().unwrap();
750 Ok(ScalarValue::from_bits(int_ty, discr.val))
751 }
752}