Do not intersect types in isinstance checks if at least one is final. by tyralla · Pull Request #16330 · python/mypy
The sphinx issue caused me some headaches, but I think I've collected some hints.
The argument cls of function restify is annotated with type | None but should be annotated (at least) with str | type | None. Mypy should complain about this in the implemented if isinstance(cls, str): check but doesn't because it assumes the intersection "sphinx.util.typing.<subclass of "type" and "str">" which in my opinion is impossible because of instance layout conflicts (and I cannot think of a way this makes sense).
Interestingly, Mypy 1.6 agrees with my reasoning when annotating with Type instead of type:
from typing import Type t1: type t2: Type if isinstance(t1, str): reveal_type(t1) # note: Revealed type is "temp.<subclass of "type" and "str">" if isinstance(t2, str): reveal_type(t2) # error: Statement is unreachable
If I change the annotation of cls from type | None to Type | None, Mypy 1.6 also does not require the type: ignore[attr-defined] comment anymore because it considers the affected line unreachable.
So, everything seems clear. However, when applying Mypy 1.6 on the following example code involving _SpecialForm instead of the complete sphinx code, it finds out about the unreachability no matter if annotating with type or Type:
from typing import Type, _SpecialForm t1: type t2: Type if isinstance(t1, _SpecialForm): # error: Subclass of "type" and "<typing special form>" cannot exist: would have incompatible method signatures reveal_type(t1) # error: Statement is unreachable if isinstance(t2, _SpecialForm): reveal_type(t2) # error: Statement is unreachable
To conclude, strange things might be going on, but they are not related to this pull request.