Commit 8cadfa12 authored by Tom Niget's avatar Tom Niget

Fix unification checks and type instantiation

parent e523e730
from typing import Self, TypeVar, Generic from typing import Self, TypeVar, Generic, Tuple
class int: class int:
...@@ -13,6 +13,7 @@ class int: ...@@ -13,6 +13,7 @@ class int:
assert int.__add__ assert int.__add__
U = TypeVar("U") U = TypeVar("U")
V = TypeVar("V")
class list(Generic[U]): class list(Generic[U]):
...@@ -44,13 +45,29 @@ def identity(x: U) -> U: ...@@ -44,13 +45,29 @@ def identity(x: U) -> U:
assert identity(1) assert identity(1)
assert identity("a") assert identity("a")
def identity_2(x: U, y: V) -> Tuple[U, V]:
...
assert list.__add__
assert list.__add__([5], [[6][0]])
assert list[U].__add__
assert list[U].__add__([1], [2])
assert list[U].__add__
assert list[int].__add__
assert identity_2(1, "a")
assert lambda x, y: identity_2(x, y)
assert lambda x: identity_2(x, x)
def print(*args) -> None: ... def print(*args) -> None: ...
def range(*args) -> Iterator[int]: ... def range(*args) -> Iterator[int]: ...
def rangeb(*args) -> Iterator[bool]: ...
assert [].__add__
assert [6].__add__ assert [6].__add__
assert [True].__add__ assert [True].__add__
assert next(range(6), None) assert lambda x: [x].__add__
assert next(rangeb(6), None)
\ No newline at end of file
assert next(range(6), None)
\ No newline at end of file
...@@ -4,7 +4,7 @@ from pathlib import Path ...@@ -4,7 +4,7 @@ from pathlib import Path
from transpiler.phases.typing.scope import VarKind, VarDecl, ScopeKind from transpiler.phases.typing.scope import VarKind, VarDecl, ScopeKind
from transpiler.phases.typing.stdlib import PRELUDE, StdlibVisitor from transpiler.phases.typing.stdlib import PRELUDE, StdlibVisitor
from transpiler.phases.typing.types import TY_TYPE, TY_INT, TY_STR, TY_BOOL, TY_COMPLEX, TY_NONE, FunctionType, \ from transpiler.phases.typing.types import TY_TYPE, TY_INT, TY_STR, TY_BOOL, TY_COMPLEX, TY_NONE, FunctionType, \
TypeVariable, TY_MODULE, CppType, PyList, TypeType, Forked, Task, Future, PyIterator TypeVariable, TY_MODULE, CppType, PyList, TypeType, Forked, Task, Future, PyIterator, TupleType
PRELUDE.vars.update({ PRELUDE.vars.update({
# "int": VarDecl(VarKind.LOCAL, TY_TYPE, TY_INT), # "int": VarDecl(VarKind.LOCAL, TY_TYPE, TY_INT),
...@@ -28,7 +28,8 @@ PRELUDE.vars.update({ ...@@ -28,7 +28,8 @@ PRELUDE.vars.update({
"Forked": VarDecl(VarKind.LOCAL, TypeType(Forked)), "Forked": VarDecl(VarKind.LOCAL, TypeType(Forked)),
"Task": VarDecl(VarKind.LOCAL, TypeType(Task)), "Task": VarDecl(VarKind.LOCAL, TypeType(Task)),
"Future": VarDecl(VarKind.LOCAL, TypeType(Future)), "Future": VarDecl(VarKind.LOCAL, TypeType(Future)),
"Iterator": VarDecl(VarKind.LOCAL, TypeType(PyIterator)) "Iterator": VarDecl(VarKind.LOCAL, TypeType(PyIterator)),
"Tuple": VarDecl(VarKind.LOCAL, TypeType(TupleType)),
}) })
typon_std = Path(__file__).parent.parent.parent.parent / "stdlib" typon_std = Path(__file__).parent.parent.parent.parent / "stdlib"
......
import abc import abc
import ast import ast
import inspect
from typing import List from typing import List
from transpiler.phases.typing import ScopeKind, VarDecl, VarKind from transpiler.phases.typing import ScopeKind, VarDecl, VarKind
...@@ -108,7 +109,7 @@ class ScoperExprVisitor(ScoperVisitor): ...@@ -108,7 +109,7 @@ class ScoperExprVisitor(ScoperVisitor):
try: try:
ftype.unify(equivalent) ftype.unify(equivalent)
except IncompatibleTypesError as e: except IncompatibleTypesError as e:
raise IncompatibleTypesError(f"Cannot call {ftype} with {equivalent}: {e}") raise IncompatibleTypesError(f"Cannot call {ftype} with ({(', '.join(map(str, arguments)))}): {e}")
return ftype.return_type return ftype.return_type
def visit_Lambda(self, node: ast.Lambda) -> BaseType: def visit_Lambda(self, node: ast.Lambda) -> BaseType:
...@@ -147,6 +148,12 @@ class ScoperExprVisitor(ScoperVisitor): ...@@ -147,6 +148,12 @@ class ScoperExprVisitor(ScoperVisitor):
if isinstance(ltype, TypeType): if isinstance(ltype, TypeType):
ltype = ltype.type_object ltype = ltype.type_object
bound = False bound = False
if isinstance(ltype, abc.ABCMeta):
ctor = ltype.__init__
args = list(inspect.signature(ctor).parameters.values())[1:]
if not all(arg.annotation == BaseType for arg in args):
raise NotImplementedError("I don't know how to handle this type")
ltype = ltype(*(TypeVariable() for _ in args))
if attr := ltype.members.get(name): if attr := ltype.members.get(name):
return attr return attr
if meth := ltype.methods.get(name): if meth := ltype.methods.get(name):
...@@ -187,7 +194,7 @@ class ScoperExprVisitor(ScoperVisitor): ...@@ -187,7 +194,7 @@ class ScoperExprVisitor(ScoperVisitor):
args = [self.visit(e) for e in args] args = [self.visit(e) for e in args]
if isinstance(left, TypeType) and isinstance(left.type_object, abc.ABCMeta): if isinstance(left, TypeType) and isinstance(left.type_object, abc.ABCMeta):
# generic # generic
return TypeType(left.type_object(*[arg.type_object for arg in args])) return TypeType(left.type_object(*[arg.type_object if isinstance(arg, TypeType) else arg for arg in args]))
pass pass
return self.make_dunder([left, *args], "getitem") return self.make_dunder([left, *args], "getitem")
......
import dataclasses
import typing import typing
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from dataclasses import dataclass, field from dataclasses import dataclass, field
...@@ -41,6 +42,10 @@ class BaseType(ABC): ...@@ -41,6 +42,10 @@ class BaseType(ABC):
def contains_internal(self, other: "BaseType") -> bool: def contains_internal(self, other: "BaseType") -> bool:
pass pass
# @abstractmethod
# def clone(self) -> "BaseType":
# pass
def gen_sub(self, this: "BaseType", typevars: Dict[str, "BaseType"]) -> "Self": def gen_sub(self, this: "BaseType", typevars: Dict[str, "BaseType"]) -> "Self":
return self return self
...@@ -49,6 +54,8 @@ class BaseType(ABC): ...@@ -49,6 +54,8 @@ class BaseType(ABC):
T = typing.TypeVar("T") T = typing.TypeVar("T")
class MagicType(BaseType, typing.Generic[T]): class MagicType(BaseType, typing.Generic[T]):
val: T val: T
...@@ -66,6 +73,9 @@ class MagicType(BaseType, typing.Generic[T]): ...@@ -66,6 +73,9 @@ class MagicType(BaseType, typing.Generic[T]):
def __str__(self): def __str__(self):
return str(self.val) return str(self.val)
def clone(self) -> "BaseType":
return MagicType(self.val)
cur_var = 0 cur_var = 0
...@@ -161,6 +171,9 @@ class TypeOperator(BaseType, ABC): ...@@ -161,6 +171,9 @@ class TypeOperator(BaseType, ABC):
if not (self.variadic or other.variadic): if not (self.variadic or other.variadic):
raise IncompatibleTypesError(f"Cannot unify {self} and {other} with different number of arguments") raise IncompatibleTypesError(f"Cannot unify {self} and {other} with different number of arguments")
if len(self.args) == 0:
if self.name != other.name:
raise IncompatibleTypesError(f"Cannot unify {self} and {other}")
for i, (a, b) in enumerate(zip_longest(self.args, other.args)): for i, (a, b) in enumerate(zip_longest(self.args, other.args)):
if a is None and self.variadic or b is None and other.variadic: if a is None and self.variadic or b is None and other.variadic:
continue continue
...@@ -171,7 +184,6 @@ class TypeOperator(BaseType, ABC): ...@@ -171,7 +184,6 @@ class TypeOperator(BaseType, ABC):
if a != b: if a != b:
raise IncompatibleTypesError(f"Cannot unify {a} and {b}") raise IncompatibleTypesError(f"Cannot unify {a} and {b}")
def contains_internal(self, other: "BaseType") -> bool: def contains_internal(self, other: "BaseType") -> bool:
return any(arg.contains(other) for arg in self.args) return any(arg.contains(other) for arg in self.args)
...@@ -182,20 +194,23 @@ class TypeOperator(BaseType, ABC): ...@@ -182,20 +194,23 @@ class TypeOperator(BaseType, ABC):
return hash((self.name, tuple(self.args))) return hash((self.name, tuple(self.args)))
def gen_sub(self, this: BaseType, typevars) -> "Self": def gen_sub(self, this: BaseType, typevars) -> "Self":
if len(self.args) == 0:
return self
res = object.__new__(self.__class__) # todo: ugly... should make a clone() res = object.__new__(self.__class__) # todo: ugly... should make a clone()
if isinstance(this, TypeOperator): if isinstance(this, TypeOperator):
vardict = dict(zip(typevars.keys(), this.args)) vardict = dict(zip(typevars.keys(), this.args))
else: else:
vardict = typevars vardict = typevars
for k in dataclasses.fields(self):
setattr(res, k.name, getattr(self, k.name))
res.args = [arg.resolve().gen_sub(this, vardict) for arg in self.args] res.args = [arg.resolve().gen_sub(this, vardict) for arg in self.args]
res.name = self.name
res.variadic = self.variadic
return res return res
def to_list(self) -> List["BaseType"]: def to_list(self) -> List["BaseType"]:
return [self, *self.args] return [self, *self.args]
class FunctionType(TypeOperator): class FunctionType(TypeOperator):
def __init__(self, args: List[BaseType], ret: BaseType): def __init__(self, args: List[BaseType], ret: BaseType):
super().__init__([ret, *args]) super().__init__([ret, *args])
...@@ -287,6 +302,7 @@ class PyDict(TypeOperator): ...@@ -287,6 +302,7 @@ class PyDict(TypeOperator):
def value_type(self): def value_type(self):
return self.args[1] return self.args[1]
class PyIterator(TypeOperator): class PyIterator(TypeOperator):
def __init__(self, arg: BaseType): def __init__(self, arg: BaseType):
super().__init__([arg], "iter") super().__init__([arg], "iter")
...@@ -296,9 +312,8 @@ class PyIterator(TypeOperator): ...@@ -296,9 +312,8 @@ class PyIterator(TypeOperator):
return self.args[0] return self.args[0]
class TupleType(TypeOperator): class TupleType(TypeOperator):
def __init__(self, args: List[BaseType]): def __init__(self, *args: List[BaseType]):
super().__init__(args, "tuple") super().__init__(args, "tuple")
...@@ -334,17 +349,23 @@ class Promise(TypeOperator, ABC): ...@@ -334,17 +349,23 @@ class Promise(TypeOperator, ABC):
return [PyIterator(self.return_type), *super().get_parents()] return [PyIterator(self.return_type), *super().get_parents()]
return super().get_parents() return super().get_parents()
class Forked(Promise): class Forked(Promise):
"""Only use this for type specs""" """Only use this for type specs"""
def __init__(self, ret: BaseType): def __init__(self, ret: BaseType):
super().__init__(ret, PromiseKind.FORKED) super().__init__(ret, PromiseKind.FORKED)
class Task(Promise): class Task(Promise):
"""Only use this for type specs""" """Only use this for type specs"""
def __init__(self, ret: BaseType): def __init__(self, ret: BaseType):
super().__init__(ret, PromiseKind.TASK) super().__init__(ret, PromiseKind.TASK)
class Future(Promise): class Future(Promise):
"""Only use this for type specs""" """Only use this for type specs"""
def __init__(self, ret: BaseType): def __init__(self, ret: BaseType):
super().__init__(ret, PromiseKind.FUTURE) super().__init__(ret, PromiseKind.FUTURE)
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment