sway_core/language/ty/declaration/
abi.rs

1use super::{TyDeclParsedType, TyTraitInterfaceItem, TyTraitItem};
2use crate::{
3    ast_elements::type_parameter::ConstGenericExpr,
4    decl_engine::DeclEngineGet as _,
5    engine_threading::*,
6    language::parsed::{self, AbiDeclaration},
7    transform,
8    type_system::*,
9};
10use serde::{Deserialize, Serialize};
11use std::hash::{Hash, Hasher};
12use sway_error::{
13    error::CompileError,
14    handler::{ErrorEmitted, Handler},
15};
16use sway_types::{Ident, Named, Span, Spanned};
17
18/// A [TyAbiDecl] contains the type-checked version of the parse tree's
19/// [AbiDeclaration].
20#[derive(Clone, Debug, Serialize, Deserialize)]
21pub struct TyAbiDecl {
22    /// The name of the abi trait (also known as a "contract trait")
23    pub name: Ident,
24    /// The methods a contract is required to implement in order opt in to this interface
25    pub interface_surface: Vec<TyTraitInterfaceItem>,
26    pub supertraits: Vec<parsed::Supertrait>,
27    pub items: Vec<TyTraitItem>,
28    pub span: Span,
29    pub attributes: transform::Attributes,
30}
31
32fn has_const_generics(type_id: TypeId, engines: &Engines) -> bool {
33    let types = type_id.extract_any_including_self(engines, &|_| true, vec![], 0);
34
35    for (t, _) in types {
36        let t = engines.te().get(t);
37        match &*t {
38            TypeInfo::StringArray(length) => match length.expr() {
39                ConstGenericExpr::Literal { .. } => {}
40                ConstGenericExpr::AmbiguousVariableExpression { .. } => return true,
41            },
42            TypeInfo::Enum(decl_id) => {
43                let decl = engines.de().get(decl_id);
44                let any_const_generics = decl
45                    .generic_parameters
46                    .iter()
47                    .any(|x| x.as_const_parameter().is_some());
48                if any_const_generics {
49                    return true;
50                }
51            }
52            TypeInfo::Struct(decl_id) => {
53                let decl = engines.de().get(decl_id);
54                let any_const_generics = decl
55                    .generic_parameters
56                    .iter()
57                    .any(|x| x.as_const_parameter().is_some());
58                if any_const_generics {
59                    return true;
60                }
61
62                for field in decl.fields.iter() {
63                    let any_const_generics =
64                        has_const_generics(field.type_argument.type_id, engines);
65                    if any_const_generics {
66                        return true;
67                    }
68                }
69            }
70            TypeInfo::Tuple(items) => {
71                for item in items {
72                    let any_const_generics = has_const_generics(item.type_id, engines);
73                    if any_const_generics {
74                        return true;
75                    }
76                }
77            }
78            TypeInfo::Array(item, length) => {
79                let any_const_generics = has_const_generics(item.type_id, engines);
80                if any_const_generics {
81                    return true;
82                }
83
84                match length.expr() {
85                    ConstGenericExpr::Literal { .. } => {}
86                    ConstGenericExpr::AmbiguousVariableExpression { .. } => return true,
87                }
88            }
89            _ => {}
90        }
91    }
92
93    false
94}
95
96impl TyAbiDecl {
97    pub(crate) fn forbid_const_generics(
98        &self,
99        handler: &Handler,
100        engines: &Engines,
101    ) -> Result<(), ErrorEmitted> {
102        for item in self.interface_surface.iter() {
103            match item {
104                TyTraitInterfaceItem::TraitFn(decl_ref) => {
105                    let decl = engines.de().get(decl_ref.id());
106
107                    if has_const_generics(decl.return_type.type_id, engines) {
108                        let err = handler.emit_err(CompileError::ConstGenericNotSupportedHere {
109                            span: decl.return_type.span(),
110                        });
111                        return Err(err);
112                    }
113
114                    for arg in decl.parameters.iter() {
115                        if has_const_generics(arg.type_argument.type_id, engines) {
116                            let err =
117                                handler.emit_err(CompileError::ConstGenericNotSupportedHere {
118                                    span: arg.type_argument.span.clone(),
119                                });
120                            return Err(err);
121                        }
122                    }
123                }
124                TyTraitInterfaceItem::Constant(_) => {}
125                TyTraitInterfaceItem::Type(_) => {}
126            }
127        }
128
129        for item in self.items.iter() {
130            match item {
131                TyTraitItem::Fn(decl_ref) => {
132                    let decl = engines.de().get(decl_ref.id());
133                    if has_const_generics(decl.return_type.type_id, engines) {
134                        let err = handler.emit_err(CompileError::ConstGenericNotSupportedHere {
135                            span: decl.return_type.span(),
136                        });
137                        return Err(err);
138                    }
139
140                    for arg in decl.parameters.iter() {
141                        if has_const_generics(arg.type_argument.type_id, engines) {
142                            let err =
143                                handler.emit_err(CompileError::ConstGenericNotSupportedHere {
144                                    span: arg.type_argument.span.clone(),
145                                });
146                            return Err(err);
147                        }
148                    }
149                }
150                TyTraitItem::Constant(_) => {}
151                TyTraitItem::Type(_) => {}
152            }
153        }
154
155        Ok(())
156    }
157}
158
159impl TyDeclParsedType for TyAbiDecl {
160    type ParsedType = AbiDeclaration;
161}
162
163impl EqWithEngines for TyAbiDecl {}
164impl PartialEqWithEngines for TyAbiDecl {
165    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
166        let TyAbiDecl {
167            name: ln,
168            interface_surface: lis,
169            supertraits: ls,
170            items: li,
171            // these fields are not compared because they aren't relevant/a
172            // reliable source of obj v. obj distinction
173            attributes: _,
174            span: _,
175        } = self;
176        let TyAbiDecl {
177            name: rn,
178            interface_surface: ris,
179            supertraits: rs,
180            items: ri,
181            // these fields are not compared because they aren't relevant/a
182            // reliable source of obj v. obj distinction
183            attributes: _,
184            span: _,
185        } = other;
186        ln == rn && lis.eq(ris, ctx) && li.eq(ri, ctx) && ls.eq(rs, ctx)
187    }
188}
189
190impl HashWithEngines for TyAbiDecl {
191    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
192        let TyAbiDecl {
193            name,
194            interface_surface,
195            items,
196            supertraits,
197            // these fields are not hashed because they aren't relevant/a
198            // reliable source of obj v. obj distinction
199            attributes: _,
200            span: _,
201        } = self;
202        name.hash(state);
203        interface_surface.hash(state, engines);
204        items.hash(state, engines);
205        supertraits.hash(state, engines);
206    }
207}
208
209impl CreateTypeId for TyAbiDecl {
210    fn create_type_id(&self, engines: &Engines) -> TypeId {
211        engines
212            .te()
213            .new_contract_caller(engines, AbiName::Known(self.name.clone().into()), None)
214    }
215}
216
217impl Spanned for TyAbiDecl {
218    fn span(&self) -> Span {
219        self.span.clone()
220    }
221}
222
223impl Named for TyAbiDecl {
224    fn name(&self) -> &Ident {
225        &self.name
226    }
227}