charon_lib/ast/
krate.rs

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