I like what happens here in the absence of Any at least, but I notice you did not specify what happens in the case of subclassing of Any or an unknown type
This case would still be under-specified
from untyped import IsAny
class Foo(IsAny):
pass
- object as the implicit root provides no guidance here.
- it’s not possible for the type system to determine if this is Hashable anymore.
I still think subclassing of Any was not considered properly and should not have ever happened, but the “best understanding” we have is that in this case it’s an unknown, but compatible type. This still doesn’t help with hash though, as hash being None or being a method returning an int are both compatible options.
This could be fixed in a few ways, but the way I would pick that actually has a chance of happening is that with only unknown types as bases, the following happens in order:
- If hash is defined or set to None, directly or implicitly on Foo, Any is compatible, so it’s assumed to follow the rules here, and Foo defining it is fine.
- Otherwise, hash is assumed to be a method returning int as the default implementation provides. This keeps Any compatible with Hashable until proven otherwise.
This opens up a type hole, but we’re talking about subclassing Any, which as everyone has observed already is riddled with type holes. This can be fixed minimally by just setting hash to None on Foo where it causes a problem or longer-term improving the typing of the base.