Skip to main content

charon_lib/ast/items/
trait_decl.rs

1use crate::ast::*;
2use crate::ids::IndexVec;
3use derive_generic_visitor::{Drive, DriveMut, DriveTwo};
4use serde_state::DeserializeState;
5use serde_state::SerializeState;
6
7#[derive(
8    Debug,
9    Clone,
10    Copy,
11    SerializeState,
12    DeserializeState,
13    Drive,
14    DriveMut,
15    DriveTwo,
16    PartialEq,
17    Eq,
18    Hash,
19    PartialOrd,
20    Ord,
21)]
22#[drive(skip)]
23#[serde_state(stateless)]
24pub struct TraitItemName(pub ustr::Ustr);
25
26generate_index_type!(TraitMethodId, "TraitMethod");
27generate_index_type!(AssocTypeId, "AssocType");
28generate_index_type!(AssocConstId, "AssocConst");
29
30/// A trait **declaration**.
31///
32/// For instance:
33/// ```text
34/// trait Foo {
35///   type Bar;
36///
37///   fn baz(...); // required method (see below)
38///
39///   fn test() -> bool { true } // provided method (see below)
40/// }
41/// ```
42///
43/// In case of a trait declaration, we don't include the provided methods (the methods
44/// with a default implementation): they will be translated on a per-need basis. This is
45/// important for two reasons:
46/// - this makes the trait definitions a lot smaller (the Iterator trait
47///   has *one* declared function and more than 70 provided functions)
48/// - this is important for the external traits, whose provided methods
49///   often use features we don't support yet
50///
51/// Remark:
52/// In Aeneas, we still translate the provided methods on an individual basis,
53/// and in such a way thay they take as input a trait instance. This means that
54/// we can use default methods *but*:
55/// - implementations of required methods shoudln't call default methods
56/// - trait implementations shouldn't redefine required methods
57///
58/// The use case we have in mind is [std::iter::Iterator]: it declares one required
59/// method (`next`) that should be implemented for every iterator, and defines many
60/// helpers like `all`, `map`, etc. that shouldn't be re-implemented.
61/// Of course, this forbids other useful use cases such as visitors implemented
62/// by means of traits.
63#[allow(clippy::type_complexity)]
64#[derive(
65    Debug, PartialEq, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut, DriveTwo,
66)]
67pub struct TraitDecl {
68    pub def_id: TraitDeclId,
69    pub item_meta: ItemMeta,
70    /// Distinguishes normal traits from trait aliases.
71    pub src: TraitDeclSource,
72    pub generics: GenericParams,
73    /// The "parent" clauses: the supertraits.
74    ///
75    /// Supertraits are actually regular where clauses, but we decided to have
76    /// a custom treatment.
77    /// ```text
78    /// trait Foo : Bar {
79    ///             ^^^
80    ///         supertrait, that we treat as a parent predicate
81    /// }
82    /// ```
83    /// TODO: actually, as of today, we consider that all trait clauses of
84    /// trait declarations are parent clauses.
85    pub implied_clauses: IndexVec<TraitClauseId, TraitParam>,
86    /// The associated constants declared in the trait.
87    pub consts: IndexMap<AssocConstId, TraitAssocConst>,
88    /// The associated types declared in the trait. The binder binds the generic parameters of the
89    /// type if it is a GAT (Generic Associated Type). For a plain associated type the binder binds
90    /// nothing.
91    pub types: IndexMap<AssocTypeId, Binder<TraitAssocTy>>,
92    /// The methods declared by the trait. The binder binds the generic parameters of the method.
93    ///
94    /// ```rust
95    /// trait Trait<T> {
96    ///   // The `Binder` for this method binds `'a` and `U`.
97    ///   fn method<'a, U>(x: &'a U);
98    /// }
99    /// ```
100    pub methods: IndexMap<TraitMethodId, Binder<TraitMethod>>,
101    /// The virtual table struct for this trait, if it has one.
102    /// It is guaranteed that the trait has a vtable iff it is dyn-compatible.
103    pub vtable: Option<TypeDeclRef>,
104}
105
106/// An associated constant in a trait.
107#[derive(
108    Debug, PartialEq, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut, DriveTwo,
109)]
110pub struct TraitAssocConst {
111    pub name: TraitItemName,
112    #[serde_state(stateless)]
113    pub attr_info: AttrInfo,
114    pub ty: Ty,
115    pub default: Option<GlobalDeclRef>,
116}
117
118/// An associated type in a trait.
119#[derive(
120    Debug, PartialEq, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut, DriveTwo,
121)]
122pub struct TraitAssocTy {
123    pub name: TraitItemName,
124    #[serde_state(stateless)]
125    pub attr_info: AttrInfo,
126    pub default: Option<TraitAssocTyImpl>,
127    /// List of trait clauses that apply to this type.
128    pub implied_clauses: IndexVec<TraitClauseId, TraitParam>,
129}
130
131/// A trait method.
132#[derive(
133    Debug, PartialEq, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut, DriveTwo,
134)]
135pub struct TraitMethod {
136    pub name: TraitItemName,
137    pub item_meta: ItemMeta,
138    pub signature: FunSig,
139    /// The default method implementation, if there is one.
140    pub default: Option<FunDeclRef>,
141}
142
143/// Where the trait comes from.
144#[derive(
145    Debug, Clone, Copy, PartialEq, Eq, SerializeState, DeserializeState, Drive, DriveMut, DriveTwo,
146)]
147#[cfg_attr(feature = "charon_on_charon", charon::variants_suffix("TraitDecl"))]
148pub enum TraitDeclSource {
149    /// A regular trait.
150    Normal,
151    /// The trait declaration coming from a trait alias.
152    TraitAlias,
153}
154
155impl TraitDecl {
156    pub fn methods(&self) -> impl Iterator<Item = &Binder<TraitMethod>> {
157        self.methods.iter()
158    }
159}
160
161impl Binder<TraitAssocTy> {
162    pub fn name(&self) -> &TraitItemName {
163        &self.skip_binder.name
164    }
165}
166impl Binder<TraitMethod> {
167    pub fn name(&self) -> TraitItemName {
168        self.skip_binder.name
169    }
170}