diff --git a/crates/abi/src/builder.rs b/crates/abi/src/builder.rs index 765f323ac6..518b34fd8d 100644 --- a/crates/abi/src/builder.rs +++ b/crates/abi/src/builder.rs @@ -3,7 +3,7 @@ use crate::elements::{ ModuleAbis, }; use crate::AbiError; -use fe_analyzer::namespace::items::{ContractId, ModuleId}; +use fe_analyzer::namespace::items::{ContractId, FunctionId, ModuleId}; use fe_analyzer::namespace::types; use fe_analyzer::AnalyzerDb; @@ -50,55 +50,52 @@ fn contract_def(db: &dyn AnalyzerDb, contract: ContractId) -> Contract { }) .collect(); - let functions = contract - .functions(db) + let mut functions = contract + .public_functions(db) .iter() - .filter_map(|(name, func)| { - if func.is_public(db) { - let sig = func.signature(db); - let (name, func_type) = match name.as_str() { - "__init__" => ("".to_owned(), FuncType::Constructor), - _ => (name.to_owned(), FuncType::Function), - }; + .map(|(name, func)| function_def(db, name, *func, FuncType::Function)) + .collect::>(); - let inputs = sig - .params - .iter() - .map(|param| { - let typ = param.typ.clone().expect("function parameter type error"); + if let Some(init_fn) = contract.init_function(db) { + functions.push(function_def(db, "", init_fn, FuncType::Constructor)); + } - FuncInput { - name: param.name.to_owned(), - typ: typ.abi_json_name(), - components: components(db, &typ), - } - }) - .collect(); + Contract { events, functions } +} - let return_type = sig.return_type.clone().expect("function return type error"); - let outputs = if return_type.is_unit() { - vec![] - } else { - vec![FuncOutput { - name: "".to_string(), - typ: return_type.abi_json_name(), - components: components(db, &return_type), - }] - }; +fn function_def(db: &dyn AnalyzerDb, name: &str, fn_id: FunctionId, typ: FuncType) -> Function { + let sig = fn_id.signature(db); + let inputs = sig + .params + .iter() + .map(|param| { + let typ = param.typ.clone().expect("function parameter type error"); - Some(Function { - name, - typ: func_type, - inputs, - outputs, - }) - } else { - None + FuncInput { + name: param.name.to_owned(), + typ: typ.abi_json_name(), + components: components(db, &typ), } }) .collect(); - Contract { events, functions } + let return_type = sig.return_type.clone().expect("function return type error"); + let outputs = if return_type.is_unit() { + vec![] + } else { + vec![FuncOutput { + name: "".to_string(), + typ: return_type.abi_json_name(), + components: components(db, &return_type), + }] + }; + + Function { + name: name.to_string(), + typ, + inputs, + outputs, + } } fn components(db: &dyn AnalyzerDb, typ: &types::FixedSize) -> Vec { @@ -157,13 +154,13 @@ mod tests { assert_eq!(abi.events[0].name, "Food"); // function count assert_eq!(abi.functions.len(), 2); - // __init__ - assert_eq!(abi.functions[0].name, ""); - assert_eq!(abi.functions[0].inputs[0].typ, "address",); // bar - assert_eq!(abi.functions[1].name, "bar",); - assert_eq!(abi.functions[1].inputs[0].typ, "uint256",); - assert_eq!(abi.functions[1].outputs[0].typ, "uint256[10]",); + assert_eq!(abi.functions[0].name, "bar",); + assert_eq!(abi.functions[0].inputs[0].typ, "uint256",); + assert_eq!(abi.functions[0].outputs[0].typ, "uint256[10]",); + // __init__ always comes after normal functions + assert_eq!(abi.functions[1].name, ""); + assert_eq!(abi.functions[1].inputs[0].typ, "address",); } else { panic!("contract \"Foo\" not found in module") } diff --git a/crates/analyzer/src/db.rs b/crates/analyzer/src/db.rs index 6aac0a2a6e..09cbe95c22 100644 --- a/crates/analyzer/src/db.rs +++ b/crates/analyzer/src/db.rs @@ -45,6 +45,7 @@ pub trait AnalyzerDb { #[salsa::interned] fn intern_event(&self, data: Rc) -> EventId; + // Module #[salsa::invoke(queries::module::module_all_type_defs)] fn module_all_type_defs(&self, module: ModuleId) -> Rc>; #[salsa::invoke(queries::module::module_type_def_map)] @@ -61,14 +62,21 @@ pub trait AnalyzerDb { #[salsa::invoke(queries::module::module_structs)] fn module_structs(&self, module: ModuleId) -> Rc>; + // Contract #[salsa::invoke(queries::contracts::contract_all_functions)] fn contract_all_functions(&self, id: ContractId) -> Rc>; #[salsa::invoke(queries::contracts::contract_function_map)] fn contract_function_map(&self, id: ContractId) -> Analysis>>; + #[salsa::invoke(queries::contracts::contract_public_function_map)] + fn contract_public_function_map(&self, id: ContractId) -> Rc>; + #[salsa::invoke(queries::contracts::contract_init_function)] + fn contract_init_function(&self, id: ContractId) -> Analysis>; + #[salsa::invoke(queries::contracts::contract_all_events)] fn contract_all_events(&self, id: ContractId) -> Rc>; #[salsa::invoke(queries::contracts::contract_event_map)] fn contract_event_map(&self, id: ContractId) -> Analysis>>; + #[salsa::invoke(queries::contracts::contract_all_fields)] fn contract_all_fields(&self, id: ContractId) -> Rc>; #[salsa::invoke(queries::contracts::contract_field_map)] @@ -80,11 +88,13 @@ pub trait AnalyzerDb { field: ContractFieldId, ) -> Analysis>; + // Function #[salsa::invoke(queries::functions::function_signature)] fn function_signature(&self, id: FunctionId) -> Analysis>; #[salsa::invoke(queries::functions::function_body)] fn function_body(&self, id: FunctionId) -> Analysis>; + // Struct #[salsa::invoke(queries::structs::struct_type)] fn struct_type(&self, id: StructId) -> Rc; #[salsa::invoke(queries::structs::struct_all_fields)] @@ -97,9 +107,11 @@ pub trait AnalyzerDb { field: StructFieldId, ) -> Analysis>; + // Event #[salsa::invoke(queries::events::event_type)] fn event_type(&self, event: EventId) -> Analysis>; + // Type alias #[salsa::invoke(queries::types::type_alias_type)] #[salsa::cycle(queries::types::type_alias_type_cycle)] fn type_alias_type(&self, id: TypeAliasId) -> Analysis>; diff --git a/crates/analyzer/src/db/queries/contracts.rs b/crates/analyzer/src/db/queries/contracts.rs index aef6acb0af..b7782f6154 100644 --- a/crates/analyzer/src/db/queries/contracts.rs +++ b/crates/analyzer/src/db/queries/contracts.rs @@ -5,6 +5,7 @@ use crate::namespace::items::{self, ContractFieldId, ContractId, EventId, Functi use crate::namespace::scopes::ItemScope; use crate::namespace::types; use crate::traversal::types::type_desc; +use fe_common::diagnostics::Label; use fe_parser::ast; use indexmap::map::{Entry, IndexMap}; @@ -36,9 +37,11 @@ pub fn contract_function_map( for func in contract.all_functions(db).iter() { let def = &func.data(db).ast; - let name = def.name().to_string(); + if def.name() == "__init__" { + continue; + } - match map.entry(name) { + match map.entry(def.name().to_string()) { Entry::Occupied(entry) => { scope.duplicate_name_error( &format!( @@ -61,6 +64,71 @@ pub fn contract_function_map( } } +pub fn contract_public_function_map( + db: &dyn AnalyzerDb, + contract: ContractId, +) -> Rc> { + Rc::new( + contract + .functions(db) + .iter() + .filter_map(|(name, func)| func.is_public(db).then(|| (name.clone(), *func))) + .collect(), + ) +} + +pub fn contract_init_function( + db: &dyn AnalyzerDb, + contract: ContractId, +) -> Analysis> { + let all_fns = contract.all_functions(db); + let mut init_fns = all_fns.iter().filter_map(|func| { + let def = &func.data(db).ast; + (def.name() == "__init__").then(|| (func, def.span)) + }); + + let mut diagnostics = vec![]; + + let first_def = init_fns.next(); + if let Some((_, dupe_span)) = init_fns.next() { + let mut labels = vec![ + Label::primary(first_def.unwrap().1, "`__init__` first defined here"), + Label::secondary(dupe_span, "`init` redefined here"), + ]; + for (_, dupe_span) in init_fns { + labels.push(Label::secondary(dupe_span, "`init` redefined here")); + } + diagnostics.push(errors::fancy_error( + &format!( + "`fn __init__()` is defined multiple times in `contract {}`", + contract.name(db), + ), + labels, + vec![], + )); + } + + if let Some((id, span)) = first_def { + // `__init__` must be `pub`. + // Return type is checked in `queries::functions::function_signature`. + if !id.data(db).ast.kind.is_pub { + diagnostics.push(errors::fancy_error( + "`__init__` function is not public", + vec![Label::primary(span, "`__init__` function must be public")], + vec![ + "Hint: Add the `pub` modifier.".to_string(), + "Example: `pub fn __init__():`".to_string(), + ], + )); + } + } + + Analysis { + value: first_def.map(|(id, _span)| *id), + diagnostics: Rc::new(diagnostics), + } +} + pub fn contract_all_events(db: &dyn AnalyzerDb, contract: ContractId) -> Rc> { let body = &contract.data(db).ast.kind.body; Rc::new( diff --git a/crates/analyzer/src/db/queries/functions.rs b/crates/analyzer/src/db/queries/functions.rs index 7702b1b0b2..e32e7a2f26 100644 --- a/crates/analyzer/src/db/queries/functions.rs +++ b/crates/analyzer/src/db/queries/functions.rs @@ -65,21 +65,6 @@ pub fn function_signature( }) .collect(); - // `__init__` must be `pub`. - if def.name.kind == "__init__" && !def.is_pub { - scope.fancy_error( - "`__init__` function is not public", - vec![Label::primary( - node.span, - "`__init__` function must be public", - )], - vec![ - "Hint: Add the `pub` modifier.".to_string(), - "Example: `pub fn __init__():`".to_string(), - ], - ); - } - let return_type = def .return_type .as_ref() diff --git a/crates/analyzer/src/namespace/items.rs b/crates/analyzer/src/namespace/items.rs index ae959a876d..e42fadce05 100644 --- a/crates/analyzer/src/namespace/items.rs +++ b/crates/analyzer/src/namespace/items.rs @@ -218,28 +218,46 @@ impl ContractId { Some((field.typ(db), index)) } - pub fn function(&self, db: &dyn AnalyzerDb, name: &str) -> Option { - self.functions(db).get(name).copied() + pub fn init_function(&self, db: &dyn AnalyzerDb) -> Option { + db.contract_init_function(*self).value } + /// User functions, public and not. Excludes `__init__`. pub fn functions(&self, db: &dyn AnalyzerDb) -> Rc> { db.contract_function_map(*self).value } - /// All functions, including duplicates + /// Lookup a function by name. Searches all user functions, private or not. Excludes init function. + pub fn function(&self, db: &dyn AnalyzerDb, name: &str) -> Option { + self.functions(db).get(name).copied() + } + + /// Excludes `__init__`. + pub fn public_functions(&self, db: &dyn AnalyzerDb) -> Rc> { + db.contract_public_function_map(*self) + } + + /// Lookup a function by name. Matches on public and private functions, excludes init function. + pub fn public_function(&self, db: &dyn AnalyzerDb, name: &str) -> Option { + self.public_functions(db).get(name).copied() + } + + /// A `Vec` of every function defined in the contract, including duplicates and the init function. pub fn all_functions(&self, db: &dyn AnalyzerDb) -> Rc> { db.contract_all_functions(*self) } + /// Lookup an event by name. pub fn event(&self, db: &dyn AnalyzerDb, name: &str) -> Option { self.events(db).get(name).copied() } + /// A map of events defined within the contract. pub fn events(&self, db: &dyn AnalyzerDb) -> Rc> { db.contract_event_map(*self).value } - /// All events, including duplicates + /// A `Vec` of all events defined within the contract, including those with duplicate names. pub fn all_events(&self, db: &dyn AnalyzerDb) -> Rc> { db.contract_all_events(*self) } @@ -258,6 +276,7 @@ impl ContractId { .for_each(|event| event.sink_diagnostics(db, sink)); // functions + db.contract_init_function(*self).sink_diagnostics(sink); db.contract_function_map(*self).sink_diagnostics(sink); db.contract_all_functions(*self) .iter() diff --git a/crates/analyzer/src/traversal/expressions.rs b/crates/analyzer/src/traversal/expressions.rs index dc7ed98c6b..b1095eda2a 100644 --- a/crates/analyzer/src/traversal/expressions.rs +++ b/crates/analyzer/src/traversal/expressions.rs @@ -820,12 +820,34 @@ fn expr_call_args( .collect::, _>>() } +fn check_for_call_to_init_fn( + scope: &mut BlockScope, + name: &str, + span: Span, +) -> Result<(), FatalError> { + if name == "__init__" { + scope.fancy_error( + "`__init__()` is not directly callable", + vec![Label::primary(span, "")], + vec![ + "Note: `__init__` is the constructor function, and can't be called at runtime." + .into(), + ], + ); + Err(FatalError::new()) + } else { + Ok(()) + } +} + fn expr_call_self_attribute( scope: &mut BlockScope, func_name: &str, name_span: Span, args: &Node>>, ) -> Result { + check_for_call_to_init_fn(scope, func_name, name_span)?; + if let Some(func) = scope.root.contract_function(func_name) { let sig = func.signature(scope.root.db); validate_arg_count(scope, func_name, name_span, args, sig.params.len()); @@ -1034,6 +1056,8 @@ fn expr_call_type_attribute( vec![format!("Note: Consider using a dedicated factory contract to create instances of `{}`", contract_name)]); }; + // TODO: we should check for SomeContract.__init__() here and suggest create/create2 + match (typ.clone(), ContractTypeMethod::from_str(func_name)) { (Type::Contract(contract), Ok(ContractTypeMethod::Create2)) => { validate_arg_count(scope, func_name, name_span, args, 2); @@ -1095,7 +1119,9 @@ fn expr_call_contract_attribute( name_span: Span, args: &Node>>, ) -> Result { - if let Some(function) = contract.id.function(scope.db(), func_name) { + check_for_call_to_init_fn(scope, func_name, name_span)?; + + if let Some(function) = contract.id.public_function(scope.db(), func_name) { let sig = function.signature(scope.db()); let return_type = sig.return_type.clone()?; @@ -1104,6 +1130,22 @@ fn expr_call_contract_attribute( let location = Location::assign_location(&return_type); Ok(ExpressionAttributes::new(return_type.into(), location)) + } else if let Some(function) = contract.id.function(scope.db(), func_name) { + scope.fancy_error( + &format!( + "The function `{}` on `contract {}` is private", + func_name, contract.name + ), + vec![ + Label::primary(name_span, "this function is not `pub`"), + Label::secondary( + function.data(scope.db()).ast.span, + format!("`{}` is defined here", func_name), + ), + ], + vec![], + ); + Err(FatalError::new()) } else { scope.fancy_error( &format!( diff --git a/crates/analyzer/tests/errors.rs b/crates/analyzer/tests/errors.rs index a0bb195318..516846224a 100644 --- a/crates/analyzer/tests/errors.rs +++ b/crates/analyzer/tests/errors.rs @@ -149,6 +149,7 @@ test_file! { call_keccak_with_wrong_type } test_file! { call_undefined_function_on_external_contract } test_file! { call_undefined_function_on_memory_struct } test_file! { call_undefined_function_on_storage_struct } +test_file! { call_non_pub_fn_on_external_contract } test_file! { cannot_move } test_file! { cannot_move2 } test_file! { circular_dependency_create } @@ -201,6 +202,9 @@ test_file! { struct_call_bad_args } test_file! { struct_call_without_kw_args } test_file! { non_pub_init } test_file! { init_wrong_return_type } +test_file! { init_duplicate_def } +test_file! { init_call_on_self } +test_file! { init_call_on_external_contract } test_file! { abi_encode_u256 } test_file! { abi_encode_from_storage } test_file! { assert_sto_msg_no_copy } diff --git a/crates/analyzer/tests/snapshots/errors__call_non_pub_fn_on_external_contract.snap b/crates/analyzer/tests/snapshots/errors__call_non_pub_fn_on_external_contract.snap new file mode 100644 index 0000000000..6a01751fcb --- /dev/null +++ b/crates/analyzer/tests/snapshots/errors__call_non_pub_fn_on_external_contract.snap @@ -0,0 +1,16 @@ +--- +source: crates/analyzer/tests/errors.rs +expression: "error_string(&path, &src)" + +--- +error: The function `do_private_thingz` on `contract Foo` is private + ┌─ compile_errors/call_non_pub_fn_on_external_contract.fe:9:21 + │ +4 │ ╭ fn do_private_thingz(): +5 │ │ self.val = 100 + │ ╰───────────────────' `do_private_thingz` is defined here + · │ +9 │ Foo(address(0)).do_private_thingz() + │ ^^^^^^^^^^^^^^^^^ this function is not `pub` + + diff --git a/crates/analyzer/tests/snapshots/errors__init_call_on_external_contract.snap b/crates/analyzer/tests/snapshots/errors__init_call_on_external_contract.snap new file mode 100644 index 0000000000..78e6184a72 --- /dev/null +++ b/crates/analyzer/tests/snapshots/errors__init_call_on_external_contract.snap @@ -0,0 +1,14 @@ +--- +source: crates/analyzer/tests/errors.rs +expression: "error_string(&path, &src)" + +--- +error: `__init__()` is not directly callable + ┌─ compile_errors/init_call_on_external_contract.fe:12:9 + │ +12 │ foo.__init__() + │ ^^^^^^^^ + │ + = Note: `__init__` is the constructor function, and can't be called at runtime. + + diff --git a/crates/analyzer/tests/snapshots/errors__init_call_on_self.snap b/crates/analyzer/tests/snapshots/errors__init_call_on_self.snap new file mode 100644 index 0000000000..cb8f3a4055 --- /dev/null +++ b/crates/analyzer/tests/snapshots/errors__init_call_on_self.snap @@ -0,0 +1,14 @@ +--- +source: crates/analyzer/tests/errors.rs +expression: "error_string(&path, &src)" + +--- +error: `__init__()` is not directly callable + ┌─ compile_errors/init_call_on_self.fe:6:5 + │ +6 │ self.__init__() + │ ^^^^^^^^^^^^^ + │ + = Note: `__init__` is the constructor function, and can't be called at runtime. + + diff --git a/crates/analyzer/tests/snapshots/errors__init_duplicate_def.snap b/crates/analyzer/tests/snapshots/errors__init_duplicate_def.snap new file mode 100644 index 0000000000..6925d61ce5 --- /dev/null +++ b/crates/analyzer/tests/snapshots/errors__init_duplicate_def.snap @@ -0,0 +1,21 @@ +--- +source: crates/analyzer/tests/errors.rs +expression: "error_string(&path, &src)" + +--- +error: `fn __init__()` is defined multiple times in `contract Foo` + ┌─ compile_errors/init_duplicate_def.fe:2:5 + │ + 2 │ ╭ pub fn __init__(): + 3 │ │ pass + │ ╰────────────────^ `__init__` first defined here + · │ + 8 │ ╭ pub fn __init__(): + 9 │ │ 1 + 2 + │ ╰───────────────' `init` redefined here +10 │ +11 │ ╭ pub fn __init__(): +12 │ │ 3 + 4 + │ ╰─────────────' `init` redefined here + + diff --git a/crates/analyzer/tests/snapshots/errors__init_wrong_return_type.snap b/crates/analyzer/tests/snapshots/errors__init_wrong_return_type.snap index e2c5420704..7dea1c441b 100644 --- a/crates/analyzer/tests/snapshots/errors__init_wrong_return_type.snap +++ b/crates/analyzer/tests/snapshots/errors__init_wrong_return_type.snap @@ -3,21 +3,11 @@ source: crates/analyzer/tests/errors.rs expression: "error_string(&path, &src)" --- -error: `__init__` function is not public - ┌─ compile_errors/init_wrong_return_type.fe:2:5 - │ -2 │ ╭ fn __init__() -> u64: -3 │ │ return 10 - │ ╰─────────────────^ `__init__` function must be public - │ - = Hint: Add the `pub` modifier. - = Example: `pub fn __init__():` - error: `__init__` function has incorrect return type - ┌─ compile_errors/init_wrong_return_type.fe:2:22 + ┌─ compile_errors/init_wrong_return_type.fe:2:26 │ -2 │ fn __init__() -> u64: - │ ^^^ return type should be `()` +2 │ pub fn __init__() -> u64: + │ ^^^ return type should be `()` │ = Hint: Remove the return type specification. = Example: `pub fn __init__():` diff --git a/crates/test-files/fixtures/compile_errors/call_non_pub_fn_on_external_contract.fe b/crates/test-files/fixtures/compile_errors/call_non_pub_fn_on_external_contract.fe new file mode 100644 index 0000000000..34e9c947bf --- /dev/null +++ b/crates/test-files/fixtures/compile_errors/call_non_pub_fn_on_external_contract.fe @@ -0,0 +1,9 @@ + +contract Foo: + val: u8 + fn do_private_thingz(): + self.val = 100 + +contract Bar: + fn test(): + Foo(address(0)).do_private_thingz() diff --git a/crates/test-files/fixtures/compile_errors/init_call_on_external_contract.fe b/crates/test-files/fixtures/compile_errors/init_call_on_external_contract.fe new file mode 100644 index 0000000000..3754ebc441 --- /dev/null +++ b/crates/test-files/fixtures/compile_errors/init_call_on_external_contract.fe @@ -0,0 +1,12 @@ +contract Foo: + pub fn __init__(): + pass + pub fn f(): + pass + + +contract Bar: + fn b(): + foo: Foo = Foo(address(0)) + foo.f() + foo.__init__() diff --git a/crates/test-files/fixtures/compile_errors/init_call_on_self.fe b/crates/test-files/fixtures/compile_errors/init_call_on_self.fe new file mode 100644 index 0000000000..4ea3bd3649 --- /dev/null +++ b/crates/test-files/fixtures/compile_errors/init_call_on_self.fe @@ -0,0 +1,6 @@ +contract Foo: + pub fn __init__(): + pass + + fn bar(): + self.__init__() \ No newline at end of file diff --git a/crates/test-files/fixtures/compile_errors/init_duplicate_def.fe b/crates/test-files/fixtures/compile_errors/init_duplicate_def.fe new file mode 100644 index 0000000000..f50a160553 --- /dev/null +++ b/crates/test-files/fixtures/compile_errors/init_duplicate_def.fe @@ -0,0 +1,12 @@ +contract Foo: + pub fn __init__(): + pass + + pub fn bar(): + pass + + pub fn __init__(): + 1 + 2 + + pub fn __init__(): + 3 + 4 diff --git a/crates/test-files/fixtures/compile_errors/init_wrong_return_type.fe b/crates/test-files/fixtures/compile_errors/init_wrong_return_type.fe index 3482087c09..56e02ab555 100644 --- a/crates/test-files/fixtures/compile_errors/init_wrong_return_type.fe +++ b/crates/test-files/fixtures/compile_errors/init_wrong_return_type.fe @@ -1,3 +1,3 @@ contract Foo: - fn __init__() -> u64: + pub fn __init__() -> u64: return 10 \ No newline at end of file diff --git a/crates/yulgen/src/mappers/contracts.rs b/crates/yulgen/src/mappers/contracts.rs index 2531d50580..14c5cc47a4 100644 --- a/crates/yulgen/src/mappers/contracts.rs +++ b/crates/yulgen/src/mappers/contracts.rs @@ -17,9 +17,9 @@ pub fn contract_def( let contract_name = contract.name(db); let mut context = ContractContext::default(); - let init_function = contract.functions(db).get("__init__").map(|id| { + let init_function = contract.init_function(db).map(|id| { ( - functions::func_def(db, &mut context, *id), + functions::func_def(db, &mut context, id), id.signature(db) .params .iter() @@ -30,11 +30,8 @@ pub fn contract_def( let user_functions = contract .functions(db) - .iter() - .filter_map(|(name, function)| match name.as_str() { - "__init__" => None, - _ => Some(functions::func_def(db, &mut context, *function)), - }) + .values() + .map(|func| functions::func_def(db, &mut context, *func)) .collect::>(); // build the set of functions needed during runtime diff --git a/crates/yulgen/src/runtime/mod.rs b/crates/yulgen/src/runtime/mod.rs index 63eb9e1c96..764f413fd9 100644 --- a/crates/yulgen/src/runtime/mod.rs +++ b/crates/yulgen/src/runtime/mod.rs @@ -38,9 +38,9 @@ pub fn build( .concat(); let public_functions: Vec> = contract - .all_functions(db) - .iter() - .filter_map(|func| func.is_public(db).then(|| func.signature(db))) + .public_functions(db) + .values() + .map(|func| func.signature(db)) .collect(); let encoding = { @@ -134,7 +134,7 @@ pub fn build( }) .collect(); - let init_params_batch = if let Some(init_fn) = contract.function(db, "__init__") { + let init_params_batch = if let Some(init_fn) = contract.init_function(db) { let sig = init_fn.signature(db); vec![( to_abi_types(db, &sig.param_types()), @@ -218,27 +218,25 @@ pub fn build_with_abi_dispatcher( contract: ContractId, ) -> Vec { let public_functions = contract - .functions(db) + .public_functions(db) .iter() - .filter_map(|(name, id)| { - (name != "__init__" && id.is_public(db)).then(|| { - let sig = id.signature(db); - let return_type = sig.return_type.clone().expect("fn return type error"); - let return_type = (!return_type.is_unit()).then(|| return_type.as_abi_type(db)); - let param_types = sig - .params - .iter() - .map(|param| { - param - .typ - .clone() - .expect("fn param type error") - .as_abi_type(db) - }) - .collect::>(); + .map(|(name, id)| { + let sig = id.signature(db); + let return_type = sig.return_type.clone().expect("fn return type error"); + let return_type = (!return_type.is_unit()).then(|| return_type.as_abi_type(db)); + let param_types = sig + .params + .iter() + .map(|param| { + param + .typ + .clone() + .expect("fn param type error") + .as_abi_type(db) + }) + .collect::>(); - (name.to_string(), param_types, return_type) - }) + (name.to_string(), param_types, return_type) }) .collect::>();