import copy class Type: methods: dict[str, tuple[list['Type'], 'Type', set[str]]] fields: dict[str, 'Type'] def __init__(self): self.methods = {} self.fields = {} def __eq__(self, other): return False def get_vars(self): return [] def subst(self, subst: dict[str, 'Type']): return self def inv_subst(self, subst: list[tuple['Type', 'TypeVariable']]): for t, tv in subst: if self == t: return tv return self class BotType: def __eq__(self, other): return isinstance(other, BotType) class PrimitiveType(Type): name: str def __init__(self, name: str): super().__init__() self.name = name def __str__(self): return self.name def __eq__(self, other): return isinstance(other, PrimitiveType) and self.name == other.name class TypeVariable(Type): name: str # this may be a list of str, Type may not be determined when type variables # are instantiated... # and they cannot contain other type variables constraints: list[Type] def __init__(self, name: str, constraints: list[Type]): super().__init__() self.name = name self.constraints = constraints def __str__(self): return self.name def __eq__(self, other): return isinstance(other, TypeVariable) and self.name == other.name def get_vars(self): return [self] def subst(self, subst: dict[str, Type]): if self.name in subst: return subst[self.name] return self class ClassType(Type): name: str parents: list['ClassType'] methods: dict[str, tuple[list[Type], Type, set[str]]] fields: dict[str, Type] def __init__(self, name: str): super().__init__() self.name = name self.parents = [] def __str__(self): return self.name def __eq__(self, other): return isinstance(other, ClassType) and self.name == other.name class SelfType(Type): def __str__(self): return 'self' class VirtualClassType(Type): base: ClassType def __init__(self, base: ClassType): super().__init__() self.base = base def __str__(self): return f"virtual[{self.base}]" def __eq__(self, other): return isinstance(other, VirtualClassType) and self.base== other.base class ParametricType(Type): params: list[Type] def __init__(self, params: list[Type]): super().__init__() self.params = params def __eq__(self, other): if type(self) != type(other) or len(self.params) != len(other.params): return False for x, y in zip(self.params, other.params): if x != y: return False return True def get_vars(self): result = [] for p in self.params: vars = p.get_vars() for v in vars: if v not in result: result.append(v) return result def subst(self, subst: dict[str, Type]): s = copy.copy(self) s.params = [v.subst(subst) for v in self.params] return s def inv_subst(self, subst: list[tuple['Type', 'TypeVariable']]): for t, tv in subst: if self == t: return tv s = copy.copy(self) s.params = [v.inv_subst(subst) for v in self.params] return s class ListType(ParametricType): def __init__(self, param: Type): super().__init__([param]) def __str__(self): return f"list[{self.params[0]}]" class TupleType(ParametricType): def __init__(self, params: list[Type]): super().__init__(params) def __str__(self): return f"tuple[{', '.join([str(v) for v in self.params])}]" class Context: variables: dict[str, TypeVariable] types: dict[str, Type] functions: dict[str, tuple[list[Type], Type, set[str]]] def __init__(self, variables, types): self.variables = variables self.types = types self.functions = {}