type5 is much more first principles based, so we get a lot of weird quirks removed: - FromLiteral no longer needs to understand AST - Type unifications works more like Haskell - Function types are just ordinary types, saving a lot of manual busywork and more.
249 lines
5.2 KiB
Python
249 lines
5.2 KiB
Python
import pytest
|
|
|
|
from phasm.exceptions import StaticError
|
|
from phasm.type5.solver import Type5SolverException
|
|
|
|
from ..helpers import Suite
|
|
|
|
|
|
@pytest.mark.integration_test
|
|
def test_struct_0():
|
|
code_py = """
|
|
class CheckedValue:
|
|
value: i32
|
|
|
|
@exported
|
|
def testEntry() -> i32:
|
|
return helper(CheckedValue(23))
|
|
|
|
def helper(cv: CheckedValue) -> i32:
|
|
return cv.value
|
|
"""
|
|
|
|
result = Suite(code_py).run_code()
|
|
|
|
assert 23 == result.returned_value
|
|
|
|
@pytest.mark.integration_test
|
|
def test_struct_1():
|
|
code_py = """
|
|
class Rectangle:
|
|
height: i32
|
|
width: i32
|
|
border: i32
|
|
|
|
@exported
|
|
def testEntry() -> i32:
|
|
return helper(Rectangle(100, 150, 2))
|
|
|
|
def helper(shape: Rectangle) -> i32:
|
|
return shape.height + shape.width + shape.border
|
|
"""
|
|
|
|
result = Suite(code_py).run_code()
|
|
|
|
assert 252 == result.returned_value
|
|
|
|
@pytest.mark.integration_test
|
|
def test_struct_2():
|
|
code_py = """
|
|
class Rectangle:
|
|
height: i32
|
|
width: i32
|
|
border: i32
|
|
|
|
@exported
|
|
def testEntry() -> i32:
|
|
return helper(Rectangle(100, 150, 2), Rectangle(200, 90, 3))
|
|
|
|
def helper(shape1: Rectangle, shape2: Rectangle) -> i32:
|
|
return shape1.height + shape1.width + shape1.border + shape2.height + shape2.width + shape2.border
|
|
"""
|
|
|
|
result = Suite(code_py).run_code()
|
|
|
|
assert 545 == result.returned_value
|
|
|
|
@pytest.mark.integration_test
|
|
def test_type_mismatch_struct_call_root():
|
|
code_py = """
|
|
class CheckedValueBlue:
|
|
value: i32
|
|
|
|
class CheckedValueRed:
|
|
value: i32
|
|
|
|
CONST: CheckedValueBlue = CheckedValueRed(1)
|
|
"""
|
|
|
|
with pytest.raises(Type5SolverException, match='Not the same type'):
|
|
Suite(code_py).run_code()
|
|
|
|
@pytest.mark.integration_test
|
|
def test_type_mismatch_struct_call_nested():
|
|
code_py = """
|
|
class CheckedValueBlue:
|
|
value: i32
|
|
|
|
class CheckedValueRed:
|
|
value: i32
|
|
|
|
CONST: (CheckedValueBlue, u32, ) = (CheckedValueRed(1), 16, )
|
|
"""
|
|
|
|
with pytest.raises(Type5SolverException, match='Not the same type'):
|
|
Suite(code_py).run_code()
|
|
|
|
@pytest.mark.integration_test
|
|
def test_type_mismatch_struct_call_arg_count():
|
|
code_py = """
|
|
class CheckedValue:
|
|
value1: i32
|
|
value2: i32
|
|
|
|
CONST: CheckedValue = CheckedValue(1)
|
|
"""
|
|
|
|
with pytest.raises(Type5SolverException, match='Not the same type'):
|
|
Suite(code_py).run_code()
|
|
|
|
@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(Type5SolverException, match='Not the same type'):
|
|
Suite(code_py).run_code()
|
|
|
|
@pytest.mark.integration_test
|
|
def test_name_already_use_struct():
|
|
code_py = """
|
|
class Struct:
|
|
param: i32
|
|
|
|
class Struct:
|
|
param: i64
|
|
"""
|
|
|
|
with pytest.raises(StaticError, match='Struct already defined as type'):
|
|
Suite(code_py).run_code()
|
|
|
|
@pytest.mark.integration_test
|
|
def test_name_already_use_type():
|
|
code_py = """
|
|
class f32:
|
|
param: i32
|
|
"""
|
|
|
|
with pytest.raises(StaticError, match='f32 already defined as type'):
|
|
Suite(code_py).run_code()
|
|
|
|
@pytest.mark.integration_test
|
|
def test_struct_not_accessible():
|
|
code_py = """
|
|
@exported
|
|
def testEntry(x: u8) -> u8:
|
|
return x.y
|
|
"""
|
|
|
|
with pytest.raises(Type5SolverException, match='Must be a struct'):
|
|
Suite(code_py).run_code()
|
|
|
|
@pytest.mark.integration_test
|
|
def test_struct_does_not_have_field():
|
|
code_py = """
|
|
class CheckedValue:
|
|
value: i32
|
|
|
|
@exported
|
|
def testEntry(x: CheckedValue) -> u8:
|
|
return x.y
|
|
"""
|
|
|
|
with pytest.raises(Type5SolverException, match='Must have a field with this name'):
|
|
Suite(code_py).run_code()
|
|
|
|
@pytest.mark.integration_test
|
|
def test_struct_literal_does_not_fit():
|
|
code_py = """
|
|
class CheckedValue:
|
|
value: i32
|
|
|
|
@exported
|
|
def testEntry() -> CheckedValue:
|
|
return 14
|
|
"""
|
|
|
|
with pytest.raises(Type5SolverException, match='Cannot convert from literal integer'):
|
|
Suite(code_py).run_code()
|
|
|
|
@pytest.mark.integration_test
|
|
def test_struct_wrong_struct():
|
|
code_py = """
|
|
class CheckedValue:
|
|
value: i32
|
|
|
|
class MessedValue:
|
|
value: i32
|
|
|
|
@exported
|
|
def testEntry() -> CheckedValue:
|
|
return MessedValue(14)
|
|
"""
|
|
|
|
with pytest.raises(Type5SolverException, match='Not the same type'):
|
|
Suite(code_py).run_code()
|
|
|
|
@pytest.mark.integration_test
|
|
def test_struct_wrong_arg_count():
|
|
code_py = """
|
|
class CheckedValue:
|
|
value1: i32
|
|
value2: i32
|
|
|
|
@exported
|
|
def testEntry() -> CheckedValue:
|
|
return CheckedValue(14)
|
|
"""
|
|
|
|
with pytest.raises(Type5SolverException, match='Not the same type'):
|
|
Suite(code_py).run_code()
|
|
|
|
@pytest.mark.integration_test
|
|
def test_struct_export_constant():
|
|
code_py = """
|
|
class CheckedValue:
|
|
value: i32
|
|
|
|
CONSTANT: CheckedValue = CheckedValue(32)
|
|
|
|
@exported
|
|
def testEntry() -> CheckedValue:
|
|
return CONSTANT
|
|
"""
|
|
|
|
result = Suite(code_py).run_code()
|
|
|
|
assert {"value": 32} == result.returned_value
|
|
|
|
@pytest.mark.integration_test
|
|
def test_struct_export_instantiation():
|
|
code_py = """
|
|
class CheckedValue:
|
|
value: i32
|
|
|
|
@exported
|
|
def testEntry() -> CheckedValue:
|
|
return CheckedValue(32)
|
|
"""
|
|
|
|
result = Suite(code_py).run_code()
|
|
|
|
assert {"value": 32} == result.returned_value
|