1use super::translate_crate::TransItemSource;
3use super::translate_ctx::{ItemTransCtx, TranslateCtx};
4use charon_lib::ast::*;
5use hax_frontend_exporter::{self as hax, DefPathItem};
6use itertools::Itertools;
7use std::cmp::Ord;
8use std::path::{Component, PathBuf};
9
10impl<'tcx, 'ctx> TranslateCtx<'tcx> {
12 fn register_file(&mut self, filename: FileName, span: rustc_span::Span) -> FileId {
15 match self.file_to_id.get(&filename) {
17 Some(id) => *id,
18 None => {
19 let source_file = self.tcx.sess.source_map().lookup_source_file(span.lo());
20 let file = File {
21 name: filename.clone(),
22 contents: source_file.src.as_deref().cloned(),
23 };
24 let id = self.translated.files.push(file);
25 self.file_to_id.insert(filename, id);
26 id
27 }
28 }
29 }
30
31 pub fn translate_filename(&mut self, name: &hax::FileName) -> meta::FileName {
32 match name {
33 hax::FileName::Real(name) => {
34 use hax::RealFileName;
35 match name {
36 RealFileName::LocalPath(path) => {
37 let path = if let Ok(path) = path.strip_prefix(&self.sysroot) {
38 if let Ok(path) = path.strip_prefix("lib/rustlib/src/rust") {
43 let mut rewritten_path: PathBuf = "/rustc".into();
44 rewritten_path.extend(path);
45 rewritten_path
46 } else {
47 let mut rewritten_path: PathBuf = "/toolchain".into();
49 rewritten_path.extend(path);
50 rewritten_path
51 }
52 } else {
53 path.clone()
54 };
55 FileName::Local(path)
56 }
57 RealFileName::Remapped { virtual_name, .. } => {
58 let mut components_iter = virtual_name.components();
62 if let Some(
63 [Component::RootDir, Component::Normal(rustc), Component::Normal(hash)],
64 ) = components_iter.by_ref().array_chunks().next()
65 && rustc.to_str() == Some("rustc")
66 && hash.len() == 40
67 {
68 let path_without_hash = [Component::RootDir, Component::Normal(rustc)]
69 .into_iter()
70 .chain(components_iter)
71 .collect();
72 FileName::Virtual(path_without_hash)
73 } else {
74 FileName::Virtual(virtual_name.clone())
75 }
76 }
77 }
78 }
79 _ => FileName::NotReal(format!("{name:?}")),
82 }
83 }
84
85 pub fn translate_raw_span(&mut self, rspan: &hax::Span) -> meta::RawSpan {
86 let filename = self.translate_filename(&rspan.filename);
87 let rust_span = rspan.rust_span_data.unwrap().span();
88 let file_id = match &filename {
89 FileName::NotReal(_) => {
90 unimplemented!();
92 }
93 FileName::Virtual(_) | FileName::Local(_) => self.register_file(filename, rust_span),
94 };
95
96 fn convert_loc(loc: &hax::Loc) -> Loc {
97 Loc {
98 line: loc.line,
99 col: loc.col,
100 }
101 }
102 let beg = convert_loc(&rspan.lo);
103 let end = convert_loc(&rspan.hi);
104
105 meta::RawSpan { file_id, beg, end }
107 }
108
109 pub fn translate_span_from_source_info(
111 &mut self,
112 source_scopes: &hax::IndexVec<hax::SourceScope, hax::SourceScopeData>,
113 source_info: &hax::SourceInfo,
114 ) -> Span {
115 let span = self.translate_raw_span(&source_info.span);
117
118 let mut parent_span = None;
120 let mut scope_data = &source_scopes[source_info.scope];
121 while let Some(parent_scope) = scope_data.inlined_parent_scope {
122 scope_data = &source_scopes[parent_scope];
123 parent_span = Some(&scope_data.span);
124 }
125
126 if let Some(parent_span) = parent_span {
127 let parent_span = self.translate_raw_span(parent_span);
128 Span {
129 span: parent_span,
130 generated_from_span: Some(span),
131 }
132 } else {
133 Span {
134 span,
135 generated_from_span: None,
136 }
137 }
138 }
139
140 pub(crate) fn translate_span_from_hax(&mut self, span: &hax::Span) -> Span {
141 Span {
142 span: self.translate_raw_span(span),
143 generated_from_span: None,
144 }
145 }
146
147 pub(crate) fn def_span(&mut self, def_id: &hax::DefId) -> Span {
148 let span = def_id.def_span(&self.hax_state);
149 self.translate_span_from_hax(&span)
150 }
151}
152
153impl<'tcx, 'ctx> TranslateCtx<'tcx> {
155 fn path_elem_for_def(
156 &mut self,
157 span: Span,
158 def_id: &hax::DefId,
159 ) -> Result<Option<PathElem>, Error> {
160 let path_elem = def_id.path_item();
161 let disambiguator = Disambiguator::new(path_elem.disambiguator as usize);
164 let path_elem = match path_elem.data {
166 DefPathItem::CrateRoot { name, .. } => {
167 error_assert!(self, span, path_elem.disambiguator == 0);
169 Some(PathElem::Ident(name.clone(), disambiguator))
170 }
171 DefPathItem::TypeNs(None) => None,
174 DefPathItem::TypeNs(Some(symbol))
175 | DefPathItem::ValueNs(symbol)
176 | DefPathItem::MacroNs(symbol) => Some(PathElem::Ident(symbol, disambiguator)),
177 DefPathItem::Impl => {
178 let full_def = self.hax_def(def_id)?;
179 let impl_elem = match full_def.kind() {
183 hax::FullDefKind::InherentImpl { ty, .. } => {
185 let mut bt_ctx = ItemTransCtx::new(def_id.clone(), None, self);
189 bt_ctx.translate_def_generics(span, &full_def)?;
190 let ty = bt_ctx.translate_ty(span, &ty)?;
191 ImplElem::Ty(Binder {
192 kind: BinderKind::InherentImplBlock,
193 params: bt_ctx.into_generics(),
194 skip_binder: ty,
195 })
196 }
197 hax::FullDefKind::TraitImpl { .. } => {
199 let impl_id = self.register_trait_impl_id(&None, def_id);
200 ImplElem::Trait(impl_id)
201 }
202 _ => unreachable!(),
203 };
204
205 Some(PathElem::Impl(impl_elem, disambiguator))
206 }
207 DefPathItem::OpaqueTy => None,
209 DefPathItem::Closure => Some(PathElem::Ident("closure".to_string(), disambiguator)),
213 DefPathItem::ForeignMod => None,
216 DefPathItem::Ctor => None,
219 DefPathItem::Use => Some(PathElem::Ident("{use}".to_string(), disambiguator)),
220 DefPathItem::AnonConst => Some(PathElem::Ident("{const}".to_string(), disambiguator)),
221 DefPathItem::PromotedConst => Some(PathElem::Ident(
222 "{promoted_const}".to_string(),
223 disambiguator,
224 )),
225 _ => {
226 raise_error!(
227 self,
228 span,
229 "Unexpected DefPathItem for `{def_id:?}`: {path_elem:?}"
230 );
231 }
232 };
233 Ok(path_elem)
234 }
235
236 pub fn def_id_to_name(&mut self, def_id: &hax::DefId) -> Result<Name, Error> {
280 if let Some(name) = self.cached_names.get(&def_id) {
281 return Ok(name.clone());
282 }
283 trace!("Computing name for `{def_id:?}`");
284
285 let parent_name = if let Some(parent) = &def_id.parent {
286 self.def_id_to_name(parent)?
287 } else {
288 Name { name: Vec::new() }
289 };
290 let span = self.def_span(def_id);
291 let mut name = parent_name;
292 if let Some(path_elem) = self.path_elem_for_def(span, &def_id)? {
293 name.name.push(path_elem);
294 }
295
296 trace!("Computed name for `{def_id:?}`: `{name:?}`");
297 self.cached_names.insert(def_id.clone(), name.clone());
298 Ok(name)
299 }
300
301 pub fn translate_name(&mut self, src: &TransItemSource) -> Result<Name, Error> {
303 let def_id = src.as_def_id();
304 let mut name = self.def_id_to_name(def_id)?;
305 match src {
306 TransItemSource::ClosureTraitImpl(id, kind)
307 | TransItemSource::ClosureMethod(id, kind) => {
308 let _ = name.name.pop(); let impl_id = self.register_closure_trait_impl_id(&None, id, *kind);
310 name.name.push(PathElem::Impl(
311 ImplElem::Trait(impl_id),
312 Disambiguator::ZERO,
313 ));
314
315 if matches!(src, TransItemSource::ClosureMethod(..)) {
316 let fn_name = kind.method_name().to_string();
317 name.name
318 .push(PathElem::Ident(fn_name, Disambiguator::ZERO));
319 }
320 }
321 _ => {}
322 }
323 Ok(name)
324 }
325
326 pub(crate) fn translate_trait_item_name(
328 &mut self,
329 def_id: &hax::DefId,
330 ) -> Result<TraitItemName, Error> {
331 let name = self.def_id_to_name(def_id)?;
333 let (name, id) = name.name.last().unwrap().as_ident().unwrap();
334 assert!(id.is_zero());
335 Ok(TraitItemName(name.to_string()))
336 }
337
338 pub(crate) fn opacity_for_name(&self, name: &Name) -> ItemOpacity {
339 self.options.opacity_for_name(&self.translated, name)
340 }
341}
342
343impl<'tcx, 'ctx> TranslateCtx<'tcx> {
345 pub(crate) fn translate_attribute(&mut self, attr: &hax::Attribute) -> Option<Attribute> {
348 use hax::Attribute as Haxttribute;
349 use hax::AttributeKind as HaxttributeKind;
350 match attr {
351 Haxttribute::Parsed(HaxttributeKind::DocComment { comment, .. }) => {
352 Some(Attribute::DocComment(comment.to_string()))
353 }
354 Haxttribute::Parsed(_) => None,
355 Haxttribute::Unparsed(attr) => {
356 let raw_attr = RawAttribute {
357 path: attr.path.clone(),
358 args: match &attr.args {
359 hax::AttrArgs::Empty => None,
360 hax::AttrArgs::Delimited(args) => Some(args.tokens.clone()),
361 hax::AttrArgs::Eq { expr, .. } => self
362 .tcx
363 .sess
364 .source_map()
365 .span_to_snippet(expr.span.rust_span_data.unwrap().span())
366 .ok(),
367 },
368 };
369 match Attribute::parse_from_raw(raw_attr) {
370 Ok(a) => Some(a),
371 Err(msg) => {
372 let span = self.translate_span_from_hax(&attr.span);
373 register_error!(self, span, "Error parsing attribute: {msg}");
374 None
375 }
376 }
377 }
378 }
379 }
380
381 pub(crate) fn translate_inline(&self, def: &hax::FullDef) -> Option<InlineAttr> {
382 match def.kind() {
383 hax::FullDefKind::Fn { inline, .. } | hax::FullDefKind::AssocFn { inline, .. } => {
384 match inline {
385 hax::InlineAttr::None => None,
386 hax::InlineAttr::Hint => Some(InlineAttr::Hint),
387 hax::InlineAttr::Never => Some(InlineAttr::Never),
388 hax::InlineAttr::Always => Some(InlineAttr::Always),
389 hax::InlineAttr::Force { .. } => Some(InlineAttr::Always),
390 }
391 }
392 _ => None,
393 }
394 }
395
396 pub(crate) fn translate_attr_info(&mut self, def: &hax::FullDef) -> AttrInfo {
397 let public = def.visibility.unwrap_or(false);
399 let inline = self.translate_inline(def);
400 let attributes = def
401 .attributes
402 .iter()
403 .filter_map(|attr| self.translate_attribute(&attr))
404 .collect_vec();
405
406 let rename = {
407 let mut renames = attributes.iter().filter_map(|a| a.as_rename()).cloned();
408 let rename = renames.next();
409 if renames.next().is_some() {
410 let span = self.translate_span_from_hax(&def.span);
411 register_error!(
412 self,
413 span,
414 "There should be at most one `charon::rename(\"...\")` \
415 or `aeneas::rename(\"...\")` attribute per declaration",
416 );
417 }
418 rename
419 };
420
421 AttrInfo {
422 attributes,
423 inline,
424 public,
425 rename,
426 }
427 }
428}
429
430impl<'tcx, 'ctx> TranslateCtx<'tcx> {
432 pub(crate) fn is_extern_item(&mut self, def: &hax::FullDef) -> bool {
434 def.parent.as_ref().is_some_and(|parent| {
435 self.hax_def(parent).is_ok_and(|parent_def| {
436 matches!(parent_def.kind(), hax::FullDefKind::ForeignMod { .. })
437 })
438 })
439 }
440
441 pub(crate) fn translate_item_meta(
443 &mut self,
444 def: &hax::FullDef,
445 item_src: &TransItemSource,
446 name: Name,
447 name_opacity: ItemOpacity,
448 ) -> ItemMeta {
449 if let Some(item_meta) = self.cached_item_metas.get(&item_src) {
450 return item_meta.clone();
451 }
452 let span = def.source_span.as_ref().unwrap_or(&def.span);
453 let span = self.translate_span_from_hax(span);
454 let attr_info = self.translate_attr_info(def);
455 let is_local = def.def_id.is_local;
456 let lang_item = def
457 .lang_item
458 .clone()
459 .or_else(|| def.diagnostic_item.clone());
460
461 let opacity = if self.is_extern_item(def)
462 || attr_info.attributes.iter().any(|attr| attr.is_opaque())
463 {
464 ItemOpacity::Opaque.max(name_opacity)
466 } else {
467 name_opacity
468 };
469
470 let item_meta = ItemMeta {
471 name,
472 span,
473 source_text: def.source_text.clone(),
474 attr_info,
475 is_local,
476 opacity,
477 lang_item,
478 };
479 self.cached_item_metas
480 .insert(item_src.clone(), item_meta.clone());
481 item_meta
482 }
483}
484
485impl<'tcx, 'ctx> ItemTransCtx<'tcx, 'ctx> {
486 pub(crate) fn translate_span_from_hax(&mut self, rspan: &hax::Span) -> Span {
487 self.t_ctx.translate_span_from_hax(rspan)
488 }
489
490 pub(crate) fn def_span(&mut self, def_id: &hax::DefId) -> Span {
491 self.t_ctx.def_span(def_id)
492 }
493}