Skip to content
New issue

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

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

Already on GitHub? # to your account

fix[lang]: transitive exports #3888

Merged
Merged
Show file tree
Hide file tree
Changes from all 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
7 changes: 1 addition & 6 deletions tests/functional/codegen/modules/test_exports.py
Copy link
Collaborator

Choose a reason for hiding this comment

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

the current test for transitive exports is pretty limited. Is there a smart way, where we can fuzz different nestedness & visibility decorators?

Copy link
Member Author

Choose a reason for hiding this comment

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

hmm i don't think we need to "fuzz" so to speak, and the external/internal distinction should be tested in other tests already. as for nesting, we could maybe set up a chaining test for like 1-5 levels of nesting.

Copy link
Collaborator

Choose a reason for hiding this comment

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

yeah, that sounds reasonable to me.

Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import pytest


def test_simple_export(make_input_bundle, get_contract):
lib1 = """
@external
Expand Down Expand Up @@ -131,9 +128,7 @@ def foo() -> uint256:
assert c.foo() == 5


# not sure if this one should work
@pytest.mark.xfail(reason="ambiguous spec")
Copy link
Collaborator

Choose a reason for hiding this comment

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

For the the future we should track these cases (i.e. ambiguous spec) somewhere properly, since we obviously forgot about it and thanks to feedback rediscovered it.

Nit: if we use xfail, we should also add the reason attribute instead of a comment to be consistent:

Copy link
Member Author

Choose a reason for hiding this comment

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

i don't really get this -- it's easy to grep the codebase or to run with pytest --runxfail. i guess you mean we should be doing this on a regular basis?

Copy link
Collaborator

Choose a reason for hiding this comment

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

it's easy to grep the codebase or to run with pytest --runxfail. i guess you mean we should be doing this on a regular basis?

My point is not that it's easy, but that we forget about certain xfail tests that are part of a bigger features (like in this case) and we forget to address it before the release.

def test_recursive_export(make_input_bundle, get_contract):
def test_transitive_export(make_input_bundle, get_contract):
lib1 = """
@external
def foo() -> uint256:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: this should be @pure

Expand Down
3 changes: 2 additions & 1 deletion vyper/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,9 @@ def format_annotation(self, value):
return None

if isinstance(node, vy_ast.VyperNode):
module_node = node.get_ancestor(vy_ast.Module)
module_node = node.module_node

# TODO: handle cases where module is None or vy_ast.Module
if module_node.get("path") not in (None, "<unknown>"):
node_msg = f'{node_msg}contract "{module_node.path}:{node.lineno}", '

Expand Down
2 changes: 1 addition & 1 deletion vyper/semantics/analysis/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ def visit_ExportsDecl(self, node):
decl_node = func_t.decl_node

if not isinstance(func_t, ContractFunctionT):
raise StructureException("not a function!", decl_node, item)
raise StructureException(f"not a function: `{func_t}`", decl_node, item)
if not func_t.is_external:
raise StructureException("can't export non-external functions!", decl_node, item)

Expand Down
4 changes: 4 additions & 0 deletions vyper/semantics/types/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,10 @@ def __init__(self, module: vy_ast.Module, name: Optional[str] = None):
# note: this checks for collisions
self.add_member(f.name, f._metadata["func_type"])

for item in self.exports_decls:
for fn_t in item._metadata["exports_info"].functions:
self.add_member(fn_t.name, fn_t)

for e in self.event_defs:
# add the type of the event so it can be used in call position
self.add_member(e.name, TYPE_T(e._metadata["event_type"])) # type: ignore
Expand Down
Loading