diff --git a/vyper/semantics/analysis/module.py b/vyper/semantics/analysis/module.py index 8a2beb61e6..ba621e1403 100644 --- a/vyper/semantics/analysis/module.py +++ b/vyper/semantics/analysis/module.py @@ -40,7 +40,7 @@ ) from vyper.semantics.data_locations import DataLocation from vyper.semantics.namespace import Namespace, get_namespace, override_global_namespace -from vyper.semantics.types import EventT, FlagT, InterfaceT, StructT +from vyper.semantics.types import TYPE_T, EventT, FlagT, InterfaceT, StructT from vyper.semantics.types.function import ContractFunctionT from vyper.semantics.types.module import ModuleT from vyper.semantics.types.utils import type_from_annotation @@ -497,6 +497,16 @@ def visit_ExportsDecl(self, node): decl = info.var_info.decl_node if not info.var_info.is_public: raise StructureException("not a public variable!", decl, item) + # e.g. self.foo_variable + if not isinstance(item, vy_ast.Attribute) or not isinstance( + get_expr_info(item.value).typ, (ModuleT, TYPE_T) + ): + raise StructureException( + "invalid export of a value", + item.value, + hint="exports should look like .", + ) + funcs = [decl._expanded_getter._metadata["func_type"]] elif isinstance(info.typ, ContractFunctionT): # regular function