Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat[lang]: support flags from imported interfaces #4253

Merged
merged 20 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions tests/functional/codegen/modules/test_interface_imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,31 @@ def foo() -> bool:
c = get_contract(main, input_bundle=input_bundle)

assert c.foo() is True


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
51 changes: 29 additions & 22 deletions vyper/semantics/types/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Fixed Show fixed Hide fixed

Check notice

Code scanning / CodeQL

Cyclic import Note

Import of module
vyper.semantics.types.user
begins an import cycle.
from vyper.utils import OrderedSet

if TYPE_CHECKING:
Expand All @@ -45,27 +45,29 @@
functions: dict,
events: dict,
structs: dict,
flags: dict,
) -> None:
validate_unique_method_ids(list(functions.values()))

members = functions | events | structs
members = functions | events | structs | flags

# 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(flags)

super().__init__(functions)

self._helper = VyperType(events | structs)
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.decl_node = decl_node

def get_type_member(self, attr, node):
# get an event or struct from this interface
# get an event, struct or flag from this interface
return TYPE_T(self._helper.get_member(attr, node))

@property
Expand Down Expand Up @@ -159,12 +161,14 @@
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,
flag_list: Optional[list[tuple[str, FlagT]]] = None,
) -> "InterfaceT":
functions = {}
events = {}
structs = {}
flags = {}

seen_items: dict = {}

Expand All @@ -179,15 +183,22 @@
_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

Check warning on line 189 in vyper/semantics/types/module.py

View check run for this annotation

Codecov / codecov/patch

vyper/semantics/types/module.py#L188-L189

Added lines #L188 - L189 were not covered by tests

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

return cls(interface_name, decl_node, functions, events, structs)
if flag_list:
for name, flag in flag_list:
_mark_seen(name, flag)
flags[name] = flag

Check warning on line 199 in vyper/semantics/types/module.py

View check run for this annotation

Codecov / codecov/patch

vyper/semantics/types/module.py#L198-L199

Added lines #L198 - L199 were not covered by tests

return cls(interface_name, decl_node, functions, events, structs, flags)

@classmethod
def from_json_abi(cls, name: str, abi: dict) -> "InterfaceT":
Expand All @@ -214,8 +225,7 @@
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)

Check warning on line 228 in vyper/semantics/types/module.py

View check run for this annotation

Codecov / codecov/patch

vyper/semantics/types/module.py#L228

Added line #L228 was not covered by tests

@classmethod
def from_ModuleT(cls, module_t: "ModuleT") -> "InterfaceT":
Expand Down Expand Up @@ -247,8 +257,9 @@
# 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]

return cls._from_lists(module_t._id, module_t.decl_node, funcs, events, structs)
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":
Expand All @@ -265,11 +276,7 @@
)
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)

Check warning on line 279 in vyper/semantics/types/module.py

View check run for this annotation

Codecov / codecov/patch

vyper/semantics/types/module.py#L279

Added line #L279 was not covered by tests
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

much cleaner now, thanks



# Datatype to store all module information.
Expand Down
Loading