1use itertools::Itertools;
18use rustc_middle::ty::TyCtxt;
19use std::cell::RefCell;
20use std::path::PathBuf;
21
22use super::translate_ctx::*;
23use charon_lib::ast::*;
24use charon_lib::options::{CliOpts, StartFrom, TranslateOptions};
25use charon_lib::transform::TransformCtx;
26use hax::SInto;
27use macros::VariantIndexArity;
28
29#[derive(Clone, Debug, PartialEq, Eq, Hash)]
33pub struct TransItemSource {
34 pub item: RustcItem,
35 pub kind: TransItemSourceKind,
36}
37
38#[derive(Clone, Debug, PartialEq, Eq, Hash)]
46pub enum RustcItem {
47 Poly(hax::DefId),
48 Mono(hax::ItemRef),
49 MonoTrait(hax::DefId),
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, VariantIndexArity)]
54pub enum TransItemSourceKind {
55 Global,
56 TraitDecl,
57 TraitImpl(TraitImplSource),
58 Fun,
59 Type,
60 InherentImpl,
62 Module,
64 DefaultedMethod(TraitImplSource, TraitItemName),
67 ClosureMethod(ClosureKind),
69 ClosureAsFnCast,
71 DropInPlaceMethod(Option<TraitImplSource>),
77 VTable,
79 VTableInstance(TraitImplSource),
81 VTableInstanceInitializer(TraitImplSource),
83 VTableMethod,
87 VTableDropShim,
89 VTableDropPreShim,
90 VTableMethodPreShim(TraitDeclId, TraitItemName),
91}
92
93#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, VariantIndexArity)]
95pub enum TraitImplSource {
96 Normal,
98 TraitAlias,
100 Closure(ClosureKind),
102 ImplicitDestruct,
105}
106
107impl TransItemSource {
108 pub fn new(item: RustcItem, kind: TransItemSourceKind) -> Self {
109 if let RustcItem::Mono(item) = &item {
110 if item.has_param {
111 panic!("Item is not monomorphic: {item:?}")
112 }
113 } else if let RustcItem::MonoTrait(_) = &item {
114 if !matches!(
115 kind,
116 TransItemSourceKind::TraitDecl | TransItemSourceKind::VTable
117 ) {
118 panic!("Item kind {kind:?} should not be translated as monomorphic_trait")
119 }
120 }
121 Self { item, kind }
122 }
123
124 pub fn from_item(item: &hax::ItemRef, kind: TransItemSourceKind, monomorphize: bool) -> Self {
127 if monomorphize {
128 Self::monomorphic(item, kind)
129 } else {
130 Self::polymorphic(&item.def_id, kind)
131 }
132 }
133
134 pub fn polymorphic(def_id: &hax::DefId, kind: TransItemSourceKind) -> Self {
136 Self::new(RustcItem::Poly(def_id.clone()), kind)
137 }
138
139 pub fn monomorphic(item: &hax::ItemRef, kind: TransItemSourceKind) -> Self {
141 Self::new(RustcItem::Mono(item.clone()), kind)
142 }
143
144 pub fn monomorphic_trait(def_id: &hax::DefId, kind: TransItemSourceKind) -> Self {
147 Self::new(RustcItem::MonoTrait(def_id.clone()), kind)
148 }
149
150 pub fn def_id(&self) -> &hax::DefId {
151 self.item.def_id()
152 }
153
154 pub(crate) fn with_kind(&self, kind: TransItemSourceKind) -> Self {
156 let mut ret = self.clone();
157 ret.kind = kind;
158 ret
159 }
160
161 pub(crate) fn parent(&self) -> Option<Self> {
164 let parent_kind = match self.kind {
165 TransItemSourceKind::ClosureMethod(kind) => {
166 TransItemSourceKind::TraitImpl(TraitImplSource::Closure(kind))
167 }
168 TransItemSourceKind::DefaultedMethod(impl_kind, _)
169 | TransItemSourceKind::DropInPlaceMethod(Some(impl_kind))
170 | TransItemSourceKind::VTableInstance(impl_kind)
171 | TransItemSourceKind::VTableInstanceInitializer(impl_kind) => {
172 TransItemSourceKind::TraitImpl(impl_kind)
173 }
174 TransItemSourceKind::DropInPlaceMethod(None) => TransItemSourceKind::TraitDecl,
175 _ => return None,
176 };
177 Some(self.with_kind(parent_kind))
178 }
179
180 pub(crate) fn is_derived_item(&self) -> bool {
183 use TransItemSourceKind::*;
184 match self.kind {
185 Global
186 | TraitDecl
187 | TraitImpl(TraitImplSource::Normal)
188 | InherentImpl
189 | Module
190 | Fun
191 | Type => false,
192 _ => true,
193 }
194 }
195}
196
197impl RustcItem {
198 pub fn def_id(&self) -> &hax::DefId {
199 match self {
200 RustcItem::Poly(def_id) => def_id,
201 RustcItem::Mono(item_ref) => &item_ref.def_id,
202 RustcItem::MonoTrait(def_id) => def_id,
203 }
204 }
205}
206
207impl<'tcx> TranslateCtx<'tcx> {
208 pub fn base_kind_for_item(&mut self, def_id: &hax::DefId) -> Option<TransItemSourceKind> {
211 use hax::DefKind::*;
212 Some(match &def_id.kind {
213 Enum { .. } | Struct { .. } | Union { .. } | TyAlias { .. } | ForeignTy => {
214 TransItemSourceKind::Type
215 }
216 Fn { .. } | AssocFn { .. } => TransItemSourceKind::Fun,
217 Const { .. } | Static { .. } | AssocConst { .. } => TransItemSourceKind::Global,
218 Trait { .. } | TraitAlias { .. } => TransItemSourceKind::TraitDecl,
219 Impl { of_trait: true } => TransItemSourceKind::TraitImpl(TraitImplSource::Normal),
220 Impl { of_trait: false } => TransItemSourceKind::InherentImpl,
221 Mod { .. } | ForeignMod { .. } => TransItemSourceKind::Module,
222
223 ExternCrate { .. } | GlobalAsm { .. } | Macro { .. } | Use { .. } => return None,
225 Ctor { .. } | Variant { .. } => return None,
228 AnonConst { .. }
230 | AssocTy { .. }
231 | Closure { .. }
232 | ConstParam { .. }
233 | Field { .. }
234 | InlineConst { .. }
235 | PromotedConst { .. }
236 | LifetimeParam { .. }
237 | OpaqueTy { .. }
238 | SyntheticCoroutineBody { .. }
239 | TyParam { .. } => {
240 let span = self.def_span(def_id);
241 register_error!(
242 self,
243 span,
244 "Cannot register item `{def_id:?}` with kind `{:?}`",
245 def_id.kind
246 );
247 return None;
248 }
249 })
250 }
251
252 #[tracing::instrument(skip(self))]
256 pub fn enqueue_module_item(&mut self, def_id: &hax::DefId) {
257 let Some(kind) = self.base_kind_for_item(def_id) else {
258 return;
259 };
260 let item_src = if self.options.monomorphize_with_hax {
261 if let Ok(def) = self.poly_hax_def(def_id)
262 && !def.has_any_generics()
263 {
264 TransItemSource::monomorphic(def.this(), kind)
266 } else {
267 return;
269 }
270 } else {
271 TransItemSource::polymorphic(def_id, kind)
272 };
273 let _: Option<ItemId> = self.register_and_enqueue(&None, item_src);
274 }
275
276 pub(crate) fn register_no_enqueue<T: TryFrom<ItemId>>(
277 &mut self,
278 dep_src: &Option<DepSource>,
279 src: &TransItemSource,
280 ) -> Option<T> {
281 let item_id = match self.id_map.get(src) {
282 Some(tid) => *tid,
283 None => {
284 use TransItemSourceKind::*;
285 let trans_id = match src.kind {
286 Type | VTable => ItemId::Type(self.translated.type_decls.reserve_slot()),
287 TraitDecl => ItemId::TraitDecl(self.translated.trait_decls.reserve_slot()),
288 TraitImpl(..) => ItemId::TraitImpl(self.translated.trait_impls.reserve_slot()),
289 Global | VTableInstance(..) => {
290 ItemId::Global(self.translated.global_decls.reserve_slot())
291 }
292 Fun
293 | DefaultedMethod(..)
294 | ClosureMethod(..)
295 | ClosureAsFnCast
296 | DropInPlaceMethod(..)
297 | VTableInstanceInitializer(..)
298 | VTableMethod
299 | VTableDropShim
300 | VTableDropPreShim
301 | VTableMethodPreShim(..) => {
302 ItemId::Fun(self.translated.fun_decls.reserve_slot())
303 }
304 InherentImpl | Module => return None,
305 };
306 self.id_map.insert(src.clone(), trans_id);
308 self.reverse_id_map.insert(trans_id, src.clone());
309 if let Ok(name) = self.translate_name(src) {
311 self.translated.item_names.insert(trans_id, name);
312 }
313 trans_id
314 }
315 };
316 self.errors
317 .borrow_mut()
318 .register_dep_source(dep_src, item_id, src.def_id().is_local());
319 item_id.try_into().ok()
320 }
321
322 pub(crate) fn register_and_enqueue<T: TryFrom<ItemId>>(
324 &mut self,
325 dep_src: &Option<DepSource>,
326 item_src: TransItemSource,
327 ) -> Option<T> {
328 let id = self.register_no_enqueue(dep_src, &item_src);
329 self.items_to_translate.push_back(item_src);
330 id
331 }
332
333 pub(crate) fn enqueue_id(&mut self, id: impl Into<ItemId>) {
335 let id = id.into();
336 if self.translated.get_item(id).is_none() {
337 let item_src = self.reverse_id_map[&id].clone();
338 self.items_to_translate.push_back(item_src);
339 }
340 }
341
342 pub(crate) fn register_target_info(&mut self) {
343 let target_data = &self.tcx.data_layout;
344 self.translated.target_information = krate::TargetInfo {
345 target_pointer_size: target_data.pointer_size().bytes(),
346 is_little_endian: matches!(target_data.endian, rustc_abi::Endian::Little),
347 }
348 }
349}
350
351impl<'tcx, 'ctx> ItemTransCtx<'tcx, 'ctx> {
353 pub(crate) fn make_dep_source(&self, span: Span) -> Option<DepSource> {
354 Some(DepSource {
355 src_id: self.item_id?,
356 span: self.item_src.def_id().is_local().then_some(span),
357 })
358 }
359
360 pub(crate) fn register_and_enqueue<T: TryFrom<ItemId>>(
362 &mut self,
363 span: Span,
364 item_src: TransItemSource,
365 ) -> T {
366 let dep_src = self.make_dep_source(span);
367 self.t_ctx.register_and_enqueue(&dep_src, item_src).unwrap()
368 }
369
370 pub(crate) fn register_no_enqueue<T: TryFrom<ItemId>>(
371 &mut self,
372 span: Span,
373 src: &TransItemSource,
374 ) -> T {
375 let dep_src = self.make_dep_source(span);
376 self.t_ctx.register_no_enqueue(&dep_src, src).unwrap()
377 }
378
379 pub(crate) fn register_item_maybe_enqueue<T: TryFrom<ItemId>>(
381 &mut self,
382 span: Span,
383 enqueue: bool,
384 item: &hax::ItemRef,
385 kind: TransItemSourceKind,
386 ) -> T {
387 let item = if self.monomorphize() && item.has_param {
388 item.erase(self.hax_state_with_id())
389 } else {
390 item.clone()
391 };
392 let item_src = if self.monomorphize() && matches!(kind, TransItemSourceKind::TraitDecl) {
399 TransItemSource::monomorphic_trait(&item.def_id, kind)
400 } else {
401 TransItemSource::from_item(
402 &item,
403 kind,
404 self.monomorphize()
405 && !matches!(
406 self.item_src.kind,
407 TransItemSourceKind::TraitDecl | TransItemSourceKind::VTable
408 ),
409 )
410 };
411 if enqueue {
412 self.register_and_enqueue(span, item_src)
413 } else {
414 self.register_no_enqueue(span, &item_src)
415 }
416 }
417
418 pub(crate) fn register_item<T: TryFrom<ItemId>>(
420 &mut self,
421 span: Span,
422 item: &hax::ItemRef,
423 kind: TransItemSourceKind,
424 ) -> T {
425 self.register_item_maybe_enqueue(span, true, item, kind)
426 }
427
428 #[expect(dead_code)]
430 pub(crate) fn register_item_no_enqueue<T: TryFrom<ItemId>>(
431 &mut self,
432 span: Span,
433 item: &hax::ItemRef,
434 kind: TransItemSourceKind,
435 ) -> T {
436 self.register_item_maybe_enqueue(span, false, item, kind)
437 }
438
439 pub(crate) fn translate_item_maybe_enqueue<T: TryFrom<DeclRef<ItemId>>>(
441 &mut self,
442 span: Span,
443 enqueue: bool,
444 hax_item: &hax::ItemRef,
445 kind: TransItemSourceKind,
446 ) -> Result<T, Error> {
447 let id: ItemId = self.register_item_maybe_enqueue(span, enqueue, hax_item, kind);
448 let mut generics = if self.monomorphize() && !matches!(kind, TransItemSourceKind::TraitDecl)
450 {
451 GenericArgs::empty()
452 } else {
453 self.translate_generic_args(span, &hax_item.generic_args, &hax_item.impl_exprs)?
454 };
455
456 if matches!(
459 hax_item.def_id.kind,
460 hax::DefKind::Fn { .. } | hax::DefKind::AssocFn { .. } | hax::DefKind::Closure { .. }
461 ) {
462 let def = self.hax_def(hax_item)?;
463 match def.kind() {
464 hax::FullDefKind::Fn { sig, .. } | hax::FullDefKind::AssocFn { sig, .. } => {
465 generics.regions.extend(
466 sig.bound_vars
467 .iter()
468 .map(|_| self.translate_erased_region()),
469 );
470 }
471 hax::FullDefKind::Closure { args, .. } => {
472 let upvar_regions = if self.item_src.def_id() == &args.item.def_id {
473 assert!(self.outermost_binder().closure_upvar_tys.is_some());
474 self.outermost_binder().closure_upvar_regions.len()
475 } else {
476 let adt_decl_id: ItemId =
480 self.register_item(span, hax_item, TransItemSourceKind::Type);
481 let adt_decl = self.get_or_translate(adt_decl_id)?;
482 let adt_generics = adt_decl.generic_params();
483 adt_generics.regions.elem_count() - generics.regions.elem_count()
484 };
485 generics
486 .regions
487 .extend((0..upvar_regions).map(|_| self.translate_erased_region()));
488 if let TransItemSourceKind::TraitImpl(TraitImplSource::Closure(..))
489 | TransItemSourceKind::ClosureMethod(..)
490 | TransItemSourceKind::ClosureAsFnCast = kind
491 {
492 generics.regions.extend(
493 args.fn_sig
494 .bound_vars
495 .iter()
496 .map(|_| self.translate_erased_region()),
497 );
498 }
499 if let TransItemSourceKind::ClosureMethod(
500 ClosureKind::FnMut | ClosureKind::Fn,
501 ) = kind
502 {
503 generics.regions.push(self.translate_erased_region());
504 }
505 if self.item_src.def_id() == &args.item.def_id {
509 let depth = self.binding_levels.depth();
510 for (a, b) in generics.regions.iter_mut().zip(
511 self.outermost_binder()
512 .params
513 .identity_args_at_depth(depth)
514 .regions,
515 ) {
516 *a = b;
517 }
518 }
519 }
520 _ => {}
521 }
522 }
523
524 let trait_ref = hax_item
525 .in_trait
526 .as_ref()
527 .map(|impl_expr| self.translate_trait_impl_expr(span, impl_expr))
528 .transpose()?;
529 let item = DeclRef {
530 id,
531 generics: Box::new(generics),
532 trait_ref,
533 };
534 Ok(item.try_into().ok().unwrap())
535 }
536
537 pub(crate) fn translate_item<T: TryFrom<DeclRef<ItemId>>>(
543 &mut self,
544 span: Span,
545 item: &hax::ItemRef,
546 kind: TransItemSourceKind,
547 ) -> Result<T, Error> {
548 self.translate_item_maybe_enqueue(span, true, item, kind)
549 }
550
551 #[expect(dead_code)]
553 pub(crate) fn translate_item_no_enqueue<T: TryFrom<DeclRef<ItemId>>>(
554 &mut self,
555 span: Span,
556 item: &hax::ItemRef,
557 kind: TransItemSourceKind,
558 ) -> Result<T, Error> {
559 self.translate_item_maybe_enqueue(span, false, item, kind)
560 }
561
562 pub(crate) fn translate_type_decl_ref(
564 &mut self,
565 span: Span,
566 item: &hax::ItemRef,
567 ) -> Result<TypeDeclRef, Error> {
568 match self.recognize_builtin_type(item)? {
569 Some(id) => {
570 let generics =
571 self.translate_generic_args(span, &item.generic_args, &item.impl_exprs)?;
572 Ok(TypeDeclRef {
573 id: TypeId::Builtin(id),
574 generics: Box::new(generics),
575 })
576 }
577 None => self.translate_item(span, item, TransItemSourceKind::Type),
578 }
579 }
580
581 pub(crate) fn translate_fun_item(
583 &mut self,
584 span: Span,
585 item: &hax::ItemRef,
586 kind: TransItemSourceKind,
587 ) -> Result<MaybeBuiltinFunDeclRef, Error> {
588 match self.recognize_builtin_fun(item)? {
589 Some(id) => {
590 let generics =
591 self.translate_generic_args(span, &item.generic_args, &item.impl_exprs)?;
592 Ok(MaybeBuiltinFunDeclRef {
593 id: FunId::Builtin(id),
594 generics: Box::new(generics),
595 trait_ref: None,
596 })
597 }
598 None => self.translate_item(span, item, kind),
599 }
600 }
601
602 #[tracing::instrument(skip(self, span))]
605 pub(crate) fn translate_bound_fn_ptr(
606 &mut self,
607 span: Span,
608 item: &hax::ItemRef,
609 kind: TransItemSourceKind,
610 ) -> Result<RegionBinder<FnPtr>, Error> {
611 let fun_item = self.translate_fun_item(span, item, kind)?;
612 let fun_id = match fun_item.trait_ref {
613 None => FnPtrKind::Fun(fun_item.id),
615 Some(trait_ref) => {
617 let name = self.t_ctx.translate_trait_item_name(&item.def_id)?;
618 let method_decl_id = *fun_item
619 .id
620 .as_regular()
621 .expect("methods are not builtin functions");
622 self.mark_method_as_used(trait_ref.trait_decl_ref.skip_binder.id, name);
623 FnPtrKind::Trait(trait_ref.move_under_binder(), name, method_decl_id)
624 }
625 };
626 let late_bound = match self.hax_def(item)?.kind() {
627 hax::FullDefKind::Fn { sig, .. } | hax::FullDefKind::AssocFn { sig, .. } => {
628 sig.as_ref().rebind(())
629 }
630 _ => hax::Binder {
631 value: (),
632 bound_vars: vec![],
633 },
634 };
635 self.translate_region_binder(span, &late_bound, |ctx, _| {
636 let mut generics = fun_item.generics.move_under_binder();
637 for (a, b) in generics.regions.iter_mut().rev().zip(
640 ctx.innermost_binder()
641 .params
642 .identity_args()
643 .regions
644 .into_iter()
645 .rev(),
646 ) {
647 *a = b;
648 }
649 Ok(FnPtr::new(fun_id, generics))
650 })
651 }
652
653 pub(crate) fn translate_fn_ptr(
654 &mut self,
655 span: Span,
656 item: &hax::ItemRef,
657 kind: TransItemSourceKind,
658 ) -> Result<FnPtr, Error> {
659 let fn_ptr = self.translate_bound_fn_ptr(span, item, kind)?;
660 let fn_ptr = self.erase_region_binder(fn_ptr);
661 Ok(fn_ptr)
662 }
663
664 pub(crate) fn translate_global_decl_ref(
665 &mut self,
666 span: Span,
667 item: &hax::ItemRef,
668 ) -> Result<GlobalDeclRef, Error> {
669 self.translate_item(span, item, TransItemSourceKind::Global)
670 }
671
672 pub(crate) fn translate_trait_decl_ref(
673 &mut self,
674 span: Span,
675 item: &hax::ItemRef,
676 ) -> Result<TraitDeclRef, Error> {
677 self.translate_item(span, item, TransItemSourceKind::TraitDecl)
678 }
679
680 pub(crate) fn translate_trait_impl_ref(
681 &mut self,
682 span: Span,
683 item: &hax::ItemRef,
684 kind: TraitImplSource,
685 ) -> Result<TraitImplRef, Error> {
686 self.translate_item(span, item, TransItemSourceKind::TraitImpl(kind))
687 }
688}
689
690#[tracing::instrument(skip(tcx))]
691pub fn translate<'tcx, 'ctx>(
692 cli_options: &CliOpts,
693 tcx: TyCtxt<'tcx>,
694 sysroot: PathBuf,
695) -> Result<TransformCtx, Error> {
696 let mut error_ctx = ErrorCtx::new(!cli_options.abort_on_error, cli_options.error_on_warnings);
697 let translate_options = TranslateOptions::new(&mut error_ctx, cli_options);
698
699 let hax_state = hax::state::State::new(
700 tcx,
701 hax::options::Options {
702 item_ref_use_concrete_impl: true,
703 inline_anon_consts: !translate_options.raw_consts,
704 bounds_options: hax::options::BoundsOptions {
705 resolve_destruct: translate_options.add_destruct_bounds,
706 prune_sized: cli_options.hide_marker_traits,
707 },
708 },
709 );
710
711 let crate_def_id: hax::DefId = rustc_span::def_id::CRATE_DEF_ID
712 .to_def_id()
713 .sinto(&hax_state);
714 let crate_name = crate_def_id.crate_name(&hax_state).to_string();
715 trace!("# Crate: {}", crate_name);
716
717 let mut ctx = TranslateCtx {
718 tcx,
719 sysroot,
720 hax_state,
721 options: translate_options,
722 errors: RefCell::new(error_ctx),
723 translated: TranslatedCrate {
724 crate_name,
725 options: cli_options.clone(),
726 ..TranslatedCrate::default()
727 },
728 method_status: Default::default(),
729 id_map: Default::default(),
730 reverse_id_map: Default::default(),
731 file_to_id: Default::default(),
732 items_to_translate: Default::default(),
733 processed: Default::default(),
734 translate_stack: Default::default(),
735 cached_item_metas: Default::default(),
736 cached_names: Default::default(),
737 lt_mutability_computer: Default::default(),
738 translated_preshims: Default::default(),
739 };
740 ctx.register_target_info();
741
742 for start_from in ctx.options.start_from.clone() {
744 match start_from {
745 StartFrom::Pattern { pattern, strict } => {
746 match super::resolve_path::def_path_def_ids(&ctx.hax_state, &pattern, strict) {
747 Ok(resolved) => {
748 for def_id in resolved {
749 let def_id: hax::DefId = def_id.sinto(&ctx.hax_state);
750 ctx.enqueue_module_item(&def_id);
751 }
752 }
753 Err(err) => {
754 register_error!(
755 ctx,
756 Span::dummy(),
757 "when processing starting pattern `{pattern}`: {err}"
758 );
759 }
760 }
761 }
762 StartFrom::Attribute(attr_name) => {
763 let attr_path = attr_name
764 .split("::")
765 .map(|x| rustc_span::Symbol::intern(x))
766 .collect_vec();
767 let mut add_if_attr_matches = |ldid: rustc_hir::def_id::LocalDefId| {
768 let def_id: hax::DefId = ldid.to_def_id().sinto(&ctx.hax_state);
769 if !matches!(def_id.kind, hax::DefKind::Mod)
770 && def_id.attrs(tcx).iter().any(|a| a.path_matches(&attr_path))
771 {
772 ctx.enqueue_module_item(&def_id);
773 }
774 };
775 for ldid in tcx.hir_crate_items(()).definitions() {
776 add_if_attr_matches(ldid)
777 }
778 }
779 StartFrom::Pub => {
780 let mut add_if_matches = |ldid: rustc_hir::def_id::LocalDefId| {
781 let def_id: hax::DefId = ldid.to_def_id().sinto(&ctx.hax_state);
782 if !matches!(def_id.kind, hax::DefKind::Mod)
783 && def_id.visibility(tcx) == Some(true)
784 {
785 ctx.enqueue_module_item(&def_id);
786 }
787 };
788 for ldid in tcx.hir_crate_items(()).definitions() {
789 add_if_matches(ldid)
790 }
791 }
792 }
793 }
794
795 if ctx.errors.borrow().has_errors() {
796 return Err(Error::dummy());
798 }
799
800 trace!(
801 "Queue after we explored the crate:\n{:?}",
802 &ctx.items_to_translate
803 );
804
805 ctx.translate_unit_metadata_const();
806
807 while let Some(item_src) = ctx.items_to_translate.pop_front() {
817 if ctx.processed.insert(item_src.clone()) {
818 ctx.translate_item(&item_src);
819 }
820 }
821
822 ctx.remove_unused_methods();
825
826 Ok(TransformCtx {
828 options: ctx.options,
829 translated: ctx.translated,
830 errors: ctx.errors,
831 })
832}