Various small fixes

Re-implementing some things that were broken.

Also, if a typing error is found, and we detect an
infinite loop, we return the errors instead, as that's
probably what causing the loop anyhow.
This commit is contained in:
Johan B.W. de Vries 2022-12-18 14:26:10 +01:00
parent 05e7c356ea
commit 6d426753c8
9 changed files with 66 additions and 20 deletions

View File

@ -63,6 +63,11 @@ def type3(inp: type3types.Type3OrPlaceholder) -> wasm.WasmType:
if inp is type3types.f64:
return wasm.WasmTypeFloat64()
if inp is type3types.bytes:
# bytes are passed as pointer
# And pointers are i32
return wasm.WasmTypeInt32()
if isinstance(inp, type3types.StructType3):
# Structs and tuples are passed as pointer
# And pointers are i32
@ -273,13 +278,13 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
wgn.add_statement(f'f64.{inp.operator}')
return
# TODO: Broken after new type system
# if isinstance(inp.type, typing.TypeInt32):
# if inp.operator == 'len':
# if isinstance(inp.right.type, typing.TypeBytes):
# wgn.i32.load()
# return
if inp.type3 is type3types.u32:
if inp.operator == 'len':
if inp.right.type3 is type3types.bytes:
wgn.i32.load()
return
# TODO: Broken after new type system
# if inp.operator == 'cast':
# if isinstance(inp.type, typing.TypeUInt32) and isinstance(inp.right.type, typing.TypeUInt8):
# # Nothing to do, you can use an u8 value as a u32 no problem

View File

@ -154,6 +154,17 @@ class MustImplementTypeClassConstraint(ConstraintBase):
type_class3: str
type3: types.Type3OrPlaceholder
DATA = {
'u8': {'BitWiseOperation', 'BasicMathOperation'},
'u32': {'BitWiseOperation', 'BasicMathOperation'},
'u64': {'BitWiseOperation', 'BasicMathOperation'},
'i32': {'BasicMathOperation'},
'i64': {'BasicMathOperation'},
'bytes': {'Sized'},
'f32': {'BasicMathOperation', 'FloatingPoint'},
'f64': {'BasicMathOperation', 'FloatingPoint'},
}
def __init__(self, type_class3: str, type3: types.Type3OrPlaceholder, comment: Optional[str] = None) -> None:
super().__init__(comment=comment)
@ -168,14 +179,7 @@ class MustImplementTypeClassConstraint(ConstraintBase):
if isinstance(typ, types.PlaceholderForType):
return RequireTypeSubstitutes()
if 'BitWiseOperation' == self.type_class3 and (typ is types.u8 or typ is types.u32 or typ is types.u64):
return None
if 'BasicMathOperation' == self.type_class3 and (
typ is types.u8 or typ is types.u32 or typ is types.u64
or typ is types.i32 or typ is types.i64
or typ is types.f32 or typ is types.f64
):
if self.type_class3 in self.__class__.DATA.get(typ.name, set()):
return None
return Error(f'{typ.name} does not implement the {self.type_class3} type class')

View File

@ -15,6 +15,8 @@ from .constraints import (
LiteralFitsConstraint, MustImplementTypeClassConstraint, SameTypeConstraint,
)
from . import types as type3types
def phasm_type3_generate_constraints(inp: ourlang.Module) -> List[ConstraintBase]:
ctx = Context()
@ -37,6 +39,21 @@ def expression(ctx: Context, inp: ourlang.Expression) -> Generator[ConstraintBas
comment=f'typeOf("{inp.variable.name}") == typeOf({inp.variable.name})')
return
if isinstance(inp, ourlang.UnaryOp):
if 'len' == inp.operator:
yield from expression(ctx, inp.right)
yield MustImplementTypeClassConstraint('Sized', inp.right.type3)
yield SameTypeConstraint(type3types.u32, inp.type3, comment='len :: Sized a => a -> u32')
return
if 'sqrt' == inp.operator:
yield from expression(ctx, inp.right)
yield MustImplementTypeClassConstraint('FloatingPoint', inp.right.type3)
yield SameTypeConstraint(inp.right.type3, inp.type3, comment='sqrt :: FloatingPoint a => a -> a')
return
raise NotImplementedError(expression, inp, inp.operator)
if isinstance(inp, ourlang.BinaryOp):
if inp.operator in ('|', '&', '^', ):
yield from expression(ctx, inp.left)
@ -47,6 +64,17 @@ def expression(ctx: Context, inp: ourlang.Expression) -> Generator[ConstraintBas
comment=f'({inp.operator}) :: a -> a -> a')
return
if inp.operator in ('>>', '<<', ):
yield from expression(ctx, inp.left)
yield from expression(ctx, inp.right)
yield MustImplementTypeClassConstraint('BitWiseOperation', inp.left.type3)
yield SameTypeConstraint(inp.left.type3, inp.type3,
comment=f'({inp.operator}) :: a -> u64 -> a')
yield SameTypeConstraint(type3types.u64, inp.right.type3,
comment=f'({inp.operator}) :: a -> u64 -> a')
return
if inp.operator in ('+', '-', '*', '/', ):
yield from expression(ctx, inp.left)
yield from expression(ctx, inp.right)

View File

@ -76,6 +76,9 @@ def phasm_type3(inp: ourlang.Module, verbose: bool = False) -> None:
new_placeholder_substitutes_len = len(placeholder_substitutes)
if old_constraint_ids == new_constraint_ids and old_placeholder_substitutes_len == new_placeholder_substitutes_len:
if error_list:
raise Type3Exception(error_list)
raise Exception('Cannot type this program - not enough information')
constraint_list = new_constraint_list

View File

@ -215,6 +215,11 @@ f64 = Type3('f64')
A 32-bits IEEE 754 float, of 64 bits width.
"""
bytes = Type3('bytes')
"""
This is a runtime-determined length piece of memory that can be indexed at runtime.
"""
static_array = Type3('static_array')
"""
This is a fixed length piece of memory that can be indexed at runtime.
@ -241,4 +246,5 @@ LOOKUP_TABLE: Dict[str, Type3] = {
'i64': i64,
'f32': f32,
'f64': f64,
'bytes': bytes,
}

View File

@ -20,13 +20,13 @@ def testEntry(f: bytes) -> bytes:
def test_bytes_length():
code_py = """
@exported
def testEntry(f: bytes) -> i32:
def testEntry(f: bytes) -> u32:
return len(f)
"""
result = Suite(code_py).run_code(b'This is another test')
result = Suite(code_py).run_code(b'This yet is another test')
assert 20 == result.returned_value
assert 24 == result.returned_value
@pytest.mark.integration_test
def test_bytes_index():

View File

@ -468,7 +468,7 @@ def testEntry() -> i32:
return helper()
"""
with pytest.raises(Type3Exception, match=r'i32.*i64'):
with pytest.raises(Type3Exception, match=r'i64 must be i32 instead'):
Suite(code_py).run_code()
@pytest.mark.integration_test

View File

@ -99,5 +99,5 @@ def testEntry(arg: Struct) -> (i32, i32, ):
return arg.param
"""
with pytest.raises(Type3Exception, match=r'\(i32, i32, \) must be ' + type_ + ' instead'):
with pytest.raises(Type3Exception, match=type_ + r' must be tuple \(i32\) \(i32\) instead'):
Suite(code_py).run_code()

View File

@ -112,7 +112,7 @@ def test_tuple_constant_type_mismatch():
CONSTANT: (u32, u8, u8, ) = (24, 4000, 1, )
"""
with pytest.raises(Type3Exception, match='Must fit in 1 byte(s)'):
with pytest.raises(Type3Exception, match=r'Must fit in 1 byte\(s\)'):
Suite(code_py).run_code()
@pytest.mark.integration_test