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