diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 44855f49afaf..04035c07c4c1 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -6040,7 +6040,15 @@ def check_for_comp(self, e: GeneratorExpr | DictionaryComprehension) -> None: # values are only part of the comprehension when all conditions are true true_map, false_map = self.chk.find_isinstance_check(condition) - self.chk.push_type_map(true_map) + if mypy.checker.is_unreachable_map(true_map): + # The condition can never be true. Unlike statements, the + # left expression is still type checked, so apply the + # impossible narrowing to the binder instead of marking + # the frame unreachable, which would discard it (#21635). + for expr, typ in true_map.items(): + self.chk.binder.put(expr, typ) + else: + self.chk.push_type_map(true_map) if codes.REDUNDANT_EXPR in self.chk.options.enabled_error_codes: if mypy.checker.is_unreachable_map(true_map): diff --git a/test-data/unit/check-isinstance.test b/test-data/unit/check-isinstance.test index acd81839fcdc..c0ae4db3eddd 100644 --- a/test-data/unit/check-isinstance.test +++ b/test-data/unit/check-isinstance.test @@ -1614,6 +1614,37 @@ reveal_type(g) # N: Revealed type is "typing.Generator[builtins.int, None, None] reveal_type(d) # N: Revealed type is "builtins.dict[builtins.int, builtins.int]" [builtins fixtures/isinstancelist.pyi] +[case testComprehensionIsInstanceImpossibleIntersection] +# https://github.com/python/mypy/issues/21635 +from typing import List + +class X: + def f(self) -> int: + return 0 +class Y: + def f(self) -> str: + return '' + +xs: List[X] = [] +l: List[Y] = [x for x in xs if isinstance(x, Y)] +g = (reveal_type(x) for x in xs if isinstance(x, Y)) # N: Revealed type is "Never" +d = {0: x for x in xs if isinstance(x, Y)} +reveal_type(d) # N: Revealed type is "builtins.dict[builtins.int, Never]" +[builtins fixtures/isinstancelist.pyi] + +[case testComprehensionIsSubclassImpossibleIntersectionFinal] +# https://github.com/python/mypy/issues/21635 +from typing import List, Type +from typing_extensions import final + +@final +class F: ... +class Other: ... + +os: List[Other] = [] +fs: List[F] = [o for o in os if isinstance(o, F)] +[builtins fixtures/isinstancelist.pyi] + [case testIsinstanceInWrongOrderInBooleanOp] # flags: --warn-unreachable class A: