diff --git a/vyper/semantics/analysis/module.py b/vyper/semantics/analysis/module.py index e50c3e6d6f..9304eb3ded 100644 --- a/vyper/semantics/analysis/module.py +++ b/vyper/semantics/analysis/module.py @@ -342,7 +342,14 @@ def visit_ImplementsDecl(self, node): type_ = type_from_annotation(node.annotation) if not isinstance(type_, InterfaceT): - raise StructureException("not an interface!", node.annotation) + msg = "Not an interface!" + hint = None + if isinstance(type_, ModuleT): + path = type_._module.path + msg += " (Since vyper v0.4.0, interface files are required" + msg += " to have a .vyi suffix.)" + hint = f"try renaming `{path}` to `{path}i`" + raise StructureException(msg, node.annotation, hint=hint) type_.validate_implements(node) @@ -627,6 +634,9 @@ def _load_import(self, node: vy_ast.VyperNode, level: int, module_str: str, alia def _load_import_helper( self, node: vy_ast.VyperNode, level: int, module_str: str, alias: str ) -> Any: + if module_str.startswith("vyper.interfaces"): + hint = "try renaming `vyper.interfaces` to `ethereum.ercs`" + raise ModuleNotFound(module_str, hint=hint) if _is_builtin(module_str): return _load_builtin_import(level, module_str) @@ -724,7 +734,7 @@ def _is_builtin(module_str): def _load_builtin_import(level: int, module_str: str) -> InterfaceT: if not _is_builtin(module_str): - raise ModuleNotFoundError(f"Not a builtin: {module_str}") from None + raise ModuleNotFoundError(f"Not a builtin: {module_str}") builtins_path = vyper.builtins.interfaces.__path__[0] # hygiene: convert to relpath to avoid leaking user directory info diff --git a/vyper/semantics/types/utils.py b/vyper/semantics/types/utils.py index c6a4531df8..96c661021f 100644 --- a/vyper/semantics/types/utils.py +++ b/vyper/semantics/types/utils.py @@ -3,6 +3,7 @@ from vyper import ast as vy_ast from vyper.exceptions import ( ArrayIndexException, + CompilerPanic, InstantiationException, InvalidType, StructureException, @@ -158,6 +159,12 @@ def _type_from_annotation(node: vy_ast.VyperNode) -> VyperType: # call from_annotation to produce a better error message. typ_.from_annotation(node) + if hasattr(typ_, "module_t"): # it's a ModuleInfo + typ_ = typ_.module_t + + if not isinstance(typ_, VyperType): + raise CompilerPanic("Not a type: {typ_}", node) + return typ_