Skip to main content

charon_lib/ast/items/
type_decl.rs

1use derive_generic_visitor::*;
2use macros::{EnumAsGetters, EnumIsA};
3use serde::{Deserialize, Serialize};
4use serde_state::{DeserializeState, SerializeState};
5
6use crate::ast::*;
7use crate::ids::IndexVec;
8use crate::utils::serialize_map_to_array::SeqHashMapToArray;
9
10/// A type declaration.
11///
12/// Types can be opaque or transparent.
13///
14/// Transparent types are local types not marked as opaque.
15/// Opaque types are the others: local types marked as opaque, and non-local
16/// types (coming from external dependencies).
17///
18/// In case the type is transparent, the declaration also contains the
19/// type definition (see [TypeDeclKind]).
20///
21/// A type can only be an ADT (structure or enumeration), as type aliases are
22/// inlined in MIR.
23#[derive(Debug, Clone)]
24#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
25#[serde_state(state_implements = DedupSerializerState)]
26pub struct TypeDecl {
27    pub def_id: TypeDeclId,
28    /// Meta information associated with the item.
29    pub item_meta: ItemMeta,
30    pub generics: GenericParams,
31    /// The context of the type: distinguishes top-level items from closure-related items etc.
32    pub src: TypeSource,
33    /// The type kind: enum, struct, or opaque.
34    pub kind: TypeDeclKind,
35    /// The layout of the type for each target. Information may be partial because of generics or
36    /// dynamically-sized types. If we cannot compute a layout, the target has no entry.
37    #[serde(with = "SeqHashMapToArray::<TargetTriple, Layout>")]
38    pub layout: SeqHashMap<TargetTriple, Layout>,
39    /// The metadata associated with a pointer to the type.
40    pub ptr_metadata: PtrMetadata,
41    /// Which built-in marker traits are implemented by this type. This is only known for
42    /// monomorphic types.
43    pub marker_traits: Option<Box<ImplementsMarkerTraits>>,
44}
45
46generate_index_type!(VariantId, "Variant");
47generate_index_type!(FieldId, "Field");
48
49#[derive(Debug, Clone)]
50#[derive(EnumIsA, EnumAsGetters)]
51#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
52pub enum TypeDeclKind {
53    Struct(IndexVec<FieldId, Field>),
54    Enum(IndexVec<VariantId, Variant>),
55    Union(IndexVec<FieldId, Field>),
56    /// An opaque type.
57    ///
58    /// Either a local type marked as opaque, or an external type.
59    Opaque,
60    /// An alias to another type. This only shows up in the top-level list of items, as rustc
61    /// inlines uses of type aliases everywhere else.
62    Alias(Ty),
63    /// Used if an error happened during the extraction, and we don't panic
64    /// on error.
65    #[cfg_attr(feature = "charon_on_charon", charon::rename("TDeclError"))]
66    Error(String),
67}
68
69#[derive(Debug, Clone)]
70#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
71#[serde_state(stateless)]
72pub struct Variant {
73    pub id: VariantId,
74    pub span: Span,
75    pub attr_info: AttrInfo,
76    #[cfg_attr(feature = "charon_on_charon", charon::rename("variant_name"))]
77    pub name: String,
78    #[serde_state(stateful)]
79    pub fields: IndexVec<FieldId, Field>,
80    /// The discriminant value outputted by `std::mem::discriminant` for this variant. This can be
81    /// different than the value stored in memory (called `tag`); that one is described by
82    /// [`Discriminator`] and [`VariantLayout::tagger`].
83    pub discriminant: IntegerValue,
84}
85
86#[derive(Debug, Clone)]
87#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
88#[serde_state(stateless)]
89pub struct Field {
90    pub span: Span,
91    pub attr_info: AttrInfo,
92    #[cfg_attr(feature = "charon_on_charon", charon::rename("field_name"))]
93    pub name: String,
94    /// Whether this field is positional, as in a tuple struct, tuple variant, or closure. If so,
95    /// its name is based on its position, such as `_0`; otherwise, it is a user-provided name.
96    pub is_positional: bool,
97    #[cfg_attr(feature = "charon_on_charon", charon::rename("field_ty"))]
98    #[serde_state(stateful)]
99    pub ty: Ty,
100}
101
102/// The metadata stored in a pointer. That's the information stored in pointers alongside
103/// their address. It's empty for `Sized` types, and interesting for unsized
104/// aka dynamically-sized types.
105#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
106#[derive(EnumIsA)]
107#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
108#[serde_state(default_state = ())]
109pub enum PtrMetadata {
110    /// Types that need no metadata, namely `T: Sized` types.
111    #[cfg_attr(feature = "charon_on_charon", charon::rename("NoMetadata"))]
112    None,
113    /// Metadata for `[T]` and `str`, and user-defined types
114    /// that directly or indirectly contain one of the two.
115    /// Of type `usize`.
116    /// Notably, length for `[T]` denotes the number of elements in the slice.
117    /// While for `str` it denotes the number of bytes in the string.
118    Length,
119    /// Metadata for `dyn Trait`, referring to the vtable struct. Has type `&'static vtable`
120    VTable(TypeDeclRef),
121    /// Unknown due to generics, but will inherit from the given type.
122    /// This is consistent with `<Ty as Pointee>::Metadata`.
123    /// Of type `TyKind::Metadata(Ty)`.
124    InheritFrom(Ty),
125}
126
127/// Where a given type came from.
128#[derive(Debug, Clone)]
129#[derive(EnumIsA, EnumAsGetters)]
130#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
131#[cfg_attr(feature = "charon_on_charon", charon::variants_suffix("Type"))]
132pub enum TypeSource {
133    /// A normal type declaration.
134    Normal,
135    /// The struct that carries the captured variables of a closure.
136    Closure { info: ClosureInfo },
137    /// Defines the vtable struct for a trait.
138    VTable {
139        /// The `dyn Trait` predicate implemented by this vtable.
140        dyn_predicate: DynPredicate,
141        /// Record what each vtable field means.
142        field_map: IndexVec<FieldId, VTableField>,
143        /// For each implied clause that is also a supertrait clause, records which field of the
144        /// vtable corresponds to it.
145        supertrait_map: IndexVec<TraitClauseId, Option<FieldId>>,
146    },
147    /// A type declaration synthesised for a builtin ADT.
148    Builtin(BuiltinAdt),
149}
150
151/// Which marker traits this type implements.
152#[derive(Debug, Clone, Copy, PartialEq, Eq)]
153#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
154#[serde_state(stateless)]
155pub struct ImplementsMarkerTraits {
156    pub is_sized: bool,
157    pub is_send: bool,
158    pub is_sync: bool,
159    pub is_freeze: bool,
160    pub is_unpin: bool,
161}
162
163#[derive(Debug, Clone, PartialEq, Eq)]
164#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
165#[cfg_attr(feature = "charon_on_charon", charon::variants_prefix("VTable"))]
166pub enum VTableField {
167    Size,
168    Align,
169    Drop,
170    Method(TraitMethodId),
171    SuperTrait(TraitClauseId),
172}
173
174/// Additional information for closures.
175#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
176#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
177pub struct ClosureInfo {
178    #[serde_state(stateless)]
179    pub kind: ClosureKind,
180    /// The `FnOnce` implementation of this closure -- always exists.
181    pub fn_once_impl: RegionBinder<TraitImplRef>,
182    /// The `FnMut` implementation of this closure, if any.
183    pub fn_mut_impl: Option<RegionBinder<TraitImplRef>>,
184    /// The `Fn` implementation of this closure, if any.
185    pub fn_impl: Option<RegionBinder<TraitImplRef>>,
186    /// The signature of the function that this closure represents.
187    pub signature: RegionBinder<FunSig>,
188}
189
190#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
191#[derive(Serialize, Deserialize, Drive, DriveMut, DriveTwo)]
192pub enum ClosureKind {
193    Fn,
194    FnMut,
195    FnOnce,
196}
197
198impl TypeDecl {
199    pub fn get_fields(&self, variant: Option<VariantId>) -> Option<&IndexVec<FieldId, Field>> {
200        match &self.kind {
201            TypeDeclKind::Struct(fields) | TypeDeclKind::Union(fields) => Some(fields),
202            TypeDeclKind::Enum(variants) => Some(&variants[variant.unwrap()].fields),
203            _ => None,
204        }
205    }
206
207    pub fn get_field(&self, variant: Option<VariantId>, field: FieldId) -> Option<&Field> {
208        self.get_fields(variant)?.get(field)
209    }
210
211    pub fn get_field_by_name(
212        &self,
213        variant: Option<VariantId>,
214        field_name: &str,
215    ) -> Option<(FieldId, &Field)> {
216        let fields = match &self.kind {
217            TypeDeclKind::Struct(fields) | TypeDeclKind::Union(fields) => fields,
218            TypeDeclKind::Enum(variants) => &variants[variant.unwrap()].fields,
219            _ => return None,
220        };
221        fields
222            .iter_enumerated()
223            .find(|(_, field)| field.name == field_name)
224    }
225
226    /// Returns a `TypeDeclRef` that refers to this type declaration, with identity generic arguments.
227    pub fn self_ref(&self) -> TypeDeclRef {
228        TypeDeclRef {
229            id: self.def_id,
230            generics: Box::new(self.generics.identity_args()),
231            builtin: self.src.as_builtin().cloned(),
232        }
233    }
234}
235
236impl Variant {
237    /// The new name for this variant, as suggested by the `#[charon::rename]` and
238    /// `#[charon::variants_prefix]` attributes.
239    pub fn renamed_name(&self) -> &str {
240        self.attr_info
241            .rename
242            .as_deref()
243            .unwrap_or(self.name.as_ref())
244    }
245
246    /// Whether this variant has a `#[charon::opaque]` annotation.
247    pub fn is_opaque(&self) -> bool {
248        self.attr_info
249            .attributes
250            .iter()
251            .any(|attr| attr.is_opaque())
252    }
253}
254
255impl Field {
256    /// The new name for this field, as suggested by the `#[charon::rename]` attribute.
257    pub fn renamed_name(&self) -> &str {
258        self.attr_info.rename.as_deref().unwrap_or(&self.name)
259    }
260
261    /// Whether this field has a `#[charon::opaque]` annotation.
262    pub fn is_opaque(&self) -> bool {
263        self.attr_info
264            .attributes
265            .iter()
266            .any(|attr| attr.is_opaque())
267    }
268}
269
270impl ClosureKind {
271    // pub fn trait_name(self) -> &'static str {}
272    pub fn method_name(self) -> &'static str {
273        match self {
274            ClosureKind::FnOnce => "call_once",
275            ClosureKind::FnMut => "call_mut",
276            ClosureKind::Fn => "call",
277        }
278    }
279}
280
281impl PtrMetadata {
282    pub fn into_type(self) -> Ty {
283        match self {
284            PtrMetadata::None => Ty::mk_unit(),
285            PtrMetadata::Length => Ty::mk_usize(),
286            PtrMetadata::VTable(type_decl_ref) => Ty::new(TyKind::Ref(
287                Region::Static,
288                Ty::new(TyKind::Adt(type_decl_ref)),
289                RefKind::Shared,
290            )),
291            PtrMetadata::InheritFrom(ty) => Ty::new(TyKind::PtrMetadata(ty)),
292        }
293    }
294}