charon_lib/ast/
krate.rs

1use crate::ast::*;
2use crate::formatter::{FmtCtx, IntoFormatter};
3use crate::ids::Vector;
4use crate::pretty::FmtWithCtx;
5use crate::reorder_decls::DeclarationsGroups;
6use derive_generic_visitor::{ControlFlow, Drive, DriveMut};
7use index_vec::Idx;
8use macros::{EnumAsGetters, EnumIsA, VariantIndexArity, VariantName};
9use serde::{Deserialize, Serialize};
10use serde_map_to_array::HashMapToArray;
11use std::cmp::{Ord, PartialOrd};
12use std::collections::HashMap;
13use std::fmt;
14
15generate_index_type!(FunDeclId, "Fun");
16generate_index_type!(TypeDeclId, "Adt");
17generate_index_type!(GlobalDeclId, "Global");
18generate_index_type!(TraitDeclId, "TraitDecl");
19generate_index_type!(TraitImplId, "TraitImpl");
20
21/// The id of a translated item.
22#[derive(
23    Copy,
24    Clone,
25    Debug,
26    PartialOrd,
27    Ord,
28    PartialEq,
29    Eq,
30    Hash,
31    EnumIsA,
32    EnumAsGetters,
33    VariantName,
34    VariantIndexArity,
35    Serialize,
36    Deserialize,
37    Drive,
38    DriveMut,
39)]
40#[charon::rename("AnyDeclId")]
41#[charon::variants_prefix("Id")]
42pub enum AnyTransId {
43    Type(TypeDeclId),
44    Fun(FunDeclId),
45    Global(GlobalDeclId),
46    TraitDecl(TraitDeclId),
47    TraitImpl(TraitImplId),
48}
49
50/// Implement `TryFrom`  and `From` to convert between an enum and its variants.
51macro_rules! wrap_unwrap_enum {
52    ($enum:ident::$variant:ident($variant_ty:ident)) => {
53        impl TryFrom<$enum> for $variant_ty {
54            type Error = ();
55            fn try_from(x: $enum) -> Result<Self, Self::Error> {
56                match x {
57                    $enum::$variant(x) => Ok(x),
58                    _ => Err(()),
59                }
60            }
61        }
62
63        impl From<$variant_ty> for $enum {
64            fn from(x: $variant_ty) -> Self {
65                $enum::$variant(x)
66            }
67        }
68    };
69}
70
71wrap_unwrap_enum!(AnyTransId::Fun(FunDeclId));
72wrap_unwrap_enum!(AnyTransId::Global(GlobalDeclId));
73wrap_unwrap_enum!(AnyTransId::Type(TypeDeclId));
74wrap_unwrap_enum!(AnyTransId::TraitDecl(TraitDeclId));
75wrap_unwrap_enum!(AnyTransId::TraitImpl(TraitImplId));
76impl TryFrom<AnyTransId> for TypeId {
77    type Error = ();
78    fn try_from(x: AnyTransId) -> Result<Self, Self::Error> {
79        Ok(TypeId::Adt(x.try_into()?))
80    }
81}
82impl TryFrom<AnyTransId> for FunId {
83    type Error = ();
84    fn try_from(x: AnyTransId) -> Result<Self, Self::Error> {
85        Ok(FunId::Regular(x.try_into()?))
86    }
87}
88
89/// A reference to a translated item.
90#[derive(
91    Debug, Clone, Copy, EnumIsA, EnumAsGetters, VariantName, VariantIndexArity, Drive, DriveMut,
92)]
93pub enum AnyTransItem<'ctx> {
94    Type(&'ctx TypeDecl),
95    Fun(&'ctx FunDecl),
96    Global(&'ctx GlobalDecl),
97    TraitDecl(&'ctx TraitDecl),
98    TraitImpl(&'ctx TraitImpl),
99}
100
101/// A mutable reference to a translated item.
102#[derive(Debug, EnumIsA, EnumAsGetters, VariantName, VariantIndexArity, Drive, DriveMut)]
103pub enum AnyTransItemMut<'ctx> {
104    Type(&'ctx mut TypeDecl),
105    Fun(&'ctx mut FunDecl),
106    Global(&'ctx mut GlobalDecl),
107    TraitDecl(&'ctx mut TraitDecl),
108    TraitImpl(&'ctx mut TraitImpl),
109}
110
111#[derive(Default, Clone, Drive, DriveMut, Serialize, Deserialize)]
112pub struct TargetInfo {
113    /// The pointer size of the target in bytes.
114    pub target_pointer_size: types::ByteCount,
115    /// Whether the target platform uses little endian byte order.
116    pub is_little_endian: bool,
117}
118
119/// The data of a translated crate.
120#[derive(Default, Clone, Drive, DriveMut, Serialize, Deserialize)]
121pub struct TranslatedCrate {
122    /// The name of the crate.
123    #[drive(skip)]
124    pub crate_name: String,
125
126    /// The options used when calling Charon. It is useful for the applications
127    /// which consumed the serialized code, to check that Charon was called with
128    /// the proper options.
129    #[drive(skip)]
130    pub options: crate::options::CliOpts,
131
132    /// Information about the target platform for which rustc is called on for the crate.
133    #[drive(skip)]
134    pub target_information: TargetInfo,
135
136    /// The names of all registered items. Available so we can know the names even of items that
137    /// failed to translate.
138    /// Invariant: after translation, any existing `AnyTransId` must have an associated name, even
139    /// if the corresponding item wasn't translated.
140    #[serde(with = "HashMapToArray::<AnyTransId, Name>")]
141    pub item_names: HashMap<AnyTransId, Name>,
142    /// Short names, for items whose last PathElem is unique.
143    #[serde(with = "HashMapToArray::<AnyTransId, Name>")]
144    pub short_names: HashMap<AnyTransId, Name>,
145
146    /// The translated files.
147    #[drive(skip)]
148    pub files: Vector<FileId, File>,
149    /// The translated type definitions
150    pub type_decls: Vector<TypeDeclId, TypeDecl>,
151    /// The translated function definitions
152    pub fun_decls: Vector<FunDeclId, FunDecl>,
153    /// The translated global definitions
154    pub global_decls: Vector<GlobalDeclId, GlobalDecl>,
155    /// The translated trait declarations
156    pub trait_decls: Vector<TraitDeclId, TraitDecl>,
157    /// The translated trait declarations
158    pub trait_impls: Vector<TraitImplId, TraitImpl>,
159    /// The re-ordered groups of declarations, initialized as empty.
160    #[drive(skip)]
161    pub ordered_decls: Option<DeclarationsGroups>,
162}
163
164impl TranslatedCrate {
165    pub fn item_name(&self, id: impl Into<AnyTransId>) -> Option<&Name> {
166        self.item_names.get(&id.into())
167    }
168
169    pub fn item_short_name(&self, id: impl Into<AnyTransId>) -> Option<&Name> {
170        let id = id.into();
171        self.short_names.get(&id).or_else(|| self.item_name(id))
172    }
173
174    pub fn get_item(&self, trans_id: impl Into<AnyTransId>) -> Option<AnyTransItem<'_>> {
175        match trans_id.into() {
176            AnyTransId::Type(id) => self.type_decls.get(id).map(AnyTransItem::Type),
177            AnyTransId::Fun(id) => self.fun_decls.get(id).map(AnyTransItem::Fun),
178            AnyTransId::Global(id) => self.global_decls.get(id).map(AnyTransItem::Global),
179            AnyTransId::TraitDecl(id) => self.trait_decls.get(id).map(AnyTransItem::TraitDecl),
180            AnyTransId::TraitImpl(id) => self.trait_impls.get(id).map(AnyTransItem::TraitImpl),
181        }
182    }
183
184    pub fn get_item_mut(&mut self, trans_id: AnyTransId) -> Option<AnyTransItemMut<'_>> {
185        match trans_id {
186            AnyTransId::Type(id) => self.type_decls.get_mut(id).map(AnyTransItemMut::Type),
187            AnyTransId::Fun(id) => self.fun_decls.get_mut(id).map(AnyTransItemMut::Fun),
188            AnyTransId::Global(id) => self.global_decls.get_mut(id).map(AnyTransItemMut::Global),
189            AnyTransId::TraitDecl(id) => {
190                self.trait_decls.get_mut(id).map(AnyTransItemMut::TraitDecl)
191            }
192            AnyTransId::TraitImpl(id) => {
193                self.trait_impls.get_mut(id).map(AnyTransItemMut::TraitImpl)
194            }
195        }
196    }
197
198    pub fn all_ids(&self) -> impl Iterator<Item = AnyTransId> + use<> {
199        self.type_decls
200            .all_indices()
201            .map(AnyTransId::Type)
202            .chain(self.trait_decls.all_indices().map(AnyTransId::TraitDecl))
203            .chain(self.trait_impls.all_indices().map(AnyTransId::TraitImpl))
204            .chain(self.global_decls.all_indices().map(AnyTransId::Global))
205            .chain(self.fun_decls.all_indices().map(AnyTransId::Fun))
206    }
207    pub fn all_items(&self) -> impl Iterator<Item = AnyTransItem<'_>> {
208        self.type_decls
209            .iter()
210            .map(AnyTransItem::Type)
211            .chain(self.trait_decls.iter().map(AnyTransItem::TraitDecl))
212            .chain(self.trait_impls.iter().map(AnyTransItem::TraitImpl))
213            .chain(self.global_decls.iter().map(AnyTransItem::Global))
214            .chain(self.fun_decls.iter().map(AnyTransItem::Fun))
215    }
216    pub fn all_items_mut(&mut self) -> impl Iterator<Item = AnyTransItemMut<'_>> {
217        self.type_decls
218            .iter_mut()
219            .map(AnyTransItemMut::Type)
220            .chain(self.trait_impls.iter_mut().map(AnyTransItemMut::TraitImpl))
221            .chain(self.trait_decls.iter_mut().map(AnyTransItemMut::TraitDecl))
222            .chain(self.fun_decls.iter_mut().map(AnyTransItemMut::Fun))
223            .chain(self.global_decls.iter_mut().map(AnyTransItemMut::Global))
224    }
225    pub fn all_items_with_ids(&self) -> impl Iterator<Item = (AnyTransId, AnyTransItem<'_>)> {
226        self.all_items().map(|item| (item.id(), item))
227    }
228}
229
230impl<'ctx> AnyTransItem<'ctx> {
231    pub fn id(&self) -> AnyTransId {
232        match self {
233            AnyTransItem::Type(d) => d.def_id.into(),
234            AnyTransItem::Fun(d) => d.def_id.into(),
235            AnyTransItem::Global(d) => d.def_id.into(),
236            AnyTransItem::TraitDecl(d) => d.def_id.into(),
237            AnyTransItem::TraitImpl(d) => d.def_id.into(),
238        }
239    }
240
241    pub fn item_meta(&self) -> &'ctx ItemMeta {
242        match self {
243            AnyTransItem::Type(d) => &d.item_meta,
244            AnyTransItem::Fun(d) => &d.item_meta,
245            AnyTransItem::Global(d) => &d.item_meta,
246            AnyTransItem::TraitDecl(d) => &d.item_meta,
247            AnyTransItem::TraitImpl(d) => &d.item_meta,
248        }
249    }
250
251    /// The generic parameters of this item.
252    pub fn generic_params(&self) -> &'ctx GenericParams {
253        match self {
254            AnyTransItem::Type(d) => &d.generics,
255            AnyTransItem::Fun(d) => &d.signature.generics,
256            AnyTransItem::Global(d) => &d.generics,
257            AnyTransItem::TraitDecl(d) => &d.generics,
258            AnyTransItem::TraitImpl(d) => &d.generics,
259        }
260    }
261
262    /// Get information about the parent of this item, if any.
263    pub fn parent_info(&self) -> &'ctx ItemKind {
264        match self {
265            AnyTransItem::Fun(d) => &d.kind,
266            AnyTransItem::Global(d) => &d.kind,
267            AnyTransItem::Type(_) | AnyTransItem::TraitDecl(_) | AnyTransItem::TraitImpl(_) => {
268                &ItemKind::TopLevel
269            }
270        }
271    }
272
273    /// See [`GenericParams::identity_args`].
274    pub fn identity_args(&self) -> GenericArgs {
275        self.generic_params().identity_args()
276    }
277
278    /// We can't implement `AstVisitable` because of the `'static` constraint, but it's ok because
279    /// `AnyTransItem` isn't contained in any of our types.
280    pub fn drive<V: VisitAst>(&self, visitor: &mut V) -> ControlFlow<V::Break> {
281        match *self {
282            AnyTransItem::Type(d) => visitor.visit(d),
283            AnyTransItem::Fun(d) => visitor.visit(d),
284            AnyTransItem::Global(d) => visitor.visit(d),
285            AnyTransItem::TraitDecl(d) => visitor.visit(d),
286            AnyTransItem::TraitImpl(d) => visitor.visit(d),
287        }
288    }
289
290    /// Visit all occurrences of that type inside `self`, in pre-order traversal.
291    pub fn dyn_visit<T: AstVisitable>(&self, f: impl FnMut(&T)) {
292        match *self {
293            AnyTransItem::Type(d) => d.dyn_visit(f),
294            AnyTransItem::Fun(d) => d.dyn_visit(f),
295            AnyTransItem::Global(d) => d.dyn_visit(f),
296            AnyTransItem::TraitDecl(d) => d.dyn_visit(f),
297            AnyTransItem::TraitImpl(d) => d.dyn_visit(f),
298        }
299    }
300}
301
302impl<'ctx> AnyTransItemMut<'ctx> {
303    pub fn as_ref(&self) -> AnyTransItem<'_> {
304        match self {
305            AnyTransItemMut::Type(d) => AnyTransItem::Type(d),
306            AnyTransItemMut::Fun(d) => AnyTransItem::Fun(d),
307            AnyTransItemMut::Global(d) => AnyTransItem::Global(d),
308            AnyTransItemMut::TraitDecl(d) => AnyTransItem::TraitDecl(d),
309            AnyTransItemMut::TraitImpl(d) => AnyTransItem::TraitImpl(d),
310        }
311    }
312    pub fn reborrow(&mut self) -> AnyTransItemMut<'_> {
313        match self {
314            AnyTransItemMut::Type(d) => AnyTransItemMut::Type(d),
315            AnyTransItemMut::Fun(d) => AnyTransItemMut::Fun(d),
316            AnyTransItemMut::Global(d) => AnyTransItemMut::Global(d),
317            AnyTransItemMut::TraitDecl(d) => AnyTransItemMut::TraitDecl(d),
318            AnyTransItemMut::TraitImpl(d) => AnyTransItemMut::TraitImpl(d),
319        }
320    }
321
322    /// The generic parameters of this item.
323    pub fn generic_params(&mut self) -> &mut GenericParams {
324        match self {
325            AnyTransItemMut::Type(d) => &mut d.generics,
326            AnyTransItemMut::Fun(d) => &mut d.signature.generics,
327            AnyTransItemMut::Global(d) => &mut d.generics,
328            AnyTransItemMut::TraitDecl(d) => &mut d.generics,
329            AnyTransItemMut::TraitImpl(d) => &mut d.generics,
330        }
331    }
332
333    /// We can't implement `AstVisitable` because of the `'static` constraint, but it's ok because
334    /// `AnyTransItemMut` isn't contained in any of our types.
335    pub fn drive_mut<V: VisitAstMut>(&mut self, visitor: &mut V) -> ControlFlow<V::Break> {
336        match self {
337            AnyTransItemMut::Type(d) => visitor.visit(*d),
338            AnyTransItemMut::Fun(d) => visitor.visit(*d),
339            AnyTransItemMut::Global(d) => visitor.visit(*d),
340            AnyTransItemMut::TraitDecl(d) => visitor.visit(*d),
341            AnyTransItemMut::TraitImpl(d) => visitor.visit(*d),
342        }
343    }
344
345    /// Visit all occurrences of that type inside `self`, in pre-order traversal.
346    pub fn dyn_visit_mut<T: AstVisitable>(&mut self, f: impl FnMut(&mut T)) {
347        match self {
348            AnyTransItemMut::Type(d) => d.dyn_visit_mut(f),
349            AnyTransItemMut::Fun(d) => d.dyn_visit_mut(f),
350            AnyTransItemMut::Global(d) => d.dyn_visit_mut(f),
351            AnyTransItemMut::TraitDecl(d) => d.dyn_visit_mut(f),
352            AnyTransItemMut::TraitImpl(d) => d.dyn_visit_mut(f),
353        }
354    }
355}
356
357impl fmt::Display for TranslatedCrate {
358    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
359        let fmt: &FmtCtx = &self.into_fmt();
360        match &self.ordered_decls {
361            None => {
362                // We do simple: types, globals, traits, functions
363                for d in &self.type_decls {
364                    writeln!(f, "{}\n", d.with_ctx(fmt))?
365                }
366                for d in &self.global_decls {
367                    writeln!(f, "{}\n", d.with_ctx(fmt))?
368                }
369                for d in &self.trait_decls {
370                    writeln!(f, "{}\n", d.with_ctx(fmt))?
371                }
372                for d in &self.trait_impls {
373                    writeln!(f, "{}\n", d.with_ctx(fmt))?
374                }
375                for d in &self.fun_decls {
376                    writeln!(f, "{}\n", d.with_ctx(fmt))?
377                }
378            }
379            Some(ordered_decls) => {
380                for gr in ordered_decls {
381                    for id in gr.get_ids() {
382                        writeln!(f, "{}\n", fmt.format_decl_id(id))?
383                    }
384                }
385            }
386        }
387        fmt::Result::Ok(())
388    }
389}
390
391impl<'tcx, 'ctx, 'a> IntoFormatter for &'a TranslatedCrate {
392    type C = FmtCtx<'a>;
393
394    fn into_fmt(self) -> Self::C {
395        FmtCtx {
396            translated: Some(self),
397            ..Default::default()
398        }
399    }
400}
401
402pub trait HasVectorOf<Id: Idx>: std::ops::Index<Id, Output: Sized> {
403    fn get_vector(&self) -> &Vector<Id, Self::Output>;
404    fn get_vector_mut(&mut self) -> &mut Vector<Id, Self::Output>;
405}
406
407/// Delegate `Index` implementations to subfields.
408macro_rules! mk_index_impls {
409    ($ty:ident.$field:ident[$idx:ty]: $output:ty) => {
410        impl std::ops::Index<$idx> for $ty {
411            type Output = $output;
412            fn index(&self, index: $idx) -> &Self::Output {
413                &self.$field[index]
414            }
415        }
416        impl std::ops::IndexMut<$idx> for $ty {
417            fn index_mut(&mut self, index: $idx) -> &mut Self::Output {
418                &mut self.$field[index]
419            }
420        }
421        impl HasVectorOf<$idx> for $ty {
422            fn get_vector(&self) -> &Vector<$idx, Self::Output> {
423                &self.$field
424            }
425            fn get_vector_mut(&mut self) -> &mut Vector<$idx, Self::Output> {
426                &mut self.$field
427            }
428        }
429    };
430}
431pub(crate) use mk_index_impls;
432
433mk_index_impls!(TranslatedCrate.type_decls[TypeDeclId]: TypeDecl);
434mk_index_impls!(TranslatedCrate.fun_decls[FunDeclId]: FunDecl);
435mk_index_impls!(TranslatedCrate.global_decls[GlobalDeclId]: GlobalDecl);
436mk_index_impls!(TranslatedCrate.trait_decls[TraitDeclId]: TraitDecl);
437mk_index_impls!(TranslatedCrate.trait_impls[TraitImplId]: TraitImpl);