diff --git a/mypy/checker.py b/mypy/checker.py index d371f40ccaae..b2a444721604 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -6812,13 +6812,20 @@ def narrow_type_by_identity_equality( # We patch this here because it is desirable to widen to any for cases like # isinstance(x, (y: Any)) continue + + arg_type = self.lookup_type(expr_in_type_expr) + if_type, else_type = self.conditional_types_with_intersection( + arg_type, [current_type_range], expr_in_type_expr + ) + if if_type is not None and ( + not current_type_range.is_upper_bound + and not is_equivalent(if_type, current_type_range.item) + ): + # type(x) and x.__class__ checks must exact match + if_type = UninhabitedType() + if_map, else_map = conditional_types_to_typemaps( - expr_in_type_expr, - *self.conditional_types_with_intersection( - self.lookup_type(expr_in_type_expr), - [current_type_range], - expr_in_type_expr, - ), + expr_in_type_expr, if_type, else_type ) is_final = ( diff --git a/test-data/unit/check-narrowing.test b/test-data/unit/check-narrowing.test index b9bb0c1efa6a..675ff86e64ae 100644 --- a/test-data/unit/check-narrowing.test +++ b/test-data/unit/check-narrowing.test @@ -3152,7 +3152,7 @@ else: reveal_type(y) # N: Revealed type is "builtins.str" [builtins fixtures/isinstance.pyi] -[case testTypeEqualsCheckUsingIsNonOverlappingChild-xfail] +[case testTypeEqualsCheckUsingIsNonOverlappingChild] # flags: --strict-equality --warn-unreachable from typing import Union @@ -3168,6 +3168,46 @@ def main(x: Union[B, C]): reveal_type(x) # N: Revealed type is "__main__.B | __main__.C" [builtins fixtures/isinstance.pyi] +[case testTypeEqualsCheckTypeVar] +# flags: --strict-equality --warn-unreachable +from typing import TypeVar + +class A: ... +class B: ... + +T = TypeVar("T") + +def forgets_about_subclasses1(self, obj: T) -> T: + if isinstance(obj, A): + return A() # E: Incompatible return value type (got "A", expected "T") + elif isinstance(obj, B): + return B() # E: Incompatible return value type (got "B", expected "T") + raise + +def correct1(self, obj: T) -> T: + if type(obj) == A: + return A() # E: Incompatible return value type (got "A", expected "T") + elif type(obj) == B: + return B() # E: Incompatible return value type (got "B", expected "T") + raise + +T_value = TypeVar("T_value", A, B) + +def forgets_about_subclasses2(self, obj: T_value) -> T_value: + if isinstance(obj, A): + return A() # E: Incompatible return value type (got "A", expected "B") + elif isinstance(obj, B): + return B() + raise + +def correct2(self, obj: T_value) -> T_value: + if type(obj) == A: + return A() + elif type(obj) == B: + return B() + raise +[builtins fixtures/primitives.pyi] + [case testTypeEqualsCheckUsingDifferentSpecializedTypes] # flags: --warn-unreachable from collections import defaultdict