Chore: Placeholders are now internal
They were exposed on AST, causing confusion. Now they're only used in constraints.
This commit is contained in:
parent
f6cb1a8c1d
commit
d9a08cf0f7
@ -6,7 +6,6 @@ from typing import Dict, Iterable, List, Optional, Union
|
|||||||
|
|
||||||
from . import prelude
|
from . import prelude
|
||||||
from .type3.functions import FunctionSignature, TypeVariableContext
|
from .type3.functions import FunctionSignature, TypeVariableContext
|
||||||
from .type3.placeholders import PlaceholderForType, Type3OrPlaceholder
|
|
||||||
from .type3.typeclasses import Type3ClassMethod
|
from .type3.typeclasses import Type3ClassMethod
|
||||||
from .type3.types import Type3
|
from .type3.types import Type3
|
||||||
|
|
||||||
@ -17,10 +16,10 @@ class Expression:
|
|||||||
"""
|
"""
|
||||||
__slots__ = ('type3', )
|
__slots__ = ('type3', )
|
||||||
|
|
||||||
type3: Type3OrPlaceholder
|
type3: Type3 | None
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.type3 = PlaceholderForType([self])
|
self.type3 = None
|
||||||
|
|
||||||
class Constant(Expression):
|
class Constant(Expression):
|
||||||
"""
|
"""
|
||||||
@ -198,10 +197,10 @@ class AccessStructMember(Expression):
|
|||||||
__slots__ = ('varref', 'struct_type3', 'member', )
|
__slots__ = ('varref', 'struct_type3', 'member', )
|
||||||
|
|
||||||
varref: VariableReference
|
varref: VariableReference
|
||||||
struct_type3: Type3OrPlaceholder
|
struct_type3: Type3
|
||||||
member: str
|
member: str
|
||||||
|
|
||||||
def __init__(self, varref: VariableReference, struct_type3: Type3OrPlaceholder, member: str) -> None:
|
def __init__(self, varref: VariableReference, struct_type3: Type3, member: str) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.varref = varref
|
self.varref = varref
|
||||||
@ -284,7 +283,7 @@ class FunctionParam:
|
|||||||
__slots__ = ('name', 'type3', )
|
__slots__ = ('name', 'type3', )
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
type3: Type3OrPlaceholder
|
type3: Type3
|
||||||
|
|
||||||
def __init__(self, name: str, type3: Type3) -> None:
|
def __init__(self, name: str, type3: Type3) -> None:
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|||||||
@ -3,10 +3,11 @@ This module contains possible constraints generated based on the AST
|
|||||||
|
|
||||||
These need to be resolved before the program can be compiled.
|
These need to be resolved before the program can be compiled.
|
||||||
"""
|
"""
|
||||||
from typing import Dict, List, Optional, Tuple, Union
|
from typing import Dict, Iterable, List, Optional, Tuple, Union
|
||||||
|
|
||||||
from .. import ourlang, prelude
|
from .. import ourlang, prelude
|
||||||
from . import placeholders, typeclasses, types
|
from . import placeholders, typeclasses, types
|
||||||
|
from .placeholders import PlaceholderForType
|
||||||
|
|
||||||
|
|
||||||
class Error:
|
class Error:
|
||||||
@ -157,7 +158,7 @@ class SameTypeConstraint(ConstraintBase):
|
|||||||
return f'SameTypeConstraint({args}, comment={repr(self.comment)})'
|
return f'SameTypeConstraint({args}, comment={repr(self.comment)})'
|
||||||
|
|
||||||
class TupleMatchConstraint(ConstraintBase):
|
class TupleMatchConstraint(ConstraintBase):
|
||||||
def __init__(self, exp_type: placeholders.Type3OrPlaceholder, args: List[placeholders.Type3OrPlaceholder], comment: str):
|
def __init__(self, exp_type: placeholders.Type3OrPlaceholder, args: Iterable[placeholders.Type3OrPlaceholder], comment: str):
|
||||||
super().__init__(comment=comment)
|
super().__init__(comment=comment)
|
||||||
|
|
||||||
self.exp_type = exp_type
|
self.exp_type = exp_type
|
||||||
@ -348,8 +349,12 @@ class LiteralFitsConstraint(ConstraintBase):
|
|||||||
LiteralFitsConstraint(x, y)
|
LiteralFitsConstraint(x, y)
|
||||||
for x, y in zip(tp_args, self.literal.value, strict=True)
|
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(
|
res.extend(
|
||||||
SameTypeConstraint(x, y.type3)
|
SameTypeConstraint(x, PlaceholderForType([y]))
|
||||||
for x, y in zip(tp_args, self.literal.value, strict=True)
|
for x, y in zip(tp_args, self.literal.value, strict=True)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -371,8 +376,12 @@ class LiteralFitsConstraint(ConstraintBase):
|
|||||||
LiteralFitsConstraint(sa_type, y)
|
LiteralFitsConstraint(sa_type, y)
|
||||||
for y in self.literal.value
|
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(
|
res.extend(
|
||||||
SameTypeConstraint(sa_type, y.type3)
|
SameTypeConstraint(sa_type, PlaceholderForType([y]))
|
||||||
for y in self.literal.value
|
for y in self.literal.value
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -396,8 +405,12 @@ class LiteralFitsConstraint(ConstraintBase):
|
|||||||
LiteralFitsConstraint(x, y)
|
LiteralFitsConstraint(x, y)
|
||||||
for x, y in zip(st_args.values(), self.literal.value, strict=True)
|
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(
|
res.extend(
|
||||||
SameTypeConstraint(x_t, y.type3, comment=f'{self.literal.struct_name}.{x_n}')
|
SameTypeConstraint(x_t, PlaceholderForType([y]), comment=f'{self.literal.struct_name}.{x_n}')
|
||||||
for (x_n, x_t, ), y in zip(st_args.items(), self.literal.value, strict=True)
|
for (x_n, x_t, ), y in zip(st_args.items(), self.literal.value, strict=True)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -421,20 +434,27 @@ class CanBeSubscriptedConstraint(ConstraintBase):
|
|||||||
"""
|
"""
|
||||||
A value that is subscipted, i.e. a[0] (tuple) or a[b] (static array)
|
A value that is subscipted, i.e. a[0] (tuple) or a[b] (static array)
|
||||||
"""
|
"""
|
||||||
__slots__ = ('ret_type3', 'type3', 'index', 'index_type3', )
|
__slots__ = ('ret_type3', 'type3', 'index', 'index_phft', )
|
||||||
|
|
||||||
ret_type3: placeholders.Type3OrPlaceholder
|
ret_type3: placeholders.Type3OrPlaceholder
|
||||||
type3: placeholders.Type3OrPlaceholder
|
type3: placeholders.Type3OrPlaceholder
|
||||||
index: ourlang.Expression
|
index: ourlang.Expression
|
||||||
index_type3: placeholders.Type3OrPlaceholder
|
index_phft: placeholders.Type3OrPlaceholder
|
||||||
|
|
||||||
def __init__(self, ret_type3: placeholders.Type3OrPlaceholder, type3: placeholders.Type3OrPlaceholder, index: ourlang.Expression, comment: Optional[str] = None) -> None:
|
def __init__(
|
||||||
|
self,
|
||||||
|
ret_type3: placeholders.PlaceholderForType,
|
||||||
|
type3: placeholders.PlaceholderForType,
|
||||||
|
index: ourlang.Expression,
|
||||||
|
index_phft: placeholders.PlaceholderForType,
|
||||||
|
comment: Optional[str] = None,
|
||||||
|
) -> None:
|
||||||
super().__init__(comment=comment)
|
super().__init__(comment=comment)
|
||||||
|
|
||||||
self.ret_type3 = ret_type3
|
self.ret_type3 = ret_type3
|
||||||
self.type3 = type3
|
self.type3 = type3
|
||||||
self.index = index
|
self.index = index
|
||||||
self.index_type3 = index.type3
|
self.index_phft = index_phft
|
||||||
|
|
||||||
def check(self) -> CheckResult:
|
def check(self) -> CheckResult:
|
||||||
exp_type = self.type3
|
exp_type = self.type3
|
||||||
@ -451,7 +471,7 @@ class CanBeSubscriptedConstraint(ConstraintBase):
|
|||||||
sa_type, sa_len = sa_args
|
sa_type, sa_len = sa_args
|
||||||
|
|
||||||
result: List[ConstraintBase] = [
|
result: List[ConstraintBase] = [
|
||||||
SameTypeConstraint(prelude.u32, self.index_type3, comment='([]) :: Subscriptable a => a b -> u32 -> b'),
|
SameTypeConstraint(prelude.u32, self.index_phft, comment='([]) :: Subscriptable a => a b -> u32 -> b'),
|
||||||
SameTypeConstraint(sa_type, self.ret_type3, comment='([]) :: Subscriptable a => a b -> u32 -> b'),
|
SameTypeConstraint(sa_type, self.ret_type3, comment='([]) :: Subscriptable a => a b -> u32 -> b'),
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -478,13 +498,13 @@ class CanBeSubscriptedConstraint(ConstraintBase):
|
|||||||
return Error('Tuple index out of range')
|
return Error('Tuple index out of range')
|
||||||
|
|
||||||
return [
|
return [
|
||||||
SameTypeConstraint(prelude.u32, self.index_type3, comment=f'Tuple subscript index {self.index.value}'),
|
SameTypeConstraint(prelude.u32, self.index_phft, 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}'),
|
SameTypeConstraint(tp_args[self.index.value], self.ret_type3, comment=f'Tuple subscript index {self.index.value}'),
|
||||||
]
|
]
|
||||||
|
|
||||||
if exp_type is prelude.bytes_:
|
if exp_type is prelude.bytes_:
|
||||||
return [
|
return [
|
||||||
SameTypeConstraint(prelude.u32, self.index_type3, comment='([]) :: bytes -> u32 -> u8'),
|
SameTypeConstraint(prelude.u32, self.index_phft, comment='([]) :: bytes -> u32 -> u8'),
|
||||||
SameTypeConstraint(prelude.u8, self.ret_type3, comment='([]) :: bytes -> u32 -> u8'),
|
SameTypeConstraint(prelude.u8, self.ret_type3, comment='([]) :: bytes -> u32 -> u8'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@ -19,6 +19,7 @@ from .constraints import (
|
|||||||
SameTypeConstraint,
|
SameTypeConstraint,
|
||||||
TupleMatchConstraint,
|
TupleMatchConstraint,
|
||||||
)
|
)
|
||||||
|
from .placeholders import PlaceholderForType
|
||||||
|
|
||||||
ConstraintGenerator = Generator[ConstraintBase, None, None]
|
ConstraintGenerator = Generator[ConstraintBase, None, None]
|
||||||
|
|
||||||
@ -28,23 +29,23 @@ def phasm_type3_generate_constraints(inp: ourlang.Module) -> List[ConstraintBase
|
|||||||
|
|
||||||
return [*module(ctx, inp)]
|
return [*module(ctx, inp)]
|
||||||
|
|
||||||
def constant(ctx: Context, inp: ourlang.Constant) -> ConstraintGenerator:
|
def constant(ctx: Context, inp: ourlang.Constant, phft: placeholders.PlaceholderForType) -> ConstraintGenerator:
|
||||||
if isinstance(inp, (ourlang.ConstantPrimitive, ourlang.ConstantBytes, ourlang.ConstantTuple, ourlang.ConstantStruct)):
|
if isinstance(inp, (ourlang.ConstantPrimitive, ourlang.ConstantBytes, ourlang.ConstantTuple, ourlang.ConstantStruct)):
|
||||||
yield LiteralFitsConstraint(
|
yield LiteralFitsConstraint(
|
||||||
inp.type3, inp,
|
phft, inp,
|
||||||
comment='The given literal must fit the expected type'
|
comment='The given literal must fit the expected type'
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
raise NotImplementedError(constant, inp)
|
raise NotImplementedError(constant, inp)
|
||||||
|
|
||||||
def expression(ctx: Context, inp: ourlang.Expression) -> ConstraintGenerator:
|
def expression(ctx: Context, inp: ourlang.Expression, phft: placeholders.PlaceholderForType) -> ConstraintGenerator:
|
||||||
if isinstance(inp, ourlang.Constant):
|
if isinstance(inp, ourlang.Constant):
|
||||||
yield from constant(ctx, inp)
|
yield from constant(ctx, inp, phft)
|
||||||
return
|
return
|
||||||
|
|
||||||
if isinstance(inp, ourlang.VariableReference):
|
if isinstance(inp, ourlang.VariableReference):
|
||||||
yield SameTypeConstraint(inp.variable.type3, inp.type3,
|
yield SameTypeConstraint(inp.variable.type3, phft,
|
||||||
comment=f'typeOf("{inp.variable.name}") == typeOf({inp.variable.name})')
|
comment=f'typeOf("{inp.variable.name}") == typeOf({inp.variable.name})')
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -60,8 +61,14 @@ def expression(ctx: Context, inp: ourlang.Expression) -> ConstraintGenerator:
|
|||||||
if isinstance(x, functions.TypeVariable)
|
if isinstance(x, functions.TypeVariable)
|
||||||
}
|
}
|
||||||
|
|
||||||
for call_arg in arguments:
|
arg_placeholders = {
|
||||||
yield from expression(ctx, call_arg)
|
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 constraint in signature.context.constraints:
|
for constraint in signature.context.constraints:
|
||||||
if isinstance(constraint, functions.Constraint_TypeClassInstanceExists):
|
if isinstance(constraint, functions.Constraint_TypeClassInstanceExists):
|
||||||
@ -81,11 +88,11 @@ def expression(ctx: Context, inp: ourlang.Expression) -> ConstraintGenerator:
|
|||||||
comment = f'The type of the value passed to argument {arg_no} of function {func_name} should match the type of that argument'
|
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):
|
if isinstance(sig_part, functions.TypeVariable):
|
||||||
yield SameTypeConstraint(type_var_map[sig_part], arg_expr.type3, comment=comment)
|
yield SameTypeConstraint(type_var_map[sig_part], arg_placeholders[arg_expr], comment=comment)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if isinstance(sig_part, type3types.Type3):
|
if isinstance(sig_part, type3types.Type3):
|
||||||
yield SameTypeConstraint(sig_part, arg_expr.type3, comment=comment)
|
yield SameTypeConstraint(sig_part, arg_placeholders[arg_expr], comment=comment)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
raise NotImplementedError(sig_part)
|
raise NotImplementedError(sig_part)
|
||||||
@ -94,11 +101,12 @@ def expression(ctx: Context, inp: ourlang.Expression) -> ConstraintGenerator:
|
|||||||
if isinstance(inp, ourlang.TupleInstantiation):
|
if isinstance(inp, ourlang.TupleInstantiation):
|
||||||
r_type = []
|
r_type = []
|
||||||
for arg in inp.elements:
|
for arg in inp.elements:
|
||||||
yield from expression(ctx, arg)
|
arg_phft = PlaceholderForType([arg])
|
||||||
r_type.append(arg.type3)
|
yield from expression(ctx, arg, arg_phft)
|
||||||
|
r_type.append(arg_phft)
|
||||||
|
|
||||||
yield TupleMatchConstraint(
|
yield TupleMatchConstraint(
|
||||||
inp.type3,
|
phft,
|
||||||
r_type,
|
r_type,
|
||||||
comment='The type of a tuple is a combination of its members'
|
comment='The type of a tuple is a combination of its members'
|
||||||
)
|
)
|
||||||
@ -106,10 +114,13 @@ def expression(ctx: Context, inp: ourlang.Expression) -> ConstraintGenerator:
|
|||||||
return
|
return
|
||||||
|
|
||||||
if isinstance(inp, ourlang.Subscript):
|
if isinstance(inp, ourlang.Subscript):
|
||||||
yield from expression(ctx, inp.varref)
|
varref_phft = PlaceholderForType([inp.varref])
|
||||||
yield from expression(ctx, inp.index)
|
index_phft = PlaceholderForType([inp.index])
|
||||||
|
|
||||||
yield CanBeSubscriptedConstraint(inp.type3, inp.varref.type3, 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)
|
||||||
return
|
return
|
||||||
|
|
||||||
if isinstance(inp, ourlang.AccessStructMember):
|
if isinstance(inp, ourlang.AccessStructMember):
|
||||||
@ -117,33 +128,40 @@ def expression(ctx: Context, inp: ourlang.Expression) -> ConstraintGenerator:
|
|||||||
st_args = prelude.struct.did_construct(inp.struct_type3)
|
st_args = prelude.struct.did_construct(inp.struct_type3)
|
||||||
assert st_args is not None # FIXME: See test_struct.py::test_struct_not_accessible
|
assert st_args is not None # FIXME: See test_struct.py::test_struct_not_accessible
|
||||||
|
|
||||||
yield from expression(ctx, inp.varref)
|
yield from expression(ctx, inp.varref, PlaceholderForType([inp.varref])) # TODO
|
||||||
yield SameTypeConstraint(st_args[inp.member], inp.type3,
|
yield SameTypeConstraint(st_args[inp.member], phft,
|
||||||
comment=f'The type of a struct member reference is the same as the type of struct member {inp.struct_type3.name}.{inp.member}')
|
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
|
return
|
||||||
|
|
||||||
if isinstance(inp, ourlang.Fold):
|
if isinstance(inp, ourlang.Fold):
|
||||||
yield from expression(ctx, inp.base)
|
base_phft = PlaceholderForType([inp.base])
|
||||||
yield from expression(ctx, inp.iter)
|
iter_phft = PlaceholderForType([inp.iter])
|
||||||
|
|
||||||
yield SameTypeConstraint(inp.func.posonlyargs[0].type3, inp.func.returns_type3, inp.base.type3, inp.type3,
|
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,
|
||||||
comment='foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b')
|
comment='foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b')
|
||||||
yield MustImplementTypeClassConstraint(ctx, 'Foldable', [inp.iter.type3])
|
yield MustImplementTypeClassConstraint(ctx, 'Foldable', [iter_phft])
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
raise NotImplementedError(expression, inp)
|
raise NotImplementedError(expression, inp)
|
||||||
|
|
||||||
def statement_return(ctx: Context, fun: ourlang.Function, inp: ourlang.StatementReturn) -> ConstraintGenerator:
|
def statement_return(ctx: Context, fun: ourlang.Function, inp: ourlang.StatementReturn) -> ConstraintGenerator:
|
||||||
yield from expression(ctx, inp.value)
|
phft = PlaceholderForType([inp.value])
|
||||||
|
|
||||||
yield SameTypeConstraint(fun.returns_type3, inp.value.type3,
|
yield from expression(ctx, inp.value, phft)
|
||||||
|
|
||||||
|
yield SameTypeConstraint(fun.returns_type3, phft,
|
||||||
comment=f'The type of the value returned from function {fun.name} should match its return type')
|
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:
|
def statement_if(ctx: Context, fun: ourlang.Function, inp: ourlang.StatementIf) -> ConstraintGenerator:
|
||||||
yield from expression(ctx, inp.test)
|
test_phft = PlaceholderForType([inp.test])
|
||||||
|
|
||||||
yield SameTypeConstraint(inp.test.type3, prelude.bool_,
|
yield from expression(ctx, inp.test, test_phft)
|
||||||
|
|
||||||
|
yield SameTypeConstraint(test_phft, prelude.bool_,
|
||||||
comment='Must pass a boolean expression to if')
|
comment='Must pass a boolean expression to if')
|
||||||
|
|
||||||
for stmt in inp.statements:
|
for stmt in inp.statements:
|
||||||
@ -173,8 +191,10 @@ def function(ctx: Context, inp: ourlang.Function) -> ConstraintGenerator:
|
|||||||
yield from statement(ctx, inp, stmt)
|
yield from statement(ctx, inp, stmt)
|
||||||
|
|
||||||
def module_constant_def(ctx: Context, inp: ourlang.ModuleConstantDef) -> ConstraintGenerator:
|
def module_constant_def(ctx: Context, inp: ourlang.ModuleConstantDef) -> ConstraintGenerator:
|
||||||
yield from constant(ctx, inp.constant)
|
phft = PlaceholderForType([inp.constant])
|
||||||
yield SameTypeConstraint(inp.type3, inp.constant.type3,
|
|
||||||
|
yield from constant(ctx, inp.constant, phft)
|
||||||
|
yield SameTypeConstraint(inp.type3, phft,
|
||||||
comment=f'The type of the value for module constant definition {inp.name} should match the type of that constant')
|
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:
|
def module(ctx: Context, inp: ourlang.Module) -> ConstraintGenerator:
|
||||||
|
|||||||
@ -115,8 +115,6 @@ 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
|
# 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 plh, typ in placeholder_substitutes.items():
|
||||||
for expr in plh.update_on_substitution:
|
for expr in plh.update_on_substitution:
|
||||||
assert expr.type3 is plh
|
|
||||||
|
|
||||||
expr.type3 = typ
|
expr.type3 = typ
|
||||||
|
|
||||||
def print_constraint(placeholder_id_map: Dict[int, str], constraint: ConstraintBase) -> None:
|
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
|
A protocol for classes that should be updated on substitution
|
||||||
"""
|
"""
|
||||||
|
|
||||||
type3: 'Type3OrPlaceholder'
|
type3: Type3 | None
|
||||||
"""
|
"""
|
||||||
The type to update
|
The type to update
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -6,7 +6,20 @@ from ..helpers import Suite
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
def test_expr_constant_literal_does_not_fit():
|
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():
|
||||||
code_py = """
|
code_py = """
|
||||||
@exported
|
@exported
|
||||||
def testEntry() -> u8:
|
def testEntry() -> u8:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user