1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use sway_error::error::CompileError;
use sway_types::Spanned;
use crate::{
decl_engine::DeclEngineInsert,
error::*,
language::{
parsed::*,
ty::{self, TyTraitItem},
},
semantic_analysis::{declaration::insert_supertraits_into_namespace, Mode, TypeCheckContext},
CompileResult,
};
impl ty::TyAbiDecl {
pub(crate) fn type_check(
ctx: TypeCheckContext,
abi_decl: AbiDeclaration,
) -> CompileResult<Self> {
let mut warnings = vec![];
let mut errors = vec![];
let AbiDeclaration {
name,
interface_surface,
supertraits,
methods,
span,
attributes,
} = abi_decl;
// We don't want the user to waste resources by contract calling
// themselves, and we don't want to do more work in the compiler,
// so we don't support the case of calling a contract's own interface
// from itself. This is by design.
// A temporary namespace for checking within this scope.
let type_engine = ctx.type_engine;
let decl_engine = ctx.decl_engine;
let contract_type = type_engine.insert(decl_engine, crate::TypeInfo::Contract);
let mut abi_namespace = ctx.namespace.clone();
let mut ctx = ctx.scoped(&mut abi_namespace).with_mode(Mode::ImplAbiFn);
// Recursively make the interface surfaces and methods of the
// supertraits available to this abi.
check!(
insert_supertraits_into_namespace(ctx.by_ref(), contract_type, &supertraits),
return err(warnings, errors),
warnings,
errors
);
// Type check the interface surface.
let mut new_interface_surface = vec![];
for item in interface_surface.into_iter() {
match item {
TraitItem::TraitFn(method) => {
let method = check!(
ty::TyTraitFn::type_check(ctx.by_ref(), method),
return err(warnings, errors),
warnings,
errors
);
for param in &method.parameters {
if param.is_reference || param.is_mutable {
errors.push(CompileError::RefMutableNotAllowedInContractAbi {
param_name: param.name.clone(),
span: param.name.span(),
})
}
}
new_interface_surface.push(ty::TyTraitInterfaceItem::TraitFn(
ctx.decl_engine.insert(method),
));
}
TraitItem::Constant(_) => {
// not implemented for now since abis and traits will be unified soon
todo!();
}
}
}
// Type check the methods.
let mut new_items = vec![];
for method in methods.into_iter() {
let method = check!(
ty::TyFunctionDecl::type_check(ctx.by_ref(), method.clone(), true, false),
ty::TyFunctionDecl::error(method.clone()),
warnings,
errors
);
for param in &method.parameters {
if param.is_reference || param.is_mutable {
errors.push(CompileError::RefMutableNotAllowedInContractAbi {
param_name: param.name.clone(),
span: param.name.span(),
})
}
}
new_items.push(TyTraitItem::Fn(ctx.decl_engine.insert(method)));
}
// Compared to regular traits, we do not insert recursively methods of ABI supertraits
// into the interface surface, we do not want supertrait methods to be available to
// the ABI user, only the contract methods can use supertrait methods
let abi_decl = ty::TyAbiDecl {
interface_surface: new_interface_surface,
supertraits,
items: new_items,
name,
span,
attributes,
};
ok(abi_decl, warnings, errors)
}
}