From be49c815ebeb6b97c33174b109791c3a53f34e80 Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Fri, 31 Oct 2025 14:58:12 +0000 Subject: [PATCH 1/3] fix[parser]: Make duplicate built-in import exception consistent --- .../codegen/modules/test_stateless_functions.py | 10 ++++++++++ vyper/semantics/analysis/imports.py | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/tests/functional/codegen/modules/test_stateless_functions.py b/tests/functional/codegen/modules/test_stateless_functions.py index 5b5dd7a635..33cc7f25b8 100644 --- a/tests/functional/codegen/modules/test_stateless_functions.py +++ b/tests/functional/codegen/modules/test_stateless_functions.py @@ -323,6 +323,16 @@ def test_reject_duplicate_imports(make_input_bundle): compiler.compile_code(contract_source, input_bundle=input_bundle) +def test_reject_duplicate_builtin_imports(make_input_bundle): + contract_source = """ +import math +import math as math2 + """ + input_bundle = make_input_bundle({"contract.vy": contract_source}) + with pytest.raises(DuplicateImport): + compiler.compile_code(contract_source, input_bundle=input_bundle) + + def test_nested_module_access(get_contract, make_input_bundle): lib1 = """ import lib2 diff --git a/vyper/semantics/analysis/imports.py b/vyper/semantics/analysis/imports.py index 02836c97a4..a521218588 100644 --- a/vyper/semantics/analysis/imports.py +++ b/vyper/semantics/analysis/imports.py @@ -88,6 +88,7 @@ class ImportAnalyzer: seen: OrderedSet[vy_ast.Module] _compiler_inputs: dict[CompilerInput, vy_ast.Module] toplevel_module: vy_ast.Module + importedBuiltins: dict[str, vy_ast.VyperNode] = dict() def __init__(self, input_bundle: InputBundle, graph: _ImportGraph, module_ast: vy_ast.Module): self.input_bundle = input_bundle @@ -187,6 +188,13 @@ def _load_import( self, node: vy_ast.VyperNode, level: int, module_str: str, alias: str ) -> tuple[CompilerInput, Any]: if _is_builtin(level, module_str): + if module_str in self.importedBuiltins: + previous_import_stmt = self.importedBuiltins[module_str] + raise DuplicateImport( + f"{module_str} imported more than once!", previous_import_stmt, node + ) + + self.importedBuiltins[module_str] = node return _load_builtin_import(level, module_str) path = _import_to_path(level, module_str) From 2011051e9be26cb80000df555a59ada71487d0eb Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Mon, 3 Nov 2025 09:04:12 +0000 Subject: [PATCH 2/3] Fix mistaken multiple import error --- vyper/semantics/analysis/imports.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vyper/semantics/analysis/imports.py b/vyper/semantics/analysis/imports.py index a521218588..ee606d6136 100644 --- a/vyper/semantics/analysis/imports.py +++ b/vyper/semantics/analysis/imports.py @@ -88,11 +88,12 @@ class ImportAnalyzer: seen: OrderedSet[vy_ast.Module] _compiler_inputs: dict[CompilerInput, vy_ast.Module] toplevel_module: vy_ast.Module - importedBuiltins: dict[str, vy_ast.VyperNode] = dict() + importedBuiltins: dict[str, vy_ast.VyperNode] def __init__(self, input_bundle: InputBundle, graph: _ImportGraph, module_ast: vy_ast.Module): self.input_bundle = input_bundle self.graph = graph + self.importedBuiltins = {} self.toplevel_module = module_ast self._ast_of: dict[int, vy_ast.Module] = {} From 46be18dba905cb2f7c43d9b0259ecdc0df0c90b2 Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Mon, 3 Nov 2025 09:49:35 +0000 Subject: [PATCH 3/3] Use self.graph for more reliability --- vyper/semantics/analysis/imports.py | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/vyper/semantics/analysis/imports.py b/vyper/semantics/analysis/imports.py index ee606d6136..ddc76a809f 100644 --- a/vyper/semantics/analysis/imports.py +++ b/vyper/semantics/analysis/imports.py @@ -88,12 +88,10 @@ class ImportAnalyzer: seen: OrderedSet[vy_ast.Module] _compiler_inputs: dict[CompilerInput, vy_ast.Module] toplevel_module: vy_ast.Module - importedBuiltins: dict[str, vy_ast.VyperNode] def __init__(self, input_bundle: InputBundle, graph: _ImportGraph, module_ast: vy_ast.Module): self.input_bundle = input_bundle self.graph = graph - self.importedBuiltins = {} self.toplevel_module = module_ast self._ast_of: dict[int, vy_ast.Module] = {} @@ -188,16 +186,6 @@ def _add_import( def _load_import( self, node: vy_ast.VyperNode, level: int, module_str: str, alias: str ) -> tuple[CompilerInput, Any]: - if _is_builtin(level, module_str): - if module_str in self.importedBuiltins: - previous_import_stmt = self.importedBuiltins[module_str] - raise DuplicateImport( - f"{module_str} imported more than once!", previous_import_stmt, node - ) - - self.importedBuiltins[module_str] = node - return _load_builtin_import(level, module_str) - path = _import_to_path(level, module_str) if path in self.graph.imported_modules: @@ -206,6 +194,9 @@ def _load_import( self.graph.imported_modules[path] = node + if _is_builtin(level, module_str): + return _load_builtin_import(level, module_str) + err = None try: