1use super::translate_ctx::*;
2use charon_lib::ast::*;
3use charon_lib::options::{CliOpts, TranslateOptions};
4use charon_lib::transform::TransformCtx;
5use hax::FullDefKind;
6use hax_frontend_exporter::{self as hax, SInto};
7use itertools::Itertools;
8use macros::VariantIndexArity;
9use rustc_middle::ty::TyCtxt;
10use std::cell::RefCell;
11use std::path::PathBuf;
12
13#[derive(Clone, Debug, PartialEq, Eq, Hash, VariantIndexArity)]
17pub enum TransItemSource {
18 Global(hax::DefId),
19 TraitDecl(hax::DefId),
20 TraitImpl(hax::DefId),
21 Fun(hax::DefId),
22 Type(hax::DefId),
23 ClosureTraitImpl(hax::DefId, ClosureKind),
25 ClosureMethod(hax::DefId, ClosureKind),
27}
28
29impl TransItemSource {
30 pub(crate) fn as_def_id(&self) -> &hax::DefId {
31 match self {
32 TransItemSource::Global(id)
33 | TransItemSource::TraitDecl(id)
34 | TransItemSource::TraitImpl(id)
35 | TransItemSource::Fun(id)
36 | TransItemSource::Type(id)
37 | TransItemSource::ClosureTraitImpl(id, _)
38 | TransItemSource::ClosureMethod(id, _) => id,
39 }
40 }
41}
42
43impl TransItemSource {
44 fn sort_key(&self) -> impl Ord {
46 let (variant_index, _) = self.variant_index_arity();
47 let def_id = self.as_def_id();
48 let closure_kind = match self {
49 Self::ClosureTraitImpl(_, k) | Self::ClosureMethod(_, k) => match k {
50 ClosureKind::Fn => 1,
51 ClosureKind::FnMut => 2,
52 ClosureKind::FnOnce => 3,
53 },
54 _ => 0,
55 };
56 (def_id.index, variant_index, closure_kind)
57 }
58}
59
60impl PartialOrd for TransItemSource {
62 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
63 Some(self.cmp(other))
64 }
65}
66impl Ord for TransItemSource {
67 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
68 self.sort_key().cmp(&other.sort_key())
69 }
70}
71
72impl<'tcx, 'ctx> TranslateCtx<'tcx> {
73 fn register_module_item(&mut self, def_id: &hax::DefId) {
76 use hax::DefKind::*;
77 trace!("Registering {def_id:?}");
78
79 match &def_id.kind {
80 Enum { .. } | Struct { .. } | Union { .. } | TyAlias { .. } | ForeignTy => {
81 let _ = self.register_type_decl_id(&None, def_id);
82 }
83 Fn { .. } | AssocFn { .. } => {
84 let _ = self.register_fun_decl_id(&None, def_id);
85 }
86 Const { .. } | Static { .. } | AssocConst { .. } => {
87 let _ = self.register_global_decl_id(&None, def_id);
88 }
89
90 Trait { .. } | TraitAlias { .. } => {
91 let _ = self.register_trait_decl_id(&None, def_id);
92 }
93 Impl { of_trait: true } => {
94 let _ = self.register_trait_impl_id(&None, def_id);
95 }
96
97 Impl { of_trait: false } | Mod { .. } | ForeignMod { .. } => {
98 let Ok(def) = self.hax_def(def_id) else {
99 return; };
101 let Ok(name) = self.def_id_to_name(&def.def_id) else {
102 return; };
104 let opacity = self.opacity_for_name(&name);
105 let trans_src = TransItemSource::TraitImpl(def.def_id.clone());
106 let item_meta = self.translate_item_meta(&def, &trans_src, name, opacity);
107 let _ = self.register_module(item_meta, &def);
108 }
109
110 ExternCrate { .. } | GlobalAsm { .. } | Macro { .. } | Use { .. } => {}
112 AnonConst { .. }
114 | AssocTy { .. }
115 | Closure { .. }
116 | ConstParam { .. }
117 | Ctor { .. }
118 | Field { .. }
119 | InlineConst { .. }
120 | PromotedConst { .. }
121 | LifetimeParam { .. }
122 | OpaqueTy { .. }
123 | SyntheticCoroutineBody { .. }
124 | TyParam { .. }
125 | Variant { .. } => {
126 let span = self.def_span(def_id);
127 register_error!(
128 self,
129 span,
130 "Cannot register item `{def_id:?}` with kind `{:?}`",
131 def_id.kind
132 );
133 }
134 }
135 }
136
137 fn register_module(&mut self, item_meta: ItemMeta, def: &hax::FullDef) -> Result<(), Error> {
141 let opacity = item_meta.opacity;
142 if !opacity.is_transparent() {
143 return Ok(());
144 }
145 match def.kind() {
146 FullDefKind::InherentImpl { items, .. } => {
147 for (_, item_def) in items {
148 self.register_module_item(&item_def.def_id);
149 }
150 }
151 FullDefKind::Mod { items, .. } => {
152 for (_, def_id) in items {
153 self.register_module_item(def_id);
154 }
155 }
156 FullDefKind::ForeignMod { items, .. } => {
157 for def_id in items {
159 self.register_module_item(def_id);
160 }
161 }
162 _ => panic!("Item should be a module but isn't: {def:?}"),
163 }
164 Ok(())
165 }
166
167 pub(crate) fn register_id_no_enqueue(
168 &mut self,
169 src: &Option<DepSource>,
170 id: TransItemSource,
171 ) -> AnyTransId {
172 let item_id = match self.id_map.get(&id) {
173 Some(tid) => *tid,
174 None => {
175 let trans_id = match id {
176 TransItemSource::Type(_) => {
177 AnyTransId::Type(self.translated.type_decls.reserve_slot())
178 }
179 TransItemSource::TraitDecl(_) => {
180 AnyTransId::TraitDecl(self.translated.trait_decls.reserve_slot())
181 }
182 TransItemSource::TraitImpl(_) | TransItemSource::ClosureTraitImpl(_, _) => {
183 AnyTransId::TraitImpl(self.translated.trait_impls.reserve_slot())
184 }
185 TransItemSource::Global(_) => {
186 AnyTransId::Global(self.translated.global_decls.reserve_slot())
187 }
188 TransItemSource::Fun(_) | TransItemSource::ClosureMethod(_, _) => {
189 AnyTransId::Fun(self.translated.fun_decls.reserve_slot())
190 }
191 };
192 self.id_map.insert(id.clone(), trans_id);
194 self.reverse_id_map.insert(trans_id, id.clone());
195 if !matches!(id, TransItemSource::TraitImpl(_)) {
198 if let Ok(name) = self.def_id_to_name(id.as_def_id()) {
199 self.translated.item_names.insert(trans_id, name);
200 }
201 }
202 trans_id
203 }
204 };
205 self.errors
206 .borrow_mut()
207 .register_dep_source(src, item_id, id.as_def_id().is_local);
208 item_id
209 }
210
211 pub(crate) fn register_and_enqueue_id(
213 &mut self,
214 src: &Option<DepSource>,
215 id: TransItemSource,
216 ) -> AnyTransId {
217 self.items_to_translate.insert(id.clone());
218 self.register_id_no_enqueue(src, id)
219 }
220
221 pub(crate) fn register_type_decl_id(
222 &mut self,
223 src: &Option<DepSource>,
224 id: &hax::DefId,
225 ) -> TypeDeclId {
226 *self
227 .register_and_enqueue_id(src, TransItemSource::Type(id.clone()))
228 .as_type()
229 .unwrap()
230 }
231
232 pub(crate) fn register_fun_decl_id(
233 &mut self,
234 src: &Option<DepSource>,
235 id: &hax::DefId,
236 ) -> FunDeclId {
237 *self
238 .register_and_enqueue_id(src, TransItemSource::Fun(id.clone()))
239 .as_fun()
240 .unwrap()
241 }
242
243 pub(crate) fn register_trait_decl_id(
244 &mut self,
245 src: &Option<DepSource>,
246 id: &hax::DefId,
247 ) -> TraitDeclId {
248 *self
249 .register_and_enqueue_id(src, TransItemSource::TraitDecl(id.clone()))
250 .as_trait_decl()
251 .unwrap()
252 }
253
254 pub(crate) fn register_trait_impl_id(
255 &mut self,
256 src: &Option<DepSource>,
257 id: &hax::DefId,
258 ) -> TraitImplId {
259 if let Ok(def) = self.hax_def(id) {
261 let trait_id = match def.kind() {
262 hax::FullDefKind::TraitImpl { trait_pred, .. } => &trait_pred.trait_ref.def_id,
263 hax::FullDefKind::TraitAlias { .. } => id,
264 _ => unreachable!(),
265 };
266 let _ = self.register_trait_decl_id(src, trait_id);
267 }
268
269 *self
270 .register_and_enqueue_id(src, TransItemSource::TraitImpl(id.clone()))
271 .as_trait_impl()
272 .unwrap()
273 }
274
275 pub(crate) fn register_closure_trait_impl_id(
276 &mut self,
277 src: &Option<DepSource>,
278 id: &hax::DefId,
279 kind: ClosureKind,
280 ) -> TraitImplId {
281 *self
282 .register_and_enqueue_id(src, TransItemSource::ClosureTraitImpl(id.clone(), kind))
283 .as_trait_impl()
284 .unwrap()
285 }
286
287 pub(crate) fn register_closure_method_decl_id(
288 &mut self,
289 src: &Option<DepSource>,
290 id: &hax::DefId,
291 kind: ClosureKind,
292 ) -> FunDeclId {
293 *self
294 .register_and_enqueue_id(src, TransItemSource::ClosureMethod(id.clone(), kind))
295 .as_fun()
296 .unwrap()
297 }
298
299 pub(crate) fn register_global_decl_id(
300 &mut self,
301 src: &Option<DepSource>,
302 id: &hax::DefId,
303 ) -> GlobalDeclId {
304 *self
305 .register_and_enqueue_id(src, TransItemSource::Global(id.clone()))
306 .as_global()
307 .unwrap()
308 }
309}
310
311impl<'tcx, 'ctx> ItemTransCtx<'tcx, 'ctx> {
313 pub(crate) fn make_dep_source(&self, span: Span) -> Option<DepSource> {
314 Some(DepSource {
315 src_id: self.item_id?,
316 span: self.def_id.is_local.then_some(span),
317 })
318 }
319
320 pub(crate) fn register_id_no_enqueue(&mut self, span: Span, id: TransItemSource) -> AnyTransId {
321 let src = self.make_dep_source(span);
322 self.t_ctx.register_id_no_enqueue(&src, id)
323 }
324
325 pub(crate) fn register_type_decl_id(&mut self, span: Span, id: &hax::DefId) -> TypeDeclId {
326 let src = self.make_dep_source(span);
327 self.t_ctx.register_type_decl_id(&src, id)
328 }
329
330 pub(crate) fn translate_type_id(
332 &mut self,
333 span: Span,
334 def_id: &hax::DefId,
335 ) -> Result<TypeId, Error> {
336 Ok(match self.recognize_builtin_type(def_id)? {
337 Some(id) => TypeId::Builtin(id),
338 None => TypeId::Adt(self.register_type_decl_id(span, def_id)),
339 })
340 }
341
342 pub(crate) fn translate_type_decl_ref(
343 &mut self,
344 span: Span,
345 item: &hax::ItemRef,
346 ) -> Result<TypeDeclRef, Error> {
347 let id = self.translate_type_id(span, &item.def_id)?;
348 let generics = self.translate_generic_args(span, &item.generic_args, &item.impl_exprs)?;
349 Ok(TypeDeclRef {
350 id,
351 generics: Box::new(generics),
352 })
353 }
354
355 pub(crate) fn register_fun_decl_id(&mut self, span: Span, id: &hax::DefId) -> FunDeclId {
356 let src = self.make_dep_source(span);
357 self.t_ctx.register_fun_decl_id(&src, id)
358 }
359
360 pub(crate) fn register_fun_decl_id_no_enqueue(
361 &mut self,
362 span: Span,
363 id: &hax::DefId,
364 ) -> FunDeclId {
365 self.register_id_no_enqueue(span, TransItemSource::Fun(id.clone()))
366 .as_fun()
367 .copied()
368 .unwrap()
369 }
370
371 pub(crate) fn translate_fun_id(
373 &mut self,
374 span: Span,
375 def_id: &hax::DefId,
376 ) -> Result<FunId, Error> {
377 Ok(match self.recognize_builtin_fun(def_id)? {
378 Some(id) => FunId::Builtin(id),
379 None => FunId::Regular(self.register_fun_decl_id(span, def_id)),
380 })
381 }
382
383 #[tracing::instrument(skip(self, span))]
386 pub(crate) fn translate_fn_ptr(
387 &mut self,
388 span: Span,
389 item: &hax::ItemRef,
390 ) -> Result<RegionBinder<FnPtr>, Error> {
391 let fun_id = self.translate_fun_id(span, &item.def_id)?;
392 let late_bound = match self.hax_def(&item.def_id)?.kind() {
393 hax::FullDefKind::Fn { sig, .. } | hax::FullDefKind::AssocFn { sig, .. } => {
394 Some(sig.as_ref().rebind(()))
395 }
396 _ => None,
397 };
398 let bound_generics = self.translate_generic_args_with_late_bound(
399 span,
400 &item.generic_args,
401 &item.impl_exprs,
402 late_bound,
403 )?;
404 let fun_id = match &item.in_trait {
405 None => FunIdOrTraitMethodRef::Fun(fun_id),
407 Some(impl_expr) => {
409 let trait_ref = self.translate_trait_impl_expr(span, impl_expr)?;
410 let name = self.t_ctx.translate_trait_item_name(&item.def_id)?;
411 let method_decl_id = *fun_id
412 .as_regular()
413 .expect("methods are not builtin functions");
414 FunIdOrTraitMethodRef::Trait(trait_ref.move_under_binder(), name, method_decl_id)
415 }
416 };
417 Ok(bound_generics.map(|generics| FnPtr {
418 func: Box::new(fun_id),
419 generics: Box::new(generics),
420 }))
421 }
422
423 pub(crate) fn register_global_decl_id(&mut self, span: Span, id: &hax::DefId) -> GlobalDeclId {
424 let src = self.make_dep_source(span);
425 self.t_ctx.register_global_decl_id(&src, id)
426 }
427
428 pub(crate) fn translate_global_decl_ref(
429 &mut self,
430 span: Span,
431 item: &hax::ItemRef,
432 ) -> Result<GlobalDeclRef, Error> {
433 let id = self.register_global_decl_id(span, &item.def_id);
434 let generics = self.translate_generic_args(span, &item.generic_args, &item.impl_exprs)?;
435 Ok(GlobalDeclRef {
436 id,
437 generics: Box::new(generics),
438 })
439 }
440
441 pub(crate) fn register_trait_decl_id(&mut self, span: Span, id: &hax::DefId) -> TraitDeclId {
442 let src = self.make_dep_source(span);
443 self.t_ctx.register_trait_decl_id(&src, id)
444 }
445
446 pub(crate) fn translate_trait_decl_ref(
447 &mut self,
448 span: Span,
449 item: &hax::ItemRef,
450 ) -> Result<TraitDeclRef, Error> {
451 let id = self.register_trait_decl_id(span, &item.def_id);
452 let generics = self.translate_generic_args(span, &item.generic_args, &item.impl_exprs)?;
453 Ok(TraitDeclRef {
454 id,
455 generics: Box::new(generics),
456 })
457 }
458
459 pub(crate) fn register_trait_impl_id(&mut self, span: Span, id: &hax::DefId) -> TraitImplId {
460 let src = self.make_dep_source(span);
461 self.t_ctx.register_trait_impl_id(&src, id)
462 }
463
464 pub(crate) fn translate_trait_impl_ref(
465 &mut self,
466 span: Span,
467 item: &hax::ItemRef,
468 ) -> Result<TraitImplRef, Error> {
469 let id = self.register_trait_impl_id(span, &item.def_id);
470 let generics = self.translate_generic_args(span, &item.generic_args, &item.impl_exprs)?;
471 Ok(TraitImplRef {
472 id,
473 generics: Box::new(generics),
474 })
475 }
476
477 pub(crate) fn register_closure_trait_impl_id(
478 &mut self,
479 span: Span,
480 id: &hax::DefId,
481 kind: ClosureKind,
482 ) -> TraitImplId {
483 let src = self.make_dep_source(span);
484 self.t_ctx.register_closure_trait_impl_id(&src, id, kind)
485 }
486
487 pub(crate) fn register_closure_method_decl_id(
488 &mut self,
489 span: Span,
490 id: &hax::DefId,
491 kind: ClosureKind,
492 ) -> FunDeclId {
493 let src = self.make_dep_source(span);
494 self.t_ctx.register_closure_method_decl_id(&src, id, kind)
495 }
496}
497
498#[tracing::instrument(skip(tcx))]
499pub fn translate<'tcx, 'ctx>(
500 options: &CliOpts,
501 tcx: TyCtxt<'tcx>,
502 sysroot: PathBuf,
503) -> TransformCtx {
504 let hax_state = hax::state::State::new(
505 tcx,
506 hax::options::Options {
507 inline_anon_consts: true,
508 resolve_drop_bounds: false,
509 },
510 );
511
512 let crate_def_id: hax::DefId = rustc_span::def_id::CRATE_DEF_ID
515 .to_def_id()
516 .sinto(&hax_state);
517 let crate_name = crate_def_id.krate.clone();
518 trace!("# Crate: {}", crate_name);
519
520 let mut error_ctx = ErrorCtx::new(!options.abort_on_error, options.error_on_warnings);
521 let translate_options = TranslateOptions::new(&mut error_ctx, options);
522 let mut ctx = TranslateCtx {
523 tcx,
524 sysroot,
525 hax_state,
526 options: translate_options,
527 errors: RefCell::new(error_ctx),
528 translated: TranslatedCrate {
529 crate_name,
530 options: options.clone(),
531 ..TranslatedCrate::default()
532 },
533 id_map: Default::default(),
534 reverse_id_map: Default::default(),
535 file_to_id: Default::default(),
536 items_to_translate: Default::default(),
537 processed: Default::default(),
538 cached_item_metas: Default::default(),
539 cached_names: Default::default(),
540 };
541
542 if options.start_from.is_empty() {
543 ctx.register_module_item(&crate_def_id);
545 } else {
546 for path in options.start_from.iter() {
548 let path = path.split("::").collect_vec();
549 let resolved = super::resolve_path::def_path_def_ids(&ctx.hax_state, &path);
550 match resolved {
551 Ok(resolved) => {
552 for def_id in resolved {
553 let def_id: hax::DefId = def_id.sinto(&ctx.hax_state);
554 ctx.register_module_item(&def_id);
555 }
556 }
557 Err(path) => {
558 let path = path.join("::");
559 register_error!(
560 ctx,
561 Span::dummy(),
562 "path {path} does not correspond to any item"
563 );
564 }
565 }
566 }
567 }
568
569 trace!(
570 "Queue after we explored the crate:\n{:?}",
571 &ctx.items_to_translate
572 );
573
574 while let Some(item_src) = ctx.items_to_translate.pop_first() {
584 trace!("About to translate item: {:?}", item_src);
585 if ctx.processed.insert(item_src.clone()) {
586 ctx.translate_item(&item_src);
587 }
588 }
589
590 TransformCtx {
592 options: ctx.options,
593 translated: ctx.translated,
594 errors: ctx.errors,
595 }
596}