ty icon indicating copy to clipboard operation
ty copied to clipboard

Emit diagnostic on unsound call to abstract `@classmethod` or `@staticmethod` with trivial body, when accessed on the class object itself

Open AlexWaygood opened this issue 1 week ago • 3 comments

Both pyright and pyrefly detect the unsoundness here, though mypy does not. We should also detect this as unsound and reject it:

from abc import abstractmethod

class F:
    @classmethod
    @abstractmethod
    def method(cls) -> int: ...

# pyright: Method "method" cannot be called because it is abstract and unimplemented  (reportAbstractUsage)
reveal_type(F.method())

Pyright and pyrefly do however allow the classmethod to be called via type[F]. You could argue that this is unsound, since you do not know whether or not you're dealing with a concrete subclass of F or not. But type[] types are generally unsound, and mypy's lint attempting to enforce similar soundness checks for type[] types has proved very unpopular. So I think we should also allow this:

from abc import abstractmethod

class F:
    @classmethod
    @abstractmethod
    def method(cls) -> int: ...

def _(x: type[F]):
    reveal_type(x.method())

AlexWaygood avatar Dec 16 '25 13:12 AlexWaygood

Note that instance methods don't need to be caught by this check, because if we implement https://github.com/astral-sh/ty/issues/1877 then it's basically impossible to call an abstract instance method.

This check should probably also include abstract staticmethods with trivial bodies, though, thinking about it

AlexWaygood avatar Dec 16 '25 20:12 AlexWaygood

But isn't this kind of thing a valid use case for abstract types and methods?

# A is a type with abstract methods

def f(a: A):
    a.some_abstract_method()

where the whole point is that you want callers to pass you concrete subtypes of A?

carljm avatar Dec 16 '25 20:12 carljm

Yes, I just said that we shouldn't include instance methods in this check, only classmethods and maybe staticmethods. And above that, I also said that we should only emit the lint for abstract classmethods/staticmethods with trivial bodies accessed on the class object itself, not when accessed on type[] types.

AlexWaygood avatar Dec 16 '25 20:12 AlexWaygood