Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade to Next #2029

Merged
merged 72 commits into from
Jun 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
384ae5b
feat: add _is_terminus attribute to nodes
iamdefinitelyahuman Jun 20, 2020
14f6ce5
feat: expand validate_call_args functionality
iamdefinitelyahuman Jun 20, 2020
476aac6
chore: update nodes typing stub
iamdefinitelyahuman Jun 20, 2020
930fe1a
chore: adjust import sequence
iamdefinitelyahuman Jun 20, 2020
5c40497
feat: Namespace object
iamdefinitelyahuman Jun 20, 2020
58426b1
feat: UnknownType / UnknownAttribute
iamdefinitelyahuman Jun 20, 2020
80c4c45
feat: ExceptionList
iamdefinitelyahuman Jun 20, 2020
50e5c72
feat: abstract data type classes
iamdefinitelyahuman Jun 20, 2020
7e9becd
feat: base type classes
iamdefinitelyahuman Jun 20, 2020
3c37d41
feat: boolean type
iamdefinitelyahuman Jun 20, 2020
b3667bb
feat: bytes32 classes
iamdefinitelyahuman Jun 20, 2020
7610380
feat: numeric type classes
iamdefinitelyahuman Jun 20, 2020
71994bf
feat: string and bytes array types
iamdefinitelyahuman Jun 20, 2020
c488f0a
feat: address type classes
iamdefinitelyahuman Jun 20, 2020
8c29b8d
feat: type validation functions
iamdefinitelyahuman Jun 20, 2020
c32a8a3
feat: array and tuple type classes
iamdefinitelyahuman Jun 20, 2020
ab0a10e
feat: mapping type classes
iamdefinitelyahuman Jun 20, 2020
4235ef3
feat: get/build functions for type classes
iamdefinitelyahuman Jun 20, 2020
6c8078a
feat: interface class types and build functions
iamdefinitelyahuman Jun 20, 2020
2c9afc1
feat: struct type classes and build functions
iamdefinitelyahuman Jun 20, 2020
b44e189
feat: type subpackage init modules
iamdefinitelyahuman Jun 20, 2020
86c5f76
feat: get_types and get_pure_types
iamdefinitelyahuman Jun 20, 2020
58a51ac
feat: event type
iamdefinitelyahuman Jun 20, 2020
74cf429
feat: function type
iamdefinitelyahuman Jun 20, 2020
64b9007
feat: environment variables
iamdefinitelyahuman Jun 20, 2020
e064c43
feat: validation node visitor base class
iamdefinitelyahuman Jun 20, 2020
d0bef4f
feat: module-level validation logic
iamdefinitelyahuman Jun 20, 2020
259442d
feat: function-level validation logic
iamdefinitelyahuman Jun 20, 2020
39a03f4
feat: validation __init__
iamdefinitelyahuman Jun 20, 2020
ac2b14c
feat: context __init__
iamdefinitelyahuman Jun 20, 2020
5eb00a6
doc: context readme
iamdefinitelyahuman Jun 20, 2020
b91ecdf
feat: add type-check logic to builtin functions
iamdefinitelyahuman Jun 20, 2020
36980b7
feat: add type checking to main compiler logic
iamdefinitelyahuman Jun 20, 2020
053ada9
test: update exception tests
iamdefinitelyahuman Jun 20, 2020
4bf8fca
test: update syntax tests
iamdefinitelyahuman Jun 20, 2020
b2481db
test: update function tests
iamdefinitelyahuman Jun 20, 2020
4924870
test: update misc tests
iamdefinitelyahuman Jun 20, 2020
7c462c5
feat: more internal exceptions, adjust where/how exceptions raise
iamdefinitelyahuman Jun 21, 2020
19ecd3e
fix: adjust get_index_value exceptions
iamdefinitelyahuman Jun 21, 2020
035d1ad
feat: handle arrays in get_type_from_abi
iamdefinitelyahuman Jun 21, 2020
fe45cba
refactor: remove `build_type_from_ann_assign`
iamdefinitelyahuman Jun 21, 2020
6428c22
refactor: move function constancy checks to validation/local
iamdefinitelyahuman Jun 21, 2020
83d9462
refactor: reduce duplicate code in op validation
iamdefinitelyahuman Jun 21, 2020
b93a5e4
test: functional tests for context/types
iamdefinitelyahuman Jun 21, 2020
786f744
test: functional tests for context/validation
iamdefinitelyahuman Jun 21, 2020
f552ec9
fix: modifications per code review
iamdefinitelyahuman Jun 22, 2020
33079b2
refactor: expand logic in get_type_from_abi
iamdefinitelyahuman Jun 22, 2020
c70b2d2
style: rename pure type to primitive
iamdefinitelyahuman Jun 22, 2020
2232557
refactor: remove redundant constants logic
iamdefinitelyahuman Jun 20, 2020
1e40d2e
feat: TypeCheckFailure exception
iamdefinitelyahuman Jun 20, 2020
44b6cfa
style: raise internal errors in parser/context
iamdefinitelyahuman Jun 20, 2020
2862a16
refactor: remove type checking assign methods in stmt
iamdefinitelyahuman Jun 22, 2020
715bd77
refactor: remove dead code from parser/external_call
iamdefinitelyahuman Jun 22, 2020
2dbb718
refactor: remove type check logic from parser_utils
iamdefinitelyahuman Jun 22, 2020
b6b5150
refactor: rebuild Stmt
iamdefinitelyahuman Jun 22, 2020
863abc7
refactor: rebuild Expr
iamdefinitelyahuman Jun 22, 2020
b2ae904
fix: handle zero division in type checking
iamdefinitelyahuman Jun 22, 2020
a89b7d9
fix: empty assert reason string
iamdefinitelyahuman Jun 23, 2020
749f494
fix: for loop checks
iamdefinitelyahuman Jun 23, 2020
c0bd847
fix: function calls
iamdefinitelyahuman Jun 23, 2020
d32a3fe
feat: add location data to types
iamdefinitelyahuman Jun 23, 2020
7a30e9f
fix: constancy check on iterated value in for loop
iamdefinitelyahuman Jun 23, 2020
a188dd8
refactor: remove dead parser code
iamdefinitelyahuman Jun 23, 2020
9f7fef8
test: fix failing tests
iamdefinitelyahuman Jun 23, 2020
43fa61c
mypy: update nodes stubfile
iamdefinitelyahuman Jun 24, 2020
3f62d6e
feat: annotate exceptions with multiple nodes
iamdefinitelyahuman Jun 24, 2020
5795396
feat: circular dependency check
iamdefinitelyahuman Jun 24, 2020
b0b3412
feat: check for modification of iterated variable across functions
iamdefinitelyahuman Jun 24, 2020
ddbba93
fix: apply constancy to interface functions
iamdefinitelyahuman Jun 24, 2020
73d3ac6
fix: indexed event limit
iamdefinitelyahuman Jun 24, 2020
ac36b2b
test: add new tests, fix failing tests
iamdefinitelyahuman Jun 24, 2020
a4039fa
refactor: swap exceptions for internal exceptions
iamdefinitelyahuman Jun 24, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions tests/cli/vyper_json/test_compile_from_input_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
exc_handler_raises,
exc_handler_to_dict,
)
from vyper.exceptions import JSONError, SyntaxException, TypeMismatch
from vyper.exceptions import InvalidType, JSONError, SyntaxException

FOO_CODE = """
import contracts.bar as Bar
Expand Down Expand Up @@ -98,7 +98,7 @@ def test_exc_handler_to_dict_syntax():
def test_exc_handler_raises_compiler():
input_json = deepcopy(INPUT_JSON)
input_json['sources']['badcode.vy'] = {'content': BAD_COMPILER_CODE}
with pytest.raises(TypeMismatch):
with pytest.raises(InvalidType):
compile_from_input_dict(input_json, exc_handler_raises)


Expand All @@ -111,7 +111,7 @@ def test_exc_handler_to_dict_compiler():
assert len(result['errors']) == 1
error = result['errors'][0]
assert error['component'] == "compiler"
assert error['type'] == "TypeMismatch"
assert error['type'] == "InvalidType"


def test_source_ids_increment():
Expand Down
2 changes: 1 addition & 1 deletion tests/compiler/test_pre_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def test_valid_semicolons(get_contract):
def test() -> int128:
a: int128 = 1
b: int128 = 2
s: bytes[300] = "this should not be a problem; because it is in a string"
s: string[300] = "this should not be a problem; because it is in a string"
s = \"\"\"this should not be a problem; because it's in a string\"\"\"
s = 'this should not be a problem;;; because it\\\'s in a string'
s = '''this should not ; \'cause it\'s in a string'''
Expand Down
32 changes: 32 additions & 0 deletions tests/functional/context/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import pytest

from vyper import ast as vy_ast
from vyper.context.namespace import get_namespace


@pytest.fixture(scope="session")
def build_node():
"""
Yields a helper function for generating a single Vyper AST node.
"""

def _build_node(source):
# docstring ensures string nodes are properly generated, not turned into docstrings
source = f"""'I am a docstring.'\n{source}"""
ast = vy_ast.parse_to_ast(source).body[0]
if isinstance(ast, vy_ast.Expr):
ast = ast.value
return ast

yield _build_node


@pytest.fixture
def namespace():
"""
Yields a clean `Namespace` object.
"""
obj = get_namespace()
obj.clear()
yield obj
obj.clear()
119 changes: 119 additions & 0 deletions tests/functional/context/test_namespace.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import pytest

from vyper.context import environment
from vyper.context.namespace import get_namespace
from vyper.context.types import get_types
from vyper.exceptions import (
CompilerPanic,
NamespaceCollision,
UndeclaredDefinition,
)


def test_get_namespace(namespace):
ns = get_namespace()
ns2 = get_namespace()
assert ns == ns2 == namespace


def test_clear(namespace):
namespace["foo"] = 42
assert "foo" in namespace

namespace.clear()
assert "foo" not in namespace


def test_builtin_context_manager(namespace):
namespace["foo"] = 42
with namespace.enter_builtin_scope():
namespace["bar"] = 1337

assert namespace["foo"] == 42
assert "bar" not in namespace


def test_builtin_context_manager_types(namespace):
with namespace.enter_builtin_scope():
for key, value in get_types().items():
assert namespace[key] == value

for key, value in get_types().items():
assert namespace[key] == value


def test_builtin_context_manager_conamespacetant_vars(namespace):
with namespace.enter_builtin_scope():
for key in environment.CONSTANT_ENVIRONMENT_VARS.keys():
assert key in namespace

for key in environment.CONSTANT_ENVIRONMENT_VARS.keys():
assert key in namespace


def test_builtin_context_manager_mutable_vars(namespace):
with namespace.enter_builtin_scope():
for key in environment.MUTABLE_ENVIRONMENT_VARS.keys():
assert key in namespace

for key in environment.MUTABLE_ENVIRONMENT_VARS.keys():
assert key not in namespace


def test_builtin_context_manager_wrong_sequence(namespace):
with namespace.enter_builtin_scope():
# fails because builtin scope may only be entered once
with pytest.raises(CompilerPanic):
with namespace.enter_builtin_scope():
pass


def test_context_manager(namespace):
with namespace.enter_builtin_scope():
namespace["foo"] = 42
with namespace.enter_scope():
namespace["bar"] = 1337

assert namespace["foo"] == 42
assert "bar" not in namespace

assert "foo" not in namespace


def test_context_manager_wrong_sequence(namespace):
with pytest.raises(CompilerPanic):
with namespace.enter_scope():
pass


def test_incorrect_context_invokation(namespace):
with pytest.raises(CompilerPanic):
with namespace:
pass


def test_namespace_collision(namespace):
namespace["foo"] = 42
with pytest.raises(NamespaceCollision):
namespace["foo"] = 1337


def test_namespace_collision_across_scopes(namespace):
with namespace.enter_builtin_scope():
namespace["foo"] = 42
with namespace.enter_scope():
with pytest.raises(NamespaceCollision):
namespace["foo"] = 1337


def test_undeclared_definition(namespace):
with pytest.raises(UndeclaredDefinition):
namespace["foo"]


def test_undeclared_definition_across_scopes(namespace):
with namespace.enter_builtin_scope():
with namespace.enter_scope():
namespace["foo"] = 42
with pytest.raises(UndeclaredDefinition):
namespace["foo"]
132 changes: 132 additions & 0 deletions tests/functional/context/types/test_pure_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import pytest

from vyper.context.types.value.address import AddressPrimitive
from vyper.context.types.value.array_value import (
BytesArrayPrimitive,
StringPrimitive,
)
from vyper.context.types.value.boolean import BoolPrimitive
from vyper.context.types.value.bytes_fixed import Bytes32Primitive
from vyper.context.types.value.numeric import (
DecimalPrimitive,
Int128Primitive,
Uint256Primitive,
)
from vyper.exceptions import (
InvalidLiteral,
OverflowException,
StructureException,
UnexpectedNodeType,
UnexpectedValue,
)

BASE_SOURCE = """
"Add a docstring so the target test node doesn't become one."
"""

PRIMITIVES = {
AddressPrimitive: "address",
BoolPrimitive: "bool",
Bytes32Primitive: "bytes32",
BytesArrayPrimitive: "bytes[1]",
DecimalPrimitive: "decimal",
Int128Primitive: "int128",
StringPrimitive: "string[1]",
Uint256Primitive: "uint256",
}


VALID_LITERALS = {
AddressPrimitive: ["0x6B175474E89094C44Da98b954EedeAC495271d0F"],
BoolPrimitive: ["True", "False"],
Bytes32Primitive: ["0x6B175474E89094C44Da98b954EedeAC495271d0F4Da98b954EedeAC495271d0F"],
BytesArrayPrimitive: [
"b''",
"b'this is thirty three bytes long!!'",
r"b'\xbe\xef'",
"0x6B175474E89094C44Da98b954EedeAC495271d0F",
"0x6B175474E89094C44Da98b954EedeAC495271d0F4Da98b954EedeAC495271d0F",
],
DecimalPrimitive: ["-1.666", "3.31337", "8008135.0", "1.2345678901"],
Int128Primitive: ["-1", "0", "12", "42"],
StringPrimitive: ["''", "'hello'", "'this is thirty three chars long!!'", "'-42'"],
Uint256Primitive: ["0", "12", "42"],
}

INVALID_LITERALS = [
"None",
"115792089237316195423570985008687907853269984665640564039457584007913129639936",
"115792089237316195423570985008687907853269984665640564039457584007913129639935.1",
]
INVALID_NODES = [
"self.{}",
"[{}]",
"({},)",
"{}()",
"{}(foo)",
"{}.foo",
"public({})",
"-{}",
"{}[1]",
"self.{}[1]",
]


# source is a combined list made from all lists in VALID_LITERALS and INVALID_LITERALS
@pytest.mark.parametrize(
"source", [x for v in VALID_LITERALS.values() for x in v] + INVALID_LITERALS
)
@pytest.mark.parametrize("Primitive", VALID_LITERALS.keys())
def test_from_literal(build_node, Primitive, source):
node = build_node(source)

if source in VALID_LITERALS[Primitive]:
obj = Primitive.from_literal(node)
assert isinstance(obj, Primitive._type)
else:
with pytest.raises((InvalidLiteral, OverflowException)):
Primitive.from_literal(node)


@pytest.mark.parametrize("Primitive,type_str", PRIMITIVES.items())
@pytest.mark.parametrize("source", INVALID_NODES + ["{}"])
def test_from_literal_invalid_node(build_node, Primitive, type_str, source):
source = source.format(type_str)
node = build_node(source)

with pytest.raises(UnexpectedNodeType):
Primitive.from_literal(node)


@pytest.mark.parametrize("Primitive", VALID_LITERALS.keys())
@pytest.mark.parametrize(
"source", [x for v in VALID_LITERALS.values() for x in v] + INVALID_LITERALS
)
def test_from_annotation_literal(build_node, Primitive, source):
node = build_node(source)

with pytest.raises(StructureException):
BoolPrimitive.from_annotation(node)


@pytest.mark.parametrize("Primitive,type_str", PRIMITIVES.items())
@pytest.mark.parametrize("source", INVALID_NODES)
def test_from_annotation_invalid_structure(build_node, Primitive, type_str, source):
source = source.format(type_str)
node = build_node(source)

with pytest.raises((UnexpectedValue, StructureException)):
Primitive.from_annotation(node)


@pytest.mark.parametrize("Primitive", PRIMITIVES.keys())
@pytest.mark.parametrize("type_str", PRIMITIVES.values())
def test_from_annotation_wrong_id(build_node, Primitive, type_str):
node = build_node(type_str)

if type_str == PRIMITIVES[Primitive]:
obj = Primitive.from_annotation(node)
assert isinstance(obj, Primitive._type)
else:
with pytest.raises((UnexpectedValue, StructureException)):
Primitive.from_annotation(node)
51 changes: 51 additions & 0 deletions tests/functional/context/types/test_type_from_abi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import pytest

from vyper.context.types import get_primitive_types
from vyper.context.types.indexable.sequence import ArrayDefinition
from vyper.context.types.utils import get_type_from_abi
from vyper.exceptions import UnknownType

BASE_TYPES = ["int128", "uint256", "bool", "address", "bytes32"]


@pytest.mark.parametrize("type_str", BASE_TYPES)
def test_base_types(namespace, type_str):
primitive = get_primitive_types()[type_str]

with namespace.enter_builtin_scope():
type_definition = get_type_from_abi({"type": type_str})

assert isinstance(type_definition, primitive._type)


@pytest.mark.parametrize("type_str", BASE_TYPES)
def test_base_types_as_arrays(namespace, type_str):
primitive = get_primitive_types()[type_str]

with namespace.enter_builtin_scope():
type_definition = get_type_from_abi({"type": f"{type_str}[3]"})

assert isinstance(type_definition, ArrayDefinition)
assert type_definition.length == 3
assert isinstance(type_definition.value_type, primitive._type)


@pytest.mark.parametrize("type_str", BASE_TYPES)
def test_base_types_as_multidimensional_arrays(namespace, type_str):
primitive = get_primitive_types()[type_str]

with namespace.enter_builtin_scope():
type_definition = get_type_from_abi({"type": f"{type_str}[3][5]"})

assert isinstance(type_definition, ArrayDefinition)
assert type_definition.length == 5
assert isinstance(type_definition.value_type, ArrayDefinition)
assert type_definition.value_type.length == 3
assert isinstance(type_definition.value_type.value_type, primitive._type)


@pytest.mark.parametrize("idx", ["0", "-1", "0x00", "'1'", "foo", "[1]", "(1,)"])
def test_invalid_index(namespace, idx):
with namespace.enter_builtin_scope():
with pytest.raises(UnknownType):
get_type_from_abi({"type": f"int128[{idx}]"})
Loading