Add tests for static checks

This commit is contained in:
Johan B.W. de Vries 2022-06-24 21:49:27 +02:00
parent 0afab89796
commit 467d409d80
2 changed files with 74 additions and 11 deletions

View File

@ -97,7 +97,7 @@ class TupleMember:
class OurTypeTuple(OurType):
"""
The tuple type, 64 bits wide
The tuple type
"""
__slots__ = ('members', )
@ -842,8 +842,14 @@ class OurVisitor:
if not isinstance(node.ctx, ast.Load):
_raise_static_error(node, 'Must be load context')
if node.id in our_locals:
return VariableReference(our_locals[node.id], node.id)
if node.id not in our_locals:
_raise_static_error(node, 'Undefined variable')
act_type = our_locals[node.id]
if exp_type != act_type:
_raise_static_error(node, f'Expected {exp_type.render()}, {node.id} is actually {act_type.render()}')
return VariableReference(act_type, node.id)
if isinstance(node, ast.Tuple):
if not isinstance(node.ctx, ast.Load):
@ -884,7 +890,7 @@ class OurVisitor:
func = module.functions[struct_constructor.name]
elif node.func.id in WEBASSEMBLY_BUILDIN_FLOAT_OPS:
if not isinstance(exp_type, (OurTypeFloat32, OurTypeFloat64, )):
_raise_static_error(node, f'Cannot make square root result in {exp_type}')
_raise_static_error(node, f'Cannot make {node.func.id} result in {exp_type}')
if 1 != len(node.args):
_raise_static_error(node, f'Function {node.func.id} requires 1 arguments but {len(node.args)} are given')
@ -901,7 +907,7 @@ class OurVisitor:
func = module.functions[node.func.id]
if func.returns != exp_type:
_raise_static_error(node, f'Function {node.func.id} does not return {exp_type.render()}')
_raise_static_error(node, f'Expected {exp_type.render()}, {func.name} actually returns {func.returns.render()}')
if len(func.posonlyargs) != len(node.args):
_raise_static_error(node, f'Function {node.func.id} requires {len(func.posonlyargs)} arguments but {len(node.args)} are given')
@ -932,7 +938,7 @@ class OurVisitor:
_raise_static_error(node, f'{node_typ.name} has no attribute {node.attr}')
if exp_type != member.type:
_raise_static_error(node, f'Expected {exp_type.render()}, got {member.type.render()} instead')
_raise_static_error(node, f'Expected {exp_type.render()}, {node.value.id}.{member.name} is actually {member.type.render()}')
return AccessStructMember(
VariableReference(node_typ, node.value.id),
@ -949,7 +955,8 @@ class OurVisitor:
if not isinstance(node.slice.value, ast.Constant):
_raise_static_error(node, 'Must subscript using a constant index') # FIXME: Implement variable indexes
if not isinstance(node.slice.value.value, int):
idx = node.slice.value.value
if not isinstance(idx, int):
_raise_static_error(node, 'Must subscript using a constant integer index')
if not isinstance(node.ctx, ast.Load):
@ -962,12 +969,12 @@ class OurVisitor:
if not isinstance(node_typ, OurTypeTuple):
_raise_static_error(node, f'Cannot take index of non-tuple {node.value.id}')
if len(node_typ.members) <= node.slice.value.value:
_raise_static_error(node, f'Index {node.slice.value.value} out of bounds for tuple {node.value.id}')
if len(node_typ.members) <= idx:
_raise_static_error(node, f'Index {idx} out of bounds for tuple {node.value.id}')
member = node_typ.members[node.slice.value.value]
member = node_typ.members[idx]
if exp_type != member.type:
_raise_static_error(node, f'Expected {exp_type.render()}, got {member.type.render()} instead')
_raise_static_error(node, f'Expected {exp_type.render()}, {node.value.id}[{idx}] is actually {member.type.render()}')
return AccessTupleMember(
VariableReference(node_typ, node.value.id),

View File

@ -0,0 +1,56 @@
import pytest
from py2wasm.utils import our_process
from py2wasm.ourlang import StaticError
@pytest.mark.integration_test
@pytest.mark.parametrize('type_', ['i32', 'i64', 'f32', 'f64'])
def test_type_mismatch_function_argument(type_):
code_py = f"""
def helper(a: {type_}) -> (i32, i32, ):
return a
"""
with pytest.raises(StaticError, match=f'Static error on line 3: Expected \\(i32, i32, \\), a is actually {type_}'):
our_process(code_py, 'test')
@pytest.mark.integration_test
@pytest.mark.parametrize('type_', ['i32', 'i64', 'f32', 'f64'])
def test_type_mismatch_struct_member(type_):
code_py = f"""
class Struct:
param: {type_}
def testEntry(arg: Struct) -> (i32, i32, ):
return arg.param
"""
with pytest.raises(StaticError, match=f'Static error on line 6: Expected \\(i32, i32, \\), arg.param is actually {type_}'):
our_process(code_py, 'test')
@pytest.mark.integration_test
@pytest.mark.parametrize('type_', ['i32', 'i64', 'f32', 'f64'])
def test_type_mismatch_tuple_member(type_):
code_py = f"""
def testEntry(arg: ({type_}, )) -> (i32, i32, ):
return arg[0]
"""
with pytest.raises(StaticError, match=f'Static error on line 3: Expected \\(i32, i32, \\), arg\\[0\\] is actually {type_}'):
our_process(code_py, 'test')
@pytest.mark.integration_test
@pytest.mark.parametrize('type_', ['i32', 'i64', 'f32', 'f64'])
def test_type_mismatch_function_result(type_):
code_py = f"""
def helper() -> {type_}:
return 1
@exported
def testEntry() -> (i32, i32, ):
return helper()
"""
with pytest.raises(StaticError, match=f'Static error on line 7: Expected \\(i32, i32, \\), helper actually returns {type_}'):
our_process(code_py, 'test')