1use itertools::Itertools;
18use rustc_middle::ty::TyCtxt;
19use std::cell::RefCell;
20use std::collections::HashSet;
21use std::path::PathBuf;
22
23use super::translate_ctx::*;
24use crate::hax;
25use crate::hax::SInto;
26use charon_lib::ast::*;
27use charon_lib::options::{CliOpts, StartFrom, TranslateOptions};
28use charon_lib::transform::TransformCtx;
29use macros::VariantIndexArity;
30
31#[derive(Clone, Debug, PartialEq, Eq, Hash)]
35pub struct TransItemSource {
36 pub item: RustcItem,
37 pub kind: TransItemSourceKind,
38}
39
40#[derive(Clone, Debug, PartialEq, Eq, Hash)]
48pub enum RustcItem {
49 Poly(hax::DefId),
50 Mono(hax::ItemRef),
51 MonoTrait(hax::DefId),
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, VariantIndexArity)]
56pub enum TransItemSourceKind {
57 Global,
58 TraitDecl,
59 TraitImpl(TraitImplSource),
60 Fun,
61 Type,
62 InherentImpl,
64 Module,
66 DefaultedMethod(TraitImplSource, TraitItemName),
69 ClosureMethod(ClosureKind),
71 ClosureAsFnCast,
73 DropInPlaceMethod(Option<TraitImplSource>),
79 VTable,
81 VTableInstance(TraitImplSource),
83 VTableInstanceInitializer(TraitImplSource),
85 VTableMethod,
89 VTableDropShim,
91 VTableDropPreShim,
92 VTableMethodPreShim(TraitDeclId, TraitItemName),
93}
94
95#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, VariantIndexArity)]
97pub enum TraitImplSource {
98 Normal,
100 TraitAlias,
102 Closure(ClosureKind),
104 ImplicitDestruct,
107}
108
109impl TransItemSource {
110 pub fn new(item: RustcItem, kind: TransItemSourceKind) -> Self {
111 if let RustcItem::Mono(item) = &item {
112 if item.has_param {
113 panic!("Item is not monomorphic: {item:?}")
114 }
115 } else if let RustcItem::MonoTrait(_) = &item
116 && !matches!(
117 kind,
118 TransItemSourceKind::TraitDecl | TransItemSourceKind::VTable
119 )
120 {
121 panic!("Item kind {kind:?} should not be translated as monomorphic_trait")
122 }
123 Self { item, kind }
124 }
125
126 pub fn from_item(item: &hax::ItemRef, kind: TransItemSourceKind, monomorphize: bool) -> Self {
129 if monomorphize {
130 Self::monomorphic(item, kind)
131 } else {
132 Self::polymorphic(&item.def_id, kind)
133 }
134 }
135
136 pub fn polymorphic(def_id: &hax::DefId, kind: TransItemSourceKind) -> Self {
138 Self::new(RustcItem::Poly(def_id.clone()), kind)
139 }
140
141 pub fn monomorphic(item: &hax::ItemRef, kind: TransItemSourceKind) -> Self {
143 Self::new(RustcItem::Mono(item.clone()), kind)
144 }
145
146 pub fn monomorphic_trait(def_id: &hax::DefId, kind: TransItemSourceKind) -> Self {
149 Self::new(RustcItem::MonoTrait(def_id.clone()), kind)
150 }
151
152 pub fn def_id(&self) -> &hax::DefId {
153 self.item.def_id()
154 }
155
156 pub(crate) fn with_kind(&self, kind: TransItemSourceKind) -> Self {
158 let mut ret = self.clone();
159 ret.kind = kind;
160 ret
161 }
162
163 pub(crate) fn parent(&self) -> Option<Self> {
166 let parent_kind = match self.kind {
167 TransItemSourceKind::ClosureMethod(kind) => {
168 TransItemSourceKind::TraitImpl(TraitImplSource::Closure(kind))
169 }
170 TransItemSourceKind::DefaultedMethod(impl_kind, _)
171 | TransItemSourceKind::DropInPlaceMethod(Some(impl_kind))
172 | TransItemSourceKind::VTableInstance(impl_kind)
173 | TransItemSourceKind::VTableInstanceInitializer(impl_kind) => {
174 TransItemSourceKind::TraitImpl(impl_kind)
175 }
176 TransItemSourceKind::DropInPlaceMethod(None) => TransItemSourceKind::TraitDecl,
177 _ => return None,
178 };
179 Some(self.with_kind(parent_kind))
180 }
181
182 pub(crate) fn is_derived_item(&self) -> bool {
185 use TransItemSourceKind::*;
186 !matches!(
187 self.kind,
188 Global
189 | TraitDecl
190 | TraitImpl(TraitImplSource::Normal)
191 | InherentImpl
192 | Module
193 | Fun
194 | Type
195 )
196 }
197}
198
199impl RustcItem {
200 pub fn def_id(&self) -> &hax::DefId {
201 match self {
202 RustcItem::Poly(def_id) => def_id,
203 RustcItem::Mono(item_ref) => &item_ref.def_id,
204 RustcItem::MonoTrait(def_id) => def_id,
205 }
206 }
207}
208
209impl<'tcx> TranslateCtx<'tcx> {
210 pub fn base_kind_for_item(&mut self, def_id: &hax::DefId) -> Option<TransItemSourceKind> {
213 use crate::hax::DefKind::*;
214 Some(match &def_id.kind {
215 Enum | Struct | Union | TyAlias | ForeignTy => TransItemSourceKind::Type,
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 let triple = self.get_target_triple();
345 let info = krate::TargetInfo {
346 target_pointer_size: target_data.pointer_size().bytes(),
347 is_little_endian: matches!(target_data.endian, rustc_abi::Endian::Little),
348 };
349 self.translated.target_information.insert(triple, info);
350 }
351}
352
353impl<'tcx, 'ctx> ItemTransCtx<'tcx, 'ctx> {
355 pub(crate) fn make_dep_source(&self, span: Span) -> Option<DepSource> {
356 Some(DepSource {
357 src_id: self.item_id?,
358 span: self.item_src.def_id().is_local().then_some(span),
359 })
360 }
361
362 pub(crate) fn register_and_enqueue<T: TryFrom<ItemId>>(
364 &mut self,
365 span: Span,
366 item_src: TransItemSource,
367 ) -> T {
368 let dep_src = self.make_dep_source(span);
369 self.t_ctx.register_and_enqueue(&dep_src, item_src).unwrap()
370 }
371
372 pub(crate) fn register_no_enqueue<T: TryFrom<ItemId>>(
373 &mut self,
374 span: Span,
375 src: &TransItemSource,
376 ) -> T {
377 let dep_src = self.make_dep_source(span);
378 self.t_ctx.register_no_enqueue(&dep_src, src).unwrap()
379 }
380
381 pub(crate) fn register_item_maybe_enqueue<T: TryFrom<ItemId>>(
383 &mut self,
384 span: Span,
385 enqueue: bool,
386 item: &hax::ItemRef,
387 kind: TransItemSourceKind,
388 ) -> T {
389 let item = if self.monomorphize() && item.has_param {
390 item.erase(self.hax_state_with_id())
391 } else {
392 item.clone()
393 };
394 let item_src = if self.monomorphize() && matches!(kind, TransItemSourceKind::TraitDecl) {
401 TransItemSource::monomorphic_trait(&item.def_id, kind)
402 } else {
403 TransItemSource::from_item(
404 &item,
405 kind,
406 self.monomorphize()
407 && !matches!(
408 self.item_src.kind,
409 TransItemSourceKind::TraitDecl | TransItemSourceKind::VTable
410 ),
411 )
412 };
413 if enqueue {
414 self.register_and_enqueue(span, item_src)
415 } else {
416 self.register_no_enqueue(span, &item_src)
417 }
418 }
419
420 pub(crate) fn register_item<T: TryFrom<ItemId>>(
422 &mut self,
423 span: Span,
424 item: &hax::ItemRef,
425 kind: TransItemSourceKind,
426 ) -> T {
427 self.register_item_maybe_enqueue(span, true, item, kind)
428 }
429
430 #[expect(dead_code)]
432 pub(crate) fn register_item_no_enqueue<T: TryFrom<ItemId>>(
433 &mut self,
434 span: Span,
435 item: &hax::ItemRef,
436 kind: TransItemSourceKind,
437 ) -> T {
438 self.register_item_maybe_enqueue(span, false, item, kind)
439 }
440
441 pub(crate) fn translate_item_maybe_enqueue<T: TryFrom<DeclRef<ItemId>>>(
443 &mut self,
444 span: Span,
445 enqueue: bool,
446 hax_item: &hax::ItemRef,
447 kind: TransItemSourceKind,
448 ) -> Result<T, Error> {
449 let id: ItemId = self.register_item_maybe_enqueue(span, enqueue, hax_item, kind);
450 let mut generics = if self.monomorphize() && !matches!(kind, TransItemSourceKind::TraitDecl)
452 {
453 GenericArgs::empty()
454 } else {
455 self.translate_generic_args(span, &hax_item.generic_args, &hax_item.impl_exprs)?
456 };
457
458 if matches!(
461 hax_item.def_id.kind,
462 hax::DefKind::Fn | hax::DefKind::AssocFn | hax::DefKind::Closure
463 ) {
464 let def = self.hax_def(hax_item)?;
465 match def.kind() {
466 hax::FullDefKind::Fn { sig, .. } | hax::FullDefKind::AssocFn { sig, .. } => {
467 generics.regions.extend(
468 sig.bound_vars
469 .iter()
470 .map(|_| self.translate_erased_region()),
471 );
472 }
473 hax::FullDefKind::Closure { args, .. } => {
474 let upvar_regions = if self.item_src.def_id() == &args.item.def_id {
475 assert!(self.outermost_binder().closure_upvar_tys.is_some());
476 self.outermost_binder().closure_upvar_regions.len()
477 } else {
478 let adt_decl_id: ItemId =
482 self.register_item(span, hax_item, TransItemSourceKind::Type);
483 let adt_decl = self.get_or_translate(adt_decl_id)?;
484 let adt_generics = adt_decl.generic_params();
485 adt_generics.regions.len() - generics.regions.len()
486 };
487 generics
488 .regions
489 .extend((0..upvar_regions).map(|_| self.translate_erased_region()));
490 if let TransItemSourceKind::TraitImpl(TraitImplSource::Closure(..))
491 | TransItemSourceKind::ClosureMethod(..)
492 | TransItemSourceKind::ClosureAsFnCast = kind
493 {
494 generics.regions.extend(
495 args.fn_sig
496 .bound_vars
497 .iter()
498 .map(|_| self.translate_erased_region()),
499 );
500 }
501 if let TransItemSourceKind::ClosureMethod(
502 ClosureKind::FnMut | ClosureKind::Fn,
503 ) = kind
504 {
505 generics.regions.push(self.translate_erased_region());
506 }
507 if self.item_src.def_id() == &args.item.def_id {
511 let depth = self.binding_levels.depth();
512 for (a, b) in generics.regions.iter_mut().zip(
513 self.outermost_binder()
514 .params
515 .identity_args_at_depth(depth)
516 .regions,
517 ) {
518 *a = b;
519 }
520 }
521 }
522 _ => {}
523 }
524 }
525
526 let trait_ref = hax_item
527 .in_trait
528 .as_ref()
529 .map(|impl_expr| self.translate_trait_impl_expr(span, impl_expr))
530 .transpose()?;
531 let item = DeclRef {
532 id,
533 generics: Box::new(generics),
534 trait_ref,
535 };
536 Ok(item.try_into().ok().unwrap())
537 }
538
539 pub(crate) fn translate_item<T: TryFrom<DeclRef<ItemId>>>(
545 &mut self,
546 span: Span,
547 item: &hax::ItemRef,
548 kind: TransItemSourceKind,
549 ) -> Result<T, Error> {
550 self.translate_item_maybe_enqueue(span, true, item, kind)
551 }
552
553 #[expect(dead_code)]
555 pub(crate) fn translate_item_no_enqueue<T: TryFrom<DeclRef<ItemId>>>(
556 &mut self,
557 span: Span,
558 item: &hax::ItemRef,
559 kind: TransItemSourceKind,
560 ) -> Result<T, Error> {
561 self.translate_item_maybe_enqueue(span, false, item, kind)
562 }
563
564 pub(crate) fn translate_type_decl_ref(
566 &mut self,
567 span: Span,
568 item: &hax::ItemRef,
569 ) -> Result<TypeDeclRef, Error> {
570 match self.recognize_builtin_type(item)? {
571 Some(id) => {
572 let generics =
573 self.translate_generic_args(span, &item.generic_args, &item.impl_exprs)?;
574 Ok(TypeDeclRef {
575 id: TypeId::Builtin(id),
576 generics: Box::new(generics),
577 })
578 }
579 None => self.translate_item(span, item, TransItemSourceKind::Type),
580 }
581 }
582
583 pub(crate) fn translate_fun_item(
585 &mut self,
586 span: Span,
587 item: &hax::ItemRef,
588 kind: TransItemSourceKind,
589 ) -> Result<MaybeBuiltinFunDeclRef, Error> {
590 match self.recognize_builtin_fun(item)? {
591 Some(id) => {
592 let generics =
593 self.translate_generic_args(span, &item.generic_args, &item.impl_exprs)?;
594 Ok(MaybeBuiltinFunDeclRef {
595 id: FunId::Builtin(id),
596 generics: Box::new(generics),
597 trait_ref: None,
598 })
599 }
600 None => self.translate_item(span, item, kind),
601 }
602 }
603
604 #[tracing::instrument(skip(self, span))]
607 pub(crate) fn translate_bound_fn_ptr(
608 &mut self,
609 span: Span,
610 item: &hax::ItemRef,
611 kind: TransItemSourceKind,
612 ) -> Result<RegionBinder<FnPtr>, Error> {
613 let fun_item = self.translate_fun_item(span, item, kind)?;
614 let fun_id = match fun_item.trait_ref {
615 None => FnPtrKind::Fun(fun_item.id),
617 Some(trait_ref) => {
619 let name = self.t_ctx.translate_trait_item_name(&item.def_id)?;
620 let method_decl_id = *fun_item
621 .id
622 .as_regular()
623 .expect("methods are not builtin functions");
624 self.mark_method_as_used(trait_ref.trait_decl_ref.skip_binder.id, name);
625 FnPtrKind::Trait(trait_ref.move_under_binder(), name, method_decl_id)
626 }
627 };
628 let late_bound = match self.hax_def(item)?.kind() {
629 hax::FullDefKind::Fn { sig, .. } | hax::FullDefKind::AssocFn { sig, .. } => {
630 sig.as_ref().rebind(())
631 }
632 _ => hax::Binder {
633 value: (),
634 bound_vars: vec![],
635 },
636 };
637 self.translate_region_binder(span, &late_bound, |ctx, _| {
638 let mut generics = fun_item.generics.move_under_binder();
639 for (a, b) in generics.regions.iter_mut().rev().zip(
642 ctx.innermost_binder()
643 .params
644 .identity_args()
645 .regions
646 .into_iter()
647 .rev(),
648 ) {
649 *a = b;
650 }
651 Ok(FnPtr::new(fun_id, generics))
652 })
653 }
654
655 pub(crate) fn translate_fn_ptr(
656 &mut self,
657 span: Span,
658 item: &hax::ItemRef,
659 kind: TransItemSourceKind,
660 ) -> Result<FnPtr, Error> {
661 let fn_ptr = self.translate_bound_fn_ptr(span, item, kind)?;
662 let fn_ptr = self.erase_region_binder(fn_ptr);
663 Ok(fn_ptr)
664 }
665
666 pub(crate) fn translate_global_decl_ref(
667 &mut self,
668 span: Span,
669 item: &hax::ItemRef,
670 ) -> Result<GlobalDeclRef, Error> {
671 self.translate_item(span, item, TransItemSourceKind::Global)
672 }
673
674 pub(crate) fn translate_trait_decl_ref(
675 &mut self,
676 span: Span,
677 item: &hax::ItemRef,
678 ) -> Result<TraitDeclRef, Error> {
679 self.translate_item(span, item, TransItemSourceKind::TraitDecl)
680 }
681
682 pub(crate) fn translate_trait_impl_ref(
683 &mut self,
684 span: Span,
685 item: &hax::ItemRef,
686 kind: TraitImplSource,
687 ) -> Result<TraitImplRef, Error> {
688 self.translate_item(span, item, TransItemSourceKind::TraitImpl(kind))
689 }
690}
691
692#[tracing::instrument(skip(tcx, error_ctx))]
693pub fn translate<'tcx>(
694 tcx: TyCtxt<'tcx>,
695 cli_options: &CliOpts,
696 mut error_ctx: ErrorCtx,
697 sysroot: PathBuf,
698) -> Result<TransformCtx, Error> {
699 let translate_options = TranslateOptions::new(&mut error_ctx, cli_options);
700
701 let traits_to_remove: HashSet<rustc_hir::def_id::DefId> = {
702 let hax_state = hax::state::State::new(tcx, hax::options::Options::default());
703 translate_options
704 .hide_traits
705 .iter()
706 .flat_map(|pat| super::resolve_path::def_path_def_ids(&hax_state, pat, true).unwrap())
707 .collect()
708 };
709 let hax_state = hax::state::State::new(
710 tcx,
711 hax::options::Options {
712 inline_anon_consts: !translate_options.raw_consts,
713 bounds_options: hax::options::BoundsOptions {
714 add_destruct_bounds: translate_options.add_destruct_bounds,
715 remove_traits: traits_to_remove,
716 },
717 },
718 );
719
720 let crate_def_id: hax::DefId = rustc_span::def_id::CRATE_DEF_ID
721 .to_def_id()
722 .sinto(&hax_state);
723 let crate_name = crate_def_id.crate_name(&hax_state).to_string();
724 trace!("# Crate: {}", crate_name);
725
726 let mut ctx = TranslateCtx {
727 tcx,
728 sysroot,
729 hax_state,
730 options: translate_options,
731 errors: RefCell::new(error_ctx),
732 translated: TranslatedCrate {
733 crate_name,
734 options: cli_options.clone(),
735 ..TranslatedCrate::default()
736 },
737 method_status: Default::default(),
738 id_map: Default::default(),
739 reverse_id_map: Default::default(),
740 file_to_id: Default::default(),
741 items_to_translate: Default::default(),
742 processed: Default::default(),
743 translate_stack: Default::default(),
744 cached_item_metas: Default::default(),
745 cached_names: Default::default(),
746 lt_mutability_computer: Default::default(),
747 translated_preshims: Default::default(),
748 };
749 ctx.register_target_info();
750
751 for start_from in ctx.options.start_from.clone() {
753 match start_from {
754 StartFrom::Pattern { pattern, strict } => {
755 match super::resolve_path::def_path_def_ids(&ctx.hax_state, &pattern, strict) {
756 Ok(resolved) => {
757 for def_id in resolved {
758 let def_id: hax::DefId = def_id.sinto(&ctx.hax_state);
759 ctx.enqueue_module_item(&def_id);
760 }
761 }
762 Err(err) => {
763 register_error!(
764 ctx,
765 Span::dummy(),
766 "when processing starting pattern `{pattern}`: {err}"
767 );
768 }
769 }
770 }
771 StartFrom::Attribute(attr_name) => {
772 let attr_path = attr_name
773 .split("::")
774 .map(rustc_span::Symbol::intern)
775 .collect_vec();
776 let mut add_if_attr_matches = |ldid: rustc_hir::def_id::LocalDefId| {
777 let def_id: hax::DefId = ldid.to_def_id().sinto(&ctx.hax_state);
778 if !matches!(def_id.kind, hax::DefKind::Mod)
779 && def_id.attrs(tcx).iter().any(|a| a.path_matches(&attr_path))
780 {
781 ctx.enqueue_module_item(&def_id);
782 }
783 };
784 for ldid in tcx.hir_crate_items(()).definitions() {
785 add_if_attr_matches(ldid)
786 }
787 }
788 StartFrom::Pub => {
789 let mut add_if_matches = |ldid: rustc_hir::def_id::LocalDefId| {
790 let def_id: hax::DefId = ldid.to_def_id().sinto(&ctx.hax_state);
791 if !matches!(def_id.kind, hax::DefKind::Mod)
792 && def_id.visibility(tcx) == Some(true)
793 {
794 ctx.enqueue_module_item(&def_id);
795 }
796 };
797 for ldid in tcx.hir_crate_items(()).definitions() {
798 add_if_matches(ldid)
799 }
800 }
801 }
802 }
803
804 if ctx.errors.borrow().has_errors() {
805 return Err(Error::dummy());
807 }
808
809 trace!(
810 "Queue after we explored the crate:\n{:?}",
811 &ctx.items_to_translate
812 );
813
814 ctx.translate_unit_metadata_const();
815
816 while let Some(item_src) = ctx.items_to_translate.pop_front() {
826 if ctx.processed.insert(item_src.clone()) {
827 ctx.translate_item(&item_src);
828 }
829 }
830
831 ctx.remove_unused_methods();
834
835 Ok(TransformCtx {
837 options: ctx.options,
838 translated: ctx.translated,
839 errors: ctx.errors,
840 })
841}