diff --git a/tests/unit/semantics/analysis/test_array_index.py b/tests/unit/semantics/analysis/test_array_index.py index b5bf86494d..31607537c3 100644 --- a/tests/unit/semantics/analysis/test_array_index.py +++ b/tests/unit/semantics/analysis/test_array_index.py @@ -55,6 +55,28 @@ def foo(): analyze_module(vyper_module, dummy_input_bundle) +def test_empty_array_index(dummy_input_bundle): + code = """ +a: constant(DynArray[uint256, 3]) = [] + +@internal +def foo(): + b: uint256 = a[0] + """ + vyper_module = parse_to_ast(code) + with pytest.raises(ArrayIndexException): + analyze_module(vyper_module, dummy_input_bundle) + + code = """ +@internal +def foo(): + b: uint256 = empty(DynArray[uint256, 3])[0] + """ + vyper_module = parse_to_ast(code) + with pytest.raises(ArrayIndexException): + analyze_module(vyper_module, dummy_input_bundle) + + @pytest.mark.parametrize("value", ["b", "self.b"]) def test_undeclared_definition(namespace, value, dummy_input_bundle): code = f""" diff --git a/vyper/builtins/functions.py b/vyper/builtins/functions.py index 280aaea266..026b88e20a 100644 --- a/vyper/builtins/functions.py +++ b/vyper/builtins/functions.py @@ -49,6 +49,7 @@ StructureException, TypeMismatch, UnfoldableNode, + UnknownType, ZeroDivisionException, ) from vyper.semantics.analysis.base import Modifiability, VarInfo @@ -2229,6 +2230,18 @@ def build_IR(self, expr, args, kwargs, context): class Empty(TypenameFoldedFunctionT): _id = "empty" + def _try_fold(self, node): + try: + type_ = self.fetch_call_return(node) + except UnknownType: + raise UnfoldableNode + + # special handling for dynamic arrays to catch indexing of zero arrays + if not isinstance(type_, DArrayT): + raise UnfoldableNode + + return vy_ast.List.from_node(node, elements=[]) + def fetch_call_return(self, node): type_ = self.infer_arg_types(node)[0].typedef if isinstance(type_, HashMapT): diff --git a/vyper/semantics/analysis/local.py b/vyper/semantics/analysis/local.py index 26c6a4ef9f..8ca6861d8b 100644 --- a/vyper/semantics/analysis/local.py +++ b/vyper/semantics/analysis/local.py @@ -6,6 +6,7 @@ from vyper import ast as vy_ast from vyper.ast.validation import validate_call_args from vyper.exceptions import ( + ArrayIndexException, CallViolation, ExceptionList, FunctionDeclarationException, @@ -920,6 +921,10 @@ def visit_Subscript(self, node: vy_ast.Subscript, typ: VyperType) -> None: # Arrays allow most int types as index: Take the least specific index_type = get_possible_types_from_node(node.slice).pop() + val = node.value.reduced() + if isinstance(val, vy_ast.List) and len(val.elements) == 0: + raise ArrayIndexException("Indexing into empty array is not allowed", node.value) + self.visit(node.value, base_type) self.visit(node.slice, index_type)