From 1b1ac45f8cd374c805ad986ab6ba25dd30b1d4ee Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Sun, 3 Nov 2024 11:45:14 +0000 Subject: [PATCH 01/31] forbid initialization of a stateless module --- vyper/semantics/analysis/module.py | 3 +++ vyper/semantics/analysis/utils.py | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/vyper/semantics/analysis/module.py b/vyper/semantics/analysis/module.py index 8a2beb61e6..e67276c5a2 100644 --- a/vyper/semantics/analysis/module.py +++ b/vyper/semantics/analysis/module.py @@ -37,6 +37,7 @@ check_modifiability, get_exact_type_from_node, get_expr_info, + is_stateless, ) from vyper.semantics.data_locations import DataLocation from vyper.semantics.namespace import Namespace, get_namespace, override_global_namespace @@ -409,6 +410,8 @@ def visit_InitializesDecl(self, node): module_info = get_expr_info(module_ref).module_info if module_info is None: raise StructureException("Not a module!", module_ref) + if is_stateless(module_info.module_node): + raise StructureException(f"Cannot initialize a stateless module {module_info.alias}!", module_ref) used_modules = {i.module_t: i for i in module_info.module_t.used_modules} diff --git a/vyper/semantics/analysis/utils.py b/vyper/semantics/analysis/utils.py index 9734087fc3..b76aebf02a 100644 --- a/vyper/semantics/analysis/utils.py +++ b/vyper/semantics/analysis/utils.py @@ -736,3 +736,16 @@ def validate_kwargs(node: vy_ast.Call, members: dict[str, VyperType], typeclass: msg = f"{typeclass} instantiation missing fields:" msg += f" {', '.join(list(missing))}" raise InstantiationException(msg, node) + +def is_stateless(module: vy_ast.Module): + """ + Determine whether a module is stateless by examining its top-level declarations. + A module has state if it contains storage variables, transient variables, or + immutables, or if it includes a "uses" or "initializes" declaration. + """ + for i in module.body: + if isinstance(i, (vy_ast.InitializesDecl, vy_ast.UsesDecl)): + return False + if isinstance(i, vy_ast.VariableDecl) and not i.is_constant: + return False + return True From 3a9e29dbc384aa801759ba2da459ed086eea424d Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Sun, 3 Nov 2024 11:51:41 +0000 Subject: [PATCH 02/31] fix tests so they do not initialize a stateless module --- tests/functional/codegen/modules/test_nonreentrant.py | 4 ++++ tests/functional/syntax/modules/test_initializers.py | 2 ++ tests/unit/compiler/test_abi.py | 8 ++++++++ 3 files changed, 14 insertions(+) diff --git a/tests/functional/codegen/modules/test_nonreentrant.py b/tests/functional/codegen/modules/test_nonreentrant.py index 69b17cbfa2..ea3297eea9 100644 --- a/tests/functional/codegen/modules/test_nonreentrant.py +++ b/tests/functional/codegen/modules/test_nonreentrant.py @@ -1,5 +1,7 @@ def test_export_nonreentrant(make_input_bundle, get_contract, tx_failed): lib1 = """ +phony: uint32 + interface Foo: def foo() -> uint256: nonpayable @@ -38,6 +40,8 @@ def __default__(): def test_internal_nonreentrant(make_input_bundle, get_contract, tx_failed): lib1 = """ +phony: uint32 + interface Foo: def foo() -> uint256: nonpayable diff --git a/tests/functional/syntax/modules/test_initializers.py b/tests/functional/syntax/modules/test_initializers.py index ead0fbcf6b..cac284fbba 100644 --- a/tests/functional/syntax/modules/test_initializers.py +++ b/tests/functional/syntax/modules/test_initializers.py @@ -835,6 +835,8 @@ def test_uses_skip_import(make_input_bundle): lib2 = """ import lib1 +phony: uint32 + @internal def foo(): pass diff --git a/tests/unit/compiler/test_abi.py b/tests/unit/compiler/test_abi.py index 430cd75344..f0f92d2ec4 100644 --- a/tests/unit/compiler/test_abi.py +++ b/tests/unit/compiler/test_abi.py @@ -218,6 +218,8 @@ def bar(x: {type}): def test_exports_abi(make_input_bundle): lib1 = """ +phony: uint32 + @external def foo(): pass @@ -330,6 +332,8 @@ def __init__(): def test_event_export_from_init(make_input_bundle): # test that events get exported when used in init functions lib1 = """ +phony: uint32 + event MyEvent: pass @@ -361,6 +365,8 @@ def __init__(): def test_event_export_from_function_export(make_input_bundle): # test events used in exported functions are exported lib1 = """ +phony: uint32 + event MyEvent: pass @@ -396,6 +402,8 @@ def foo(): def test_event_export_unused_function(make_input_bundle): # test events in unused functions are not exported lib1 = """ +phony: uint32 + event MyEvent: pass From 55272443e05a71743df39b382661f357898e0587 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Sun, 3 Nov 2024 11:57:11 +0000 Subject: [PATCH 03/31] lint --- vyper/semantics/analysis/module.py | 4 +++- vyper/semantics/analysis/utils.py | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/vyper/semantics/analysis/module.py b/vyper/semantics/analysis/module.py index e67276c5a2..9ed28d6267 100644 --- a/vyper/semantics/analysis/module.py +++ b/vyper/semantics/analysis/module.py @@ -411,7 +411,9 @@ def visit_InitializesDecl(self, node): if module_info is None: raise StructureException("Not a module!", module_ref) if is_stateless(module_info.module_node): - raise StructureException(f"Cannot initialize a stateless module {module_info.alias}!", module_ref) + raise StructureException( + f"Cannot initialize a stateless module {module_info.alias}!", module_ref + ) used_modules = {i.module_t: i for i in module_info.module_t.used_modules} diff --git a/vyper/semantics/analysis/utils.py b/vyper/semantics/analysis/utils.py index b76aebf02a..d092675aa2 100644 --- a/vyper/semantics/analysis/utils.py +++ b/vyper/semantics/analysis/utils.py @@ -737,6 +737,7 @@ def validate_kwargs(node: vy_ast.Call, members: dict[str, VyperType], typeclass: msg += f" {', '.join(list(missing))}" raise InstantiationException(msg, node) + def is_stateless(module: vy_ast.Module): """ Determine whether a module is stateless by examining its top-level declarations. From 3c695da9d0594881e02cc325e15ae69d162c687c Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Mon, 4 Nov 2024 10:55:29 +0000 Subject: [PATCH 04/31] set immutables as stateless --- vyper/semantics/analysis/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vyper/semantics/analysis/utils.py b/vyper/semantics/analysis/utils.py index d092675aa2..7955981244 100644 --- a/vyper/semantics/analysis/utils.py +++ b/vyper/semantics/analysis/utils.py @@ -747,6 +747,6 @@ def is_stateless(module: vy_ast.Module): for i in module.body: if isinstance(i, (vy_ast.InitializesDecl, vy_ast.UsesDecl)): return False - if isinstance(i, vy_ast.VariableDecl) and not i.is_constant: + if isinstance(i, vy_ast.VariableDecl) and not i.is_constant and not i.is_immutable: return False return True From 5000efc1693c0f9d9d3a05d9dd13a87c9cf0c1ec Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Mon, 4 Nov 2024 10:59:09 +0000 Subject: [PATCH 05/31] add tests --- .../syntax/modules/test_initializers.py | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/tests/functional/syntax/modules/test_initializers.py b/tests/functional/syntax/modules/test_initializers.py index cac284fbba..f8aeb7057b 100644 --- a/tests/functional/syntax/modules/test_initializers.py +++ b/tests/functional/syntax/modules/test_initializers.py @@ -1420,3 +1420,103 @@ def set_some_mod(): compile_code(main, input_bundle=input_bundle) assert e.value._message == "module `lib3.vy` is used but never initialized!" assert e.value._hint is None + + +stateful_var_modules = [ + """ +phony: uint32 + """, + """ +ended: public(bool) + """, + """ +message: transient(bool) + """, +] + + +@pytest.mark.parametrize("module", stateful_var_modules) +def test_initializes_on_modules_with_state_related_vars(module, make_input_bundle): + main = """ +import lib +initializes: lib + """ + input_bundle = make_input_bundle({"lib.vy": module, "main.vy": main}) + compile_code(main, input_bundle=input_bundle) + + +stateless_modules = [ + """ + """, + """ +@deploy +def __init__(): + pass + """, + """ +@internal +@pure +def foo(x: uint256, y: uint256) -> uint256: + return unsafe_add(x & y, (x ^ y) >> 1) + """, + """ +FOO: constant(int128) = 128 + """, + """ +foo: immutable(int128) + +@deploy +def __init__(): + foo = 2 + """, +] + + +@pytest.mark.parametrize("module", stateless_modules) +def test_forbids_initializes_on_stateless_modules(module, make_input_bundle): + main = """ +import lib +initializes: lib + """ + input_bundle = make_input_bundle({"lib.vy": module, "main.vy": main}) + with pytest.raises(StructureException): + compile_code(main, input_bundle=input_bundle) + + +def test_initializes_on_modules_with_uses(make_input_bundle): + lib0 = """ +import lib1 +uses: lib1 + +@external +def foo() -> uint32: + return lib1.phony + """ + lib1 = """ +phony: uint32 + """ + main = """ +import lib1 +initializes: lib1 + +import lib0 +initializes: lib0[lib1 := lib1] + """ + input_bundle = make_input_bundle({"lib1.vy": lib1, "lib0.vy": lib0, "main.vy": main}) + compile_code(main, input_bundle=input_bundle) + + +def test_initializes_on_modules_with_initializes(make_input_bundle): + lib0 = """ +import lib1 +initializes: lib1 + """ + lib1 = """ +phony: uint32 + """ + main = """ +import lib0 +initializes: lib0 + """ + input_bundle = make_input_bundle({"lib1.vy": lib1, "lib0.vy": lib0, "main.vy": main}) + compile_code(main, input_bundle=input_bundle) From e3d758207abfe43b88ec578d0cf19627b02b541f Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Mon, 4 Nov 2024 11:32:18 +0000 Subject: [PATCH 06/31] fix stateless test --- tests/functional/codegen/features/decorators/test_pure.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/functional/codegen/features/decorators/test_pure.py b/tests/functional/codegen/features/decorators/test_pure.py index b2c5a0945b..867763ccc0 100644 --- a/tests/functional/codegen/features/decorators/test_pure.py +++ b/tests/functional/codegen/features/decorators/test_pure.py @@ -135,6 +135,7 @@ def foo() -> uint256: def test_invalid_module_immutable_access(make_input_bundle): lib1 = """ +phony: uint32 COUNTER: immutable(uint256) @deploy From c92e1adf25a5095c64743067a6ce841747206ea0 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Mon, 4 Nov 2024 16:04:51 +0000 Subject: [PATCH 07/31] make immutables state --- tests/functional/codegen/features/decorators/test_pure.py | 1 - vyper/semantics/analysis/utils.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/functional/codegen/features/decorators/test_pure.py b/tests/functional/codegen/features/decorators/test_pure.py index 867763ccc0..b2c5a0945b 100644 --- a/tests/functional/codegen/features/decorators/test_pure.py +++ b/tests/functional/codegen/features/decorators/test_pure.py @@ -135,7 +135,6 @@ def foo() -> uint256: def test_invalid_module_immutable_access(make_input_bundle): lib1 = """ -phony: uint32 COUNTER: immutable(uint256) @deploy diff --git a/vyper/semantics/analysis/utils.py b/vyper/semantics/analysis/utils.py index 7955981244..d092675aa2 100644 --- a/vyper/semantics/analysis/utils.py +++ b/vyper/semantics/analysis/utils.py @@ -747,6 +747,6 @@ def is_stateless(module: vy_ast.Module): for i in module.body: if isinstance(i, (vy_ast.InitializesDecl, vy_ast.UsesDecl)): return False - if isinstance(i, vy_ast.VariableDecl) and not i.is_constant and not i.is_immutable: + if isinstance(i, vy_ast.VariableDecl) and not i.is_constant: return False return True From cf9178462a44ce9f5c07370c3befca8f53e49ff7 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Mon, 4 Nov 2024 16:12:28 +0000 Subject: [PATCH 08/31] fix test --- .../syntax/modules/test_initializers.py | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/tests/functional/syntax/modules/test_initializers.py b/tests/functional/syntax/modules/test_initializers.py index f8aeb7057b..5931be361a 100644 --- a/tests/functional/syntax/modules/test_initializers.py +++ b/tests/functional/syntax/modules/test_initializers.py @@ -1445,6 +1445,27 @@ def test_initializes_on_modules_with_state_related_vars(module, make_input_bundl compile_code(main, input_bundle=input_bundle) +def test_initializes_on_modules_with_immutables(make_input_bundle): + lib = """ +foo: immutable(int128) + +@deploy +def __init__(): + foo = 2 + """ + + main = """ +import lib +initializes: lib + +@deploy +def __init__(): + lib.__init__() + """ + input_bundle = make_input_bundle({"lib.vy": lib, "main.vy": main}) + compile_code(main, input_bundle=input_bundle) + + stateless_modules = [ """ """, @@ -1462,13 +1483,6 @@ def foo(x: uint256, y: uint256) -> uint256: """ FOO: constant(int128) = 128 """, - """ -foo: immutable(int128) - -@deploy -def __init__(): - foo = 2 - """, ] From 1ab6433ebb86510f6ef905c24a6abcc3e32fd7c9 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Tue, 5 Nov 2024 09:57:25 +0000 Subject: [PATCH 09/31] test transient in cancun --- tests/functional/codegen/features/test_transient.py | 12 ++++++++++++ tests/functional/syntax/modules/test_initializers.py | 7 ++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/tests/functional/codegen/features/test_transient.py b/tests/functional/codegen/features/test_transient.py index 2532def85b..cba5157259 100644 --- a/tests/functional/codegen/features/test_transient.py +++ b/tests/functional/codegen/features/test_transient.py @@ -570,3 +570,15 @@ def foo() -> (uint256[3], uint256, uint256, uint256): c = get_contract(main, input_bundle=input_bundle) assert c.foo() == ([1, 2, 3], 1, 2, 42) + + +def test_transient_is_state(make_input_bundle): + lib = """ +message: transient(bool) + """ + main = """ +import lib +initializes: lib + """ + input_bundle = make_input_bundle({"lib.vy": lib, "main.vy": main}) + compile_code(main, input_bundle=input_bundle) diff --git a/tests/functional/syntax/modules/test_initializers.py b/tests/functional/syntax/modules/test_initializers.py index 5931be361a..74b7e04a41 100644 --- a/tests/functional/syntax/modules/test_initializers.py +++ b/tests/functional/syntax/modules/test_initializers.py @@ -1422,20 +1422,17 @@ def set_some_mod(): assert e.value._hint is None -stateful_var_modules = [ +storage_var_modules = [ """ phony: uint32 """, """ ended: public(bool) """, - """ -message: transient(bool) - """, ] -@pytest.mark.parametrize("module", stateful_var_modules) +@pytest.mark.parametrize("module", storage_var_modules) def test_initializes_on_modules_with_state_related_vars(module, make_input_bundle): main = """ import lib From 28c9be759bab15b223c126fadad105c7d4a1233b Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Tue, 5 Nov 2024 10:52:49 +0000 Subject: [PATCH 10/31] make init function as state --- .../syntax/modules/test_initializers.py | 25 +++++++++++++++++++ vyper/semantics/analysis/utils.py | 2 ++ 2 files changed, 27 insertions(+) diff --git a/tests/functional/syntax/modules/test_initializers.py b/tests/functional/syntax/modules/test_initializers.py index 74b7e04a41..27498c3883 100644 --- a/tests/functional/syntax/modules/test_initializers.py +++ b/tests/functional/syntax/modules/test_initializers.py @@ -1531,3 +1531,28 @@ def test_initializes_on_modules_with_initializes(make_input_bundle): """ input_bundle = make_input_bundle({"lib1.vy": lib1, "lib0.vy": lib0, "main.vy": main}) compile_code(main, input_bundle=input_bundle) + + +def test_initializes_on_modules_with_init_function(make_input_bundle): + lib = """ +interface Foo: + def foo(): payable + +@deploy +def __init__(): + extcall Foo(self).foo() + """ + main = """ +import lib +initializes: lib + +@deploy +def __init__(): + lib.__init__() + +@external +def foo(): + pass + """ + input_bundle = make_input_bundle({"lib.vy": lib, "main.vy": main}) + compile_code(main, input_bundle=input_bundle) diff --git a/vyper/semantics/analysis/utils.py b/vyper/semantics/analysis/utils.py index d092675aa2..7f167a353d 100644 --- a/vyper/semantics/analysis/utils.py +++ b/vyper/semantics/analysis/utils.py @@ -749,4 +749,6 @@ def is_stateless(module: vy_ast.Module): return False if isinstance(i, vy_ast.VariableDecl) and not i.is_constant: return False + if isinstance(i, vy_ast.FunctionDef) and i.name == "__init__": + return False return True From 0c5f645edc2d7671d47edb28bf04412a5f5657ff Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Tue, 5 Nov 2024 10:58:06 +0000 Subject: [PATCH 11/31] remove one wrong test --- tests/functional/syntax/modules/test_initializers.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/functional/syntax/modules/test_initializers.py b/tests/functional/syntax/modules/test_initializers.py index 27498c3883..1af24f49e1 100644 --- a/tests/functional/syntax/modules/test_initializers.py +++ b/tests/functional/syntax/modules/test_initializers.py @@ -1467,11 +1467,6 @@ def __init__(): """ """, """ -@deploy -def __init__(): - pass - """, - """ @internal @pure def foo(x: uint256, y: uint256) -> uint256: From 47efc8e3b83327fab2f145c6d60b331438ecf3bb Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Sat, 9 Nov 2024 10:01:04 +0000 Subject: [PATCH 12/31] refactor is_stateless into ModuleT method --- vyper/semantics/analysis/module.py | 3 +-- vyper/semantics/analysis/utils.py | 16 ---------------- vyper/semantics/types/module.py | 15 +++++++++++++++ 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/vyper/semantics/analysis/module.py b/vyper/semantics/analysis/module.py index 9ed28d6267..6fbb011aa1 100644 --- a/vyper/semantics/analysis/module.py +++ b/vyper/semantics/analysis/module.py @@ -37,7 +37,6 @@ check_modifiability, get_exact_type_from_node, get_expr_info, - is_stateless, ) from vyper.semantics.data_locations import DataLocation from vyper.semantics.namespace import Namespace, get_namespace, override_global_namespace @@ -410,7 +409,7 @@ def visit_InitializesDecl(self, node): module_info = get_expr_info(module_ref).module_info if module_info is None: raise StructureException("Not a module!", module_ref) - if is_stateless(module_info.module_node): + if module_info.module_t.is_stateless(): raise StructureException( f"Cannot initialize a stateless module {module_info.alias}!", module_ref ) diff --git a/vyper/semantics/analysis/utils.py b/vyper/semantics/analysis/utils.py index 7f167a353d..9734087fc3 100644 --- a/vyper/semantics/analysis/utils.py +++ b/vyper/semantics/analysis/utils.py @@ -736,19 +736,3 @@ def validate_kwargs(node: vy_ast.Call, members: dict[str, VyperType], typeclass: msg = f"{typeclass} instantiation missing fields:" msg += f" {', '.join(list(missing))}" raise InstantiationException(msg, node) - - -def is_stateless(module: vy_ast.Module): - """ - Determine whether a module is stateless by examining its top-level declarations. - A module has state if it contains storage variables, transient variables, or - immutables, or if it includes a "uses" or "initializes" declaration. - """ - for i in module.body: - if isinstance(i, (vy_ast.InitializesDecl, vy_ast.UsesDecl)): - return False - if isinstance(i, vy_ast.VariableDecl) and not i.is_constant: - return False - if isinstance(i, vy_ast.FunctionDef) and i.name == "__init__": - return False - return True diff --git a/vyper/semantics/types/module.py b/vyper/semantics/types/module.py index dabeaf21b6..52873ab902 100644 --- a/vyper/semantics/types/module.py +++ b/vyper/semantics/types/module.py @@ -559,3 +559,18 @@ def immutable_section_bytes(self): @cached_property def interface(self): return InterfaceT.from_ModuleT(self) + + def is_stateless(self): + """ + Determine whether ModuleT is stateless by examining its top-level declarations. + A module has state if it contains storage variables, transient variables, or + immutables, or if it includes a "uses" or "initializes" declaration. + """ + for i in self._module.body: + if isinstance(i, (vy_ast.InitializesDecl, vy_ast.UsesDecl)): + return False + if isinstance(i, vy_ast.VariableDecl) and not i.is_constant: + return False + if isinstance(i, vy_ast.FunctionDef) and i.name == "__init__": + return False + return True From 5fe6c84a88af956286a475fb07ee7c5bede613c9 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Wed, 20 Nov 2024 10:15:44 +0100 Subject: [PATCH 13/31] simplify is_stateless --- vyper/semantics/analysis/module.py | 2 +- vyper/semantics/types/module.py | 21 +++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/vyper/semantics/analysis/module.py b/vyper/semantics/analysis/module.py index 6fbb011aa1..6c85fc17fd 100644 --- a/vyper/semantics/analysis/module.py +++ b/vyper/semantics/analysis/module.py @@ -409,7 +409,7 @@ def visit_InitializesDecl(self, node): module_info = get_expr_info(module_ref).module_info if module_info is None: raise StructureException("Not a module!", module_ref) - if module_info.module_t.is_stateless(): + if module_info.module_t.is_stateless: raise StructureException( f"Cannot initialize a stateless module {module_info.alias}!", module_ref ) diff --git a/vyper/semantics/types/module.py b/vyper/semantics/types/module.py index 52873ab902..441b8085d1 100644 --- a/vyper/semantics/types/module.py +++ b/vyper/semantics/types/module.py @@ -560,17 +560,18 @@ def immutable_section_bytes(self): def interface(self): return InterfaceT.from_ModuleT(self) + @cached_property def is_stateless(self): """ - Determine whether ModuleT is stateless by examining its top-level declarations. - A module has state if it contains storage variables, transient variables, or - immutables, or if it includes a "uses" or "initializes" declaration. + Determine whether ModuleT is stateless by examining its top-level + declarations. A module has state if it contains storage variables, + transient variables, or immutables, or if it includes a "uses" or + "initializes" declaration. """ - for i in self._module.body: - if isinstance(i, (vy_ast.InitializesDecl, vy_ast.UsesDecl)): - return False - if isinstance(i, vy_ast.VariableDecl) and not i.is_constant: - return False - if isinstance(i, vy_ast.FunctionDef) and i.name == "__init__": - return False + if len(self.initializes_decls) > 0 or len(self.uses_decls) > 0: + return False + if any(not v.is_constant for v in self.variable_decls): + return False + if self.init_function is not None: + return False return True From fececb7d7bf48782b77274089da28cd0ea6edc31 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Wed, 20 Nov 2024 10:28:20 +0100 Subject: [PATCH 14/31] promote some properties to cached properties --- vyper/semantics/types/module.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vyper/semantics/types/module.py b/vyper/semantics/types/module.py index 441b8085d1..4a554e1360 100644 --- a/vyper/semantics/types/module.py +++ b/vyper/semantics/types/module.py @@ -444,19 +444,19 @@ def find_module_info(self, needle: "ModuleT") -> Optional["ModuleInfo"]: return s return None - @property + @cached_property def variable_decls(self): return self._module.get_children(vy_ast.VariableDecl) - @property + @cached_property def uses_decls(self): return self._module.get_children(vy_ast.UsesDecl) - @property + @cached_property def initializes_decls(self): return self._module.get_children(vy_ast.InitializesDecl) - @property + @cached_property def exports_decls(self): return self._module.get_children(vy_ast.ExportsDecl) @@ -469,7 +469,7 @@ def used_modules(self): ret.append(used_module) return ret - @property + @cached_property def initialized_modules(self): # modules which are initialized to ret = [] From 4cc01bb3102a00cb686f1052319f01e01976a5a7 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Thu, 5 Dec 2024 10:41:35 +0100 Subject: [PATCH 15/31] add comment to explain a test --- tests/functional/codegen/features/test_transient.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/functional/codegen/features/test_transient.py b/tests/functional/codegen/features/test_transient.py index cba5157259..c60aee54f5 100644 --- a/tests/functional/codegen/features/test_transient.py +++ b/tests/functional/codegen/features/test_transient.py @@ -572,6 +572,7 @@ def foo() -> (uint256[3], uint256, uint256, uint256): assert c.foo() == ([1, 2, 3], 1, 2, 42) +# Testing the `initializes` statement to verify how transient variables interact with and relate to state. def test_transient_is_state(make_input_bundle): lib = """ message: transient(bool) From ba197833a9c0331a049a418fbc636470dc244a6a Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Thu, 5 Dec 2024 11:05:47 +0100 Subject: [PATCH 16/31] rename function to is_initializable --- vyper/semantics/analysis/module.py | 2 +- vyper/semantics/types/module.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vyper/semantics/analysis/module.py b/vyper/semantics/analysis/module.py index 6c85fc17fd..a258871597 100644 --- a/vyper/semantics/analysis/module.py +++ b/vyper/semantics/analysis/module.py @@ -409,7 +409,7 @@ def visit_InitializesDecl(self, node): module_info = get_expr_info(module_ref).module_info if module_info is None: raise StructureException("Not a module!", module_ref) - if module_info.module_t.is_stateless: + if module_info.module_t.is_initializable: raise StructureException( f"Cannot initialize a stateless module {module_info.alias}!", module_ref ) diff --git a/vyper/semantics/types/module.py b/vyper/semantics/types/module.py index 4a554e1360..26e74f012f 100644 --- a/vyper/semantics/types/module.py +++ b/vyper/semantics/types/module.py @@ -561,7 +561,7 @@ def interface(self): return InterfaceT.from_ModuleT(self) @cached_property - def is_stateless(self): + def is_initializable(self): """ Determine whether ModuleT is stateless by examining its top-level declarations. A module has state if it contains storage variables, From b668f41ad30703b8e888756719cd3ae22a0584ed Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Thu, 5 Dec 2024 11:13:50 +0100 Subject: [PATCH 17/31] remove redundant storage variables --- tests/functional/codegen/modules/test_nonreentrant.py | 4 ---- tests/unit/compiler/test_abi.py | 2 -- 2 files changed, 6 deletions(-) diff --git a/tests/functional/codegen/modules/test_nonreentrant.py b/tests/functional/codegen/modules/test_nonreentrant.py index ea3297eea9..69b17cbfa2 100644 --- a/tests/functional/codegen/modules/test_nonreentrant.py +++ b/tests/functional/codegen/modules/test_nonreentrant.py @@ -1,7 +1,5 @@ def test_export_nonreentrant(make_input_bundle, get_contract, tx_failed): lib1 = """ -phony: uint32 - interface Foo: def foo() -> uint256: nonpayable @@ -40,8 +38,6 @@ def __default__(): def test_internal_nonreentrant(make_input_bundle, get_contract, tx_failed): lib1 = """ -phony: uint32 - interface Foo: def foo() -> uint256: nonpayable diff --git a/tests/unit/compiler/test_abi.py b/tests/unit/compiler/test_abi.py index f0f92d2ec4..19c0095a64 100644 --- a/tests/unit/compiler/test_abi.py +++ b/tests/unit/compiler/test_abi.py @@ -332,8 +332,6 @@ def __init__(): def test_event_export_from_init(make_input_bundle): # test that events get exported when used in init functions lib1 = """ -phony: uint32 - event MyEvent: pass From 6c7a30f847d9c09422f981d83407a9da407baec7 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Thu, 5 Dec 2024 11:19:08 +0100 Subject: [PATCH 18/31] make modules with nonreentrant initializable --- vyper/semantics/types/module.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vyper/semantics/types/module.py b/vyper/semantics/types/module.py index 26e74f012f..db7b5ab01a 100644 --- a/vyper/semantics/types/module.py +++ b/vyper/semantics/types/module.py @@ -574,4 +574,9 @@ def is_initializable(self): return False if self.init_function is not None: return False + + for fun in self.functions.values(): + if fun.nonreentrant: + return False + return True From 948d047f009a7b3f75ce0b6c89e969d5a109fd9d Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Thu, 5 Dec 2024 11:23:24 +0100 Subject: [PATCH 19/31] test that nonreentrant function use state --- .../syntax/modules/test_initializers.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/functional/syntax/modules/test_initializers.py b/tests/functional/syntax/modules/test_initializers.py index 1af24f49e1..39ed2a01a9 100644 --- a/tests/functional/syntax/modules/test_initializers.py +++ b/tests/functional/syntax/modules/test_initializers.py @@ -1422,17 +1422,29 @@ def set_some_mod(): assert e.value._hint is None -storage_var_modules = [ +initializable_modules = [ """ phony: uint32 """, """ ended: public(bool) """, + """ +@external +@nonreentrant +def foo(): + pass + """, + """ +@internal +@nonreentrant +def foo(): + pass + """, ] -@pytest.mark.parametrize("module", storage_var_modules) +@pytest.mark.parametrize("module", initializable_modules) def test_initializes_on_modules_with_state_related_vars(module, make_input_bundle): main = """ import lib From 3dbbeb69fb3be493f812c3ed99c05b1a8f5e390b Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Thu, 5 Dec 2024 11:31:38 +0100 Subject: [PATCH 20/31] update comment --- vyper/semantics/types/module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vyper/semantics/types/module.py b/vyper/semantics/types/module.py index db7b5ab01a..6249023663 100644 --- a/vyper/semantics/types/module.py +++ b/vyper/semantics/types/module.py @@ -566,7 +566,7 @@ def is_initializable(self): Determine whether ModuleT is stateless by examining its top-level declarations. A module has state if it contains storage variables, transient variables, or immutables, or if it includes a "uses" or - "initializes" declaration. + "initializes" declaration, or any nonreentrancy locks. """ if len(self.initializes_decls) > 0 or len(self.uses_decls) > 0: return False From 1f4a2d6e1703a3fb056668ac208d99079e5085d5 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Fri, 6 Dec 2024 17:41:36 +0100 Subject: [PATCH 21/31] remove uses decl from initializable --- tests/functional/codegen/modules/test_module_variables.py | 2 ++ tests/functional/syntax/modules/test_initializers.py | 6 +++++- tests/unit/compiler/test_abi.py | 2 ++ vyper/semantics/types/module.py | 6 +++--- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/functional/codegen/modules/test_module_variables.py b/tests/functional/codegen/modules/test_module_variables.py index c9b79e1bcc..a521fa8c66 100644 --- a/tests/functional/codegen/modules/test_module_variables.py +++ b/tests/functional/codegen/modules/test_module_variables.py @@ -158,6 +158,8 @@ def increment_counter(): uses: lib1 +phony: uint32 + @internal def get_lib1_counter() -> uint256: return lib1.counter diff --git a/tests/functional/syntax/modules/test_initializers.py b/tests/functional/syntax/modules/test_initializers.py index 39ed2a01a9..8ea33eb36b 100644 --- a/tests/functional/syntax/modules/test_initializers.py +++ b/tests/functional/syntax/modules/test_initializers.py @@ -277,6 +277,8 @@ def test_initializer_list_module_mismatch(make_input_bundle): uses: lib1 +phony: uint32 + @internal def foo(): lib1.counter += 1 @@ -1401,6 +1403,7 @@ def test_global_initialize_missed_import_hint(make_input_bundle, chdir_tmp_path) import lib3 uses: lib3 +phony: uint32 @external def set_some_mod(): @@ -1521,7 +1524,8 @@ def foo() -> uint32: initializes: lib0[lib1 := lib1] """ input_bundle = make_input_bundle({"lib1.vy": lib1, "lib0.vy": lib0, "main.vy": main}) - compile_code(main, input_bundle=input_bundle) + with pytest.raises(StructureException): + compile_code(main, input_bundle=input_bundle) def test_initializes_on_modules_with_initializes(make_input_bundle): diff --git a/tests/unit/compiler/test_abi.py b/tests/unit/compiler/test_abi.py index 19c0095a64..8411dc186a 100644 --- a/tests/unit/compiler/test_abi.py +++ b/tests/unit/compiler/test_abi.py @@ -645,6 +645,8 @@ def update_counter(): import lib1 uses: lib1 +phony: uint32 + @internal def use_lib1(): lib1.update_counter() diff --git a/vyper/semantics/types/module.py b/vyper/semantics/types/module.py index 6249023663..b33269df91 100644 --- a/vyper/semantics/types/module.py +++ b/vyper/semantics/types/module.py @@ -565,10 +565,10 @@ def is_initializable(self): """ Determine whether ModuleT is stateless by examining its top-level declarations. A module has state if it contains storage variables, - transient variables, or immutables, or if it includes a "uses" or - "initializes" declaration, or any nonreentrancy locks. + transient variables, or immutables, or if it includes a "initializes" + declaration, or any nonreentrancy locks. """ - if len(self.initializes_decls) > 0 or len(self.uses_decls) > 0: + if len(self.initializes_decls) > 0: return False if any(not v.is_constant for v in self.variable_decls): return False From be5aa0b7c922dbfc771ef91de988158362200363 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Fri, 6 Dec 2024 19:56:43 +0100 Subject: [PATCH 22/31] rename the function so the boolean matches --- vyper/semantics/analysis/module.py | 2 +- vyper/semantics/types/module.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vyper/semantics/analysis/module.py b/vyper/semantics/analysis/module.py index a258871597..e3d3e2ea37 100644 --- a/vyper/semantics/analysis/module.py +++ b/vyper/semantics/analysis/module.py @@ -409,7 +409,7 @@ def visit_InitializesDecl(self, node): module_info = get_expr_info(module_ref).module_info if module_info is None: raise StructureException("Not a module!", module_ref) - if module_info.module_t.is_initializable: + if module_info.module_t.is_not_initializable: raise StructureException( f"Cannot initialize a stateless module {module_info.alias}!", module_ref ) diff --git a/vyper/semantics/types/module.py b/vyper/semantics/types/module.py index b33269df91..f03785ac92 100644 --- a/vyper/semantics/types/module.py +++ b/vyper/semantics/types/module.py @@ -561,7 +561,7 @@ def interface(self): return InterfaceT.from_ModuleT(self) @cached_property - def is_initializable(self): + def is_not_initializable(self): """ Determine whether ModuleT is stateless by examining its top-level declarations. A module has state if it contains storage variables, From 7b2f38b8824497e30a127bded3a1ba349990d16b Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Sat, 7 Dec 2024 10:10:04 +0100 Subject: [PATCH 23/31] refactor comment --- tests/functional/codegen/features/test_transient.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/functional/codegen/features/test_transient.py b/tests/functional/codegen/features/test_transient.py index c60aee54f5..7eb80f1ae2 100644 --- a/tests/functional/codegen/features/test_transient.py +++ b/tests/functional/codegen/features/test_transient.py @@ -572,7 +572,8 @@ def foo() -> (uint256[3], uint256, uint256, uint256): assert c.foo() == ([1, 2, 3], 1, 2, 42) -# Testing the `initializes` statement to verify how transient variables interact with and relate to state. +# Testing the `initializes` statement to verify how transient variables +# interact with and relate to state. def test_transient_is_state(make_input_bundle): lib = """ message: transient(bool) From bb4944f65711073f5b0b087b0010f6279c9d5e42 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Thu, 12 Dec 2024 14:30:59 +0100 Subject: [PATCH 24/31] change is_not_initializable to is_initializable --- vyper/semantics/analysis/module.py | 2 +- vyper/semantics/types/module.py | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/vyper/semantics/analysis/module.py b/vyper/semantics/analysis/module.py index e3d3e2ea37..ce47d1e910 100644 --- a/vyper/semantics/analysis/module.py +++ b/vyper/semantics/analysis/module.py @@ -409,7 +409,7 @@ def visit_InitializesDecl(self, node): module_info = get_expr_info(module_ref).module_info if module_info is None: raise StructureException("Not a module!", module_ref) - if module_info.module_t.is_not_initializable: + if not module_info.module_t.is_initializable: raise StructureException( f"Cannot initialize a stateless module {module_info.alias}!", module_ref ) diff --git a/vyper/semantics/types/module.py b/vyper/semantics/types/module.py index f03785ac92..0e284f17ad 100644 --- a/vyper/semantics/types/module.py +++ b/vyper/semantics/types/module.py @@ -561,22 +561,22 @@ def interface(self): return InterfaceT.from_ModuleT(self) @cached_property - def is_not_initializable(self): + def is_initializable(self): """ - Determine whether ModuleT is stateless by examining its top-level + Determine whether ModuleT can be initialised by examining its top-level declarations. A module has state if it contains storage variables, transient variables, or immutables, or if it includes a "initializes" declaration, or any nonreentrancy locks. """ if len(self.initializes_decls) > 0: - return False + return True if any(not v.is_constant for v in self.variable_decls): - return False + return True if self.init_function is not None: - return False + return True for fun in self.functions.values(): if fun.nonreentrant: - return False + return True - return True + return False From b41bc28ef5bf793a0793502cc4aafa646b4fa4b2 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Sun, 15 Dec 2024 11:45:34 +0100 Subject: [PATCH 25/31] rename variable --- vyper/semantics/types/module.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vyper/semantics/types/module.py b/vyper/semantics/types/module.py index 0e284f17ad..811625901f 100644 --- a/vyper/semantics/types/module.py +++ b/vyper/semantics/types/module.py @@ -575,8 +575,8 @@ def is_initializable(self): if self.init_function is not None: return True - for fun in self.functions.values(): - if fun.nonreentrant: + for fn_t in self.functions.values(): + if fn_t.nonreentrant: return True return False From 2bcba89609b5eeab15c794a1f2579a28501561da Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Sun, 15 Dec 2024 14:26:06 +0100 Subject: [PATCH 26/31] remove unnecessary phonies and initializes --- tests/functional/syntax/modules/test_initializers.py | 4 +--- tests/unit/compiler/test_abi.py | 11 ----------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/tests/functional/syntax/modules/test_initializers.py b/tests/functional/syntax/modules/test_initializers.py index 8ea33eb36b..3c3082d881 100644 --- a/tests/functional/syntax/modules/test_initializers.py +++ b/tests/functional/syntax/modules/test_initializers.py @@ -837,8 +837,6 @@ def test_uses_skip_import(make_input_bundle): lib2 = """ import lib1 -phony: uint32 - @internal def foo(): pass @@ -847,7 +845,7 @@ def foo(): import lib1 import lib2 -initializes: lib2 +uses: lib2 @external def foo(new_value: uint256): diff --git a/tests/unit/compiler/test_abi.py b/tests/unit/compiler/test_abi.py index 8411dc186a..63a67f4f8e 100644 --- a/tests/unit/compiler/test_abi.py +++ b/tests/unit/compiler/test_abi.py @@ -218,8 +218,6 @@ def bar(x: {type}): def test_exports_abi(make_input_bundle): lib1 = """ -phony: uint32 - @external def foo(): pass @@ -232,8 +230,6 @@ def bar(): main = """ import lib1 -initializes: lib1 - exports: lib1.foo """ input_bundle = make_input_bundle({"lib1.vy": lib1}) @@ -363,8 +359,6 @@ def __init__(): def test_event_export_from_function_export(make_input_bundle): # test events used in exported functions are exported lib1 = """ -phony: uint32 - event MyEvent: pass @@ -375,8 +369,6 @@ def foo(): main = """ import lib1 -initializes: lib1 - exports: lib1.foo """ input_bundle = make_input_bundle({"lib1.vy": lib1}) @@ -400,8 +392,6 @@ def foo(): def test_event_export_unused_function(make_input_bundle): # test events in unused functions are not exported lib1 = """ -phony: uint32 - event MyEvent: pass @@ -411,7 +401,6 @@ def foo(): """ main = """ import lib1 -initializes: lib1 # not exported/reachable from selector table @internal From 7f2f452effaf9a2449708ef2b99a9e7ece2f7c24 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Sun, 15 Dec 2024 14:49:15 +0100 Subject: [PATCH 27/31] clean up tests --- .../functional/syntax/modules/test_initializers.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/functional/syntax/modules/test_initializers.py b/tests/functional/syntax/modules/test_initializers.py index 3c3082d881..a3e0b9ba2c 100644 --- a/tests/functional/syntax/modules/test_initializers.py +++ b/tests/functional/syntax/modules/test_initializers.py @@ -1425,7 +1425,7 @@ def set_some_mod(): initializable_modules = [ """ -phony: uint32 +counter: uint32 """, """ ended: public(bool) @@ -1507,12 +1507,12 @@ def test_initializes_on_modules_with_uses(make_input_bundle): import lib1 uses: lib1 -@external +@internal def foo() -> uint32: - return lib1.phony + return lib1.counter """ lib1 = """ -phony: uint32 +counter: uint32 """ main = """ import lib1 @@ -1520,6 +1520,10 @@ def foo() -> uint32: import lib0 initializes: lib0[lib1 := lib1] + +@internal +def use_lib0(): + lib0.foo() """ input_bundle = make_input_bundle({"lib1.vy": lib1, "lib0.vy": lib0, "main.vy": main}) with pytest.raises(StructureException): @@ -1532,7 +1536,7 @@ def test_initializes_on_modules_with_initializes(make_input_bundle): initializes: lib1 """ lib1 = """ -phony: uint32 +counter: uint32 """ main = """ import lib0 From f64109fd32b64f80ea80c09ee4170922c954982a Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Mon, 30 Dec 2024 11:08:08 +0100 Subject: [PATCH 28/31] remove phony variables to fix tests with "uses" --- tests/functional/codegen/modules/test_module_variables.py | 2 -- tests/functional/syntax/modules/test_initializers.py | 7 ++----- tests/unit/compiler/test_abi.py | 2 -- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/tests/functional/codegen/modules/test_module_variables.py b/tests/functional/codegen/modules/test_module_variables.py index a521fa8c66..c9b79e1bcc 100644 --- a/tests/functional/codegen/modules/test_module_variables.py +++ b/tests/functional/codegen/modules/test_module_variables.py @@ -158,8 +158,6 @@ def increment_counter(): uses: lib1 -phony: uint32 - @internal def get_lib1_counter() -> uint256: return lib1.counter diff --git a/tests/functional/syntax/modules/test_initializers.py b/tests/functional/syntax/modules/test_initializers.py index a3e0b9ba2c..b8c648ca16 100644 --- a/tests/functional/syntax/modules/test_initializers.py +++ b/tests/functional/syntax/modules/test_initializers.py @@ -277,8 +277,6 @@ def test_initializer_list_module_mismatch(make_input_bundle): uses: lib1 -phony: uint32 - @internal def foo(): lib1.counter += 1 @@ -1401,7 +1399,6 @@ def test_global_initialize_missed_import_hint(make_input_bundle, chdir_tmp_path) import lib3 uses: lib3 -phony: uint32 @external def set_some_mod(): @@ -1526,8 +1523,8 @@ def use_lib0(): lib0.foo() """ input_bundle = make_input_bundle({"lib1.vy": lib1, "lib0.vy": lib0, "main.vy": main}) - with pytest.raises(StructureException): - compile_code(main, input_bundle=input_bundle) + #with pytest.raises(StructureException): + compile_code(main, input_bundle=input_bundle) def test_initializes_on_modules_with_initializes(make_input_bundle): diff --git a/tests/unit/compiler/test_abi.py b/tests/unit/compiler/test_abi.py index 63a67f4f8e..ea6b789c55 100644 --- a/tests/unit/compiler/test_abi.py +++ b/tests/unit/compiler/test_abi.py @@ -634,8 +634,6 @@ def update_counter(): import lib1 uses: lib1 -phony: uint32 - @internal def use_lib1(): lib1.update_counter() From bf7307c31c839e458dd53337b85b0c62e85d7ff0 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Mon, 30 Dec 2024 11:13:24 +0100 Subject: [PATCH 29/31] modify test to expect a successful compilation --- tests/functional/syntax/modules/test_initializers.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/functional/syntax/modules/test_initializers.py b/tests/functional/syntax/modules/test_initializers.py index b8c648ca16..5d36398af0 100644 --- a/tests/functional/syntax/modules/test_initializers.py +++ b/tests/functional/syntax/modules/test_initializers.py @@ -1523,7 +1523,6 @@ def use_lib0(): lib0.foo() """ input_bundle = make_input_bundle({"lib1.vy": lib1, "lib0.vy": lib0, "main.vy": main}) - #with pytest.raises(StructureException): compile_code(main, input_bundle=input_bundle) From a0759791211e1e1abf52b6fe36d7debed1b2a0ea Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Mon, 30 Dec 2024 11:25:58 +0100 Subject: [PATCH 30/31] mark uses declaration initializable --- vyper/semantics/types/module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vyper/semantics/types/module.py b/vyper/semantics/types/module.py index 811625901f..038565b006 100644 --- a/vyper/semantics/types/module.py +++ b/vyper/semantics/types/module.py @@ -568,7 +568,7 @@ def is_initializable(self): transient variables, or immutables, or if it includes a "initializes" declaration, or any nonreentrancy locks. """ - if len(self.initializes_decls) > 0: + if len(self.initializes_decls) > 0 or len(self.uses_decls) > 0: return True if any(not v.is_constant for v in self.variable_decls): return True From ef0c49da0f3ad56028372cbeaa975e939d656418 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Mon, 30 Dec 2024 12:01:35 +0100 Subject: [PATCH 31/31] add comments to tests --- tests/functional/syntax/modules/test_initializers.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/functional/syntax/modules/test_initializers.py b/tests/functional/syntax/modules/test_initializers.py index 5d36398af0..bda75bce56 100644 --- a/tests/functional/syntax/modules/test_initializers.py +++ b/tests/functional/syntax/modules/test_initializers.py @@ -1444,6 +1444,7 @@ def foo(): @pytest.mark.parametrize("module", initializable_modules) def test_initializes_on_modules_with_state_related_vars(module, make_input_bundle): + # test modules that use storage can be initialized main = """ import lib initializes: lib @@ -1453,6 +1454,7 @@ def test_initializes_on_modules_with_state_related_vars(module, make_input_bundl def test_initializes_on_modules_with_immutables(make_input_bundle): + # test modules with immutables can be initialized lib = """ foo: immutable(int128) @@ -1490,6 +1492,7 @@ def foo(x: uint256, y: uint256) -> uint256: @pytest.mark.parametrize("module", stateless_modules) def test_forbids_initializes_on_stateless_modules(module, make_input_bundle): + # test we cannot initialize modules that don't use state main = """ import lib initializes: lib