From 67f8890bbc207442bfd752ef77d30fa46dffcccb Mon Sep 17 00:00:00 2001 From: Ben Hauser Date: Sat, 10 Oct 2020 15:06:50 +0300 Subject: [PATCH 1/3] feat: add `is_dynamic_size` attribute to type definitions --- vyper/context/types/bases.py | 2 ++ vyper/context/types/indexable/sequence.py | 8 ++++++++ vyper/context/types/meta/struct.py | 4 ++++ vyper/context/types/value/array_value.py | 2 ++ 4 files changed, 16 insertions(+) diff --git a/vyper/context/types/bases.py b/vyper/context/types/bases.py index 2b4bc833ba..a6178aaa21 100644 --- a/vyper/context/types/bases.py +++ b/vyper/context/types/bases.py @@ -187,6 +187,8 @@ class BaseTypeDefinition: If `True`, the value of this object cannot be modified after assignment. """ + is_dynamic_size = False + def __init__( self, location: DataLocation = DataLocation.UNSET, diff --git a/vyper/context/types/indexable/sequence.py b/vyper/context/types/indexable/sequence.py index 87bcc06e22..51230c3949 100644 --- a/vyper/context/types/indexable/sequence.py +++ b/vyper/context/types/indexable/sequence.py @@ -66,6 +66,10 @@ def __init__( def __repr__(self): return f"{self.value_type}[{self.length}]" + @property + def is_dynamic_size(self): + return self.value_type.is_dynamic_size + def get_index_type(self, node): if isinstance(node, vy_ast.Int): if node.value < 0: @@ -107,6 +111,10 @@ def __init__(self, value_type: Tuple[BaseTypeDefinition, ...]) -> None: def __repr__(self): return self._id + @property + def is_dynamic_size(self): + return any(i for i in self.self.value_type if i.is_dynamic_size) + def get_index_type(self, node): if not isinstance(node, vy_ast.Int): raise InvalidType("Tuple indexes must be literals", node) diff --git a/vyper/context/types/meta/struct.py b/vyper/context/types/meta/struct.py index 2006f0fa2f..6e360cef1b 100644 --- a/vyper/context/types/meta/struct.py +++ b/vyper/context/types/meta/struct.py @@ -28,6 +28,10 @@ def __init__( for key, type_ in members.items(): self.add_member(key, type_) + @property + def is_dynamic_size(self): + return any(i for i in self.members.values() if i.is_dynamic_size) + def compare_type(self, other): return super().compare_type(other) and self._id == other._id diff --git a/vyper/context/types/value/array_value.py b/vyper/context/types/value/array_value.py index f18e07409d..9d98570fde 100644 --- a/vyper/context/types/value/array_value.py +++ b/vyper/context/types/value/array_value.py @@ -34,6 +34,8 @@ class _ArrayValueDefinition(ValueTypeDefinition): is applied to a literal definition. """ + is_dynamic_size = True + def __repr__(self): return f"{self._id}[{self.length}]" From 86c8efc99435bd14fafc4d62a19a83e9c9f362aa Mon Sep 17 00:00:00 2001 From: Ben Hauser Date: Sat, 10 Oct 2020 15:08:05 +0300 Subject: [PATCH 2/3] fix: add check to prevent dynamic-length struct as a function input --- vyper/context/types/function.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/vyper/context/types/function.py b/vyper/context/types/function.py index 4fb80d8a6d..3e5dc5fc85 100644 --- a/vyper/context/types/function.py +++ b/vyper/context/types/function.py @@ -7,6 +7,7 @@ from vyper.context.namespace import get_namespace from vyper.context.types.bases import BaseTypeDefinition, DataLocation from vyper.context.types.indexable.sequence import TupleDefinition +from vyper.context.types.meta.struct import StructDefinition from vyper.context.types.utils import ( StringEnum, check_constant, @@ -290,6 +291,13 @@ def from_FunctionDef( type_definition = get_type_from_annotation( arg.annotation, location=DataLocation.CALLDATA, is_immutable=True ) + if isinstance(type_definition, StructDefinition) and type_definition.is_dynamic_size: + # this is a temporary restriction and should be removed once support for dynamically + # sized structs is implemented - https://github.com/vyperlang/vyper/issues/2190 + raise ArgumentException( + "Struct with dynamically sized data cannot be used as a function input", arg + ) + if value is not None: if not check_constant(value): raise StateAccessViolation( From c4e5ffe73b89d51a8055a32705ed1ff6a7559cdd Mon Sep 17 00:00:00 2001 From: Ben Hauser Date: Sat, 10 Oct 2020 15:14:12 +0300 Subject: [PATCH 3/3] test: add test for dynamic-sized struct in calldata --- .../exceptions/test_argument_exception.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/parser/exceptions/test_argument_exception.py b/tests/parser/exceptions/test_argument_exception.py index 17f4a1bab4..b922cc08d6 100644 --- a/tests/parser/exceptions/test_argument_exception.py +++ b/tests/parser/exceptions/test_argument_exception.py @@ -89,6 +89,31 @@ def foo(): for i in range(1, 2, 3, 4): pass """, + """ +struct Foo: + a: Bytes[32] + +@external +def foo(a: Foo): + pass + """, + """ +struct Foo: + a: String[32] + +@external +def foo(a: Foo): + pass + """, + """ +struct Foo: + b: uint256 + a: String[32] + +@external +def foo(a: Foo): + pass + """, ]