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