Emit diagnostic on unsound call to abstract `@classmethod` or `@staticmethod` with trivial body, when accessed on the class object itself
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())
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
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?
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.