Numeric Generics - Where do we go from PEP 3141 and present day Mypy?

So something like this?

from __future__ import annotations
from abc import abstractmethod
from typing import Protocol, runtime_checkable

@runtime_checkable
class FloatT(Protocol):
    @abstractmethod
    def __add__(self, other: "FloatT" | "IntegerT") -> "FloatT": ...
    @abstractmethod
    def __radd__(self, other: "FloatT" | "IntegerT") -> "FloatT": ...
    @abstractmethod
    def __float__(self) -> float: ...

FloatT.register(float)

@runtime_checkable
class IntegerT(Protocol):
    @abstractmethod
    def __init__(self, value: "IntegerT"): ...
    @abstractmethod
    def __add__(self, other: "IntegerT") -> "IntegerT": ...
    @abstractmethod
    def __radd__(self, other: "IntegerT") -> "IntegerT": ...
    @abstractmethod
    def __float__(self) -> float: ...
    @abstractmethod
    def __int__(self) -> int: ...

IntegerT.register(int)

class MyFloat(FloatT):
    def __init__(self, value: FloatT | IntegerT): ...
    def __add__(self, other: FloatT | IntegerT) -> "MyFloat": ...
    def __radd__(self, other: FloatT | IntegerT) -> "MyFloat": ...
    def __float__(self) -> float: ...

class MyInteger(IntegerT):
    def __init__(self, value: IntegerT): ...
    def __add__(self, other: FloatT | IntegerT) -> "MyInteger": ...
    def __radd__(self, other: FloatT | IntegerT) -> "MyInteger": ...
    def __float__(self) -> float: ...
    def __int__(self) -> int: ...

integer_t_val: IntegerT = 0  # should validate, but doesn't
assert isinstance(MyInteger(0), IntegerT)  # works because of registration
assert isinstance(0, IntegerT)  # works because of registration
assert isinstance(0.0, FloatT)  # works because of registration
assert isinstance(MyFloat(0), FloatT)  # works because of inheritance? not sure
reveal_type(MyFloat(0) + MyInteger(0))  # should yield MyFloat
reveal_type(MyInteger(0) + 0)  # should yield MyInteger
reveal_type(0.0 + MyFloat(0))  # should yield MyFloat

I think instance checks would have to be revisited if Protocols are to be used as ancestor classes. As of now, that check is not very efficient and imposes some odd behaviors that probably aren’t appropriate for direct inheritance.

I don’t know if something like this would suffice?

class _ProtocolMeta(ABCMeta):
    # …
    def __instancecheck__(cls, instance):
        if super().__instancecheck__(instance):
            # Short circuit for direct inheritors
            return True
        else:
            # … existing implementation that checks method names, etc. …
            return False

I’m not aware enough of all of the edge cases to know what problems the above would cause.