1use super::translate_crate::*;
2use super::translate_ctx::*;
3use charon_lib::ast::ullbc_ast_utils::BodyBuilder;
4use charon_lib::ast::*;
5use charon_lib::formatter::IntoFormatter;
6use charon_lib::pretty::FmtWithCtx;
7use derive_generic_visitor::Visitor;
8use itertools::Itertools;
9use rustc_span::sym;
10use std::mem;
11use std::ops::ControlFlow;
12
13impl<'tcx, 'ctx> TranslateCtx<'tcx> {
14 pub(crate) fn translate_item(&mut self, item_src: &TransItemSource) {
15 let trans_id = self.register_no_enqueue(&None, item_src);
16 let def_id = item_src.def_id();
17 if let Some(trans_id) = trans_id {
18 if self.translate_stack.contains(&trans_id) {
19 register_error!(
20 self,
21 Span::dummy(),
22 "Cycle detected while translating {def_id:?}! Stack: {:?}",
23 &self.translate_stack
24 );
25 return;
26 } else {
27 self.translate_stack.push(trans_id);
28 }
29 }
30 self.with_def_id(def_id, trans_id, |mut ctx| {
31 let span = ctx.def_span(def_id);
32 let res = {
34 let mut ctx = std::panic::AssertUnwindSafe(&mut ctx);
36 std::panic::catch_unwind(move || ctx.translate_item_aux(item_src, trans_id))
37 };
38 match res {
39 Ok(Ok(())) => return,
40 Ok(Err(_)) => {
42 register_error!(ctx, span, "Item `{def_id:?}` caused errors; ignoring.")
43 }
44 Err(_) => register_error!(
46 ctx,
47 span,
48 "Thread panicked when extracting item `{def_id:?}`."
49 ),
50 };
51 });
52 self.translate_stack.pop();
54 }
55
56 pub(crate) fn translate_item_aux(
57 &mut self,
58 item_src: &TransItemSource,
59 trans_id: Option<ItemId>,
60 ) -> Result<(), Error> {
61 let name = self.translate_name(item_src)?;
63 if let Some(trans_id) = trans_id {
64 self.translated.item_names.insert(trans_id, name.clone());
65 }
66 let opacity = self.opacity_for_name(&name);
67 if opacity.is_invisible() {
68 return Ok(());
70 }
71 let def = self.hax_def_for_item(&item_src.item)?;
72 let item_meta = self.translate_item_meta(&def, item_src, name, opacity);
73 if item_meta.opacity.is_invisible() {
74 return Ok(());
75 }
76
77 let mut bt_ctx = ItemTransCtx::new(item_src.clone(), trans_id, self);
79 trace!(
80 "About to translate item `{:?}` as a {:?}; \
81 target_id={trans_id:?}, mono={}",
82 def.def_id(),
83 item_src.kind,
84 bt_ctx.monomorphize()
85 );
86 if !matches!(
87 &item_src.kind,
88 TransItemSourceKind::InherentImpl | TransItemSourceKind::Module,
89 ) {
90 bt_ctx.translate_item_generics(item_meta.span, &def, &item_src.kind)?;
91 }
92 match &item_src.kind {
93 TransItemSourceKind::InherentImpl | TransItemSourceKind::Module => {
94 bt_ctx.register_module(item_meta, &def);
95 }
96 TransItemSourceKind::Type => {
97 let Some(ItemId::Type(id)) = trans_id else {
98 unreachable!()
99 };
100 let ty = bt_ctx.translate_type_decl(id, item_meta, &def)?;
101 self.translated.type_decls.set_slot(id, ty);
102 }
103 TransItemSourceKind::Fun => {
104 let Some(ItemId::Fun(id)) = trans_id else {
105 unreachable!()
106 };
107 let fun_decl = bt_ctx.translate_fun_decl(id, item_meta, &def)?;
108 self.translated.fun_decls.set_slot(id, fun_decl);
109 }
110 TransItemSourceKind::Global => {
111 let Some(ItemId::Global(id)) = trans_id else {
112 unreachable!()
113 };
114 let global_decl = bt_ctx.translate_global(id, item_meta, &def)?;
115 self.translated.global_decls.set_slot(id, global_decl);
116 }
117 TransItemSourceKind::TraitDecl => {
118 let Some(ItemId::TraitDecl(id)) = trans_id else {
119 unreachable!()
120 };
121 let trait_decl = bt_ctx.translate_trait_decl(id, item_meta, &def)?;
122 self.translated.trait_decls.set_slot(id, trait_decl);
123 }
124 TransItemSourceKind::TraitImpl(kind) => {
125 let Some(ItemId::TraitImpl(id)) = trans_id else {
126 unreachable!()
127 };
128 let trait_impl = match kind {
129 TraitImplSource::Normal => bt_ctx.translate_trait_impl(id, item_meta, &def)?,
130 TraitImplSource::TraitAlias => {
131 bt_ctx.translate_trait_alias_blanket_impl(id, item_meta, &def)?
132 }
133 &TraitImplSource::Closure(kind) => {
134 bt_ctx.translate_closure_trait_impl(id, item_meta, &def, kind)?
135 }
136 TraitImplSource::ImplicitDestruct => {
137 bt_ctx.translate_implicit_destruct_impl(id, item_meta, &def)?
138 }
139 };
140 self.translated.trait_impls.set_slot(id, trait_impl);
141 }
142 &TransItemSourceKind::DefaultedMethod(impl_kind, name) => {
143 let Some(ItemId::Fun(id)) = trans_id else {
144 unreachable!()
145 };
146 let fun_decl =
147 bt_ctx.translate_defaulted_method(id, item_meta, &def, impl_kind, name)?;
148 self.translated.fun_decls.set_slot(id, fun_decl);
149 }
150 &TransItemSourceKind::ClosureMethod(kind) => {
151 let Some(ItemId::Fun(id)) = trans_id else {
152 unreachable!()
153 };
154 let fun_decl = bt_ctx.translate_closure_method(id, item_meta, &def, kind)?;
155 self.translated.fun_decls.set_slot(id, fun_decl);
156 }
157 TransItemSourceKind::ClosureAsFnCast => {
158 let Some(ItemId::Fun(id)) = trans_id else {
159 unreachable!()
160 };
161 let fun_decl = bt_ctx.translate_stateless_closure_as_fn(id, item_meta, &def)?;
162 self.translated.fun_decls.set_slot(id, fun_decl);
163 }
164 &TransItemSourceKind::DropInPlaceMethod(impl_kind) => {
165 let Some(ItemId::Fun(id)) = trans_id else {
166 unreachable!()
167 };
168 let fun_decl =
169 bt_ctx.translate_drop_in_place_method(id, item_meta, &def, impl_kind)?;
170 self.translated.fun_decls.set_slot(id, fun_decl);
171 }
172 TransItemSourceKind::VTable => {
173 let Some(ItemId::Type(id)) = trans_id else {
174 unreachable!()
175 };
176 let ty_decl = bt_ctx.translate_vtable_struct(id, item_meta, &def)?;
177 self.translated.type_decls.set_slot(id, ty_decl);
178 }
179 TransItemSourceKind::VTableInstance(impl_kind) => {
180 let Some(ItemId::Global(id)) = trans_id else {
181 unreachable!()
182 };
183 let global_decl =
184 bt_ctx.translate_vtable_instance(id, item_meta, &def, impl_kind)?;
185 self.translated.global_decls.set_slot(id, global_decl);
186 }
187 TransItemSourceKind::VTableInstanceInitializer(impl_kind) => {
188 let Some(ItemId::Fun(id)) = trans_id else {
189 unreachable!()
190 };
191 let fun_decl =
192 bt_ctx.translate_vtable_instance_init(id, item_meta, &def, impl_kind)?;
193 self.translated.fun_decls.set_slot(id, fun_decl);
194 }
195 TransItemSourceKind::VTableMethod => {
196 let Some(ItemId::Fun(id)) = trans_id else {
197 unreachable!()
198 };
199 let fun_decl = bt_ctx.translate_vtable_shim(id, item_meta, &def)?;
200 self.translated.fun_decls.set_slot(id, fun_decl);
201 }
202 TransItemSourceKind::VTableDropShim => {
203 let Some(ItemId::Fun(id)) = trans_id else {
204 unreachable!()
205 };
206 let fun_decl = bt_ctx.translate_vtable_drop_shim(id, item_meta, &def)?;
207 self.translated.fun_decls.set_slot(id, fun_decl);
208 }
209 }
210 Ok(())
211 }
212
213 pub(crate) fn get_or_translate(&mut self, id: ItemId) -> Result<krate::ItemRef<'_>, Error> {
216 if self.translated.get_item(id).is_none() {
219 let item_source = self.reverse_id_map.get(&id).unwrap().clone();
220 self.translate_item(&item_source);
221 if self.translated.get_item(id).is_none() {
222 let span = self.def_span(item_source.def_id());
223 let name = self
224 .translated
225 .item_name(id)
226 .map(|n| n.to_string_with_ctx(&self.into_fmt()))
227 .unwrap_or_else(|| id.to_string());
228 return Err(Error {
230 span,
231 msg: format!("Failed to translate item {name}."),
232 });
233 }
235 self.processed.insert(item_source.clone());
237 }
238 let item = self.translated.get_item(id);
239 Ok(item.unwrap())
240 }
241
242 pub fn translate_unit_metadata_const(&mut self) {
244 use charon_lib::ullbc_ast::*;
245 let name = Name::from_path(&["UNIT_METADATA"]);
246 let item_meta = ItemMeta {
247 name,
248 span: Span::dummy(),
249 source_text: None,
250 attr_info: AttrInfo::default(),
251 is_local: false,
252 opacity: ItemOpacity::Foreign,
253 lang_item: None,
254 };
255
256 let body = {
257 let mut builder = BodyBuilder::new(Span::dummy(), 0);
258 let _ = builder.new_var(None, Ty::mk_unit());
259 builder.build()
260 };
261
262 let global_id = self.translated.global_decls.reserve_slot();
263 let initializer = self.translated.fun_decls.push_with(|def_id| FunDecl {
264 def_id,
265 item_meta: item_meta.clone(),
266 src: ItemSource::TopLevel,
267 is_global_initializer: Some(global_id),
268 generics: Default::default(),
269 signature: FunSig {
270 is_unsafe: false,
271 inputs: vec![],
272 output: Ty::mk_unit(),
273 },
274 body: Body::Unstructured(body),
275 });
276 self.translated.global_decls.set_slot(
277 global_id,
278 GlobalDecl {
279 def_id: global_id,
280 item_meta,
281 generics: Default::default(),
282 ty: Ty::mk_unit(),
283 src: ItemSource::TopLevel,
284 global_kind: GlobalKind::NamedConst,
285 init: initializer,
286 },
287 );
288 self.translated.unit_metadata = Some(GlobalDeclRef {
289 id: global_id,
290 generics: Box::new(GenericArgs::empty()),
291 });
292 }
293
294 pub fn remove_unused_methods(&mut self) {
296 let method_is_used = |trait_id, name| {
297 self.method_status.get(trait_id).is_some_and(|map| {
298 map.get(&name)
299 .is_some_and(|status| matches!(status, MethodStatus::Used))
300 })
301 };
302 for tdecl in self.translated.trait_decls.iter_mut() {
303 tdecl
304 .methods
305 .retain(|m| method_is_used(tdecl.def_id, m.name()));
306 }
307 for timpl in self.translated.trait_impls.iter_mut() {
308 let trait_id = timpl.impl_trait.id;
309 timpl
310 .methods
311 .retain(|(name, _)| method_is_used(trait_id, *name));
312 }
313 }
314}
315
316impl ItemTransCtx<'_, '_> {
317 #[tracing::instrument(skip(self, item_meta))]
321 pub(crate) fn register_module(&mut self, item_meta: ItemMeta, def: &hax::FullDef) {
322 if !item_meta.opacity.is_transparent() {
323 return;
324 }
325 match def.kind() {
326 hax::FullDefKind::InherentImpl { items, .. } => {
327 for assoc in items {
328 self.t_ctx.enqueue_module_item(&assoc.def_id);
329 }
330 }
331 hax::FullDefKind::Mod { items, .. } => {
332 for (_, def_id) in items {
333 self.t_ctx.enqueue_module_item(def_id);
334 }
335 }
336 hax::FullDefKind::ForeignMod { items, .. } => {
337 for def_id in items {
338 self.t_ctx.enqueue_module_item(def_id);
339 }
340 }
341 _ => panic!("Item should be a module but isn't: {def:?}"),
342 }
343 }
344
345 pub(crate) fn get_item_source(
346 &mut self,
347 span: Span,
348 def: &hax::FullDef,
349 ) -> Result<ItemSource, Error> {
350 let assoc = match def.kind() {
351 hax::FullDefKind::AssocTy {
352 associated_item, ..
353 }
354 | hax::FullDefKind::AssocConst {
355 associated_item, ..
356 }
357 | hax::FullDefKind::AssocFn {
358 associated_item, ..
359 } => associated_item,
360 hax::FullDefKind::Closure { args, .. } => {
361 let info = self.translate_closure_info(span, args)?;
362 return Ok(ItemSource::Closure { info });
363 }
364 _ => return Ok(ItemSource::TopLevel),
365 };
366 Ok(match &assoc.container {
367 hax::AssocItemContainer::InherentImplContainer { .. } => ItemSource::TopLevel,
374 hax::AssocItemContainer::TraitImplContainer {
381 impl_,
382 implemented_trait_ref,
383 overrides_default,
384 ..
385 } => {
386 let impl_ref =
387 self.translate_trait_impl_ref(span, impl_, TraitImplSource::Normal)?;
388 let trait_ref = self.translate_trait_ref(span, implemented_trait_ref)?;
389 let item_name = self.t_ctx.translate_trait_item_name(def.def_id())?;
390 if matches!(def.kind(), hax::FullDefKind::AssocFn { .. }) {
391 self.mark_method_as_used(trait_ref.id, item_name);
394 }
395 ItemSource::TraitImpl {
396 impl_ref,
397 trait_ref,
398 item_name,
399 reuses_default: !overrides_default,
400 }
401 }
402 hax::AssocItemContainer::TraitContainer { trait_ref, .. } => {
410 let trait_ref = self.translate_trait_ref(span, trait_ref)?;
413 let item_name = self.t_ctx.translate_trait_item_name(def.def_id())?;
414 ItemSource::TraitDecl {
415 trait_ref,
416 item_name,
417 has_default: assoc.has_value,
418 }
419 }
420 })
421 }
422
423 #[tracing::instrument(skip(self, item_meta))]
429 pub fn translate_type_decl(
430 mut self,
431 trans_id: TypeDeclId,
432 item_meta: ItemMeta,
433 def: &hax::FullDef,
434 ) -> Result<TypeDecl, Error> {
435 let span = item_meta.span;
436
437 let src = self.get_item_source(span, def)?;
439
440 let mut repr: Option<ReprOptions> = None;
441
442 let kind = match &def.kind {
444 _ if item_meta.opacity.is_opaque() => Ok(TypeDeclKind::Opaque),
445 hax::FullDefKind::OpaqueTy | hax::FullDefKind::ForeignTy => Ok(TypeDeclKind::Opaque),
446 hax::FullDefKind::TyAlias { ty, .. } => {
447 self.error_on_impl_expr_error = false;
449 self.translate_ty(span, ty).map(TypeDeclKind::Alias)
450 }
451 hax::FullDefKind::Adt { repr: hax_repr, .. } => {
452 repr = Some(self.translate_repr_options(hax_repr));
453 self.translate_adt_def(trans_id, span, &item_meta, def)
454 }
455 hax::FullDefKind::Closure { args, .. } => self.translate_closure_adt(span, &args),
456 _ => panic!("Unexpected item when translating types: {def:?}"),
457 };
458
459 let kind = match kind {
460 Ok(kind) => kind,
461 Err(err) => TypeDeclKind::Error(err.msg),
462 };
463 let layout = self.translate_layout(def.this());
464 let ptr_metadata = self.translate_ptr_metadata(span, def.this())?;
465 let type_def = TypeDecl {
466 def_id: trans_id,
467 item_meta,
468 generics: self.into_generics(),
469 kind,
470 src,
471 layout,
472 ptr_metadata,
473 repr,
474 };
475
476 Ok(type_def)
477 }
478
479 #[tracing::instrument(skip(self, item_meta))]
481 pub fn translate_fun_decl(
482 mut self,
483 def_id: FunDeclId,
484 item_meta: ItemMeta,
485 def: &hax::FullDef,
486 ) -> Result<FunDecl, Error> {
487 let span = item_meta.span;
488
489 let src = self.get_item_source(span, def)?;
490
491 if let hax::FullDefKind::Ctor {
492 fields, output_ty, ..
493 } = def.kind()
494 {
495 let signature = FunSig {
496 inputs: fields
497 .iter()
498 .map(|field| self.translate_ty(span, &field.ty))
499 .try_collect()?,
500 output: self.translate_ty(span, output_ty)?,
501 is_unsafe: false,
502 };
503
504 let body = if item_meta.opacity.with_private_contents().is_opaque() {
505 Body::Opaque
506 } else {
507 self.build_ctor_body(span, def)?
508 };
509 return Ok(FunDecl {
510 def_id,
511 item_meta,
512 generics: self.into_generics(),
513 signature,
514 src,
515 is_global_initializer: None,
516 body,
517 });
518 }
519
520 trace!("Translating function signature");
522 let signature = match &def.kind {
523 hax::FullDefKind::Fn { sig, .. } | hax::FullDefKind::AssocFn { sig, .. } => {
524 self.translate_fun_sig(span, &sig.value)?
525 }
526 hax::FullDefKind::Const { ty, .. }
527 | hax::FullDefKind::AssocConst { ty, .. }
528 | hax::FullDefKind::Static { ty, .. } => FunSig {
529 inputs: vec![],
530 output: self.translate_ty(span, ty)?,
531 is_unsafe: false,
532 },
533 _ => panic!("Unexpected definition for function: {def:?}"),
534 };
535
536 let is_trait_method_decl_without_default = match &src {
539 ItemSource::TraitDecl { has_default, .. } => !has_default,
540 _ => false,
541 };
542
543 let is_global_initializer = matches!(
544 def.kind(),
545 hax::FullDefKind::Const { .. }
546 | hax::FullDefKind::AssocConst { .. }
547 | hax::FullDefKind::Static { .. }
548 );
549 let is_global_initializer = is_global_initializer
550 .then(|| self.register_item(span, def.this(), TransItemSourceKind::Global));
551
552 let body = if item_meta.opacity.with_private_contents().is_opaque() {
553 Body::Opaque
554 } else if is_trait_method_decl_without_default {
555 Body::TraitMethodWithoutDefault
556 } else {
557 self.translate_def_body(item_meta.span, def)
559 };
560 Ok(FunDecl {
561 def_id,
562 item_meta,
563 generics: self.into_generics(),
564 signature,
565 src,
566 is_global_initializer,
567 body,
568 })
569 }
570
571 #[tracing::instrument(skip(self, item_meta))]
573 pub fn translate_global(
574 mut self,
575 def_id: GlobalDeclId,
576 item_meta: ItemMeta,
577 def: &hax::FullDef,
578 ) -> Result<GlobalDecl, Error> {
579 let span = item_meta.span;
580
581 let item_source = self.get_item_source(span, def)?;
583
584 trace!("Translating global type");
585 let ty = match &def.kind {
586 hax::FullDefKind::Const { ty, .. }
587 | hax::FullDefKind::AssocConst { ty, .. }
588 | hax::FullDefKind::Static { ty, .. } => ty,
589 _ => panic!("Unexpected def for constant: {def:?}"),
590 };
591 let ty = self.translate_ty(span, ty)?;
592
593 let global_kind = match &def.kind {
594 hax::FullDefKind::Static { .. } => GlobalKind::Static,
595 hax::FullDefKind::Const {
596 kind: hax::ConstKind::TopLevel,
597 ..
598 }
599 | hax::FullDefKind::AssocConst { .. } => GlobalKind::NamedConst,
600 hax::FullDefKind::Const { .. } => GlobalKind::AnonConst,
601 _ => panic!("Unexpected def for constant: {def:?}"),
602 };
603
604 let initializer = self.register_item(span, def.this(), TransItemSourceKind::Fun);
605
606 Ok(GlobalDecl {
607 def_id,
608 item_meta,
609 generics: self.into_generics(),
610 ty,
611 src: item_source,
612 global_kind,
613 init: initializer,
614 })
615 }
616
617 #[tracing::instrument(skip(self, item_meta))]
618 pub fn translate_trait_decl(
619 mut self,
620 def_id: TraitDeclId,
621 item_meta: ItemMeta,
622 def: &hax::FullDef,
623 ) -> Result<TraitDecl, Error> {
624 let span = item_meta.span;
625
626 let (hax::FullDefKind::Trait {
627 implied_predicates, ..
628 }
629 | hax::FullDefKind::TraitAlias {
630 implied_predicates, ..
631 }) = def.kind()
632 else {
633 raise_error!(self, span, "Unexpected definition: {def:?}");
634 };
635
636 let mut preds =
638 self.translate_predicates(implied_predicates, PredicateOrigin::WhereClauseOnTrait)?;
639 let implied_clauses = mem::take(&mut preds.trait_clauses);
640 self.innermost_generics_mut().take_predicates_from(preds);
643
644 let vtable = self.translate_vtable_struct_ref_no_enqueue(span, def.this())?;
645
646 if let hax::FullDefKind::TraitAlias { .. } = def.kind() {
647 return Ok(TraitDecl {
649 def_id,
650 item_meta,
651 implied_clauses,
652 generics: self.into_generics(),
653 consts: Default::default(),
654 types: Default::default(),
655 methods: Default::default(),
656 vtable,
657 });
658 }
659
660 let hax::FullDefKind::Trait {
661 items,
662 self_predicate,
663 ..
664 } = &def.kind
665 else {
666 unreachable!()
667 };
668 let self_trait_ref = TraitRef::new(
669 TraitRefKind::SelfId,
670 RegionBinder::empty(self.translate_trait_predicate(span, self_predicate)?),
671 );
672 let items: Vec<(TraitItemName, &hax::AssocItem)> = items
673 .iter()
674 .map(|item| -> Result<_, Error> {
675 let name = self.t_ctx.translate_trait_item_name(&item.def_id)?;
676 Ok((name, item))
677 })
678 .try_collect()?;
679
680 let mut consts = Vec::new();
682 let mut types = Vec::new();
683 let mut methods = Vec::new();
684
685 for &(item_name, ref hax_item) in &items {
686 let item_def_id = &hax_item.def_id;
687 let item_span = self.def_span(item_def_id);
688
689 let trans_kind = match hax_item.kind {
692 hax::AssocKind::Fn { .. } => TransItemSourceKind::Fun,
693 hax::AssocKind::Const { .. } => TransItemSourceKind::Global,
694 hax::AssocKind::Type { .. } => TransItemSourceKind::Type,
695 };
696 let poly_item_def = self.poly_hax_def(item_def_id)?;
697 let (item_src, item_def) = if self.monomorphize() {
698 if poly_item_def.has_own_generics_or_predicates() {
699 continue;
704 } else {
705 let item = def.this().with_def_id(self.hax_state(), item_def_id);
706 let item_def = self.hax_def(&item)?;
707 let item_src = TransItemSource::monomorphic(&item, trans_kind);
708 (item_src, item_def)
709 }
710 } else {
711 let item_src = TransItemSource::polymorphic(item_def_id, trans_kind);
712 (item_src, poly_item_def)
713 };
714
715 match item_def.kind() {
716 hax::FullDefKind::AssocFn { .. } => {
717 let method_id = self.register_no_enqueue(item_span, &item_src);
718 self.register_method_impl(def_id, item_name, method_id);
720 if self.options.translate_all_methods
723 || item_meta.opacity.is_transparent()
724 || !hax_item.has_value
725 {
726 self.mark_method_as_used(def_id, item_name);
727 }
728
729 let binder_kind = BinderKind::TraitMethod(def_id, item_name);
730 let mut method = self.translate_binder_for_def(
731 item_span,
732 binder_kind,
733 &item_def,
734 |bt_ctx| {
735 assert_eq!(bt_ctx.binding_levels.len(), 2);
736 let fun_generics = bt_ctx
737 .outermost_binder()
738 .params
739 .identity_args_at_depth(DeBruijnId::one())
740 .concat(
741 &bt_ctx
742 .innermost_binder()
743 .params
744 .identity_args_at_depth(DeBruijnId::zero()),
745 );
746 let fn_ref = FunDeclRef {
747 id: method_id,
748 generics: Box::new(fun_generics),
749 };
750 Ok(TraitMethod {
751 name: item_name.clone(),
752 item: fn_ref,
753 })
754 },
755 )?;
756 if !self.monomorphize() {
761 struct ReplaceSelfVisitor;
762 impl VarsVisitor for ReplaceSelfVisitor {
763 fn visit_clause_var(&mut self, v: ClauseDbVar) -> Option<TraitRefKind> {
764 if let DeBruijnVar::Bound(DeBruijnId::ZERO, clause_id) = v {
765 Some(if let Some(new_id) = clause_id.index().checked_sub(1) {
767 TraitRefKind::Clause(DeBruijnVar::Bound(
768 DeBruijnId::ZERO,
769 TraitClauseId::new(new_id),
770 ))
771 } else {
772 TraitRefKind::SelfId
773 })
774 } else {
775 None
776 }
777 }
778 }
779 method.params.visit_vars(&mut ReplaceSelfVisitor);
780 method.skip_binder.visit_vars(&mut ReplaceSelfVisitor);
781 method
782 .params
783 .trait_clauses
784 .remove_and_shift_ids(TraitClauseId::ZERO);
785 method.params.trait_clauses.iter_mut().for_each(|clause| {
786 clause.clause_id -= 1;
787 });
788 }
789
790 methods.push(method);
793 }
794 hax::FullDefKind::AssocConst { ty, .. } => {
795 let default = hax_item.has_value.then(|| {
797 let id = self.register_and_enqueue(item_span, item_src);
800 let mut generics = self.the_only_binder().params.identity_args();
801 if !self.monomorphize() {
803 generics.trait_refs.push(self_trait_ref.clone());
804 }
805 GlobalDeclRef {
806 id,
807 generics: Box::new(generics),
808 }
809 });
810 let ty = self.translate_ty(item_span, ty)?;
811 consts.push(TraitAssocConst {
812 name: item_name.clone(),
813 ty,
814 default,
815 });
816 }
817 hax::FullDefKind::AssocTy { .. } if self.monomorphize() => continue,
819 hax::FullDefKind::AssocTy {
820 value,
821 implied_predicates,
822 ..
823 } => {
824 let binder_kind = BinderKind::TraitType(def_id, item_name.clone());
825 let assoc_ty =
826 self.translate_binder_for_def(item_span, binder_kind, &item_def, |ctx| {
827 let mut preds = ctx.translate_predicates(
829 &implied_predicates,
830 PredicateOrigin::TraitItem(item_name.clone()),
831 )?;
832 let implied_clauses = mem::take(&mut preds.trait_clauses);
833 ctx.innermost_generics_mut().take_predicates_from(preds);
836
837 let default = value
838 .as_ref()
839 .map(|ty| ctx.translate_ty(item_span, ty))
840 .transpose()?;
841 Ok(TraitAssocTy {
842 name: item_name.clone(),
843 default,
844 implied_clauses,
845 })
846 })?;
847 types.push(assoc_ty);
848 }
849 _ => panic!("Unexpected definition for trait item: {item_def:?}"),
850 }
851 }
852
853 if def.lang_item == Some(sym::destruct) {
854 let (method_name, method_binder) =
856 self.prepare_drop_in_place_method(def, span, def_id, None);
857 self.mark_method_as_used(def_id, method_name);
858 methods.push(method_binder.map(|fn_ref| TraitMethod {
859 name: method_name,
860 item: fn_ref,
861 }));
862 }
863
864 Ok(TraitDecl {
868 def_id,
869 item_meta,
870 implied_clauses,
871 generics: self.into_generics(),
872 consts,
873 types,
874 methods,
875 vtable,
876 })
877 }
878
879 #[tracing::instrument(skip(self, item_meta))]
880 pub fn translate_trait_impl(
881 mut self,
882 def_id: TraitImplId,
883 item_meta: ItemMeta,
884 def: &hax::FullDef,
885 ) -> Result<TraitImpl, Error> {
886 let span = item_meta.span;
887
888 let hax::FullDefKind::TraitImpl {
889 trait_pred,
890 implied_impl_exprs,
891 items: impl_items,
892 ..
893 } = &def.kind
894 else {
895 unreachable!()
896 };
897
898 let implemented_trait = self.translate_trait_ref(span, &trait_pred.trait_ref)?;
900 let trait_id = implemented_trait.id;
901 let self_predicate = TraitRef::new(
903 TraitRefKind::TraitImpl(TraitImplRef {
904 id: def_id,
905 generics: Box::new(self.the_only_binder().params.identity_args()),
906 }),
907 RegionBinder::empty(implemented_trait.clone()),
908 );
909
910 let vtable =
911 self.translate_vtable_instance_ref_no_enqueue(span, &trait_pred.trait_ref, def.this())?;
912
913 let implied_trait_refs = self.translate_trait_impl_exprs(span, &implied_impl_exprs)?;
915
916 {
917 let ctx = self.into_fmt();
919 let refs = implied_trait_refs
920 .iter()
921 .map(|c| c.with_ctx(&ctx))
922 .format("\n");
923 trace!(
924 "Trait impl: {:?}\n- implied_trait_refs:\n{}",
925 def.def_id(),
926 refs
927 );
928 }
929
930 let mut consts = Vec::new();
932 let mut types = Vec::new();
933 let mut methods = Vec::new();
934
935 for impl_item in impl_items {
936 use hax::ImplAssocItemValue::*;
937 let name = self
938 .t_ctx
939 .translate_trait_item_name(&impl_item.decl_def_id)?;
940 let item_def_id = impl_item.def_id();
941 let item_span = self.def_span(item_def_id);
942 let poly_item_def = self.poly_hax_def(item_def_id)?;
946 let trans_kind = match poly_item_def.kind() {
947 hax::FullDefKind::AssocFn { .. } => TransItemSourceKind::Fun,
948 hax::FullDefKind::AssocConst { .. } => TransItemSourceKind::Global,
949 hax::FullDefKind::AssocTy { .. } => TransItemSourceKind::Type,
950 _ => unreachable!(),
951 };
952 let (item_src, item_def) = if self.monomorphize() {
953 if poly_item_def.has_own_generics_or_predicates() {
954 continue;
955 } else {
956 let item = match &impl_item.value {
957 Provided { def_id, .. } => def.this().with_def_id(self.hax_state(), def_id),
959 _ => trait_pred
961 .trait_ref
962 .with_def_id(self.hax_state(), &impl_item.decl_def_id),
963 };
964 let item_src = TransItemSource::monomorphic(&item, trans_kind);
965 let item_def = self.hax_def_for_item(&item_src.item)?;
966 (item_src, item_def)
967 }
968 } else {
969 let item_src = TransItemSource::polymorphic(item_def_id, trans_kind);
970 (item_src, poly_item_def)
971 };
972
973 match item_def.kind() {
974 hax::FullDefKind::AssocFn { .. } => {
975 let method_id: FunDeclId = {
976 let method_src = match &impl_item.value {
977 Provided { .. } => item_src,
978 DefaultedFn { .. } => TransItemSource::from_item(
981 def.this(),
982 TransItemSourceKind::DefaultedMethod(TraitImplSource::Normal, name),
983 self.monomorphize(),
984 ),
985 _ => unreachable!(),
986 };
987 self.register_no_enqueue(item_span, &method_src)
988 };
989
990 self.register_method_impl(trait_id, name, method_id);
992 if matches!(impl_item.value, Provided { .. })
995 && item_meta.opacity.is_transparent()
996 {
997 self.mark_method_as_used(trait_id, name);
998 }
999
1000 let binder_kind = BinderKind::TraitMethod(trait_id, name);
1001 let bound_fn_ref = match &impl_item.value {
1002 Provided { .. } => self.translate_binder_for_def(
1003 item_span,
1004 binder_kind,
1005 &item_def,
1006 |ctx| {
1007 let generics = ctx
1008 .outermost_generics()
1009 .identity_args_at_depth(DeBruijnId::one())
1010 .concat(
1011 &ctx.innermost_generics()
1012 .identity_args_at_depth(DeBruijnId::zero()),
1013 );
1014 Ok(FunDeclRef {
1015 id: method_id,
1016 generics: Box::new(generics),
1017 })
1018 },
1019 )?,
1020 DefaultedFn { .. } => {
1021 let decl_methods =
1023 match self.get_or_translate(implemented_trait.id.into()) {
1024 Ok(ItemRef::TraitDecl(tdecl)) => tdecl.methods.as_slice(),
1025 _ => &[],
1026 };
1027 let Some(bound_method) = decl_methods.iter().find(|m| m.name() == name)
1028 else {
1029 continue;
1030 };
1031 let method_params = bound_method
1032 .clone()
1033 .substitute_with_self(
1034 &implemented_trait.generics,
1035 &self_predicate.kind,
1036 )
1037 .params;
1038
1039 let generics = self
1040 .outermost_generics()
1041 .identity_args_at_depth(DeBruijnId::one())
1042 .concat(&method_params.identity_args_at_depth(DeBruijnId::zero()));
1043 let fn_ref = FunDeclRef {
1044 id: method_id,
1045 generics: Box::new(generics),
1046 };
1047 Binder::new(binder_kind, method_params, fn_ref)
1048 }
1049 _ => unreachable!(),
1050 };
1051
1052 methods.push((name, bound_fn_ref));
1055 }
1056 hax::FullDefKind::AssocConst { .. } => {
1057 let id = self.register_and_enqueue(item_span, item_src);
1058 let generics = match &impl_item.value {
1061 Provided { .. } => self.the_only_binder().params.identity_args(),
1062 _ => {
1063 let mut generics = implemented_trait.generics.as_ref().clone();
1064 if !self.monomorphize() {
1066 generics.trait_refs.push(self_predicate.clone());
1067 }
1068 generics
1069 }
1070 };
1071 let gref = GlobalDeclRef {
1072 id,
1073 generics: Box::new(generics),
1074 };
1075 consts.push((name, gref));
1076 }
1077 hax::FullDefKind::AssocTy { .. } if self.monomorphize() => continue,
1079 hax::FullDefKind::AssocTy { value, .. } => {
1080 let binder_kind = BinderKind::TraitType(trait_id, name.clone());
1081 let assoc_ty =
1082 self.translate_binder_for_def(item_span, binder_kind, &item_def, |ctx| {
1083 let ty = match &impl_item.value {
1084 Provided { .. } => value.as_ref().unwrap(),
1085 DefaultedTy { ty, .. } => ty,
1086 _ => unreachable!(),
1087 };
1088 let ty = ctx.translate_ty(item_span, &ty)?;
1089 let implied_trait_refs = ctx.translate_trait_impl_exprs(
1090 item_span,
1091 &impl_item.required_impl_exprs,
1092 )?;
1093 Ok(TraitAssocTyImpl {
1094 value: ty,
1095 implied_trait_refs,
1096 })
1097 })?;
1098 types.push((name.clone(), assoc_ty));
1099 }
1100 _ => panic!("Unexpected definition for trait item: {item_def:?}"),
1101 }
1102 }
1103
1104 let implemented_trait_def = self.poly_hax_def(&trait_pred.trait_ref.def_id)?;
1105 if implemented_trait_def.lang_item == Some(sym::destruct) {
1106 raise_error!(
1107 self,
1108 span,
1109 "found an explicit impl of `core::marker::Destruct`, this should not happen"
1110 );
1111 }
1112
1113 Ok(TraitImpl {
1114 def_id,
1115 item_meta,
1116 impl_trait: implemented_trait,
1117 generics: self.into_generics(),
1118 implied_trait_refs,
1119 consts,
1120 types,
1121 methods,
1122 vtable,
1123 })
1124 }
1125
1126 #[tracing::instrument(skip(self, item_meta))]
1136 pub fn translate_trait_alias_blanket_impl(
1137 mut self,
1138 def_id: TraitImplId,
1139 item_meta: ItemMeta,
1140 def: &hax::FullDef,
1141 ) -> Result<TraitImpl, Error> {
1142 let span = item_meta.span;
1143
1144 let hax::FullDefKind::TraitAlias {
1145 implied_predicates, ..
1146 } = &def.kind
1147 else {
1148 raise_error!(self, span, "Unexpected definition: {def:?}");
1149 };
1150
1151 let trait_id = self.register_item(span, def.this(), TransItemSourceKind::TraitDecl);
1152
1153 assert!(self.innermost_generics_mut().trait_clauses.is_empty());
1155 self.register_predicates(implied_predicates, PredicateOrigin::WhereClauseOnTrait)?;
1156
1157 let mut generics = self.the_only_binder().params.identity_args();
1158 let implied_trait_refs = mem::take(&mut generics.trait_refs);
1160 let implemented_trait = TraitDeclRef {
1161 id: trait_id,
1162 generics: Box::new(generics),
1163 };
1164
1165 let mut timpl = TraitImpl {
1166 def_id,
1167 item_meta,
1168 impl_trait: implemented_trait,
1169 generics: self.the_only_binder().params.clone(),
1170 implied_trait_refs,
1171 consts: Default::default(),
1172 types: Default::default(),
1173 methods: Default::default(),
1174 vtable: None,
1176 };
1177 {
1180 struct FixSelfVisitor {
1181 binder_depth: DeBruijnId,
1182 }
1183 struct UnhandledSelf;
1184 impl Visitor for FixSelfVisitor {
1185 type Break = UnhandledSelf;
1186 }
1187 impl VisitorWithBinderDepth for FixSelfVisitor {
1188 fn binder_depth_mut(&mut self) -> &mut DeBruijnId {
1189 &mut self.binder_depth
1190 }
1191 }
1192 impl VisitAstMut for FixSelfVisitor {
1193 fn visit<'a, T: AstVisitable>(&'a mut self, x: &mut T) -> ControlFlow<Self::Break> {
1194 VisitWithBinderDepth::new(self).visit(x)
1195 }
1196 fn visit_trait_ref_kind(
1197 &mut self,
1198 kind: &mut TraitRefKind,
1199 ) -> ControlFlow<Self::Break> {
1200 match kind {
1201 TraitRefKind::SelfId => return ControlFlow::Break(UnhandledSelf),
1202 TraitRefKind::ParentClause(sub, clause_id)
1203 if matches!(sub.kind, TraitRefKind::SelfId) =>
1204 {
1205 *kind = TraitRefKind::Clause(DeBruijnVar::bound(
1206 self.binder_depth,
1207 *clause_id,
1208 ))
1209 }
1210 _ => (),
1211 }
1212 self.visit_inner(kind)
1213 }
1214 }
1215 match timpl.drive_mut(&mut FixSelfVisitor {
1216 binder_depth: DeBruijnId::zero(),
1217 }) {
1218 ControlFlow::Continue(()) => {}
1219 ControlFlow::Break(UnhandledSelf) => {
1220 register_error!(
1221 self,
1222 span,
1223 "Found `Self` clause we can't handle \
1224 in a trait alias blanket impl."
1225 );
1226 }
1227 }
1228 };
1229
1230 Ok(timpl)
1231 }
1232
1233 #[tracing::instrument(skip(self, item_meta))]
1236 pub fn translate_virtual_trait_impl(
1237 &mut self,
1238 def_id: TraitImplId,
1239 item_meta: ItemMeta,
1240 vimpl: &hax::VirtualTraitImpl,
1241 ) -> Result<TraitImpl, Error> {
1242 let span = item_meta.span;
1243 let trait_def = self.hax_def(&vimpl.trait_pred.trait_ref)?;
1244 let hax::FullDefKind::Trait {
1245 items: trait_items, ..
1246 } = trait_def.kind()
1247 else {
1248 panic!()
1249 };
1250
1251 let implemented_trait = self.translate_trait_predicate(span, &vimpl.trait_pred)?;
1252 let implied_trait_refs =
1253 self.translate_trait_impl_exprs(span, &vimpl.implied_impl_exprs)?;
1254
1255 let mut types = vec![];
1256 if !self.monomorphize() {
1258 let type_items = trait_items.iter().filter(|assoc| match assoc.kind {
1259 hax::AssocKind::Type { .. } => true,
1260 _ => false,
1261 });
1262 for ((ty, impl_exprs), assoc) in vimpl.types.iter().zip(type_items) {
1263 let name = self.t_ctx.translate_trait_item_name(&assoc.def_id)?;
1264 let assoc_ty = TraitAssocTyImpl {
1265 value: self.translate_ty(span, ty)?,
1266 implied_trait_refs: self.translate_trait_impl_exprs(span, impl_exprs)?,
1267 };
1268 let binder_kind = BinderKind::TraitType(implemented_trait.id, name.clone());
1269 types.push((name, Binder::empty(binder_kind, assoc_ty)));
1270 }
1271 }
1272
1273 let generics = self.the_only_binder().params.clone();
1274 Ok(TraitImpl {
1275 def_id,
1276 item_meta,
1277 impl_trait: implemented_trait,
1278 generics,
1279 implied_trait_refs,
1280 consts: vec![],
1281 types,
1282 methods: vec![],
1283 vtable: None,
1285 })
1286 }
1287
1288 pub fn register_method_impl(
1292 &mut self,
1293 trait_id: TraitDeclId,
1294 method_name: TraitItemName,
1295 method_id: FunDeclId,
1296 ) {
1297 match self
1298 .method_status
1299 .get_or_extend_and_insert_default(trait_id)
1300 .entry(method_name)
1301 .or_default()
1302 {
1303 MethodStatus::Unused { implementors } => {
1304 implementors.insert(method_id);
1305 }
1306 MethodStatus::Used => {
1307 self.enqueue_id(method_id);
1308 }
1309 }
1310 }
1311
1312 pub fn mark_method_as_used(&mut self, trait_id: TraitDeclId, method_name: TraitItemName) {
1315 let method_status = self
1316 .method_status
1317 .get_or_extend_and_insert_default(trait_id)
1318 .entry(method_name)
1319 .or_default();
1320 match method_status {
1321 MethodStatus::Unused { implementors } => {
1322 let implementors = mem::take(implementors);
1323 *method_status = MethodStatus::Used;
1324 for fun_id in implementors {
1325 self.enqueue_id(fun_id);
1326 }
1327 }
1328 MethodStatus::Used => {}
1329 }
1330 }
1331
1332 #[tracing::instrument(skip(self, item_meta))]
1335 pub fn translate_defaulted_method(
1336 &mut self,
1337 def_id: FunDeclId,
1338 item_meta: ItemMeta,
1339 def: &hax::FullDef,
1340 impl_kind: TraitImplSource,
1341 method_name: TraitItemName,
1342 ) -> Result<FunDecl, Error> {
1343 let span = item_meta.span;
1344
1345 let hax::FullDefKind::TraitImpl { trait_pred, .. } = &def.kind else {
1346 unreachable!()
1347 };
1348
1349 let implemented_trait = self.translate_trait_ref(span, &trait_pred.trait_ref)?;
1351 let self_impl_ref = self.translate_trait_impl_ref(span, def.this(), impl_kind)?;
1353 let self_predicate_kind = TraitRefKind::TraitImpl(self_impl_ref.clone());
1354
1355 let ItemRef::TraitDecl(tdecl) = self.get_or_translate(implemented_trait.id.into())? else {
1357 panic!()
1358 };
1359 let Some(bound_method) = tdecl.methods.iter().find(|m| m.name() == method_name) else {
1360 raise_error!(
1361 self,
1362 span,
1363 "Could not find a method with name \
1364 `{method_name}` in trait `{:?}`",
1365 trait_pred.trait_ref.def_id,
1366 )
1367 };
1368 let bound_fn_ref: Binder<FunDeclRef> = bound_method
1369 .clone()
1370 .substitute_with_self(&implemented_trait.generics, &self_predicate_kind)
1371 .map(|m| m.item);
1372
1373 let bound_fn_ref: Binder<Binder<FunDeclRef>> = Binder {
1377 params: self.outermost_generics().clone(),
1378 skip_binder: bound_fn_ref,
1379 kind: BinderKind::Other,
1380 };
1381 let bound_fn_ref: Binder<FunDeclRef> = bound_fn_ref.flatten();
1382
1383 let original_method_id = bound_fn_ref.skip_binder.id;
1385 let ItemRef::Fun(fun_decl) = self.get_or_translate(original_method_id.into())? else {
1386 panic!()
1387 };
1388 let mut fun_decl = fun_decl
1389 .clone()
1390 .substitute_params(bound_fn_ref.map(|x| *x.generics));
1391
1392 fun_decl.def_id = def_id;
1394 fun_decl.item_meta = ItemMeta {
1397 name: item_meta.name,
1398 opacity: item_meta.opacity,
1399 is_local: item_meta.is_local,
1400 span: item_meta.span,
1401 source_text: fun_decl.item_meta.source_text,
1402 attr_info: fun_decl.item_meta.attr_info,
1403 lang_item: fun_decl.item_meta.lang_item,
1404 };
1405 fun_decl.src = if let ItemSource::TraitDecl {
1406 trait_ref,
1407 item_name,
1408 ..
1409 } = fun_decl.src
1410 {
1411 ItemSource::TraitImpl {
1412 impl_ref: self_impl_ref.clone(),
1413 trait_ref,
1414 item_name,
1415 reuses_default: true,
1416 }
1417 } else {
1418 unreachable!()
1419 };
1420 if !item_meta.opacity.is_transparent() {
1421 fun_decl.body = Body::Opaque;
1422 }
1423
1424 Ok(fun_decl)
1425 }
1426}