charon_lib/ast/
krate.rs

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