Compare commits
No commits in common. "4f19a5e503495b6d90d87ffefc879712887ea7e7" and "f6cb1a8c1dbf0541df6bc23f94b261ef95cb3c97" have entirely different histories.
4f19a5e503
...
f6cb1a8c1d
5
TODO.md
5
TODO.md
@ -28,8 +28,3 @@
|
||||
- Functions don't seem to be a thing on typing level yet?
|
||||
- Related to the FIXME in phasm_type3?
|
||||
- Type constuctor should also be able to constuct placeholders - somehow.
|
||||
|
||||
|
||||
- Check placeholders only used in constraints and constraintgenerator
|
||||
- Simply typed check in compiler:
|
||||
- isinstance(element.type3, type3types.Type3) => element.type3 is not None
|
||||
|
||||
@ -6,6 +6,7 @@ from typing import Dict, Iterable, List, Optional, Union
|
||||
|
||||
from . import prelude
|
||||
from .type3.functions import FunctionSignature, TypeVariableContext
|
||||
from .type3.placeholders import PlaceholderForType, Type3OrPlaceholder
|
||||
from .type3.typeclasses import Type3ClassMethod
|
||||
from .type3.types import Type3
|
||||
|
||||
@ -16,10 +17,10 @@ class Expression:
|
||||
"""
|
||||
__slots__ = ('type3', )
|
||||
|
||||
type3: Type3 | None
|
||||
type3: Type3OrPlaceholder
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.type3 = None
|
||||
self.type3 = PlaceholderForType([self])
|
||||
|
||||
class Constant(Expression):
|
||||
"""
|
||||
@ -197,10 +198,10 @@ class AccessStructMember(Expression):
|
||||
__slots__ = ('varref', 'struct_type3', 'member', )
|
||||
|
||||
varref: VariableReference
|
||||
struct_type3: Type3
|
||||
struct_type3: Type3OrPlaceholder
|
||||
member: str
|
||||
|
||||
def __init__(self, varref: VariableReference, struct_type3: Type3, member: str) -> None:
|
||||
def __init__(self, varref: VariableReference, struct_type3: Type3OrPlaceholder, member: str) -> None:
|
||||
super().__init__()
|
||||
|
||||
self.varref = varref
|
||||
@ -283,7 +284,7 @@ class FunctionParam:
|
||||
__slots__ = ('name', 'type3', )
|
||||
|
||||
name: str
|
||||
type3: Type3
|
||||
type3: Type3OrPlaceholder
|
||||
|
||||
def __init__(self, name: str, type3: Type3) -> None:
|
||||
self.name = name
|
||||
|
||||
@ -3,11 +3,10 @@ This module contains possible constraints generated based on the AST
|
||||
|
||||
These need to be resolved before the program can be compiled.
|
||||
"""
|
||||
from typing import Dict, Iterable, List, Optional, Tuple, Union
|
||||
from typing import Dict, List, Optional, Tuple, Union
|
||||
|
||||
from .. import ourlang, prelude
|
||||
from . import placeholders, typeclasses, types
|
||||
from .placeholders import PlaceholderForType
|
||||
|
||||
|
||||
class Error:
|
||||
@ -33,13 +32,13 @@ class RequireTypeSubstitutes:
|
||||
typing of the program, so this constraint can be updated.
|
||||
"""
|
||||
|
||||
SubstitutionMap = Dict[PlaceholderForType, types.Type3]
|
||||
SubstitutionMap = Dict[placeholders.PlaceholderForType, types.Type3]
|
||||
|
||||
NewConstraintList = List['ConstraintBase']
|
||||
|
||||
CheckResult = Union[None, SubstitutionMap, Error, NewConstraintList, RequireTypeSubstitutes]
|
||||
|
||||
HumanReadableRet = Tuple[str, Dict[str, Union[str, ourlang.Expression, types.Type3, PlaceholderForType]]]
|
||||
HumanReadableRet = Tuple[str, Dict[str, Union[str, ourlang.Expression, types.Type3, placeholders.PlaceholderForType]]]
|
||||
|
||||
class Context:
|
||||
"""
|
||||
@ -99,9 +98,9 @@ class SameTypeConstraint(ConstraintBase):
|
||||
"""
|
||||
__slots__ = ('type_list', )
|
||||
|
||||
type_list: List[PlaceholderForType]
|
||||
type_list: List[placeholders.Type3OrPlaceholder]
|
||||
|
||||
def __init__(self, *type_list: PlaceholderForType, comment: Optional[str] = None) -> None:
|
||||
def __init__(self, *type_list: placeholders.Type3OrPlaceholder, comment: Optional[str] = None) -> None:
|
||||
super().__init__(comment=comment)
|
||||
|
||||
assert len(type_list) > 1
|
||||
@ -111,10 +110,18 @@ class SameTypeConstraint(ConstraintBase):
|
||||
known_types: List[types.Type3] = []
|
||||
phft_list = []
|
||||
for typ in self.type_list:
|
||||
if isinstance(typ, types.Type3):
|
||||
known_types.append(typ)
|
||||
continue
|
||||
|
||||
if isinstance(typ, placeholders.PlaceholderForType):
|
||||
if typ.resolve_as is not None:
|
||||
known_types.append(typ.resolve_as)
|
||||
else:
|
||||
phft_list.append(typ)
|
||||
continue
|
||||
|
||||
raise NotImplementedError(typ)
|
||||
|
||||
if not known_types:
|
||||
return RequireTypeSubstitutes()
|
||||
@ -150,7 +157,7 @@ class SameTypeConstraint(ConstraintBase):
|
||||
return f'SameTypeConstraint({args}, comment={repr(self.comment)})'
|
||||
|
||||
class TupleMatchConstraint(ConstraintBase):
|
||||
def __init__(self, exp_type: PlaceholderForType, args: Iterable[PlaceholderForType], comment: str):
|
||||
def __init__(self, exp_type: placeholders.Type3OrPlaceholder, args: List[placeholders.Type3OrPlaceholder], comment: str):
|
||||
super().__init__(comment=comment)
|
||||
|
||||
self.exp_type = exp_type
|
||||
@ -158,7 +165,7 @@ class TupleMatchConstraint(ConstraintBase):
|
||||
|
||||
def check(self) -> CheckResult:
|
||||
exp_type = self.exp_type
|
||||
if isinstance(exp_type, PlaceholderForType):
|
||||
if isinstance(exp_type, placeholders.PlaceholderForType):
|
||||
if exp_type.resolve_as is None:
|
||||
return RequireTypeSubstitutes()
|
||||
|
||||
@ -198,13 +205,13 @@ class MustImplementTypeClassConstraint(ConstraintBase):
|
||||
|
||||
context: Context
|
||||
type_class3: Union[str, typeclasses.Type3Class]
|
||||
types: list[PlaceholderForType]
|
||||
types: list[placeholders.Type3OrPlaceholder]
|
||||
|
||||
DATA = {
|
||||
'bytes': {'Foldable'},
|
||||
}
|
||||
|
||||
def __init__(self, context: Context, type_class3: Union[str, typeclasses.Type3Class], types: list[PlaceholderForType], comment: Optional[str] = None) -> None:
|
||||
def __init__(self, context: Context, type_class3: Union[str, typeclasses.Type3Class], types: list[placeholders.Type3OrPlaceholder], comment: Optional[str] = None) -> None:
|
||||
super().__init__(comment=comment)
|
||||
|
||||
self.context = context
|
||||
@ -214,10 +221,10 @@ class MustImplementTypeClassConstraint(ConstraintBase):
|
||||
def check(self) -> CheckResult:
|
||||
typ_list = []
|
||||
for typ in self.types:
|
||||
if isinstance(typ, PlaceholderForType) and typ.resolve_as is not None:
|
||||
if isinstance(typ, placeholders.PlaceholderForType) and typ.resolve_as is not None:
|
||||
typ = typ.resolve_as
|
||||
|
||||
if isinstance(typ, PlaceholderForType):
|
||||
if isinstance(typ, placeholders.PlaceholderForType):
|
||||
return RequireTypeSubstitutes()
|
||||
|
||||
typ_list.append(typ)
|
||||
@ -259,12 +266,12 @@ class LiteralFitsConstraint(ConstraintBase):
|
||||
"""
|
||||
__slots__ = ('type3', 'literal', )
|
||||
|
||||
type3: PlaceholderForType
|
||||
type3: placeholders.Type3OrPlaceholder
|
||||
literal: Union[ourlang.ConstantPrimitive, ourlang.ConstantBytes, ourlang.ConstantTuple, ourlang.ConstantStruct]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
type3: PlaceholderForType,
|
||||
type3: placeholders.Type3OrPlaceholder,
|
||||
literal: Union[ourlang.ConstantPrimitive, ourlang.ConstantBytes, ourlang.ConstantTuple, ourlang.ConstantStruct],
|
||||
comment: Optional[str] = None,
|
||||
) -> None:
|
||||
@ -288,7 +295,7 @@ class LiteralFitsConstraint(ConstraintBase):
|
||||
'f64': None,
|
||||
}
|
||||
|
||||
if isinstance(self.type3, PlaceholderForType):
|
||||
if isinstance(self.type3, placeholders.PlaceholderForType):
|
||||
if self.type3.resolve_as is None:
|
||||
return RequireTypeSubstitutes()
|
||||
|
||||
@ -341,12 +348,8 @@ class LiteralFitsConstraint(ConstraintBase):
|
||||
LiteralFitsConstraint(x, y)
|
||||
for x, y in zip(tp_args, self.literal.value, strict=True)
|
||||
)
|
||||
|
||||
# Generate placeholders so each Literal expression
|
||||
# gets updated when we figure out the type of the
|
||||
# expression the literal is used in
|
||||
res.extend(
|
||||
SameTypeConstraint(x, PlaceholderForType([y]))
|
||||
SameTypeConstraint(x, y.type3)
|
||||
for x, y in zip(tp_args, self.literal.value, strict=True)
|
||||
)
|
||||
|
||||
@ -368,12 +371,8 @@ class LiteralFitsConstraint(ConstraintBase):
|
||||
LiteralFitsConstraint(sa_type, y)
|
||||
for y in self.literal.value
|
||||
)
|
||||
|
||||
# Generate placeholders so each Literal expression
|
||||
# gets updated when we figure out the type of the
|
||||
# expression the literal is used in
|
||||
res.extend(
|
||||
SameTypeConstraint(sa_type, PlaceholderForType([y]))
|
||||
SameTypeConstraint(sa_type, y.type3)
|
||||
for y in self.literal.value
|
||||
)
|
||||
|
||||
@ -397,12 +396,8 @@ class LiteralFitsConstraint(ConstraintBase):
|
||||
LiteralFitsConstraint(x, y)
|
||||
for x, y in zip(st_args.values(), self.literal.value, strict=True)
|
||||
)
|
||||
|
||||
# Generate placeholders so each Literal expression
|
||||
# gets updated when we figure out the type of the
|
||||
# expression the literal is used in
|
||||
res.extend(
|
||||
SameTypeConstraint(x_t, PlaceholderForType([y]), comment=f'{self.literal.struct_name}.{x_n}')
|
||||
SameTypeConstraint(x_t, y.type3, comment=f'{self.literal.struct_name}.{x_n}')
|
||||
for (x_n, x_t, ), y in zip(st_args.items(), self.literal.value, strict=True)
|
||||
)
|
||||
|
||||
@ -426,31 +421,24 @@ class CanBeSubscriptedConstraint(ConstraintBase):
|
||||
"""
|
||||
A value that is subscipted, i.e. a[0] (tuple) or a[b] (static array)
|
||||
"""
|
||||
__slots__ = ('ret_type3', 'type3', 'index', 'index_phft', )
|
||||
__slots__ = ('ret_type3', 'type3', 'index', 'index_type3', )
|
||||
|
||||
ret_type3: PlaceholderForType
|
||||
type3: PlaceholderForType
|
||||
ret_type3: placeholders.Type3OrPlaceholder
|
||||
type3: placeholders.Type3OrPlaceholder
|
||||
index: ourlang.Expression
|
||||
index_phft: PlaceholderForType
|
||||
index_type3: placeholders.Type3OrPlaceholder
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
ret_type3: PlaceholderForType,
|
||||
type3: PlaceholderForType,
|
||||
index: ourlang.Expression,
|
||||
index_phft: PlaceholderForType,
|
||||
comment: Optional[str] = None,
|
||||
) -> None:
|
||||
def __init__(self, ret_type3: placeholders.Type3OrPlaceholder, type3: placeholders.Type3OrPlaceholder, index: ourlang.Expression, comment: Optional[str] = None) -> None:
|
||||
super().__init__(comment=comment)
|
||||
|
||||
self.ret_type3 = ret_type3
|
||||
self.type3 = type3
|
||||
self.index = index
|
||||
self.index_phft = index_phft
|
||||
self.index_type3 = index.type3
|
||||
|
||||
def check(self) -> CheckResult:
|
||||
exp_type = self.type3
|
||||
if isinstance(exp_type, PlaceholderForType):
|
||||
if isinstance(exp_type, placeholders.PlaceholderForType):
|
||||
if exp_type.resolve_as is None:
|
||||
return RequireTypeSubstitutes()
|
||||
|
||||
@ -463,7 +451,7 @@ class CanBeSubscriptedConstraint(ConstraintBase):
|
||||
sa_type, sa_len = sa_args
|
||||
|
||||
result: List[ConstraintBase] = [
|
||||
SameTypeConstraint(prelude.u32, self.index_phft, comment='([]) :: Subscriptable a => a b -> u32 -> b'),
|
||||
SameTypeConstraint(prelude.u32, self.index_type3, comment='([]) :: Subscriptable a => a b -> u32 -> b'),
|
||||
SameTypeConstraint(sa_type, self.ret_type3, comment='([]) :: Subscriptable a => a b -> u32 -> b'),
|
||||
]
|
||||
|
||||
@ -490,13 +478,13 @@ class CanBeSubscriptedConstraint(ConstraintBase):
|
||||
return Error('Tuple index out of range')
|
||||
|
||||
return [
|
||||
SameTypeConstraint(prelude.u32, self.index_phft, comment=f'Tuple subscript index {self.index.value}'),
|
||||
SameTypeConstraint(prelude.u32, self.index_type3, comment=f'Tuple subscript index {self.index.value}'),
|
||||
SameTypeConstraint(tp_args[self.index.value], self.ret_type3, comment=f'Tuple subscript index {self.index.value}'),
|
||||
]
|
||||
|
||||
if exp_type is prelude.bytes_:
|
||||
return [
|
||||
SameTypeConstraint(prelude.u32, self.index_phft, comment='([]) :: bytes -> u32 -> u8'),
|
||||
SameTypeConstraint(prelude.u32, self.index_type3, comment='([]) :: bytes -> u32 -> u8'),
|
||||
SameTypeConstraint(prelude.u8, self.ret_type3, comment='([]) :: bytes -> u32 -> u8'),
|
||||
]
|
||||
|
||||
|
||||
@ -19,7 +19,6 @@ from .constraints import (
|
||||
SameTypeConstraint,
|
||||
TupleMatchConstraint,
|
||||
)
|
||||
from .placeholders import PlaceholderForType
|
||||
|
||||
ConstraintGenerator = Generator[ConstraintBase, None, None]
|
||||
|
||||
@ -29,23 +28,23 @@ def phasm_type3_generate_constraints(inp: ourlang.Module) -> List[ConstraintBase
|
||||
|
||||
return [*module(ctx, inp)]
|
||||
|
||||
def constant(ctx: Context, inp: ourlang.Constant, phft: placeholders.PlaceholderForType) -> ConstraintGenerator:
|
||||
def constant(ctx: Context, inp: ourlang.Constant) -> ConstraintGenerator:
|
||||
if isinstance(inp, (ourlang.ConstantPrimitive, ourlang.ConstantBytes, ourlang.ConstantTuple, ourlang.ConstantStruct)):
|
||||
yield LiteralFitsConstraint(
|
||||
phft, inp,
|
||||
inp.type3, inp,
|
||||
comment='The given literal must fit the expected type'
|
||||
)
|
||||
return
|
||||
|
||||
raise NotImplementedError(constant, inp)
|
||||
|
||||
def expression(ctx: Context, inp: ourlang.Expression, phft: placeholders.PlaceholderForType) -> ConstraintGenerator:
|
||||
def expression(ctx: Context, inp: ourlang.Expression) -> ConstraintGenerator:
|
||||
if isinstance(inp, ourlang.Constant):
|
||||
yield from constant(ctx, inp, phft)
|
||||
yield from constant(ctx, inp)
|
||||
return
|
||||
|
||||
if isinstance(inp, ourlang.VariableReference):
|
||||
yield SameTypeConstraint(inp.variable.type3, phft,
|
||||
yield SameTypeConstraint(inp.variable.type3, inp.type3,
|
||||
comment=f'typeOf("{inp.variable.name}") == typeOf({inp.variable.name})')
|
||||
return
|
||||
|
||||
@ -61,14 +60,8 @@ def expression(ctx: Context, inp: ourlang.Expression, phft: placeholders.Placeho
|
||||
if isinstance(x, functions.TypeVariable)
|
||||
}
|
||||
|
||||
arg_placeholders = {
|
||||
arg_expr: PlaceholderForType([arg_expr])
|
||||
for arg_expr in arguments
|
||||
}
|
||||
arg_placeholders[inp] = phft
|
||||
|
||||
for arg_expr in arguments:
|
||||
yield from expression(ctx, arg_expr, arg_placeholders[arg_expr])
|
||||
for call_arg in arguments:
|
||||
yield from expression(ctx, call_arg)
|
||||
|
||||
for constraint in signature.context.constraints:
|
||||
if isinstance(constraint, functions.Constraint_TypeClassInstanceExists):
|
||||
@ -88,11 +81,11 @@ def expression(ctx: Context, inp: ourlang.Expression, phft: placeholders.Placeho
|
||||
comment = f'The type of the value passed to argument {arg_no} of function {func_name} should match the type of that argument'
|
||||
|
||||
if isinstance(sig_part, functions.TypeVariable):
|
||||
yield SameTypeConstraint(type_var_map[sig_part], arg_placeholders[arg_expr], comment=comment)
|
||||
yield SameTypeConstraint(type_var_map[sig_part], arg_expr.type3, comment=comment)
|
||||
continue
|
||||
|
||||
if isinstance(sig_part, type3types.Type3):
|
||||
yield SameTypeConstraint(sig_part, arg_placeholders[arg_expr], comment=comment)
|
||||
yield SameTypeConstraint(sig_part, arg_expr.type3, comment=comment)
|
||||
continue
|
||||
|
||||
raise NotImplementedError(sig_part)
|
||||
@ -101,12 +94,11 @@ def expression(ctx: Context, inp: ourlang.Expression, phft: placeholders.Placeho
|
||||
if isinstance(inp, ourlang.TupleInstantiation):
|
||||
r_type = []
|
||||
for arg in inp.elements:
|
||||
arg_phft = PlaceholderForType([arg])
|
||||
yield from expression(ctx, arg, arg_phft)
|
||||
r_type.append(arg_phft)
|
||||
yield from expression(ctx, arg)
|
||||
r_type.append(arg.type3)
|
||||
|
||||
yield TupleMatchConstraint(
|
||||
phft,
|
||||
inp.type3,
|
||||
r_type,
|
||||
comment='The type of a tuple is a combination of its members'
|
||||
)
|
||||
@ -114,13 +106,10 @@ def expression(ctx: Context, inp: ourlang.Expression, phft: placeholders.Placeho
|
||||
return
|
||||
|
||||
if isinstance(inp, ourlang.Subscript):
|
||||
varref_phft = PlaceholderForType([inp.varref])
|
||||
index_phft = PlaceholderForType([inp.index])
|
||||
yield from expression(ctx, inp.varref)
|
||||
yield from expression(ctx, inp.index)
|
||||
|
||||
yield from expression(ctx, inp.varref, varref_phft)
|
||||
yield from expression(ctx, inp.index, index_phft)
|
||||
|
||||
yield CanBeSubscriptedConstraint(phft, varref_phft, inp.index, index_phft)
|
||||
yield CanBeSubscriptedConstraint(inp.type3, inp.varref.type3, inp.index)
|
||||
return
|
||||
|
||||
if isinstance(inp, ourlang.AccessStructMember):
|
||||
@ -128,40 +117,33 @@ def expression(ctx: Context, inp: ourlang.Expression, phft: placeholders.Placeho
|
||||
st_args = prelude.struct.did_construct(inp.struct_type3)
|
||||
assert st_args is not None # FIXME: See test_struct.py::test_struct_not_accessible
|
||||
|
||||
yield from expression(ctx, inp.varref, PlaceholderForType([inp.varref])) # TODO
|
||||
yield SameTypeConstraint(st_args[inp.member], phft,
|
||||
yield from expression(ctx, inp.varref)
|
||||
yield SameTypeConstraint(st_args[inp.member], inp.type3,
|
||||
comment=f'The type of a struct member reference is the same as the type of struct member {inp.struct_type3.name}.{inp.member}')
|
||||
return
|
||||
|
||||
if isinstance(inp, ourlang.Fold):
|
||||
base_phft = PlaceholderForType([inp.base])
|
||||
iter_phft = PlaceholderForType([inp.iter])
|
||||
yield from expression(ctx, inp.base)
|
||||
yield from expression(ctx, inp.iter)
|
||||
|
||||
yield from expression(ctx, inp.base, base_phft)
|
||||
yield from expression(ctx, inp.iter, iter_phft)
|
||||
|
||||
yield SameTypeConstraint(inp.func.posonlyargs[0].type3, inp.func.returns_type3, base_phft, phft,
|
||||
yield SameTypeConstraint(inp.func.posonlyargs[0].type3, inp.func.returns_type3, inp.base.type3, inp.type3,
|
||||
comment='foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b')
|
||||
yield MustImplementTypeClassConstraint(ctx, 'Foldable', [iter_phft])
|
||||
yield MustImplementTypeClassConstraint(ctx, 'Foldable', [inp.iter.type3])
|
||||
|
||||
return
|
||||
|
||||
raise NotImplementedError(expression, inp)
|
||||
|
||||
def statement_return(ctx: Context, fun: ourlang.Function, inp: ourlang.StatementReturn) -> ConstraintGenerator:
|
||||
phft = PlaceholderForType([inp.value])
|
||||
yield from expression(ctx, inp.value)
|
||||
|
||||
yield from expression(ctx, inp.value, phft)
|
||||
|
||||
yield SameTypeConstraint(fun.returns_type3, phft,
|
||||
yield SameTypeConstraint(fun.returns_type3, inp.value.type3,
|
||||
comment=f'The type of the value returned from function {fun.name} should match its return type')
|
||||
|
||||
def statement_if(ctx: Context, fun: ourlang.Function, inp: ourlang.StatementIf) -> ConstraintGenerator:
|
||||
test_phft = PlaceholderForType([inp.test])
|
||||
yield from expression(ctx, inp.test)
|
||||
|
||||
yield from expression(ctx, inp.test, test_phft)
|
||||
|
||||
yield SameTypeConstraint(test_phft, prelude.bool_,
|
||||
yield SameTypeConstraint(inp.test.type3, prelude.bool_,
|
||||
comment='Must pass a boolean expression to if')
|
||||
|
||||
for stmt in inp.statements:
|
||||
@ -191,10 +173,8 @@ def function(ctx: Context, inp: ourlang.Function) -> ConstraintGenerator:
|
||||
yield from statement(ctx, inp, stmt)
|
||||
|
||||
def module_constant_def(ctx: Context, inp: ourlang.ModuleConstantDef) -> ConstraintGenerator:
|
||||
phft = PlaceholderForType([inp.constant])
|
||||
|
||||
yield from constant(ctx, inp.constant, phft)
|
||||
yield SameTypeConstraint(inp.type3, phft,
|
||||
yield from constant(ctx, inp.constant)
|
||||
yield SameTypeConstraint(inp.type3, inp.constant.type3,
|
||||
comment=f'The type of the value for module constant definition {inp.name} should match the type of that constant')
|
||||
|
||||
def module(ctx: Context, inp: ourlang.Module) -> ConstraintGenerator:
|
||||
|
||||
@ -115,6 +115,8 @@ def phasm_type3(inp: ourlang.Module, verbose: bool = False) -> None:
|
||||
# FIXME: This doesn't work with e.g. `:: [a] -> a`, as the placeholder is inside a type
|
||||
for plh, typ in placeholder_substitutes.items():
|
||||
for expr in plh.update_on_substitution:
|
||||
assert expr.type3 is plh
|
||||
|
||||
expr.type3 = typ
|
||||
|
||||
def print_constraint(placeholder_id_map: Dict[int, str], constraint: ConstraintBase) -> None:
|
||||
|
||||
@ -14,7 +14,7 @@ class ExpressionProtocol(Protocol):
|
||||
A protocol for classes that should be updated on substitution
|
||||
"""
|
||||
|
||||
type3: Type3 | None
|
||||
type3: 'Type3OrPlaceholder'
|
||||
"""
|
||||
The type to update
|
||||
"""
|
||||
|
||||
@ -6,20 +6,7 @@ from ..helpers import Suite
|
||||
|
||||
|
||||
@pytest.mark.integration_test
|
||||
def test_expr_constant_literal_does_not_fit_module_constant():
|
||||
code_py = """
|
||||
CONSTANT: u8 = 1000
|
||||
|
||||
@exported
|
||||
def testEntry() -> u8:
|
||||
return CONSTANT
|
||||
"""
|
||||
|
||||
with pytest.raises(Type3Exception, match=r'Must fit in 1 byte\(s\)'):
|
||||
Suite(code_py).run_code()
|
||||
|
||||
@pytest.mark.integration_test
|
||||
def test_expr_constant_literal_does_not_fit_return():
|
||||
def test_expr_constant_literal_does_not_fit():
|
||||
code_py = """
|
||||
@exported
|
||||
def testEntry() -> u8:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user