Compare commits
2 Commits
6b66935c67
...
4f19a5e503
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f19a5e503 | ||
|
|
0953975980 |
5
TODO.md
5
TODO.md
@ -28,3 +28,8 @@
|
|||||||
- Functions don't seem to be a thing on typing level yet?
|
- Functions don't seem to be a thing on typing level yet?
|
||||||
- Related to the FIXME in phasm_type3?
|
- Related to the FIXME in phasm_type3?
|
||||||
- Type constuctor should also be able to constuct placeholders - somehow.
|
- 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,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:
|
||||||
@ -32,13 +33,13 @@ class RequireTypeSubstitutes:
|
|||||||
typing of the program, so this constraint can be updated.
|
typing of the program, so this constraint can be updated.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
SubstitutionMap = Dict[placeholders.PlaceholderForType, types.Type3]
|
SubstitutionMap = Dict[PlaceholderForType, types.Type3]
|
||||||
|
|
||||||
NewConstraintList = List['ConstraintBase']
|
NewConstraintList = List['ConstraintBase']
|
||||||
|
|
||||||
CheckResult = Union[None, SubstitutionMap, Error, NewConstraintList, RequireTypeSubstitutes]
|
CheckResult = Union[None, SubstitutionMap, Error, NewConstraintList, RequireTypeSubstitutes]
|
||||||
|
|
||||||
HumanReadableRet = Tuple[str, Dict[str, Union[str, ourlang.Expression, types.Type3, placeholders.PlaceholderForType]]]
|
HumanReadableRet = Tuple[str, Dict[str, Union[str, ourlang.Expression, types.Type3, PlaceholderForType]]]
|
||||||
|
|
||||||
class Context:
|
class Context:
|
||||||
"""
|
"""
|
||||||
@ -98,9 +99,9 @@ class SameTypeConstraint(ConstraintBase):
|
|||||||
"""
|
"""
|
||||||
__slots__ = ('type_list', )
|
__slots__ = ('type_list', )
|
||||||
|
|
||||||
type_list: List[placeholders.Type3OrPlaceholder]
|
type_list: List[PlaceholderForType]
|
||||||
|
|
||||||
def __init__(self, *type_list: placeholders.Type3OrPlaceholder, comment: Optional[str] = None) -> None:
|
def __init__(self, *type_list: PlaceholderForType, comment: Optional[str] = None) -> None:
|
||||||
super().__init__(comment=comment)
|
super().__init__(comment=comment)
|
||||||
|
|
||||||
assert len(type_list) > 1
|
assert len(type_list) > 1
|
||||||
@ -110,18 +111,10 @@ class SameTypeConstraint(ConstraintBase):
|
|||||||
known_types: List[types.Type3] = []
|
known_types: List[types.Type3] = []
|
||||||
phft_list = []
|
phft_list = []
|
||||||
for typ in self.type_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:
|
if typ.resolve_as is not None:
|
||||||
known_types.append(typ.resolve_as)
|
known_types.append(typ.resolve_as)
|
||||||
else:
|
else:
|
||||||
phft_list.append(typ)
|
phft_list.append(typ)
|
||||||
continue
|
|
||||||
|
|
||||||
raise NotImplementedError(typ)
|
|
||||||
|
|
||||||
if not known_types:
|
if not known_types:
|
||||||
return RequireTypeSubstitutes()
|
return RequireTypeSubstitutes()
|
||||||
@ -157,7 +150,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: PlaceholderForType, args: Iterable[PlaceholderForType], comment: str):
|
||||||
super().__init__(comment=comment)
|
super().__init__(comment=comment)
|
||||||
|
|
||||||
self.exp_type = exp_type
|
self.exp_type = exp_type
|
||||||
@ -165,7 +158,7 @@ class TupleMatchConstraint(ConstraintBase):
|
|||||||
|
|
||||||
def check(self) -> CheckResult:
|
def check(self) -> CheckResult:
|
||||||
exp_type = self.exp_type
|
exp_type = self.exp_type
|
||||||
if isinstance(exp_type, placeholders.PlaceholderForType):
|
if isinstance(exp_type, PlaceholderForType):
|
||||||
if exp_type.resolve_as is None:
|
if exp_type.resolve_as is None:
|
||||||
return RequireTypeSubstitutes()
|
return RequireTypeSubstitutes()
|
||||||
|
|
||||||
@ -205,13 +198,13 @@ class MustImplementTypeClassConstraint(ConstraintBase):
|
|||||||
|
|
||||||
context: Context
|
context: Context
|
||||||
type_class3: Union[str, typeclasses.Type3Class]
|
type_class3: Union[str, typeclasses.Type3Class]
|
||||||
types: list[placeholders.Type3OrPlaceholder]
|
types: list[PlaceholderForType]
|
||||||
|
|
||||||
DATA = {
|
DATA = {
|
||||||
'bytes': {'Foldable'},
|
'bytes': {'Foldable'},
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, context: Context, type_class3: Union[str, typeclasses.Type3Class], types: list[placeholders.Type3OrPlaceholder], comment: Optional[str] = None) -> None:
|
def __init__(self, context: Context, type_class3: Union[str, typeclasses.Type3Class], types: list[PlaceholderForType], comment: Optional[str] = None) -> None:
|
||||||
super().__init__(comment=comment)
|
super().__init__(comment=comment)
|
||||||
|
|
||||||
self.context = context
|
self.context = context
|
||||||
@ -221,10 +214,10 @@ class MustImplementTypeClassConstraint(ConstraintBase):
|
|||||||
def check(self) -> CheckResult:
|
def check(self) -> CheckResult:
|
||||||
typ_list = []
|
typ_list = []
|
||||||
for typ in self.types:
|
for typ in self.types:
|
||||||
if isinstance(typ, placeholders.PlaceholderForType) and typ.resolve_as is not None:
|
if isinstance(typ, PlaceholderForType) and typ.resolve_as is not None:
|
||||||
typ = typ.resolve_as
|
typ = typ.resolve_as
|
||||||
|
|
||||||
if isinstance(typ, placeholders.PlaceholderForType):
|
if isinstance(typ, PlaceholderForType):
|
||||||
return RequireTypeSubstitutes()
|
return RequireTypeSubstitutes()
|
||||||
|
|
||||||
typ_list.append(typ)
|
typ_list.append(typ)
|
||||||
@ -266,12 +259,12 @@ class LiteralFitsConstraint(ConstraintBase):
|
|||||||
"""
|
"""
|
||||||
__slots__ = ('type3', 'literal', )
|
__slots__ = ('type3', 'literal', )
|
||||||
|
|
||||||
type3: placeholders.Type3OrPlaceholder
|
type3: PlaceholderForType
|
||||||
literal: Union[ourlang.ConstantPrimitive, ourlang.ConstantBytes, ourlang.ConstantTuple, ourlang.ConstantStruct]
|
literal: Union[ourlang.ConstantPrimitive, ourlang.ConstantBytes, ourlang.ConstantTuple, ourlang.ConstantStruct]
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
type3: placeholders.Type3OrPlaceholder,
|
type3: PlaceholderForType,
|
||||||
literal: Union[ourlang.ConstantPrimitive, ourlang.ConstantBytes, ourlang.ConstantTuple, ourlang.ConstantStruct],
|
literal: Union[ourlang.ConstantPrimitive, ourlang.ConstantBytes, ourlang.ConstantTuple, ourlang.ConstantStruct],
|
||||||
comment: Optional[str] = None,
|
comment: Optional[str] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -295,7 +288,7 @@ class LiteralFitsConstraint(ConstraintBase):
|
|||||||
'f64': None,
|
'f64': None,
|
||||||
}
|
}
|
||||||
|
|
||||||
if isinstance(self.type3, placeholders.PlaceholderForType):
|
if isinstance(self.type3, PlaceholderForType):
|
||||||
if self.type3.resolve_as is None:
|
if self.type3.resolve_as is None:
|
||||||
return RequireTypeSubstitutes()
|
return RequireTypeSubstitutes()
|
||||||
|
|
||||||
@ -348,8 +341,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 +368,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 +397,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,24 +426,31 @@ 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: PlaceholderForType
|
||||||
type3: placeholders.Type3OrPlaceholder
|
type3: PlaceholderForType
|
||||||
index: ourlang.Expression
|
index: ourlang.Expression
|
||||||
index_type3: placeholders.Type3OrPlaceholder
|
index_phft: PlaceholderForType
|
||||||
|
|
||||||
def __init__(self, ret_type3: placeholders.Type3OrPlaceholder, type3: placeholders.Type3OrPlaceholder, index: ourlang.Expression, comment: Optional[str] = None) -> None:
|
def __init__(
|
||||||
|
self,
|
||||||
|
ret_type3: PlaceholderForType,
|
||||||
|
type3: PlaceholderForType,
|
||||||
|
index: ourlang.Expression,
|
||||||
|
index_phft: 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
|
||||||
if isinstance(exp_type, placeholders.PlaceholderForType):
|
if isinstance(exp_type, PlaceholderForType):
|
||||||
if exp_type.resolve_as is None:
|
if exp_type.resolve_as is None:
|
||||||
return RequireTypeSubstitutes()
|
return RequireTypeSubstitutes()
|
||||||
|
|
||||||
@ -451,7 +463,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 +490,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