Skip to main content

charon_lib/ast/
items.rs

1use crate::ast::*;
2use derive_generic_visitor::{ControlFlow, Drive, DriveMut, DriveTwo, VisitTwo, Visitor};
3use macros::{EnumAsGetters, EnumIsA, VariantIndexArity, VariantName};
4
5pub mod fun_decl;
6pub mod global_decl;
7pub mod item_ids;
8pub mod layout;
9pub mod layout_guarantees;
10pub mod trait_decl;
11pub mod trait_impl;
12pub mod type_decl;
13
14pub use fun_decl::*;
15pub use global_decl::*;
16pub use item_ids::*;
17pub use layout::*;
18pub use layout_guarantees::*;
19pub use trait_decl::*;
20pub use trait_impl::*;
21pub use type_decl::*;
22
23/// A translated item.
24#[derive(
25    Debug, EnumIsA, EnumAsGetters, VariantName, VariantIndexArity, Drive, DriveMut, DriveTwo,
26)]
27pub enum ItemByVal {
28    Type(TypeDecl),
29    Fun(FunDecl),
30    Global(GlobalDecl),
31    TraitDecl(TraitDecl),
32    TraitImpl(TraitImpl),
33}
34
35/// A reference to a translated item.
36#[derive(
37    Debug,
38    Clone,
39    Copy,
40    EnumIsA,
41    EnumAsGetters,
42    VariantName,
43    VariantIndexArity,
44    Drive,
45    DriveMut,
46    DriveTwo,
47)]
48pub enum ItemRef<'ctx> {
49    Type(&'ctx TypeDecl),
50    Fun(&'ctx FunDecl),
51    Global(&'ctx GlobalDecl),
52    TraitDecl(&'ctx TraitDecl),
53    TraitImpl(&'ctx TraitImpl),
54}
55
56/// A mutable reference to a translated item.
57#[derive(
58    Debug, EnumIsA, EnumAsGetters, VariantName, VariantIndexArity, Drive, DriveMut, DriveTwo,
59)]
60pub enum ItemRefMut<'ctx> {
61    Type(&'ctx mut TypeDecl),
62    Fun(&'ctx mut FunDecl),
63    Global(&'ctx mut GlobalDecl),
64    TraitDecl(&'ctx mut TraitDecl),
65    TraitImpl(&'ctx mut TraitImpl),
66}
67
68impl ItemByVal {
69    pub fn as_ref(&self) -> ItemRef<'_> {
70        match self {
71            Self::Type(d) => ItemRef::Type(d),
72            Self::Fun(d) => ItemRef::Fun(d),
73            Self::Global(d) => ItemRef::Global(d),
74            Self::TraitDecl(d) => ItemRef::TraitDecl(d),
75            Self::TraitImpl(d) => ItemRef::TraitImpl(d),
76        }
77    }
78    pub fn as_mut(&mut self) -> ItemRefMut<'_> {
79        match self {
80            Self::Type(d) => ItemRefMut::Type(d),
81            Self::Fun(d) => ItemRefMut::Fun(d),
82            Self::Global(d) => ItemRefMut::Global(d),
83            Self::TraitDecl(d) => ItemRefMut::TraitDecl(d),
84            Self::TraitImpl(d) => ItemRefMut::TraitImpl(d),
85        }
86    }
87}
88
89impl<'ctx> ItemRef<'ctx> {
90    pub fn id(&self) -> ItemId {
91        match self {
92            ItemRef::Type(d) => d.def_id.into(),
93            ItemRef::Fun(d) => d.def_id.into(),
94            ItemRef::Global(d) => d.def_id.into(),
95            ItemRef::TraitDecl(d) => d.def_id.into(),
96            ItemRef::TraitImpl(d) => d.def_id.into(),
97        }
98    }
99
100    pub fn to_owned(&self) -> ItemByVal {
101        match *self {
102            Self::Type(d) => ItemByVal::Type(d.clone()),
103            Self::Fun(d) => ItemByVal::Fun(d.clone()),
104            Self::Global(d) => ItemByVal::Global(d.clone()),
105            Self::TraitDecl(d) => ItemByVal::TraitDecl(d.clone()),
106            Self::TraitImpl(d) => ItemByVal::TraitImpl(d.clone()),
107        }
108    }
109
110    pub fn item_meta(&self) -> &'ctx ItemMeta {
111        match self {
112            Self::Type(d) => &d.item_meta,
113            Self::Fun(d) => &d.item_meta,
114            Self::Global(d) => &d.item_meta,
115            Self::TraitDecl(d) => &d.item_meta,
116            Self::TraitImpl(d) => &d.item_meta,
117        }
118    }
119    /// The generic parameters of this item.
120    pub fn generic_params(&self) -> &'ctx GenericParams {
121        match self {
122            ItemRef::Type(d) => &d.generics,
123            ItemRef::Fun(d) => &d.generics,
124            ItemRef::Global(d) => &d.generics,
125            ItemRef::TraitDecl(d) => &d.generics,
126            ItemRef::TraitImpl(d) => &d.generics,
127        }
128    }
129
130    /// See [`GenericParams::identity_args`].
131    pub fn identity_args(&self) -> GenericArgs {
132        self.generic_params().identity_args()
133    }
134
135    /// We can't implement `AstVisitable` because of the `'static` constraint, but it's ok because
136    /// `ItemRef` isn't contained in any of our types.
137    pub fn drive<V: VisitAst>(&self, visitor: &mut V) -> ControlFlow<V::Break> {
138        match *self {
139            ItemRef::Type(d) => visitor.visit(d),
140            ItemRef::Fun(d) => visitor.visit(d),
141            ItemRef::Global(d) => visitor.visit(d),
142            ItemRef::TraitDecl(d) => visitor.visit(d),
143            ItemRef::TraitImpl(d) => visitor.visit(d),
144        }
145    }
146
147    /// Visit two items in lockstep.
148    pub fn drive_two<V: ZipAst>(&self, other: &Self, visitor: &mut V) -> ControlFlow<V::Break> {
149        /// Adapter needed because `ZipAst => Any => 'static` so `&'ctx X` can't be `ZipAst`.
150        struct ItemRefZipVisitor<'a, V>(&'a mut V);
151
152        impl<V: Visitor> Visitor for ItemRefZipVisitor<'_, V> {
153            type Break = V::Break;
154        }
155
156        impl<'s, 'ctx, T: AstVisitable, V: ZipAst> VisitTwo<'s, &'ctx T> for ItemRefZipVisitor<'_, V> {
157            fn visit(&mut self, left: &'s &'ctx T, right: &'s &'ctx T) -> ControlFlow<Self::Break> {
158                self.0.visit(*left, *right)
159            }
160        }
161
162        DriveTwo::drive_two_inner(self, other, &mut ItemRefZipVisitor(visitor))
163    }
164
165    /// Visit all occurrences of that type inside `self`, in pre-order traversal.
166    pub fn dyn_visit<T: AstVisitable>(&self, f: impl FnMut(&T)) {
167        match *self {
168            ItemRef::Type(d) => d.dyn_visit(f),
169            ItemRef::Fun(d) => d.dyn_visit(f),
170            ItemRef::Global(d) => d.dyn_visit(f),
171            ItemRef::TraitDecl(d) => d.dyn_visit(f),
172            ItemRef::TraitImpl(d) => d.dyn_visit(f),
173        }
174    }
175}
176
177impl<'ctx> ItemRefMut<'ctx> {
178    pub fn as_ref(&self) -> ItemRef<'_> {
179        match self {
180            ItemRefMut::Type(d) => ItemRef::Type(d),
181            ItemRefMut::Fun(d) => ItemRef::Fun(d),
182            ItemRefMut::Global(d) => ItemRef::Global(d),
183            ItemRefMut::TraitDecl(d) => ItemRef::TraitDecl(d),
184            ItemRefMut::TraitImpl(d) => ItemRef::TraitImpl(d),
185        }
186    }
187    pub fn reborrow(&mut self) -> ItemRefMut<'_> {
188        match self {
189            ItemRefMut::Type(d) => ItemRefMut::Type(d),
190            ItemRefMut::Fun(d) => ItemRefMut::Fun(d),
191            ItemRefMut::Global(d) => ItemRefMut::Global(d),
192            ItemRefMut::TraitDecl(d) => ItemRefMut::TraitDecl(d),
193            ItemRefMut::TraitImpl(d) => ItemRefMut::TraitImpl(d),
194        }
195    }
196
197    pub fn set_id(&mut self, id: ItemId) {
198        match (self, id) {
199            (Self::Type(d), ItemId::Type(id)) => d.def_id = id,
200            (Self::Fun(d), ItemId::Fun(id)) => d.def_id = id,
201            (Self::Global(d), ItemId::Global(id)) => d.def_id = id,
202            (Self::TraitDecl(d), ItemId::TraitDecl(id)) => d.def_id = id,
203            (Self::TraitImpl(d), ItemId::TraitImpl(id)) => d.def_id = id,
204            _ => unreachable!(),
205        }
206    }
207
208    pub fn item_meta(&mut self) -> &mut ItemMeta {
209        match self {
210            Self::Type(d) => &mut d.item_meta,
211            Self::Fun(d) => &mut d.item_meta,
212            Self::Global(d) => &mut d.item_meta,
213            Self::TraitDecl(d) => &mut d.item_meta,
214            Self::TraitImpl(d) => &mut d.item_meta,
215        }
216    }
217    /// The generic parameters of this item.
218    pub fn generic_params(&mut self) -> &mut GenericParams {
219        match self {
220            ItemRefMut::Type(d) => &mut d.generics,
221            ItemRefMut::Fun(d) => &mut d.generics,
222            ItemRefMut::Global(d) => &mut d.generics,
223            ItemRefMut::TraitDecl(d) => &mut d.generics,
224            ItemRefMut::TraitImpl(d) => &mut d.generics,
225        }
226    }
227
228    /// We can't implement `AstVisitable` because of the `'static` constraint, but it's ok because
229    /// `ItemRefMut` isn't contained in any of our types.
230    pub fn drive_mut<V: VisitAstMut>(&mut self, visitor: &mut V) -> ControlFlow<V::Break> {
231        match self {
232            ItemRefMut::Type(d) => visitor.visit(*d),
233            ItemRefMut::Fun(d) => visitor.visit(*d),
234            ItemRefMut::Global(d) => visitor.visit(*d),
235            ItemRefMut::TraitDecl(d) => visitor.visit(*d),
236            ItemRefMut::TraitImpl(d) => visitor.visit(*d),
237        }
238    }
239
240    /// Visit all occurrences of that type inside `self`, in pre-order traversal.
241    pub fn dyn_visit_mut<T: AstVisitable>(&mut self, f: impl FnMut(&mut T)) {
242        match self {
243            ItemRefMut::Type(d) => d.dyn_visit_mut(f),
244            ItemRefMut::Fun(d) => d.dyn_visit_mut(f),
245            ItemRefMut::Global(d) => d.dyn_visit_mut(f),
246            ItemRefMut::TraitDecl(d) => d.dyn_visit_mut(f),
247            ItemRefMut::TraitImpl(d) => d.dyn_visit_mut(f),
248        }
249    }
250}