Skip to main content

sway_core/language/ty/declaration/
trait.rs

1use crate::{
2    decl_engine::{
3        DeclEngineInsert, DeclRefConstant, DeclRefFunction, DeclRefTraitFn, DeclRefTraitType,
4        MaterializeConstGenerics, ReplaceFunctionImplementingType,
5    },
6    engine_threading::*,
7    has_changes,
8    language::{
9        parsed::{self, TraitDeclaration},
10        ty::{TyDecl, TyDeclParsedType},
11        CallPath, Visibility,
12    },
13    semantic_analysis::{
14        TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckFinalization,
15        TypeCheckFinalizationContext,
16    },
17    transform,
18    type_system::*,
19    HasChanges,
20};
21use monomorphization::MonomorphizeHelper;
22use serde::{Deserialize, Serialize};
23use std::{
24    fmt,
25    hash::{Hash, Hasher},
26};
27use sway_error::handler::{ErrorEmitted, Handler};
28use sway_types::{Ident, Named, Span, Spanned};
29
30#[derive(Clone, Debug, Serialize, Deserialize)]
31pub struct TyTraitDecl {
32    pub name: Ident,
33    pub type_parameters: Vec<TypeParameter>,
34    pub self_type: TypeParameter,
35    pub interface_surface: Vec<TyTraitInterfaceItem>,
36    pub items: Vec<TyTraitItem>,
37    pub supertraits: Vec<parsed::Supertrait>,
38    pub visibility: Visibility,
39    pub attributes: transform::Attributes,
40    pub call_path: CallPath,
41    pub span: Span,
42}
43
44impl TyDeclParsedType for TyTraitDecl {
45    type ParsedType = TraitDeclaration;
46}
47
48#[derive(Clone, Debug, Serialize, Deserialize)]
49pub enum TyTraitInterfaceItem {
50    TraitFn(DeclRefTraitFn),
51    Constant(DeclRefConstant),
52    Type(DeclRefTraitType),
53}
54
55impl DisplayWithEngines for TyTraitInterfaceItem {
56    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
57        write!(f, "{:?}", engines.help_out(self))
58    }
59}
60
61impl DebugWithEngines for TyTraitInterfaceItem {
62    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
63        write!(
64            f,
65            "TyTraitItem {}",
66            match self {
67                TyTraitInterfaceItem::TraitFn(fn_ref) => format!(
68                    "fn {:?}",
69                    engines.help_out(&*engines.de().get_trait_fn(fn_ref))
70                ),
71                TyTraitInterfaceItem::Constant(const_ref) => format!(
72                    "const {:?}",
73                    engines.help_out(&*engines.de().get_constant(const_ref))
74                ),
75                TyTraitInterfaceItem::Type(type_ref) => format!(
76                    "type {:?}",
77                    engines.help_out(&*engines.de().get_type(type_ref))
78                ),
79            }
80        )
81    }
82}
83
84#[derive(Clone, Debug, Serialize, Deserialize)]
85pub enum TyTraitItem {
86    Fn(DeclRefFunction),
87    Constant(DeclRefConstant),
88    Type(DeclRefTraitType),
89}
90
91impl DisplayWithEngines for TyTraitItem {
92    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
93        write!(f, "{:?}", engines.help_out(self))
94    }
95}
96
97impl DebugWithEngines for TyTraitItem {
98    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
99        write!(
100            f,
101            "TyTraitItem {}",
102            match self {
103                TyTraitItem::Fn(fn_ref) => format!(
104                    "fn {:?}",
105                    engines.help_out(&*engines.de().get_function(fn_ref))
106                ),
107                TyTraitItem::Constant(const_ref) => format!(
108                    "const {:?}",
109                    engines.help_out(&*engines.de().get_constant(const_ref))
110                ),
111                TyTraitItem::Type(type_ref) => format!(
112                    "type {:?}",
113                    engines.help_out(&*engines.de().get_type(type_ref))
114                ),
115            }
116        )
117    }
118}
119
120impl Named for TyTraitDecl {
121    fn name(&self) -> &Ident {
122        &self.name
123    }
124}
125
126impl Spanned for TyTraitDecl {
127    fn span(&self) -> Span {
128        self.span.clone()
129    }
130}
131
132impl EqWithEngines for TyTraitDecl {}
133impl PartialEqWithEngines for TyTraitDecl {
134    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
135        self.name == other.name
136            && self.type_parameters.eq(&other.type_parameters, ctx)
137            && self.interface_surface.eq(&other.interface_surface, ctx)
138            && self.items.eq(&other.items, ctx)
139            && self.supertraits.eq(&other.supertraits, ctx)
140            && self.visibility == other.visibility
141    }
142}
143
144impl HashWithEngines for TyTraitDecl {
145    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
146        let TyTraitDecl {
147            name,
148            type_parameters,
149            self_type,
150            interface_surface,
151            items,
152            supertraits,
153            visibility,
154            // these fields are not hashed because they aren't relevant/a
155            // reliable source of obj v. obj distinction
156            attributes: _,
157            span: _,
158            call_path: _,
159        } = self;
160        name.hash(state);
161        type_parameters.hash(state, engines);
162        self_type.hash(state, engines);
163        interface_surface.hash(state, engines);
164        items.hash(state, engines);
165        supertraits.hash(state, engines);
166        visibility.hash(state);
167    }
168}
169
170impl MaterializeConstGenerics for TyTraitDecl {
171    fn materialize_const_generics(
172        &mut self,
173        _engines: &Engines,
174        _handler: &Handler,
175        _name: &str,
176        _value: &crate::language::ty::TyExpression,
177    ) -> Result<HasChanges, ErrorEmitted> {
178        Ok(HasChanges::No)
179    }
180}
181
182impl EqWithEngines for TyTraitInterfaceItem {}
183impl PartialEqWithEngines for TyTraitInterfaceItem {
184    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
185        match (self, other) {
186            (TyTraitInterfaceItem::TraitFn(id), TyTraitInterfaceItem::TraitFn(other_id)) => {
187                id.eq(other_id, ctx)
188            }
189            (TyTraitInterfaceItem::Constant(id), TyTraitInterfaceItem::Constant(other_id)) => {
190                id.eq(other_id, ctx)
191            }
192            _ => false,
193        }
194    }
195}
196
197impl EqWithEngines for TyTraitItem {}
198impl PartialEqWithEngines for TyTraitItem {
199    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
200        match (self, other) {
201            (TyTraitItem::Fn(id), TyTraitItem::Fn(other_id)) => id.eq(other_id, ctx),
202            (TyTraitItem::Constant(id), TyTraitItem::Constant(other_id)) => id.eq(other_id, ctx),
203            _ => false,
204        }
205    }
206}
207
208impl HashWithEngines for TyTraitInterfaceItem {
209    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
210        match self {
211            TyTraitInterfaceItem::TraitFn(fn_decl) => fn_decl.hash(state, engines),
212            TyTraitInterfaceItem::Constant(const_decl) => const_decl.hash(state, engines),
213            TyTraitInterfaceItem::Type(type_decl) => type_decl.hash(state, engines),
214        }
215    }
216}
217
218impl HashWithEngines for TyTraitItem {
219    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
220        match self {
221            TyTraitItem::Fn(fn_decl) => fn_decl.hash(state, engines),
222            TyTraitItem::Constant(const_decl) => const_decl.hash(state, engines),
223            TyTraitItem::Type(type_decl) => type_decl.hash(state, engines),
224        }
225    }
226}
227
228impl TypeCheckAnalysis for TyTraitItem {
229    fn type_check_analyze(
230        &self,
231        handler: &Handler,
232        ctx: &mut TypeCheckAnalysisContext,
233    ) -> Result<(), ErrorEmitted> {
234        let decl_engine = ctx.engines.de();
235
236        match self {
237            TyTraitItem::Fn(node) => {
238                node.type_check_analyze(handler, ctx)?;
239            }
240            TyTraitItem::Constant(node) => {
241                let item_const = decl_engine.get_constant(node);
242                item_const.type_check_analyze(handler, ctx)?;
243            }
244            TyTraitItem::Type(node) => {
245                let item_type = decl_engine.get_type(node);
246                item_type.type_check_analyze(handler, ctx)?;
247            }
248        }
249
250        Ok(())
251    }
252}
253
254impl TypeCheckFinalization for TyTraitItem {
255    fn type_check_finalize(
256        &mut self,
257        handler: &Handler,
258        ctx: &mut TypeCheckFinalizationContext,
259    ) -> Result<HasChanges, ErrorEmitted> {
260        let decl_engine = ctx.engines.de();
261        let has_changes = match self {
262            TyTraitItem::Fn(node) => {
263                let mut item_fn = (*decl_engine.get_function(node)).clone();
264                let has_changes = item_fn.type_check_finalize(handler, ctx)?;
265                if has_changes.has_changes() {
266                    *node = decl_engine.insert_modified(item_fn, *node.id())
267                }
268                has_changes
269            }
270            TyTraitItem::Constant(node) => {
271                let mut item_const = (*decl_engine.get_constant(node)).clone();
272                let has_changes = item_const.type_check_finalize(handler, ctx)?;
273                if has_changes.has_changes() {
274                    *node = decl_engine.insert_modified(item_const, *node.id())
275                }
276                has_changes
277            }
278            TyTraitItem::Type(_node) => HasChanges::No,
279        };
280        Ok(has_changes)
281    }
282}
283
284impl Spanned for TyTraitItem {
285    fn span(&self) -> Span {
286        match self {
287            TyTraitItem::Fn(fn_decl) => fn_decl.span(),
288            TyTraitItem::Constant(const_decl) => const_decl.span(),
289            TyTraitItem::Type(type_decl) => type_decl.span(),
290        }
291    }
292}
293
294impl SubstTypes for TyTraitDecl {
295    fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
296        has_changes! {
297            self.type_parameters.subst(ctx);
298            self.interface_surface
299                .iter_mut()
300                .fold(HasChanges::No, |has_changes, item| match item {
301                    TyTraitInterfaceItem::TraitFn(item_ref) => {
302                        if let Some(new_item_ref) = item_ref
303                            .clone()
304                            .subst_types_and_insert_new_with_parent(ctx) {
305                            item_ref.replace_id(*new_item_ref.id());
306                            HasChanges::Yes
307                        } else {
308                            HasChanges::No
309                        }
310                    }
311                    TyTraitInterfaceItem::Constant(decl_ref) => {
312                        if let Some(new_decl_ref) = decl_ref
313                            .clone()
314                            .subst_types_and_insert_new(ctx) {
315                            decl_ref.replace_id(*new_decl_ref.id());
316                            HasChanges::Yes
317                        } else{
318                            HasChanges::No
319                        }
320                    }
321                    TyTraitInterfaceItem::Type(decl_ref) => {
322                        if let Some(new_decl_ref) = decl_ref
323                            .clone()
324                            .subst_types_and_insert_new(ctx) {
325                            decl_ref.replace_id(*new_decl_ref.id());
326                            HasChanges::Yes
327                        } else{
328                            HasChanges::No
329                        }
330                    }
331                } | has_changes);
332            self.items.iter_mut().fold(HasChanges::No, |has_changes, item| match item {
333                TyTraitItem::Fn(item_ref) => {
334                    if let Some(new_item_ref) = item_ref
335                        .clone()
336                        .subst_types_and_insert_new_with_parent(ctx)
337                    {
338                        item_ref.replace_id(*new_item_ref.id());
339                        HasChanges::Yes
340                    } else {
341                        HasChanges::No
342                    }
343                }
344                TyTraitItem::Constant(item_ref) => {
345                    if let Some(new_decl_ref) = item_ref
346                        .clone()
347                        .subst_types_and_insert_new_with_parent(ctx)
348                    {
349                        item_ref.replace_id(*new_decl_ref.id());
350                        HasChanges::Yes
351                    } else {
352                        HasChanges::No
353                    }
354                }
355                TyTraitItem::Type(item_ref) => {
356                    if let Some(new_decl_ref) = item_ref
357                        .clone()
358                        .subst_types_and_insert_new_with_parent(ctx)
359                    {
360                        item_ref.replace_id(*new_decl_ref.id());
361                        HasChanges::Yes
362                    } else {
363                        HasChanges::No
364                    }
365                }
366            } | has_changes);
367        }
368    }
369}
370
371impl SubstTypes for TyTraitItem {
372    fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
373        match self {
374            TyTraitItem::Fn(fn_decl) => fn_decl.subst(ctx),
375            TyTraitItem::Constant(const_decl) => const_decl.subst(ctx),
376            TyTraitItem::Type(type_decl) => type_decl.subst(ctx),
377        }
378    }
379}
380
381impl ReplaceFunctionImplementingType for TyTraitItem {
382    fn replace_implementing_type(&mut self, engines: &Engines, implementing_type: TyDecl) {
383        match self {
384            TyTraitItem::Fn(decl_ref) => {
385                decl_ref.replace_implementing_type(engines, implementing_type)
386            }
387            TyTraitItem::Constant(_decl_ref) => {
388                // ignore, only needed for functions
389            }
390            TyTraitItem::Type(_decl_ref) => {
391                // ignore, only needed for functions
392            }
393        }
394    }
395}
396
397impl MonomorphizeHelper for TyTraitDecl {
398    fn name(&self) -> &Ident {
399        &self.name
400    }
401
402    fn type_parameters(&self) -> &[TypeParameter] {
403        &self.type_parameters
404    }
405
406    fn has_self_type_param(&self) -> bool {
407        true
408    }
409}