1use super::translate_crate::RustcItem;
3use super::translate_ctx::*;
4use super::translate_generics::BindingLevel;
5use charon_lib::ast::*;
6use hax::DefPathItem;
7use itertools::Itertools;
8use std::cmp::Ord;
9use std::path::{Component, PathBuf};
10
11impl<'tcx, 'ctx> TranslateCtx<'tcx> {
13 fn register_file(&mut self, filename: FileName, span: rustc_span::Span) -> FileId {
16 match self.file_to_id.get(&filename) {
18 Some(id) => *id,
19 None => {
20 let source_file = self.tcx.sess.source_map().lookup_source_file(span.lo());
21 let crate_name = self.tcx.crate_name(source_file.cnum).to_string();
22 let file = File {
23 name: filename.clone(),
24 crate_name,
25 contents: source_file.src.as_deref().cloned(),
26 };
27 let id = self.translated.files.push(file);
28 self.file_to_id.insert(filename, id);
29 id
30 }
31 }
32 }
33
34 pub fn translate_filename(&mut self, name: &hax::FileName) -> meta::FileName {
35 match name {
36 hax::FileName::Real(name) => {
37 use hax::RealFileName;
38 match name {
39 RealFileName::LocalPath(path) => {
40 let path = if let Ok(path) = path.strip_prefix(&self.sysroot) {
41 if let Ok(path) = path.strip_prefix("lib/rustlib/src/rust") {
46 let mut rewritten_path: PathBuf = "/rustc".into();
47 rewritten_path.extend(path);
48 rewritten_path
49 } else {
50 let mut rewritten_path: PathBuf = "/toolchain".into();
52 rewritten_path.extend(path);
53 rewritten_path
54 }
55 } else {
56 let cargo_home = std::env::var("CARGO_HOME")
60 .map(PathBuf::from)
61 .ok()
62 .or_else(|| std::env::home_dir().map(|p| p.join(".cargo")));
63 if let Some(cargo_home) = cargo_home
64 && let Ok(path) = path.strip_prefix(cargo_home)
65 {
66 let mut rewritten_path: PathBuf = "/cargo".into();
68 rewritten_path.extend(path);
69 rewritten_path
70 } else {
71 path.clone()
72 }
73 };
74 FileName::Local(path)
75 }
76 RealFileName::Remapped { virtual_name, .. } => {
77 let mut components_iter = virtual_name.components();
81 if let Some(
82 [
83 Component::RootDir,
84 Component::Normal(rustc),
85 Component::Normal(hash),
86 ],
87 ) = components_iter.by_ref().array_chunks().next()
88 && rustc.to_str() == Some("rustc")
89 && hash.len() == 40
90 {
91 let path_without_hash = [Component::RootDir, Component::Normal(rustc)]
92 .into_iter()
93 .chain(components_iter)
94 .collect();
95 FileName::Virtual(path_without_hash)
96 } else {
97 FileName::Virtual(virtual_name.clone())
98 }
99 }
100 }
101 }
102 _ => FileName::NotReal(format!("{name:?}")),
105 }
106 }
107
108 pub fn translate_span_data(&mut self, rspan: &hax::Span) -> meta::SpanData {
109 let filename = self.translate_filename(&rspan.filename);
110 let rust_span = rspan.rust_span_data.unwrap().span();
111 let file_id = match &filename {
112 FileName::NotReal(_) => {
113 unimplemented!();
115 }
116 FileName::Virtual(_) | FileName::Local(_) => self.register_file(filename, rust_span),
117 };
118
119 fn convert_loc(loc: &hax::Loc) -> Loc {
120 Loc {
121 line: loc.line,
122 col: loc.col,
123 }
124 }
125 let beg = convert_loc(&rspan.lo);
126 let end = convert_loc(&rspan.hi);
127
128 meta::SpanData { file_id, beg, end }
130 }
131
132 pub fn translate_span_from_source_info(
134 &mut self,
135 source_scopes: &hax::IndexVec<hax::SourceScope, hax::SourceScopeData>,
136 source_info: &hax::SourceInfo,
137 ) -> Span {
138 let data = self.translate_span_data(&source_info.span);
140
141 let mut parent_span = None;
143 let mut scope_data = &source_scopes[source_info.scope];
144 while let Some(parent_scope) = scope_data.inlined_parent_scope {
145 scope_data = &source_scopes[parent_scope];
146 parent_span = Some(&scope_data.span);
147 }
148
149 if let Some(parent_span) = parent_span {
150 let parent_span = self.translate_span_data(parent_span);
151 Span {
152 data: parent_span,
153 generated_from_span: Some(data),
154 }
155 } else {
156 Span {
157 data,
158 generated_from_span: None,
159 }
160 }
161 }
162
163 pub(crate) fn translate_span_from_hax(&mut self, span: &hax::Span) -> Span {
164 Span {
165 data: self.translate_span_data(span),
166 generated_from_span: None,
167 }
168 }
169
170 pub(crate) fn def_span(&mut self, def_id: &hax::DefId) -> Span {
171 let span = def_id.def_span(&self.hax_state);
172 self.translate_span_from_hax(&span)
173 }
174}
175
176impl<'tcx, 'ctx> TranslateCtx<'tcx> {
178 fn path_elem_for_def(
179 &mut self,
180 span: Span,
181 item: &RustcItem,
182 ) -> Result<Option<PathElem>, Error> {
183 let def_id = item.def_id();
184 let path_elem = def_id.path_item();
185 let disambiguator = Disambiguator::new(path_elem.disambiguator as usize);
188 let path_elem = match path_elem.data {
190 DefPathItem::CrateRoot { name, .. } => {
191 error_assert!(self, span, path_elem.disambiguator == 0);
193 Some(PathElem::Ident(name.clone(), disambiguator))
194 }
195 DefPathItem::TypeNs(symbol)
198 | DefPathItem::ValueNs(symbol)
199 | DefPathItem::MacroNs(symbol) => Some(PathElem::Ident(symbol, disambiguator)),
200 DefPathItem::Impl => {
201 let full_def = self.hax_def_for_item(item)?;
202 let impl_elem = match full_def.kind() {
206 hax::FullDefKind::InherentImpl { ty, .. } => {
208 let mut bt_ctx = ItemTransCtx::new(
212 TransItemSource::new(item.clone(), TransItemSourceKind::InherentImpl),
213 None,
214 self,
215 );
216 bt_ctx.translate_def_generics(span, &full_def)?;
217 let ty = bt_ctx.translate_ty(span, &ty)?;
218 ImplElem::Ty(Binder {
219 kind: BinderKind::InherentImplBlock,
220 params: bt_ctx.into_generics(),
221 skip_binder: ty,
222 })
223 }
224 hax::FullDefKind::TraitImpl { .. } => {
226 let impl_id = {
227 let item_src = TransItemSource::new(
228 item.clone(),
229 TransItemSourceKind::TraitImpl(TraitImplSource::Normal),
230 );
231 self.register_and_enqueue(&None, item_src).unwrap()
232 };
233 ImplElem::Trait(impl_id)
234 }
235 _ => unreachable!(),
236 };
237
238 Some(PathElem::Impl(impl_elem))
239 }
240 DefPathItem::OpaqueTy => None,
242 DefPathItem::Closure => Some(PathElem::Ident("closure".to_string(), disambiguator)),
246 DefPathItem::ForeignMod => None,
249 DefPathItem::Ctor => None,
252 DefPathItem::Use => Some(PathElem::Ident("{use}".to_string(), disambiguator)),
253 DefPathItem::AnonConst => Some(PathElem::Ident("{const}".to_string(), disambiguator)),
254 DefPathItem::PromotedConst => Some(PathElem::Ident(
255 "{promoted_const}".to_string(),
256 disambiguator,
257 )),
258 _ => {
259 raise_error!(
260 self,
261 span,
262 "Unexpected DefPathItem for `{def_id:?}`: {path_elem:?}"
263 );
264 }
265 };
266 Ok(path_elem)
267 }
268
269 fn name_for_item(&mut self, item: &RustcItem) -> Result<Name, Error> {
313 if let Some(name) = self.cached_names.get(item) {
314 return Ok(name.clone());
315 }
316 let def_id = item.def_id();
317 trace!("Computing name for `{def_id:?}`");
318
319 let parent_name = if let Some(parent_id) = &def_id.parent {
320 let def = self.hax_def_for_item(item)?;
321 if matches!(item, RustcItem::Mono(..))
322 && let Some(parent_item) = def.typing_parent(&self.hax_state)
323 {
324 self.name_for_item(&RustcItem::Mono(parent_item.clone()))?
325 } else {
326 self.name_for_item(&RustcItem::Poly(parent_id.clone()))?
327 }
328 } else {
329 Name { name: Vec::new() }
330 };
331 let span = self.def_span(def_id);
332 let mut name = parent_name;
333 if let Some(path_elem) = self.path_elem_for_def(span, item)? {
334 name.name.push(path_elem);
335 }
336
337 trace!("Computed name for `{def_id:?}`: `{name:?}`");
338 self.cached_names.insert(item.clone(), name.clone());
339 Ok(name)
340 }
341
342 pub fn name_for_src(&mut self, src: &TransItemSource) -> Result<Name, Error> {
345 let mut name = if let Some(parent) = src.parent() {
346 self.name_for_src(&parent)?
347 } else {
348 self.name_for_item(&src.item)?
349 };
350 match &src.kind {
351 TransItemSourceKind::Type
353 | TransItemSourceKind::Fun
354 | TransItemSourceKind::Global
355 | TransItemSourceKind::TraitImpl(TraitImplSource::Normal)
356 | TransItemSourceKind::TraitDecl
357 | TransItemSourceKind::InherentImpl
358 | TransItemSourceKind::Module => {}
359
360 TransItemSourceKind::TraitImpl(
361 kind @ (TraitImplSource::Closure(..)
362 | TraitImplSource::ImplicitDestruct
363 | TraitImplSource::TraitAlias),
364 ) => {
365 if let TraitImplSource::Closure(..) = kind {
366 let _ = name.name.pop(); }
368 let impl_id = self.register_and_enqueue(&None, src.clone()).unwrap();
369 name.name.push(PathElem::Impl(ImplElem::Trait(impl_id)));
370 }
371 TransItemSourceKind::DefaultedMethod(_, method_name) => {
372 name.name.push(PathElem::Ident(
373 method_name.to_string(),
374 Disambiguator::ZERO,
375 ));
376 }
377 TransItemSourceKind::ClosureMethod(kind) => {
378 let fn_name = kind.method_name().to_string();
379 name.name
380 .push(PathElem::Ident(fn_name, Disambiguator::ZERO));
381 }
382 TransItemSourceKind::DropInPlaceMethod(..) => {
383 name.name.push(PathElem::Ident(
384 "drop_in_place".to_string(),
385 Disambiguator::ZERO,
386 ));
387 }
388 TransItemSourceKind::ClosureAsFnCast => {
389 name.name
390 .push(PathElem::Ident("as_fn".into(), Disambiguator::ZERO));
391 }
392 TransItemSourceKind::VTable
393 | TransItemSourceKind::VTableInstance(..)
394 | TransItemSourceKind::VTableInstanceInitializer(..) => {
395 name.name
396 .push(PathElem::Ident("{vtable}".into(), Disambiguator::ZERO));
397 }
398 TransItemSourceKind::VTableMethod => {
399 name.name.push(PathElem::Ident(
400 "{vtable_method}".into(),
401 Disambiguator::ZERO,
402 ));
403 }
404 TransItemSourceKind::VTableDropShim => {
405 name.name.push(PathElem::Ident(
406 "{vtable_drop_shim}".into(),
407 Disambiguator::ZERO,
408 ));
409 }
410 }
411 Ok(name)
412 }
413
414 pub fn translate_name(&mut self, src: &TransItemSource) -> Result<Name, Error> {
416 let mut name = self.name_for_src(src)?;
417 if let RustcItem::Mono(item_ref) = &src.item
419 && !item_ref.generic_args.is_empty()
420 {
421 let trans_id = self.register_no_enqueue(&None, src).unwrap();
422 let span = self.def_span(&item_ref.def_id);
423 let mut bt_ctx = ItemTransCtx::new(src.clone(), trans_id, self);
424 bt_ctx.binding_levels.push(BindingLevel::new(true));
425 let args = bt_ctx.translate_generic_args(
426 span,
427 &item_ref.generic_args,
428 &item_ref.impl_exprs,
429 )?;
430 name.name.push(PathElem::Instantiated(Box::new(Binder {
431 params: GenericParams::empty(),
432 skip_binder: args,
433 kind: BinderKind::Other,
434 })));
435 }
436 Ok(name)
437 }
438
439 pub(crate) fn translate_trait_item_name(
441 &mut self,
442 def_id: &hax::DefId,
443 ) -> Result<TraitItemName, Error> {
444 let def = self.poly_hax_def(def_id)?;
445 let assoc = match def.kind() {
446 hax::FullDefKind::AssocTy {
447 associated_item, ..
448 }
449 | hax::FullDefKind::AssocConst {
450 associated_item, ..
451 }
452 | hax::FullDefKind::AssocFn {
453 associated_item, ..
454 } => associated_item,
455 _ => panic!("Unexpected def for associated item: {def:?}"),
456 };
457 Ok(TraitItemName(
458 assoc.name.as_ref().map(|n| n.into()).unwrap_or_default(),
459 ))
460 }
461
462 pub(crate) fn opacity_for_name(&self, name: &Name) -> ItemOpacity {
463 self.options.opacity_for_name(&self.translated, name)
464 }
465}
466
467impl<'tcx, 'ctx> TranslateCtx<'tcx> {
469 pub(crate) fn translate_attribute(&mut self, attr: &hax::Attribute) -> Option<Attribute> {
472 use hax::Attribute as Haxttribute;
473 use hax::AttributeKind as HaxttributeKind;
474 match attr {
475 Haxttribute::Parsed(HaxttributeKind::DocComment { comment, .. }) => {
476 Some(Attribute::DocComment(comment.to_string()))
477 }
478 Haxttribute::Parsed(_) => None,
479 Haxttribute::Unparsed(attr) => {
480 let raw_attr = RawAttribute {
481 path: attr.path.clone(),
482 args: match &attr.args {
483 hax::AttrArgs::Empty => None,
484 hax::AttrArgs::Delimited(args) => Some(args.tokens.clone()),
485 hax::AttrArgs::Eq { expr, .. } => self
486 .tcx
487 .sess
488 .source_map()
489 .span_to_snippet(expr.span.rust_span_data.unwrap().span())
490 .ok(),
491 },
492 };
493 match Attribute::parse_from_raw(raw_attr) {
494 Ok(a) => Some(a),
495 Err(msg) => {
496 let span = self.translate_span_from_hax(&attr.span);
497 register_error!(self, span, "Error parsing attribute: {msg}");
498 None
499 }
500 }
501 }
502 }
503 }
504
505 pub(crate) fn translate_inline(&self, def: &hax::FullDef) -> Option<InlineAttr> {
506 match def.kind() {
507 hax::FullDefKind::Fn { inline, .. } | hax::FullDefKind::AssocFn { inline, .. } => {
508 match inline {
509 hax::InlineAttr::None => None,
510 hax::InlineAttr::Hint => Some(InlineAttr::Hint),
511 hax::InlineAttr::Never => Some(InlineAttr::Never),
512 hax::InlineAttr::Always => Some(InlineAttr::Always),
513 hax::InlineAttr::Force { .. } => Some(InlineAttr::Always),
514 }
515 }
516 _ => None,
517 }
518 }
519
520 pub(crate) fn translate_attr_info(&mut self, def: &hax::FullDef) -> AttrInfo {
521 let public = def.visibility.unwrap_or(false);
523 let inline = self.translate_inline(def);
524 let attributes = def
525 .attributes
526 .iter()
527 .filter_map(|attr| self.translate_attribute(&attr))
528 .collect_vec();
529
530 let rename = {
531 let mut renames = attributes.iter().filter_map(|a| a.as_rename()).cloned();
532 let rename = renames.next();
533 if renames.next().is_some() {
534 let span = self.translate_span_from_hax(&def.span);
535 register_error!(
536 self,
537 span,
538 "There should be at most one `charon::rename(\"...\")` \
539 or `aeneas::rename(\"...\")` attribute per declaration",
540 );
541 }
542 rename
543 };
544
545 AttrInfo {
546 attributes,
547 inline,
548 public,
549 rename,
550 }
551 }
552}
553
554impl<'tcx, 'ctx> TranslateCtx<'tcx> {
556 pub(crate) fn is_extern_item(&mut self, def: &hax::FullDef) -> bool {
558 def.def_id()
559 .parent
560 .as_ref()
561 .is_some_and(|parent| matches!(parent.kind, hax::DefKind::ForeignMod { .. }))
562 }
563
564 pub(crate) fn translate_item_meta(
566 &mut self,
567 def: &hax::FullDef,
568 item_src: &TransItemSource,
569 name: Name,
570 name_opacity: ItemOpacity,
571 ) -> ItemMeta {
572 if let Some(item_meta) = self.cached_item_metas.get(&item_src) {
573 return item_meta.clone();
574 }
575 let span = def.source_span.as_ref().unwrap_or(&def.span);
576 let span = self.translate_span_from_hax(span);
577 let is_local = def.def_id().is_local;
578 let (attr_info, lang_item) = if item_src.is_derived_item() {
579 (AttrInfo::default(), None)
580 } else {
581 let attr_info = self.translate_attr_info(def);
582 let lang_item = def
583 .lang_item
584 .clone()
585 .or_else(|| def.diagnostic_item.clone());
586 (attr_info, lang_item)
587 };
588
589 let opacity = if self.is_extern_item(def)
590 || attr_info.attributes.iter().any(|attr| attr.is_opaque())
591 {
592 ItemOpacity::Opaque.max(name_opacity)
594 } else {
595 name_opacity
596 };
597
598 let item_meta = ItemMeta {
599 name,
600 span,
601 source_text: def.source_text.clone(),
602 attr_info,
603 is_local,
604 opacity,
605 lang_item,
606 };
607 self.cached_item_metas
608 .insert(item_src.clone(), item_meta.clone());
609 item_meta
610 }
611}
612
613impl<'tcx, 'ctx> ItemTransCtx<'tcx, 'ctx> {
614 pub(crate) fn translate_span_from_hax(&mut self, rspan: &hax::Span) -> Span {
615 self.t_ctx.translate_span_from_hax(rspan)
616 }
617
618 pub(crate) fn def_span(&mut self, def_id: &hax::DefId) -> Span {
619 self.t_ctx.def_span(def_id)
620 }
621}