Cleans up imports
Rather than accessing the classes from the module, this MR cleans up the code a bit to use the classes directly.
This commit is contained in:
parent
b5f0fda133
commit
df5c1911bf
@ -8,10 +8,18 @@ from . import codestyle, ourlang, prelude, wasm
|
||||
from .runtime import calculate_alloc_size, calculate_member_offset
|
||||
from .stdlib import alloc as stdlib_alloc
|
||||
from .stdlib import types as stdlib_types
|
||||
from .type3 import functions as type3functions
|
||||
from .type3 import typeclasses as type3classes
|
||||
from .type3 import types as type3types
|
||||
from .type3.functions import TypeVariable
|
||||
from .type3.routers import NoRouteForTypeException, TypeApplicationRouter
|
||||
from .type3.typeclasses import Type3ClassMethod
|
||||
from .type3.types import (
|
||||
IntType3,
|
||||
Type3,
|
||||
TypeApplication_Struct,
|
||||
TypeApplication_TypeInt,
|
||||
TypeApplication_TypeStar,
|
||||
TypeConstructor_StaticArray,
|
||||
TypeConstructor_Tuple,
|
||||
)
|
||||
from .wasmgenerator import Generator as WasmGenerator
|
||||
|
||||
TYPE3_ASSERTION_ERROR = 'You must call phasm_type3 after calling phasm_parse before your program can be compiled'
|
||||
@ -37,7 +45,7 @@ def phasm_compile(inp: ourlang.Module) -> wasm.Module:
|
||||
"""
|
||||
return module(inp)
|
||||
|
||||
def type3(inp: type3types.Type3) -> wasm.WasmType:
|
||||
def type3(inp: Type3) -> wasm.WasmType:
|
||||
"""
|
||||
Compile: type
|
||||
|
||||
@ -98,18 +106,18 @@ def tuple_instantiation(wgn: WasmGenerator, inp: ourlang.TupleInstantiation) ->
|
||||
"""
|
||||
assert inp.type3 is not None, TYPE3_ASSERTION_ERROR
|
||||
|
||||
args: tuple[type3types.Type3, ...]
|
||||
args: tuple[Type3, ...]
|
||||
|
||||
if isinstance(inp.type3.application, type3types.TypeApplication_TypeStar):
|
||||
if isinstance(inp.type3.application, TypeApplication_TypeStar):
|
||||
# Possibly paranoid assert. If we have a future variadic type,
|
||||
# does it also do this tuple instantation like this?
|
||||
assert isinstance(inp.type3.application.constructor, type3types.TypeConstructor_Tuple)
|
||||
assert isinstance(inp.type3.application.constructor, TypeConstructor_Tuple)
|
||||
|
||||
args = inp.type3.application.arguments
|
||||
elif isinstance(inp.type3.application, type3types.TypeApplication_TypeInt):
|
||||
elif isinstance(inp.type3.application, TypeApplication_TypeInt):
|
||||
# Possibly paranoid assert. If we have a future type of kind * -> Int -> *,
|
||||
# does it also do this tuple instantation like this?
|
||||
assert isinstance(inp.type3.application.constructor, type3types.TypeConstructor_StaticArray)
|
||||
assert isinstance(inp.type3.application.constructor, TypeConstructor_StaticArray)
|
||||
|
||||
sa_type, sa_len = inp.type3.application.arguments
|
||||
|
||||
@ -162,7 +170,7 @@ def expression_subscript_bytes(
|
||||
|
||||
def expression_subscript_static_array(
|
||||
attrs: tuple[WasmGenerator, ourlang.Subscript],
|
||||
args: tuple[type3types.Type3, type3types.IntType3],
|
||||
args: tuple[Type3, IntType3],
|
||||
) -> None:
|
||||
wgn, inp = attrs
|
||||
|
||||
@ -194,7 +202,7 @@ def expression_subscript_static_array(
|
||||
|
||||
def expression_subscript_tuple(
|
||||
attrs: tuple[WasmGenerator, ourlang.Subscript],
|
||||
args: tuple[type3types.Type3, ...],
|
||||
args: tuple[Type3, ...],
|
||||
) -> None:
|
||||
wgn, inp = attrs
|
||||
|
||||
@ -292,16 +300,16 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
||||
expression(wgn, inp.left)
|
||||
expression(wgn, inp.right)
|
||||
|
||||
type_var_map: dict[type3functions.TypeVariable, type3types.Type3] = {}
|
||||
type_var_map: dict[TypeVariable, Type3] = {}
|
||||
|
||||
for type_var, arg_expr in zip(inp.operator.signature.args, [inp.left, inp.right, inp], strict=True):
|
||||
assert arg_expr.type3 is not None, TYPE3_ASSERTION_ERROR
|
||||
|
||||
if isinstance(type_var, type3types.Type3):
|
||||
if isinstance(type_var, Type3):
|
||||
# Fixed type, not part of the lookup requirements
|
||||
continue
|
||||
|
||||
if isinstance(type_var, type3functions.TypeVariable):
|
||||
if isinstance(type_var, TypeVariable):
|
||||
type_var_map[type_var] = arg_expr.type3
|
||||
continue
|
||||
|
||||
@ -315,18 +323,18 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
||||
for arg in inp.arguments:
|
||||
expression(wgn, arg)
|
||||
|
||||
if isinstance(inp.function, type3classes.Type3ClassMethod):
|
||||
if isinstance(inp.function, Type3ClassMethod):
|
||||
# FIXME: Duplicate code with BinaryOp
|
||||
type_var_map = {}
|
||||
|
||||
for type_var, arg_expr in zip(inp.function.signature.args, inp.arguments + [inp], strict=True):
|
||||
assert arg_expr.type3 is not None, TYPE3_ASSERTION_ERROR
|
||||
|
||||
if isinstance(type_var, type3types.Type3):
|
||||
if isinstance(type_var, Type3):
|
||||
# Fixed type, not part of the lookup requirements
|
||||
continue
|
||||
|
||||
if isinstance(type_var, type3functions.TypeVariable):
|
||||
if isinstance(type_var, TypeVariable):
|
||||
type_var_map[type_var] = arg_expr.type3
|
||||
continue
|
||||
|
||||
@ -356,7 +364,7 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
||||
if isinstance(inp, ourlang.AccessStructMember):
|
||||
assert inp.struct_type3 is not None, TYPE3_ASSERTION_ERROR
|
||||
|
||||
assert isinstance(inp.struct_type3.application, type3types.TypeApplication_Struct)
|
||||
assert isinstance(inp.struct_type3.application, TypeApplication_Struct)
|
||||
|
||||
member_type = dict(inp.struct_type3.application.arguments)[inp.member]
|
||||
|
||||
@ -739,7 +747,7 @@ def module(inp: ourlang.Module) -> wasm.Module:
|
||||
return result
|
||||
|
||||
def _generate_struct_constructor(wgn: WasmGenerator, inp: ourlang.StructConstructor) -> None:
|
||||
assert isinstance(inp.struct_type3.application, type3types.TypeApplication_Struct)
|
||||
assert isinstance(inp.struct_type3.application, TypeApplication_Struct)
|
||||
|
||||
st_args = inp.struct_type3.application.arguments
|
||||
|
||||
|
||||
@ -32,8 +32,8 @@ from .ourlang import (
|
||||
VariableReference,
|
||||
)
|
||||
from .prelude import PRELUDE_METHODS, PRELUDE_OPERATORS, PRELUDE_TYPES
|
||||
from .type3 import typeclasses as type3typeclasses
|
||||
from .type3 import types as type3types
|
||||
from .type3.typeclasses import Type3ClassMethod
|
||||
from .type3.types import IntType3, Type3
|
||||
|
||||
|
||||
def phasm_parse(source: str) -> Module:
|
||||
@ -226,7 +226,7 @@ class OurVisitor:
|
||||
_not_implemented(not node.keywords, 'ClassDef.keywords')
|
||||
_not_implemented(not node.decorator_list, 'ClassDef.decorator_list')
|
||||
|
||||
members: Dict[str, type3types.Type3] = {}
|
||||
members: Dict[str, Type3] = {}
|
||||
|
||||
for stmt in node.body:
|
||||
if not isinstance(stmt, ast.AnnAssign):
|
||||
@ -352,7 +352,7 @@ class OurVisitor:
|
||||
|
||||
def visit_Module_FunctionDef_expr(self, module: Module, function: Function, our_locals: OurLocals, node: ast.expr) -> Expression:
|
||||
if isinstance(node, ast.BinOp):
|
||||
operator: Union[str, type3typeclasses.Type3ClassMethod]
|
||||
operator: Union[str, Type3ClassMethod]
|
||||
|
||||
if isinstance(node.op, ast.Add):
|
||||
operator = '+'
|
||||
@ -471,7 +471,7 @@ class OurVisitor:
|
||||
if not isinstance(node.func.ctx, ast.Load):
|
||||
_raise_static_error(node, 'Must be load context')
|
||||
|
||||
func: Union[Function, type3typeclasses.Type3ClassMethod]
|
||||
func: Union[Function, Type3ClassMethod]
|
||||
|
||||
if node.func.id in PRELUDE_METHODS:
|
||||
func = PRELUDE_METHODS[node.func.id]
|
||||
@ -617,7 +617,7 @@ class OurVisitor:
|
||||
|
||||
raise NotImplementedError(f'{node.value} as constant')
|
||||
|
||||
def visit_type(self, module: Module, node: ast.expr) -> type3types.Type3:
|
||||
def visit_type(self, module: Module, node: ast.expr) -> Type3:
|
||||
if isinstance(node, ast.Constant):
|
||||
if node.value is None:
|
||||
return prelude.none
|
||||
@ -645,7 +645,7 @@ class OurVisitor:
|
||||
|
||||
return prelude.static_array(
|
||||
self.visit_type(module, node.value),
|
||||
type3types.IntType3(node.slice.value),
|
||||
IntType3(node.slice.value),
|
||||
)
|
||||
|
||||
if isinstance(node, ast.Tuple):
|
||||
|
||||
@ -6,9 +6,19 @@ These need to be resolved before the program can be compiled.
|
||||
from typing import Any, Dict, Iterable, List, Optional, Tuple, Union
|
||||
|
||||
from .. import ourlang, prelude
|
||||
from . import placeholders, typeclasses, types
|
||||
from .placeholders import PlaceholderForType
|
||||
from .placeholders import PlaceholderForType, Type3OrPlaceholder
|
||||
from .routers import NoRouteForTypeException, TypeApplicationRouter
|
||||
from .typeclasses import Type3Class
|
||||
from .types import (
|
||||
IntType3,
|
||||
Type3,
|
||||
TypeApplication_Nullary,
|
||||
TypeApplication_Struct,
|
||||
TypeApplication_TypeInt,
|
||||
TypeApplication_TypeStar,
|
||||
TypeConstructor_Base,
|
||||
TypeConstructor_Struct,
|
||||
)
|
||||
|
||||
|
||||
class Error:
|
||||
@ -34,13 +44,13 @@ class RequireTypeSubstitutes:
|
||||
typing of the program, so this constraint can be updated.
|
||||
"""
|
||||
|
||||
SubstitutionMap = Dict[placeholders.PlaceholderForType, types.Type3]
|
||||
SubstitutionMap = Dict[PlaceholderForType, Type3]
|
||||
|
||||
NewConstraintList = List['ConstraintBase']
|
||||
|
||||
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, Type3, PlaceholderForType]]]
|
||||
|
||||
class Context:
|
||||
"""
|
||||
@ -50,7 +60,7 @@ class Context:
|
||||
__slots__ = ('type_class_instances_existing', )
|
||||
|
||||
# Constraint_TypeClassInstanceExists
|
||||
type_class_instances_existing: set[tuple[typeclasses.Type3Class, tuple[Union[types.Type3, types.TypeConstructor_Base[Any], types.TypeConstructor_Struct], ...]]]
|
||||
type_class_instances_existing: set[tuple[Type3Class, tuple[Union[Type3, TypeConstructor_Base[Any], TypeConstructor_Struct], ...]]]
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.type_class_instances_existing = set()
|
||||
@ -100,23 +110,23 @@ class SameTypeConstraint(ConstraintBase):
|
||||
"""
|
||||
__slots__ = ('type_list', )
|
||||
|
||||
type_list: List[placeholders.Type3OrPlaceholder]
|
||||
type_list: List[Type3OrPlaceholder]
|
||||
|
||||
def __init__(self, *type_list: placeholders.Type3OrPlaceholder, comment: Optional[str] = None) -> None:
|
||||
def __init__(self, *type_list: Type3OrPlaceholder, comment: Optional[str] = None) -> None:
|
||||
super().__init__(comment=comment)
|
||||
|
||||
assert len(type_list) > 1
|
||||
self.type_list = [*type_list]
|
||||
|
||||
def check(self) -> CheckResult:
|
||||
known_types: List[types.Type3] = []
|
||||
known_types: List[Type3] = []
|
||||
phft_list = []
|
||||
for typ in self.type_list:
|
||||
if isinstance(typ, types.Type3):
|
||||
if isinstance(typ, Type3):
|
||||
known_types.append(typ)
|
||||
continue
|
||||
|
||||
if isinstance(typ, placeholders.PlaceholderForType):
|
||||
if isinstance(typ, PlaceholderForType):
|
||||
if typ.resolve_as is not None:
|
||||
known_types.append(typ.resolve_as)
|
||||
else:
|
||||
@ -133,7 +143,7 @@ class SameTypeConstraint(ConstraintBase):
|
||||
if ktyp != first_type:
|
||||
return Error(f'{ktyp:s} must be {first_type:s} instead', comment=self.comment)
|
||||
|
||||
if not placeholders:
|
||||
if not phft_list:
|
||||
return None
|
||||
|
||||
for phft in phft_list:
|
||||
@ -177,10 +187,10 @@ class SameTypeArgumentConstraint(ConstraintBase):
|
||||
tc_typ = self.tc_var.resolve_as
|
||||
arg_typ = self.arg_var.resolve_as
|
||||
|
||||
if isinstance(tc_typ.application, types.TypeApplication_Nullary):
|
||||
if isinstance(tc_typ.application, TypeApplication_Nullary):
|
||||
return Error(f'{tc_typ:s} must be a constructed type instead')
|
||||
|
||||
if isinstance(tc_typ.application, types.TypeApplication_TypeStar):
|
||||
if isinstance(tc_typ.application, TypeApplication_TypeStar):
|
||||
# Sure, it's a constructed type. But it's like a struct,
|
||||
# though without the way to implement type classes
|
||||
# Presumably, doing a naked `foo :: t a -> a`
|
||||
@ -190,7 +200,7 @@ class SameTypeArgumentConstraint(ConstraintBase):
|
||||
|
||||
# FIXME: This feels sketchy. Shouldn't the type variable
|
||||
# have the exact same number as arguments?
|
||||
if isinstance(tc_typ.application, types.TypeApplication_TypeInt):
|
||||
if isinstance(tc_typ.application, TypeApplication_TypeInt):
|
||||
if tc_typ.application.arguments[0] == arg_typ:
|
||||
return None
|
||||
|
||||
@ -201,16 +211,16 @@ class SameTypeArgumentConstraint(ConstraintBase):
|
||||
class TupleMatchConstraint(ConstraintBase):
|
||||
__slots__ = ('exp_type', 'args', )
|
||||
|
||||
exp_type: placeholders.Type3OrPlaceholder
|
||||
args: list[placeholders.Type3OrPlaceholder]
|
||||
exp_type: Type3OrPlaceholder
|
||||
args: list[Type3OrPlaceholder]
|
||||
|
||||
def __init__(self, exp_type: placeholders.Type3OrPlaceholder, args: Iterable[placeholders.Type3OrPlaceholder], comment: str):
|
||||
def __init__(self, exp_type: Type3OrPlaceholder, args: Iterable[Type3OrPlaceholder], comment: str):
|
||||
super().__init__(comment=comment)
|
||||
|
||||
self.exp_type = exp_type
|
||||
self.args = list(args)
|
||||
|
||||
def _generate_static_array(self, sa_args: tuple[types.Type3, types.IntType3]) -> CheckResult:
|
||||
def _generate_static_array(self, sa_args: tuple[Type3, IntType3]) -> CheckResult:
|
||||
sa_type, sa_len = sa_args
|
||||
|
||||
if sa_len.value != len(self.args):
|
||||
@ -221,7 +231,7 @@ class TupleMatchConstraint(ConstraintBase):
|
||||
for arg in self.args
|
||||
]
|
||||
|
||||
def _generate_tuple(self, tp_args: tuple[types.Type3, ...]) -> CheckResult:
|
||||
def _generate_tuple(self, tp_args: tuple[Type3, ...]) -> CheckResult:
|
||||
if len(tp_args) != len(self.args):
|
||||
return Error('Mismatch between applied types argument count', comment=self.comment)
|
||||
|
||||
@ -236,7 +246,7 @@ class TupleMatchConstraint(ConstraintBase):
|
||||
|
||||
def check(self) -> CheckResult:
|
||||
exp_type = self.exp_type
|
||||
if isinstance(exp_type, placeholders.PlaceholderForType):
|
||||
if isinstance(exp_type, PlaceholderForType):
|
||||
if exp_type.resolve_as is None:
|
||||
return RequireTypeSubstitutes()
|
||||
|
||||
@ -254,34 +264,34 @@ class MustImplementTypeClassConstraint(ConstraintBase):
|
||||
__slots__ = ('context', 'type_class3', 'types', )
|
||||
|
||||
context: Context
|
||||
type_class3: Union[str, typeclasses.Type3Class]
|
||||
types: list[placeholders.Type3OrPlaceholder]
|
||||
type_class3: Union[str, Type3Class]
|
||||
types: list[Type3OrPlaceholder]
|
||||
|
||||
DATA = {
|
||||
'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, Type3Class], typ_list: list[Type3OrPlaceholder], comment: Optional[str] = None) -> None:
|
||||
super().__init__(comment=comment)
|
||||
|
||||
self.context = context
|
||||
self.type_class3 = type_class3
|
||||
self.types = types
|
||||
self.types = typ_list
|
||||
|
||||
def check(self) -> CheckResult:
|
||||
typ_list: list[types.Type3 | types.TypeConstructor_Base[Any] | types.TypeConstructor_Struct] = []
|
||||
typ_list: list[Type3 | TypeConstructor_Base[Any] | TypeConstructor_Struct] = []
|
||||
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
|
||||
|
||||
if isinstance(typ, placeholders.PlaceholderForType):
|
||||
if isinstance(typ, PlaceholderForType):
|
||||
return RequireTypeSubstitutes()
|
||||
|
||||
if isinstance(typ.application, (types.TypeApplication_Nullary, types.TypeApplication_Struct, )):
|
||||
if isinstance(typ.application, (TypeApplication_Nullary, TypeApplication_Struct, )):
|
||||
typ_list.append(typ)
|
||||
continue
|
||||
|
||||
if isinstance(typ.application, (types.TypeApplication_TypeInt, types.TypeApplication_TypeStar)):
|
||||
if isinstance(typ.application, (TypeApplication_TypeInt, TypeApplication_TypeStar)):
|
||||
typ_list.append(typ.application.constructor)
|
||||
continue
|
||||
|
||||
@ -289,7 +299,7 @@ class MustImplementTypeClassConstraint(ConstraintBase):
|
||||
|
||||
assert len(typ_list) == len(self.types)
|
||||
|
||||
if isinstance(self.type_class3, typeclasses.Type3Class):
|
||||
if isinstance(self.type_class3, Type3Class):
|
||||
key = (self.type_class3, tuple(typ_list), )
|
||||
if key in self.context.type_class_instances_existing:
|
||||
return None
|
||||
@ -324,12 +334,12 @@ class LiteralFitsConstraint(ConstraintBase):
|
||||
"""
|
||||
__slots__ = ('type3', 'literal', )
|
||||
|
||||
type3: placeholders.Type3OrPlaceholder
|
||||
type3: Type3OrPlaceholder
|
||||
literal: Union[ourlang.ConstantPrimitive, ourlang.ConstantBytes, ourlang.ConstantTuple, ourlang.ConstantStruct]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
type3: placeholders.Type3OrPlaceholder,
|
||||
type3: Type3OrPlaceholder,
|
||||
literal: Union[ourlang.ConstantPrimitive, ourlang.ConstantBytes, ourlang.ConstantTuple, ourlang.ConstantStruct],
|
||||
comment: Optional[str] = None,
|
||||
) -> None:
|
||||
@ -338,7 +348,7 @@ class LiteralFitsConstraint(ConstraintBase):
|
||||
self.type3 = type3
|
||||
self.literal = literal
|
||||
|
||||
def _generate_static_array(self, sa_args: tuple[types.Type3, types.IntType3]) -> CheckResult:
|
||||
def _generate_static_array(self, sa_args: tuple[Type3, IntType3]) -> CheckResult:
|
||||
if not isinstance(self.literal, ourlang.ConstantTuple):
|
||||
return Error('Must be tuple', comment=self.comment)
|
||||
|
||||
@ -364,7 +374,7 @@ class LiteralFitsConstraint(ConstraintBase):
|
||||
|
||||
return res
|
||||
|
||||
def _generate_struct(self, st_args: tuple[tuple[str, types.Type3], ...]) -> CheckResult:
|
||||
def _generate_struct(self, st_args: tuple[tuple[str, Type3], ...]) -> CheckResult:
|
||||
if not isinstance(self.literal, ourlang.ConstantStruct):
|
||||
return Error('Must be struct')
|
||||
|
||||
@ -388,7 +398,7 @@ class LiteralFitsConstraint(ConstraintBase):
|
||||
|
||||
return res
|
||||
|
||||
def _generate_tuple(self, tp_args: tuple[types.Type3, ...]) -> CheckResult:
|
||||
def _generate_tuple(self, tp_args: tuple[Type3, ...]) -> CheckResult:
|
||||
if not isinstance(self.literal, ourlang.ConstantTuple):
|
||||
return Error('Must be tuple', comment=self.comment)
|
||||
|
||||
@ -432,7 +442,7 @@ class LiteralFitsConstraint(ConstraintBase):
|
||||
'f64': None,
|
||||
}
|
||||
|
||||
if isinstance(self.type3, placeholders.PlaceholderForType):
|
||||
if isinstance(self.type3, PlaceholderForType):
|
||||
if self.type3.resolve_as is None:
|
||||
return RequireTypeSubstitutes()
|
||||
|
||||
@ -492,17 +502,17 @@ class CanBeSubscriptedConstraint(ConstraintBase):
|
||||
"""
|
||||
__slots__ = ('ret_type3', 'type3', 'index', 'index_phft', )
|
||||
|
||||
ret_type3: placeholders.Type3OrPlaceholder
|
||||
type3: placeholders.Type3OrPlaceholder
|
||||
ret_type3: Type3OrPlaceholder
|
||||
type3: Type3OrPlaceholder
|
||||
index: ourlang.Expression
|
||||
index_phft: placeholders.Type3OrPlaceholder
|
||||
index_phft: Type3OrPlaceholder
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
ret_type3: placeholders.PlaceholderForType,
|
||||
type3: placeholders.PlaceholderForType,
|
||||
ret_type3: PlaceholderForType,
|
||||
type3: PlaceholderForType,
|
||||
index: ourlang.Expression,
|
||||
index_phft: placeholders.PlaceholderForType,
|
||||
index_phft: PlaceholderForType,
|
||||
comment: Optional[str] = None,
|
||||
) -> None:
|
||||
super().__init__(comment=comment)
|
||||
@ -518,7 +528,7 @@ class CanBeSubscriptedConstraint(ConstraintBase):
|
||||
SameTypeConstraint(prelude.u8, self.ret_type3, comment='([]) :: bytes -> u32 -> u8'),
|
||||
]
|
||||
|
||||
def _generate_static_array(self, sa_args: tuple[types.Type3, types.IntType3]) -> CheckResult:
|
||||
def _generate_static_array(self, sa_args: tuple[Type3, IntType3]) -> CheckResult:
|
||||
sa_type, sa_len = sa_args
|
||||
|
||||
if isinstance(self.index, ourlang.ConstantPrimitive):
|
||||
@ -532,7 +542,7 @@ class CanBeSubscriptedConstraint(ConstraintBase):
|
||||
SameTypeConstraint(sa_type, self.ret_type3, comment='([]) :: Subscriptable a => a b -> u32 -> b'),
|
||||
]
|
||||
|
||||
def _generate_tuple(self, tp_args: tuple[types.Type3, ...]) -> CheckResult:
|
||||
def _generate_tuple(self, tp_args: tuple[Type3, ...]) -> CheckResult:
|
||||
# We special case tuples to allow for ease of use to the programmer
|
||||
# e.g. rather than having to do `fst a` and `snd a` and only have to-sized tuples
|
||||
# we use a[0] and a[1] and allow for a[2] and on.
|
||||
@ -558,7 +568,7 @@ class CanBeSubscriptedConstraint(ConstraintBase):
|
||||
|
||||
def check(self) -> CheckResult:
|
||||
exp_type = self.type3
|
||||
if isinstance(exp_type, placeholders.PlaceholderForType):
|
||||
if isinstance(exp_type, PlaceholderForType):
|
||||
if exp_type.resolve_as is None:
|
||||
return RequireTypeSubstitutes()
|
||||
|
||||
|
||||
@ -6,10 +6,6 @@ The constraints solver can then try to resolve all constraints.
|
||||
from typing import Generator, List
|
||||
|
||||
from .. import ourlang, prelude
|
||||
from . import functions as functions
|
||||
from . import placeholders as placeholders
|
||||
from . import typeclasses as typeclasses
|
||||
from . import types as type3types
|
||||
from .constraints import (
|
||||
CanBeSubscriptedConstraint,
|
||||
ConstraintBase,
|
||||
@ -20,7 +16,14 @@ from .constraints import (
|
||||
SameTypeConstraint,
|
||||
TupleMatchConstraint,
|
||||
)
|
||||
from .functions import (
|
||||
Constraint_TypeClassInstanceExists,
|
||||
FunctionSignature,
|
||||
TypeVariable,
|
||||
TypeVariableApplication_Unary,
|
||||
)
|
||||
from .placeholders import PlaceholderForType
|
||||
from .types import Type3, TypeApplication_Struct
|
||||
|
||||
ConstraintGenerator = Generator[ConstraintBase, None, None]
|
||||
|
||||
@ -30,7 +33,7 @@ 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, phft: PlaceholderForType) -> ConstraintGenerator:
|
||||
if isinstance(inp, (ourlang.ConstantPrimitive, ourlang.ConstantBytes, ourlang.ConstantTuple, ourlang.ConstantStruct)):
|
||||
yield LiteralFitsConstraint(
|
||||
phft, inp,
|
||||
@ -63,7 +66,7 @@ def expression_function_call(ctx: Context, inp: ourlang.FunctionCall, phft: Plac
|
||||
def _expression_function_call(
|
||||
ctx: Context,
|
||||
func_name: str,
|
||||
signature: functions.FunctionSignature,
|
||||
signature: FunctionSignature,
|
||||
arguments: list[ourlang.Expression],
|
||||
return_expr: ourlang.Expression,
|
||||
return_phft: PlaceholderForType,
|
||||
@ -92,13 +95,13 @@ def _expression_function_call(
|
||||
# placeholder here. These don't need to update anything once
|
||||
# subsituted - that's done by arg_placeholders.
|
||||
type_var_map = {
|
||||
x: placeholders.PlaceholderForType([])
|
||||
x: PlaceholderForType([])
|
||||
for x in signature.args
|
||||
if isinstance(x, functions.TypeVariable)
|
||||
if isinstance(x, TypeVariable)
|
||||
}
|
||||
|
||||
for constraint in signature.context.constraints:
|
||||
if isinstance(constraint, functions.Constraint_TypeClassInstanceExists):
|
||||
if isinstance(constraint, Constraint_TypeClassInstanceExists):
|
||||
yield MustImplementTypeClassConstraint(
|
||||
ctx,
|
||||
constraint.type_class3,
|
||||
@ -113,7 +116,7 @@ def _expression_function_call(
|
||||
# That is, given `foo :: t a -> a` we need to ensure
|
||||
# that both a's are the same.
|
||||
for sig_arg in signature.args:
|
||||
if isinstance(sig_arg, type3types.Type3):
|
||||
if isinstance(sig_arg, Type3):
|
||||
# Not a type variable at all
|
||||
continue
|
||||
|
||||
@ -121,7 +124,7 @@ def _expression_function_call(
|
||||
# Not a type variable for a type constructor
|
||||
continue
|
||||
|
||||
if not isinstance(sig_arg.application, functions.TypeVariableApplication_Unary):
|
||||
if not isinstance(sig_arg.application, TypeVariableApplication_Unary):
|
||||
raise NotImplementedError(sig_arg.application)
|
||||
|
||||
assert sig_arg.application.arguments in type_var_map # When does this happen?
|
||||
@ -139,18 +142,18 @@ def _expression_function_call(
|
||||
else:
|
||||
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, TypeVariable):
|
||||
yield SameTypeConstraint(type_var_map[sig_part], arg_placeholders[arg_expr], comment=comment)
|
||||
continue
|
||||
|
||||
if isinstance(sig_part, type3types.Type3):
|
||||
if isinstance(sig_part, Type3):
|
||||
yield SameTypeConstraint(sig_part, arg_placeholders[arg_expr], comment=comment)
|
||||
continue
|
||||
|
||||
raise NotImplementedError(sig_part)
|
||||
return
|
||||
|
||||
def expression(ctx: Context, inp: ourlang.Expression, phft: placeholders.PlaceholderForType) -> ConstraintGenerator:
|
||||
def expression(ctx: Context, inp: ourlang.Expression, phft: PlaceholderForType) -> ConstraintGenerator:
|
||||
if isinstance(inp, ourlang.Constant):
|
||||
yield from constant(ctx, inp, phft)
|
||||
return
|
||||
@ -194,7 +197,7 @@ def expression(ctx: Context, inp: ourlang.Expression, phft: placeholders.Placeho
|
||||
return
|
||||
|
||||
if isinstance(inp, ourlang.AccessStructMember):
|
||||
assert isinstance(inp.struct_type3.application, type3types.TypeApplication_Struct) # FIXME: See test_struct.py::test_struct_not_accessible
|
||||
assert isinstance(inp.struct_type3.application, TypeApplication_Struct) # FIXME: See test_struct.py::test_struct_not_accessible
|
||||
|
||||
mem_typ = dict(inp.struct_type3.application.arguments)[inp.member]
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user