feat(checker): define members on builtin types

This commit is contained in:
2026-06-13 12:39:46 +02:00
parent a1f2937e16
commit dafe0b471a
3 changed files with 157 additions and 57 deletions

View File

@@ -0,0 +1,152 @@
extend float {
def hex: fn() -> str
def is_integer: fn() -> bool
prop real: float
prop imag: float
def conjugate: fn() -> float
def __add__: fn(value: float, /) -> float
def __sub__: fn(value: float, /) -> float
def __mul__: fn(value: float, /) -> float
def __floordiv__: fn(value: float, /) -> float
def __truediv__: fn(value: float, /) -> float
def __mod__: fn(value: float, /) -> float
// def __divmod__: fn(value: float, /) -> tuple[float, float]
def __pow__: fn(value: int, /) -> float
// positive __value -> float; negative __value -> complex
// return type must be Any as `float | complex` causes too many false-positive errors
def __pow__: fn(value: float, /) -> Any
def __radd__: fn(value: float, /) -> float
def __rsub__: fn(value: float, /) -> float
def __rmul__: fn(value: float, /) -> float
def __rfloordiv__: fn(value: float, /) -> float
def __rtruediv__: fn(value: float, /) -> float
def __rmod__: fn(value: float, /) -> float
// def __rdivmod__: fn(value: float, /) -> tuple[float, float]
// def __rpow__: fn(value: _PositiveInteger, mod: None = None, /) -> float
// def __rpow__: fn(value: _NegativeInteger, mod: None = None, /) -> complex
// Returning `complex` for the general case gives too many false-positive errors.
// def __rpow__: fn(value: float, mod: None = None, /) -> Any
// def __getnewargs__: fn() -> tuple[float]
def __trunc__: fn() -> int
def __ceil__: fn() -> int
def __floor__: fn() -> int
def __round__: fn(ndigits: None?, /) -> int
def __round__: fn(ndigits: int, /) -> float
def __eq__: fn(value: object, /) -> bool
def __ne__: fn(value: object, /) -> bool
def __lt__: fn(value: float, /) -> bool
def __le__: fn(value: float, /) -> bool
def __gt__: fn(value: float, /) -> bool
def __ge__: fn(value: float, /) -> bool
def __neg__: fn() -> float
def __pos__: fn() -> float
def __int__: fn() -> int
def __float__: fn() -> float
def __abs__: fn() -> float
def __hash__: fn() -> int
def __bool__: fn() -> bool
def __format__: fn(format_spec: str, /) -> str
}
extend int {
prop real: int
prop imag: int
prop numerator: int
prop denominator: int
def conjugate: fn() -> int
def bit_length: fn() -> int
def bit_count: fn() -> int
def to_bytes: fn(length: int?, byteorder: str?, *, signed: bool?) -> bytes
def __add__: fn(value: int, /) -> int
def __sub__: fn(value: int, /) -> int
def __mul__: fn(value: int, /) -> int
def __floordiv__: fn(value: int, /) -> int
def __truediv__: fn(value: int, /) -> float
def __mod__: fn(value: int, /) -> int
// def __divmod__: fn(value: int, /) -> tuple[int, int]
def __radd__: fn(value: int, /) -> int
def __rsub__: fn(value: int, /) -> int
def __rmul__: fn(value: int, /) -> int
def __rfloordiv__: fn(value: int, /) -> int
def __rtruediv__: fn(value: int, /) -> float
def __rmod__: fn(value: int, /) -> int
// def __rdivmod__: fn(value: int, /) -> tuple[int, int]
def __pow__: fn(value: int, /) -> int
// def __pow__: fn(value: _PositiveInteger, mod: None = None, /) -> int
// def __pow__: fn(value: _NegativeInteger, mod: None = None, /) -> float
// positive __value -> int; negative __value -> float
// return type must be Any as `int | float` causes too many false-positive errors
// def __pow__: fn(value: int, mod: None = None, /) -> Any
// def __pow__: fn(value: int, mod: int, /) -> int
def __rpow__: fn(value: int, /) -> Any
def __and__: fn(value: int, /) -> int
def __or__: fn(value: int, /) -> int
def __xor__: fn(value: int, /) -> int
def __lshift__: fn(value: int, /) -> int
def __rshift__: fn(value: int, /) -> int
def __rand__: fn(value: int, /) -> int
def __ror__: fn(value: int, /) -> int
def __rxor__: fn(value: int, /) -> int
def __rlshift__: fn(value: int, /) -> int
def __rrshift__: fn(value: int, /) -> int
def __neg__: fn() -> int
def __pos__: fn() -> int
def __invert__: fn() -> int
def __trunc__: fn() -> int
def __ceil__: fn() -> int
def __floor__: fn() -> int
def __round__: fn(ndigits: None?, /) -> int
def __round__: fn(ndigits: int, /) -> int
// def __getnewargs__: fn() -> tuple[int]
def __eq__: fn(value: object, /) -> bool
def __ne__: fn(value: object, /) -> bool
def __lt__: fn(value: int, /) -> bool
def __le__: fn(value: int, /) -> bool
def __gt__: fn(value: int, /) -> bool
def __ge__: fn(value: int, /) -> bool
def __float__: fn() -> float
def __int__: fn() -> int
def __abs__: fn() -> int
def __hash__: fn() -> int
def __bool__: fn() -> bool
def __index__: fn() -> int
def __format__: fn(format_spec: str, /) -> str
}
extend list[T] {
def copy: fn () -> list[T]
def append: fn (object: T, /) -> None
def extend: fn (iterable: list[T], /) -> None
def pop: fn (index: int?, /) -> T
def index: fn (value: T, start: int?, stop: int?, /) -> int
def count: fn (value: T, /) -> int
def insert: fn (index: int, object: T, /) -> None
def remove: fn (value: T, /) -> None
def sort: fn (*, reverse: bool?) -> None
def __len__: fn () -> int
// def __iter__: fn () -> Iterator[T]
def __getitem__: fn (i: int, /) -> T
//__getitem__: fn (s: slice, /) -> list[T]
def __setitem__: fn (key: int, value: T, /) -> None
//__setitem__: fn (key: slice, value: list[T], /) -> None
def __delitem__: fn (key: int, /) -> None
// def __delitem__: fn (key: slice, /) -> None
// def __add__: fn[S <: T] (value: list[S], /) -> list[T]
def __add__: fn (value: list[T], /) -> list[T]
def __iadd__: fn (value: list[T], /) -> list[T]
def __mul__: fn (value: int, /) -> list[T]
def __rmul__: fn (value: int, /) -> list[T]
def __imul__: fn (value: int, /) -> list[T]
def __contains__: fn (key: object, /) -> bool
// def __reversed__: fn (self) -> Iterator[_T]
def __gt__: fn (value: list[T], /) -> bool
def __ge__: fn (value: list[T], /) -> bool
def __lt__: fn (value: list[T], /) -> bool
def __le__: fn (value: list[T], /) -> bool
def __eq__: fn (value: object, /) -> bool
prop __doc__: str
}

View File

@@ -4,8 +4,6 @@ from typing import TYPE_CHECKING
from midas.checker.types import ( from midas.checker.types import (
BaseType, BaseType,
ComplexType,
Function,
GenericType, GenericType,
Type, Type,
TypeVar, TypeVar,
@@ -43,70 +41,17 @@ def basic_op(reg: TypesRegistry, type: Type, op: str):
def define_builtins(reg: TypesRegistry): def define_builtins(reg: TypesRegistry):
"""Define builtin types and operations""" """Define builtin types and operations"""
unit = reg.define_type("None", UnitType()) unit = reg.define_type("None", UnitType())
object = reg.define_type("object", BaseType(name="object"))
bool = reg.define_type("bool", BaseType(name="bool")) bool = reg.define_type("bool", BaseType(name="bool"))
int = reg.define_type("int", BaseType(name="int")) int = reg.define_type("int", BaseType(name="int"))
float = reg.define_type("float", BaseType(name="float")) float = reg.define_type("float", BaseType(name="float"))
str = reg.define_type("str", BaseType(name="str")) str = reg.define_type("str", BaseType(name="str"))
basic_op(reg, int, "__add__") # int + int = int
basic_op(reg, int, "__sub__") # int - int = int
basic_op(reg, int, "__mul__") # int * int = int
basic_op(reg, int, "__pow__") # int ** int = int
basic_op(reg, int, "__mod__") # int % int = int
basic_op(reg, int, "__and__") # int & int = int
basic_op(reg, int, "__or__") # int | int = int
basic_op(reg, int, "__xor__") # int ^ int = int
op(reg, int, "__lt__", int, bool) # int < int = bool
op(reg, int, "__gt__", int, bool) # int > int = bool
op(reg, int, "__le__", int, bool) # int <= int = bool
op(reg, int, "__ge__", int, bool) # int >= int = bool
op(reg, int, "__eq__", int, bool) # int == int = bool
basic_op(reg, float, "__add__") # float + float = float
basic_op(reg, float, "__sub__") # float - float = float
basic_op(reg, float, "__mul__") # float * float = float
basic_op(reg, float, "__truediv__") # float / float = float
op(reg, float, "__lt__", float, bool) # float < float = bool
op(reg, float, "__gt__", float, bool) # float > float = bool
op(reg, float, "__le__", float, bool) # float <= float = bool
op(reg, float, "__ge__", float, bool) # float >= float = bool
op(reg, float, "__eq__", float, bool) # float == float = bool
basic_op(reg, str, "__add__") # str + str = str
op(reg, str, "__eq__", str, bool) # str == str = bool
op(reg, int, "__lt__", float, bool) # int < float = bool
op(reg, int, "__gt__", float, bool) # int > float = bool
op(reg, int, "__le__", float, bool) # int <= float = bool
op(reg, int, "__ge__", float, bool) # int >= float = bool
op(reg, int, "__eq__", float, bool) # int == float = bool
op(reg, float, "__lt__", int, bool) # float < int = bool
op(reg, float, "__gt__", int, bool) # float > int = bool
op(reg, float, "__le__", int, bool) # float <= int = bool
op(reg, float, "__ge__", int, bool) # float >= int = bool
op(reg, float, "__eq__", int, bool) # float == int = bool
list = reg.define_type( list = reg.define_type(
"list", "list",
GenericType( GenericType(
name="list", name="list",
params=[TypeVar(name="T", bound=None)], params=[TypeVar(name="T", bound=None)],
body=ComplexType( body=BaseType(name="list"),
properties={
"append": Function(
name="append",
pos_args=[
Function.Argument(
pos=0,
name="object",
type=TypeVar(name="T", bound=None),
required=True,
)
],
args=[],
kw_args=[],
returns=UnitType(),
)
}
),
), ),
) )

View File

@@ -1,4 +1,5 @@
import logging import logging
from pathlib import Path
from typing import Optional from typing import Optional
import midas.ast.midas as m import midas.ast.midas as m
@@ -33,6 +34,8 @@ class MidasTyper(m.Stmt.Visitor[None], m.Expr.Visitor[None], m.Type.Visitor[Type
self._current_name: Optional[str] = None self._current_name: Optional[str] = None
define_builtins(self.types) define_builtins(self.types)
builtins_path: Path = (Path(__file__).parent / "builtins.midas").resolve()
self.process(builtins_path.read_text(), str(builtins_path))
def process(self, source: str, path: Optional[str]): def process(self, source: str, path: Optional[str]):
self.reporter = self.reporter.for_file(path) self.reporter = self.reporter.for_file(path)