From 12da260f7cabb55b81ea94f2399be40a8ebe58cc Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Mon, 21 Oct 2024 19:51:06 -0400 Subject: [PATCH] feat[lang]: reject `implements` for empty interfaces `implements: ` for an empty interface likely indicates a bug in user code, reject it. --- .../syntax/modules/test_implements.py | 21 +++++++++++++++++++ vyper/semantics/types/module.py | 4 ++++ 2 files changed, 25 insertions(+) diff --git a/tests/functional/syntax/modules/test_implements.py b/tests/functional/syntax/modules/test_implements.py index c292e198d9..4144b0f28b 100644 --- a/tests/functional/syntax/modules/test_implements.py +++ b/tests/functional/syntax/modules/test_implements.py @@ -1,4 +1,7 @@ +import pytest + from vyper.compiler import compile_code +from vyper.exceptions import StructureException def test_implements_from_vyi(make_input_bundle): @@ -49,3 +52,21 @@ def foo(): # implementation input_bundle = make_input_bundle({"some_interface.vyi": vyi, "lib1.vy": lib1, "lib2.vy": lib2}) assert compile_code(main, input_bundle=input_bundle) is not None + + +def test_implements_empty_vyi(make_input_bundle, tmp_path): + vyi = "" + input_bundle = make_input_bundle({"some_interface.vyi": vyi}) + main = """ +import some_interface + +implements: some_interface + """ + with pytest.raises(StructureException) as e: + _ = compile_code(main, input_bundle=input_bundle) + + vyi_path = (tmp_path / "some_interface.vyi").as_posix() + assert ( + e.value._message + == f"Tried to implement `{vyi_path}`, but it has no functions to implement!" + ) diff --git a/vyper/semantics/types/module.py b/vyper/semantics/types/module.py index dabeaf21b6..7ba73da87f 100644 --- a/vyper/semantics/types/module.py +++ b/vyper/semantics/types/module.py @@ -112,6 +112,10 @@ def _ctor_modifiability_for_call(self, node: vy_ast.Call, modifiability: Modifia def validate_implements( self, node: vy_ast.ImplementsDecl, functions: dict[ContractFunctionT, vy_ast.VyperNode] ) -> None: + if len(self.functions) == 0: + msg = f"Tried to implement `{self}`, but it has no functions to implement!" + raise StructureException(msg, node) + # only external functions can implement interfaces fns_by_name = {fn_t.name: fn_t for fn_t in functions.keys()}