From 6a87f5466b360a1046500866a49408207b9bf884 Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Sun, 22 Sep 2024 17:13:35 +0800 Subject: [PATCH 01/15] support .vyi const --- vyper/semantics/analysis/constant_folding.py | 8 +++--- vyper/semantics/types/module.py | 29 ++++++++++++++------ 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/vyper/semantics/analysis/constant_folding.py b/vyper/semantics/analysis/constant_folding.py index 6e4166dc52..88645d7b75 100644 --- a/vyper/semantics/analysis/constant_folding.py +++ b/vyper/semantics/analysis/constant_folding.py @@ -2,6 +2,7 @@ from vyper.exceptions import InvalidLiteral, UnfoldableNode, VyperException from vyper.semantics.analysis.base import VarInfo from vyper.semantics.analysis.common import VyperNodeVisitorBase +from vyper.semantics.types.module import InterfaceT from vyper.semantics.namespace import get_namespace @@ -105,12 +106,11 @@ def visit_Attribute(self, node) -> vy_ast.ExprNode: # not super type-safe but we don't care. just catch AttributeErrors # and move on try: - module_t = namespace[value.id].module_t - + ns_member = namespace[value.id] + module_t = ns_member if isinstance(ns_member, InterfaceT) else ns_member.module_t for module_name in path: module_t = module_t.members[module_name].module_t - - varinfo = module_t.get_member(node.attr, node) + varinfo = module_t.get_type_member(node.attr, node) if isinstance(module_t, InterfaceT) else module_t.get_member(node.attr, node) return varinfo.decl_node.value.get_folded_value() except (VyperException, AttributeError, KeyError): diff --git a/vyper/semantics/types/module.py b/vyper/semantics/types/module.py index ba72842c65..d1568a5c96 100644 --- a/vyper/semantics/types/module.py +++ b/vyper/semantics/types/module.py @@ -10,7 +10,7 @@ StructureException, UnfoldableNode, ) -from vyper.semantics.analysis.base import Modifiability +from vyper.semantics.analysis.base import Modifiability, VarInfo from vyper.semantics.analysis.utils import ( check_modifiability, get_exact_type_from_node, @@ -45,28 +45,33 @@ def __init__( functions: dict, events: dict, structs: dict, + constants: dict, ) -> None: validate_unique_method_ids(list(functions.values())) - members = functions | events | structs + members = functions | events | structs | constants # sanity check: by construction, there should be no duplicates. - assert len(members) == len(functions) + len(events) + len(structs) + assert len(members) == len(functions) + len(events) + len(structs) + len(constants) super().__init__(functions) - self._helper = VyperType(events | structs) + self._helper = VyperType(events | structs | constants) self._id = _id self._helper._id = _id self.functions = functions self.events = events self.structs = structs + self.constants = constants self.decl_node = decl_node def get_type_member(self, attr, node): - # get an event or struct from this interface - return TYPE_T(self._helper.get_member(attr, node)) + # get an event, struct or constant from this interface + type_member = self._helper.get_member(attr, node) + if isinstance(type_member, (EventT, StructT)): + return TYPE_T(type_member) + return type_member @property def getter_signature(self): @@ -161,10 +166,12 @@ def _from_lists( function_list: list[tuple[str, ContractFunctionT]], event_list: list[tuple[str, EventT]], struct_list: list[tuple[str, StructT]], + constant_list: list[tuple[str, VarInfo]], ) -> "InterfaceT": functions = {} events = {} structs = {} + constants = {} seen_items: dict = {} @@ -187,7 +194,11 @@ def _mark_seen(name, item): _mark_seen(name, struct) structs[name] = struct - return cls(interface_name, decl_node, functions, events, structs) + for name, constant in constant_list: + _mark_seen(name, constant) + constants[name] = constant + + return cls(interface_name, decl_node, functions, events, structs, constants) @classmethod def from_json_abi(cls, name: str, abi: dict) -> "InterfaceT": @@ -247,8 +258,8 @@ def from_ModuleT(cls, module_t: "ModuleT") -> "InterfaceT": # these are accessible via import, but they do not show up # in the ABI json structs = [(node.name, node._metadata["struct_type"]) for node in module_t.struct_defs] - - return cls._from_lists(module_t._id, module_t.decl_node, funcs, events, structs) + constants = [(node.target.id, node.target._metadata["varinfo"]) for node in module_t.variable_decls if node.target._metadata["varinfo"].modifiability is Modifiability.CONSTANT] + return cls._from_lists(module_t._id, module_t.decl_node, funcs, events, structs, constants) @classmethod def from_InterfaceDef(cls, node: vy_ast.InterfaceDef) -> "InterfaceT": From 9edcd528cd274a668ac24749a739f83fc670beac Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Sun, 22 Sep 2024 17:26:05 +0800 Subject: [PATCH 02/15] fix lint --- vyper/semantics/analysis/constant_folding.py | 6 +++++- vyper/semantics/types/module.py | 19 +++++++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/vyper/semantics/analysis/constant_folding.py b/vyper/semantics/analysis/constant_folding.py index 88645d7b75..b42bd9d005 100644 --- a/vyper/semantics/analysis/constant_folding.py +++ b/vyper/semantics/analysis/constant_folding.py @@ -110,7 +110,11 @@ def visit_Attribute(self, node) -> vy_ast.ExprNode: module_t = ns_member if isinstance(ns_member, InterfaceT) else ns_member.module_t for module_name in path: module_t = module_t.members[module_name].module_t - varinfo = module_t.get_type_member(node.attr, node) if isinstance(module_t, InterfaceT) else module_t.get_member(node.attr, node) + varinfo = ( + module_t.get_type_member(node.attr, node) + if isinstance(module_t, InterfaceT) + else module_t.get_member(node.attr, node) + ) return varinfo.decl_node.value.get_folded_value() except (VyperException, AttributeError, KeyError): diff --git a/vyper/semantics/types/module.py b/vyper/semantics/types/module.py index d1568a5c96..b97870c376 100644 --- a/vyper/semantics/types/module.py +++ b/vyper/semantics/types/module.py @@ -45,10 +45,12 @@ def __init__( functions: dict, events: dict, structs: dict, - constants: dict, + constants: Optional[dict] = None, ) -> None: validate_unique_method_ids(list(functions.values())) + constants = constants if constants else {} + members = functions | events | structs | constants # sanity check: by construction, there should be no duplicates. @@ -166,7 +168,7 @@ def _from_lists( function_list: list[tuple[str, ContractFunctionT]], event_list: list[tuple[str, EventT]], struct_list: list[tuple[str, StructT]], - constant_list: list[tuple[str, VarInfo]], + constant_list: Optional[list[tuple[str, VarInfo]]] = None, ) -> "InterfaceT": functions = {} events = {} @@ -194,9 +196,10 @@ def _mark_seen(name, item): _mark_seen(name, struct) structs[name] = struct - for name, constant in constant_list: - _mark_seen(name, constant) - constants[name] = constant + if constant_list: + for name, constant in constant_list: + _mark_seen(name, constant) + constants[name] = constant return cls(interface_name, decl_node, functions, events, structs, constants) @@ -258,7 +261,11 @@ def from_ModuleT(cls, module_t: "ModuleT") -> "InterfaceT": # these are accessible via import, but they do not show up # in the ABI json structs = [(node.name, node._metadata["struct_type"]) for node in module_t.struct_defs] - constants = [(node.target.id, node.target._metadata["varinfo"]) for node in module_t.variable_decls if node.target._metadata["varinfo"].modifiability is Modifiability.CONSTANT] + constants = [ + (node.target.id, node.target._metadata["varinfo"]) + for node in module_t.variable_decls + if node.target._metadata["varinfo"].modifiability is Modifiability.CONSTANT + ] return cls._from_lists(module_t._id, module_t.decl_node, funcs, events, structs, constants) @classmethod From 2065c238993991e5db8e63e6f734db05b43b80ea Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Sun, 22 Sep 2024 17:28:36 +0800 Subject: [PATCH 03/15] fix more lint --- vyper/semantics/analysis/constant_folding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vyper/semantics/analysis/constant_folding.py b/vyper/semantics/analysis/constant_folding.py index b42bd9d005..ee4a061a08 100644 --- a/vyper/semantics/analysis/constant_folding.py +++ b/vyper/semantics/analysis/constant_folding.py @@ -2,8 +2,8 @@ from vyper.exceptions import InvalidLiteral, UnfoldableNode, VyperException from vyper.semantics.analysis.base import VarInfo from vyper.semantics.analysis.common import VyperNodeVisitorBase -from vyper.semantics.types.module import InterfaceT from vyper.semantics.namespace import get_namespace +from vyper.semantics.types.module import InterfaceT def constant_fold(module_ast: vy_ast.Module): From c718e2864761322d1b6ef5adc911fae2996427d0 Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Mon, 23 Sep 2024 21:56:24 +0800 Subject: [PATCH 04/15] apply bts suggestions --- 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 b97870c376..8cb3dc6ee0 100644 --- a/vyper/semantics/types/module.py +++ b/vyper/semantics/types/module.py @@ -49,7 +49,7 @@ def __init__( ) -> None: validate_unique_method_ids(list(functions.values())) - constants = constants if constants else {} + constants = constants or {} members = functions | events | structs | constants @@ -264,7 +264,7 @@ def from_ModuleT(cls, module_t: "ModuleT") -> "InterfaceT": constants = [ (node.target.id, node.target._metadata["varinfo"]) for node in module_t.variable_decls - if node.target._metadata["varinfo"].modifiability is Modifiability.CONSTANT + if node.is_constant ] return cls._from_lists(module_t._id, module_t.decl_node, funcs, events, structs, constants) From 8a932a3702a9bd131aee9e79afa49ee94bcb359f Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Mon, 23 Sep 2024 21:57:14 +0800 Subject: [PATCH 05/15] fix public constants case --- vyper/semantics/types/module.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/vyper/semantics/types/module.py b/vyper/semantics/types/module.py index 8cb3dc6ee0..fa95cb83fa 100644 --- a/vyper/semantics/types/module.py +++ b/vyper/semantics/types/module.py @@ -50,11 +50,16 @@ def __init__( validate_unique_method_ids(list(functions.values())) constants = constants or {} + public_constants = { + k: varinfo for k, varinfo in constants.items() if varinfo.decl_node.is_public + } members = functions | events | structs | constants # sanity check: by construction, there should be no duplicates. - assert len(members) == len(functions) + len(events) + len(structs) + len(constants) + assert len(members) == len(functions) + len(events) + len(structs) + len(constants) - len( + public_constants + ) super().__init__(functions) @@ -179,9 +184,15 @@ def _from_lists( def _mark_seen(name, item): if name in seen_items: + prev = seen_items[name] + if ( + isinstance(prev, ContractFunctionT) + and isinstance(item, VarInfo) + and item.decl_node.is_public + ): + return msg = f"multiple functions or events named '{name}'!" - prev_decl = seen_items[name].decl_node - raise NamespaceCollision(msg, item.decl_node, prev_decl=prev_decl) + raise NamespaceCollision(msg, item.decl_node, prev_decl=prev.decl_node) seen_items[name] = item for name, function in function_list: From 69e5b3e9bc38426e68aafc8c9463083ce1de77c3 Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Thu, 26 Sep 2024 22:27:24 +0800 Subject: [PATCH 06/15] change signatures --- vyper/semantics/types/module.py | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/vyper/semantics/types/module.py b/vyper/semantics/types/module.py index fa95cb83fa..480aecde96 100644 --- a/vyper/semantics/types/module.py +++ b/vyper/semantics/types/module.py @@ -45,11 +45,10 @@ def __init__( functions: dict, events: dict, structs: dict, - constants: Optional[dict] = None, + constants: dict, ) -> None: validate_unique_method_ids(list(functions.values())) - constants = constants or {} public_constants = { k: varinfo for k, varinfo in constants.items() if varinfo.decl_node.is_public } @@ -171,8 +170,8 @@ def _from_lists( interface_name: str, decl_node: Optional[vy_ast.VyperNode], function_list: list[tuple[str, ContractFunctionT]], - event_list: list[tuple[str, EventT]], - struct_list: list[tuple[str, StructT]], + event_list: Optional[list[tuple[str, EventT]]] = None, + struct_list: Optional[list[tuple[str, StructT]]] = None, constant_list: Optional[list[tuple[str, VarInfo]]] = None, ) -> "InterfaceT": functions = {} @@ -199,13 +198,15 @@ def _mark_seen(name, item): _mark_seen(name, function) functions[name] = function - for name, event in event_list: - _mark_seen(name, event) - events[name] = event + if event_list: + for name, event in event_list: + _mark_seen(name, event) + events[name] = event - for name, struct in struct_list: - _mark_seen(name, struct) - structs[name] = struct + if struct_list: + for name, struct in struct_list: + _mark_seen(name, struct) + structs[name] = struct if constant_list: for name, constant in constant_list: @@ -239,8 +240,7 @@ def from_json_abi(cls, name: str, abi: dict) -> "InterfaceT": for item in [i for i in abi if i.get("type") == "event"]: events.append((item["name"], EventT.from_abi(item))) - structs: list = [] # no structs in json ABI (as of yet) - return cls._from_lists(name, None, functions, events, structs) + return cls._from_lists(name, None, functions, events) @classmethod def from_ModuleT(cls, module_t: "ModuleT") -> "InterfaceT": @@ -294,11 +294,7 @@ def from_InterfaceDef(cls, node: vy_ast.InterfaceDef) -> "InterfaceT": ) functions.append((func_ast.name, ContractFunctionT.from_InterfaceDef(func_ast))) - # no structs or events in InterfaceDefs - events: list = [] - structs: list = [] - - return cls._from_lists(node.name, node, functions, events, structs) + return cls._from_lists(node.name, node, functions) # Datatype to store all module information. From 8439d5bf15369d6b171bb74d2c474c6a0fec9509 Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Sat, 28 Sep 2024 22:38:50 +0800 Subject: [PATCH 07/15] add flags --- vyper/semantics/types/module.py | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/vyper/semantics/types/module.py b/vyper/semantics/types/module.py index 480aecde96..c1f75db83e 100644 --- a/vyper/semantics/types/module.py +++ b/vyper/semantics/types/module.py @@ -21,7 +21,7 @@ from vyper.semantics.types.base import TYPE_T, VyperType, is_type_t from vyper.semantics.types.function import ContractFunctionT from vyper.semantics.types.primitives import AddressT -from vyper.semantics.types.user import EventT, StructT, _UserType +from vyper.semantics.types.user import EventT, FlagT, StructT, _UserType from vyper.utils import OrderedSet, sha256sum if TYPE_CHECKING: @@ -45,6 +45,7 @@ def __init__( functions: dict, events: dict, structs: dict, + flags: dict, constants: dict, ) -> None: validate_unique_method_ids(list(functions.values())) @@ -53,21 +54,22 @@ def __init__( k: varinfo for k, varinfo in constants.items() if varinfo.decl_node.is_public } - members = functions | events | structs | constants + members = functions | events | structs | flags | constants # sanity check: by construction, there should be no duplicates. - assert len(members) == len(functions) + len(events) + len(structs) + len(constants) - len( - public_constants - ) + assert len(members) == len(functions) + len(events) + len(structs) + len(flags) + len( + constants + ) - len(public_constants) super().__init__(functions) - self._helper = VyperType(events | structs | constants) + self._helper = VyperType(events | structs | flags | constants) self._id = _id self._helper._id = _id self.functions = functions self.events = events self.structs = structs + self.flags = flags self.constants = constants self.decl_node = decl_node @@ -75,7 +77,7 @@ def __init__( def get_type_member(self, attr, node): # get an event, struct or constant from this interface type_member = self._helper.get_member(attr, node) - if isinstance(type_member, (EventT, StructT)): + if isinstance(type_member, (EventT, FlagT, StructT)): return TYPE_T(type_member) return type_member @@ -172,11 +174,13 @@ def _from_lists( function_list: list[tuple[str, ContractFunctionT]], event_list: Optional[list[tuple[str, EventT]]] = None, struct_list: Optional[list[tuple[str, StructT]]] = None, + flag_list: Optional[list[tuple[str, FlagT]]] = None, constant_list: Optional[list[tuple[str, VarInfo]]] = None, ) -> "InterfaceT": functions = {} events = {} structs = {} + flags = {} constants = {} seen_items: dict = {} @@ -208,12 +212,17 @@ def _mark_seen(name, item): _mark_seen(name, struct) structs[name] = struct + if flag_list: + for name, flag in flag_list: + _mark_seen(name, flag) + flags[name] = flag + if constant_list: for name, constant in constant_list: _mark_seen(name, constant) constants[name] = constant - return cls(interface_name, decl_node, functions, events, structs, constants) + return cls(interface_name, decl_node, functions, events, structs, flags, constants) @classmethod def from_json_abi(cls, name: str, abi: dict) -> "InterfaceT": @@ -272,12 +281,15 @@ def from_ModuleT(cls, module_t: "ModuleT") -> "InterfaceT": # these are accessible via import, but they do not show up # in the ABI json structs = [(node.name, node._metadata["struct_type"]) for node in module_t.struct_defs] + flags = [(node.name, node._metadata["flag_type"]) for node in module_t.flag_defs] constants = [ (node.target.id, node.target._metadata["varinfo"]) for node in module_t.variable_decls if node.is_constant ] - return cls._from_lists(module_t._id, module_t.decl_node, funcs, events, structs, constants) + return cls._from_lists( + module_t._id, module_t.decl_node, funcs, events, structs, flags, constants + ) @classmethod def from_InterfaceDef(cls, node: vy_ast.InterfaceDef) -> "InterfaceT": From 2539997354502e84a95549e6fe9162359d66ca7b Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Wed, 2 Oct 2024 16:27:46 +0800 Subject: [PATCH 08/15] add tests --- .../codegen/modules/test_interface_imports.py | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/tests/functional/codegen/modules/test_interface_imports.py b/tests/functional/codegen/modules/test_interface_imports.py index c0fae6496c..485430516e 100644 --- a/tests/functional/codegen/modules/test_interface_imports.py +++ b/tests/functional/codegen/modules/test_interface_imports.py @@ -58,3 +58,56 @@ def foo() -> bool: c = get_contract(main, input_bundle=input_bundle) assert c.foo() is True + + +def test_import_interface_constants(make_input_bundle, get_contract): + ifaces = """ +FOO: constant(uint256) = 3 + +interface IFoo: + def foo() -> DynArray[uint256, FOO]: nonpayable + """ + + contract = """ +import ifaces + +implements: ifaces + +@external +def foo() -> DynArray[uint256, ifaces.FOO]: + return [1, 2, ifaces.FOO] + """ + + input_bundle = make_input_bundle({"ifaces.vyi": ifaces}) + + c = get_contract(contract, input_bundle=input_bundle) + + assert c.foo() == [1, 2, 3] + + +def test_import_interface_flags(make_input_bundle, get_contract): + ifaces = """ +flag Foo: + BOO + MOO + POO + +interface IFoo: + def foo() -> Foo: nonpayable + """ + + contract = """ +import ifaces + +implements: ifaces + +@external +def foo() -> ifaces.Foo: + return ifaces.Foo.POO + """ + + input_bundle = make_input_bundle({"ifaces.vyi": ifaces}) + + c = get_contract(contract, input_bundle=input_bundle) + + assert c.foo() == 4 From d2e8aea3486a9733608009bf7613794cdc71ec4c Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Fri, 4 Oct 2024 16:05:47 +0800 Subject: [PATCH 09/15] apply cc suggestions --- 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 c1f75db83e..4ddab64188 100644 --- a/vyper/semantics/types/module.py +++ b/vyper/semantics/types/module.py @@ -77,7 +77,7 @@ def __init__( def get_type_member(self, attr, node): # get an event, struct or constant from this interface type_member = self._helper.get_member(attr, node) - if isinstance(type_member, (EventT, FlagT, StructT)): + if isinstance(type_member, _UserType): return TYPE_T(type_member) return type_member From 76824a100be428e88124ab229070f18054b208fc Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Sat, 12 Oct 2024 09:34:36 +0800 Subject: [PATCH 10/15] rollback constants --- .../codegen/modules/test_interface_imports.py | 25 --------------- vyper/semantics/analysis/constant_folding.py | 12 +++---- vyper/semantics/analysis/local.py | 2 ++ vyper/semantics/types/module.py | 32 +++---------------- 4 files changed, 11 insertions(+), 60 deletions(-) diff --git a/tests/functional/codegen/modules/test_interface_imports.py b/tests/functional/codegen/modules/test_interface_imports.py index 485430516e..3f0f8cb010 100644 --- a/tests/functional/codegen/modules/test_interface_imports.py +++ b/tests/functional/codegen/modules/test_interface_imports.py @@ -60,31 +60,6 @@ def foo() -> bool: assert c.foo() is True -def test_import_interface_constants(make_input_bundle, get_contract): - ifaces = """ -FOO: constant(uint256) = 3 - -interface IFoo: - def foo() -> DynArray[uint256, FOO]: nonpayable - """ - - contract = """ -import ifaces - -implements: ifaces - -@external -def foo() -> DynArray[uint256, ifaces.FOO]: - return [1, 2, ifaces.FOO] - """ - - input_bundle = make_input_bundle({"ifaces.vyi": ifaces}) - - c = get_contract(contract, input_bundle=input_bundle) - - assert c.foo() == [1, 2, 3] - - def test_import_interface_flags(make_input_bundle, get_contract): ifaces = """ flag Foo: diff --git a/vyper/semantics/analysis/constant_folding.py b/vyper/semantics/analysis/constant_folding.py index 9ef3f2ec93..5556905687 100644 --- a/vyper/semantics/analysis/constant_folding.py +++ b/vyper/semantics/analysis/constant_folding.py @@ -3,7 +3,6 @@ from vyper.semantics.analysis.base import VarInfo from vyper.semantics.analysis.common import VyperNodeVisitorBase from vyper.semantics.namespace import get_namespace -from vyper.semantics.types.module import InterfaceT def constant_fold(module_ast: vy_ast.Module): @@ -91,6 +90,7 @@ def visit_Name(self, node) -> vy_ast.ExprNode: raise UnfoldableNode("unknown name", node) def visit_Attribute(self, node) -> vy_ast.ExprNode: + print("visit Attribute") namespace = get_namespace() path = [] value = node.value @@ -101,20 +101,16 @@ def visit_Attribute(self, node) -> vy_ast.ExprNode: path.reverse() if not isinstance(value, vy_ast.Name): + print("not foldable") raise UnfoldableNode("not a module", value) # not super type-safe but we don't care. just catch AttributeErrors # and move on try: - ns_member = namespace[value.id] - module_t = ns_member if isinstance(ns_member, InterfaceT) else ns_member.module_t + module_t = namespace[value.id].module_t for module_name in path: module_t = module_t.members[module_name].module_t - varinfo = ( - module_t.get_type_member(node.attr, node) - if isinstance(module_t, InterfaceT) - else module_t.get_member(node.attr, node) - ) + varinfo = module_t.get_member(node.attr, node) return varinfo.decl_node.value.get_folded_value() except (VyperException, AttributeError, KeyError): diff --git a/vyper/semantics/analysis/local.py b/vyper/semantics/analysis/local.py index b5292b1dad..46a05f5328 100644 --- a/vyper/semantics/analysis/local.py +++ b/vyper/semantics/analysis/local.py @@ -700,6 +700,7 @@ def visit(self, node, typ): self.visit(folded_node, typ) def visit_Attribute(self, node: vy_ast.Attribute, typ: VyperType) -> None: + print("local - visit_Attribute") _validate_msg_data_attribute(node) # CMC 2023-10-19 TODO generalize this to mutability check on every node. @@ -714,6 +715,7 @@ def visit_Attribute(self, node: vy_ast.Attribute, typ: VyperType) -> None: _validate_pure_access(node, typ) value_type = get_exact_type_from_node(node.value) + print("value type: ", value_type) _validate_address_code(node, value_type) diff --git a/vyper/semantics/types/module.py b/vyper/semantics/types/module.py index 4ddab64188..33e7ff1ab3 100644 --- a/vyper/semantics/types/module.py +++ b/vyper/semantics/types/module.py @@ -46,31 +46,23 @@ def __init__( events: dict, structs: dict, flags: dict, - constants: dict, ) -> None: validate_unique_method_ids(list(functions.values())) - public_constants = { - k: varinfo for k, varinfo in constants.items() if varinfo.decl_node.is_public - } - - members = functions | events | structs | flags | constants + members = functions | events | structs | flags # sanity check: by construction, there should be no duplicates. - assert len(members) == len(functions) + len(events) + len(structs) + len(flags) + len( - constants - ) - len(public_constants) + assert len(members) == len(functions) + len(events) + len(structs) + len(flags) super().__init__(functions) - self._helper = VyperType(events | structs | flags | constants) + self._helper = VyperType(events | structs | flags) self._id = _id self._helper._id = _id self.functions = functions self.events = events self.structs = structs self.flags = flags - self.constants = constants self.decl_node = decl_node @@ -175,13 +167,11 @@ def _from_lists( event_list: Optional[list[tuple[str, EventT]]] = None, struct_list: Optional[list[tuple[str, StructT]]] = None, flag_list: Optional[list[tuple[str, FlagT]]] = None, - constant_list: Optional[list[tuple[str, VarInfo]]] = None, ) -> "InterfaceT": functions = {} events = {} structs = {} flags = {} - constants = {} seen_items: dict = {} @@ -217,12 +207,7 @@ def _mark_seen(name, item): _mark_seen(name, flag) flags[name] = flag - if constant_list: - for name, constant in constant_list: - _mark_seen(name, constant) - constants[name] = constant - - return cls(interface_name, decl_node, functions, events, structs, flags, constants) + return cls(interface_name, decl_node, functions, events, structs, flags) @classmethod def from_json_abi(cls, name: str, abi: dict) -> "InterfaceT": @@ -282,14 +267,7 @@ def from_ModuleT(cls, module_t: "ModuleT") -> "InterfaceT": # in the ABI json structs = [(node.name, node._metadata["struct_type"]) for node in module_t.struct_defs] flags = [(node.name, node._metadata["flag_type"]) for node in module_t.flag_defs] - constants = [ - (node.target.id, node.target._metadata["varinfo"]) - for node in module_t.variable_decls - if node.is_constant - ] - return cls._from_lists( - module_t._id, module_t.decl_node, funcs, events, structs, flags, constants - ) + return cls._from_lists(module_t._id, module_t.decl_node, funcs, events, structs, flags) @classmethod def from_InterfaceDef(cls, node: vy_ast.InterfaceDef) -> "InterfaceT": From be6001565cfa3e0a1741673eb9fab7acb4ccbd08 Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Sat, 12 Oct 2024 09:36:02 +0800 Subject: [PATCH 11/15] remove debug prints --- vyper/semantics/analysis/local.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/vyper/semantics/analysis/local.py b/vyper/semantics/analysis/local.py index 1e3d05678e..809c6532c6 100644 --- a/vyper/semantics/analysis/local.py +++ b/vyper/semantics/analysis/local.py @@ -700,7 +700,6 @@ def visit(self, node, typ): self.visit(folded_node, typ) def visit_Attribute(self, node: vy_ast.Attribute, typ: VyperType) -> None: - print("local - visit_Attribute") _validate_msg_data_attribute(node) # CMC 2023-10-19 TODO generalize this to mutability check on every node. @@ -715,7 +714,6 @@ def visit_Attribute(self, node: vy_ast.Attribute, typ: VyperType) -> None: _validate_pure_access(node, typ) value_type = get_exact_type_from_node(node.value) - print("value type: ", value_type) _validate_address_code(node, value_type) From 223d6b3f73cb7f35f79129eab3ab4f683e9deeae Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Sat, 12 Oct 2024 09:38:41 +0800 Subject: [PATCH 12/15] more rollbacks --- vyper/semantics/types/module.py | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/vyper/semantics/types/module.py b/vyper/semantics/types/module.py index 33e7ff1ab3..46ec6d4a75 100644 --- a/vyper/semantics/types/module.py +++ b/vyper/semantics/types/module.py @@ -10,7 +10,7 @@ StructureException, UnfoldableNode, ) -from vyper.semantics.analysis.base import Modifiability, VarInfo +from vyper.semantics.analysis.base import Modifiability from vyper.semantics.analysis.utils import ( check_modifiability, get_exact_type_from_node, @@ -68,10 +68,7 @@ def __init__( def get_type_member(self, attr, node): # get an event, struct or constant from this interface - type_member = self._helper.get_member(attr, node) - if isinstance(type_member, _UserType): - return TYPE_T(type_member) - return type_member + return TYPE_T(self._helper.get_member(attr, node)) @property def getter_signature(self): @@ -177,15 +174,9 @@ def _from_lists( def _mark_seen(name, item): if name in seen_items: - prev = seen_items[name] - if ( - isinstance(prev, ContractFunctionT) - and isinstance(item, VarInfo) - and item.decl_node.is_public - ): - return msg = f"multiple functions or events named '{name}'!" - raise NamespaceCollision(msg, item.decl_node, prev_decl=prev.decl_node) + prev_decl = seen_items[name].decl_node + raise NamespaceCollision(msg, item.decl_node, prev_decl=prev_decl) seen_items[name] = item for name, function in function_list: @@ -267,6 +258,7 @@ def from_ModuleT(cls, module_t: "ModuleT") -> "InterfaceT": # in the ABI json structs = [(node.name, node._metadata["struct_type"]) for node in module_t.struct_defs] flags = [(node.name, node._metadata["flag_type"]) for node in module_t.flag_defs] + return cls._from_lists(module_t._id, module_t.decl_node, funcs, events, structs, flags) @classmethod From 39e955dbcde0dddc983351f54644c833736dd790 Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Sat, 12 Oct 2024 09:39:08 +0800 Subject: [PATCH 13/15] remove more debug prints --- vyper/semantics/analysis/constant_folding.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/vyper/semantics/analysis/constant_folding.py b/vyper/semantics/analysis/constant_folding.py index 5556905687..80c5b5ab04 100644 --- a/vyper/semantics/analysis/constant_folding.py +++ b/vyper/semantics/analysis/constant_folding.py @@ -90,7 +90,6 @@ def visit_Name(self, node) -> vy_ast.ExprNode: raise UnfoldableNode("unknown name", node) def visit_Attribute(self, node) -> vy_ast.ExprNode: - print("visit Attribute") namespace = get_namespace() path = [] value = node.value @@ -101,7 +100,6 @@ def visit_Attribute(self, node) -> vy_ast.ExprNode: path.reverse() if not isinstance(value, vy_ast.Name): - print("not foldable") raise UnfoldableNode("not a module", value) # not super type-safe but we don't care. just catch AttributeErrors From 785b606572711203bd1ddca2d3518ada4521b194 Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Sat, 12 Oct 2024 09:40:09 +0800 Subject: [PATCH 14/15] clean up --- vyper/semantics/analysis/constant_folding.py | 2 ++ vyper/semantics/types/module.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/vyper/semantics/analysis/constant_folding.py b/vyper/semantics/analysis/constant_folding.py index 80c5b5ab04..98cab0f8cb 100644 --- a/vyper/semantics/analysis/constant_folding.py +++ b/vyper/semantics/analysis/constant_folding.py @@ -106,8 +106,10 @@ def visit_Attribute(self, node) -> vy_ast.ExprNode: # and move on try: module_t = namespace[value.id].module_t + for module_name in path: module_t = module_t.members[module_name].module_t + varinfo = module_t.get_member(node.attr, node) return varinfo.decl_node.value.get_folded_value() diff --git a/vyper/semantics/types/module.py b/vyper/semantics/types/module.py index 46ec6d4a75..11f083fb54 100644 --- a/vyper/semantics/types/module.py +++ b/vyper/semantics/types/module.py @@ -67,7 +67,7 @@ def __init__( self.decl_node = decl_node def get_type_member(self, attr, node): - # get an event, struct or constant from this interface + # get an event, struct or flag from this interface return TYPE_T(self._helper.get_member(attr, node)) @property From d936b866506d4a3b7368a318ded5da217dbb6833 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Mon, 14 Oct 2024 21:28:44 -0400 Subject: [PATCH 15/15] small cleanup --- vyper/semantics/types/module.py | 34 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/vyper/semantics/types/module.py b/vyper/semantics/types/module.py index 866d302a78..dabeaf21b6 100644 --- a/vyper/semantics/types/module.py +++ b/vyper/semantics/types/module.py @@ -165,10 +165,10 @@ def _from_lists( struct_list: Optional[list[tuple[str, StructT]]] = None, flag_list: Optional[list[tuple[str, FlagT]]] = None, ) -> "InterfaceT": - functions = {} - events = {} - structs = {} - flags = {} + functions: dict[str, ContractFunctionT] = {} + events: dict[str, EventT] = {} + structs: dict[str, StructT] = {} + flags: dict[str, FlagT] = {} seen_items: dict = {} @@ -179,24 +179,18 @@ def _mark_seen(name, item): raise NamespaceCollision(msg, item.decl_node, prev_decl=prev_decl) seen_items[name] = item - for name, function in function_list: - _mark_seen(name, function) - functions[name] = function + def _process(dst_dict, items): + if items is None: + return - if event_list: - for name, event in event_list: - _mark_seen(name, event) - events[name] = event + for name, item in items: + _mark_seen(name, item) + dst_dict[name] = item - if struct_list: - for name, struct in struct_list: - _mark_seen(name, struct) - structs[name] = struct - - if flag_list: - for name, flag in flag_list: - _mark_seen(name, flag) - flags[name] = flag + _process(functions, function_list) + _process(events, event_list) + _process(structs, struct_list) + _process(flags, flag_list) return cls(interface_name, decl_node, functions, events, structs, flags)