Skip to content

Commit 4c8b224

Browse files
committed
Fix TypeIs narrowing before isinstance
1 parent 0cd1541 commit 4c8b224

2 files changed

Lines changed: 34 additions & 3 deletions

File tree

mypy/checker.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6591,11 +6591,23 @@ def find_isinstance_check_helper(
65916591
if len(node.args) != 2: # the error will be reported elsewhere
65926592
return {}, {}
65936593
if literal(expr) == LITERAL_TYPE:
6594+
original_type = self.lookup_type(expr)
6595+
current_type = self.expr_checker.narrow_type_from_binder(
6596+
expr, original_type
6597+
)
6598+
yes_type, no_type = self.conditional_types_with_intersection(
6599+
current_type, self.get_isinstance_type(node.args[1]), expr
6600+
)
6601+
if (
6602+
self.binder.get(expr) is not None
6603+
and yes_type is not None
6604+
and is_subtype(current_type, yes_type, ignore_promotions=True)
6605+
):
6606+
yes_type = current_type
65946607
return conditional_types_to_typemaps(
65956608
expr,
6596-
*self.conditional_types_with_intersection(
6597-
self.lookup_type(expr), self.get_isinstance_type(node.args[1]), expr
6598-
),
6609+
yes_type,
6610+
no_type,
65996611
)
66006612
elif refers_to_fullname(node.callee, "builtins.issubclass"):
66016613
if len(node.args) != 2: # the error will be reported elsewhere

test-data/unit/check-typeis.test

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,25 @@ def main(a: Union[Point, Line, int]) -> None:
2626

2727
[builtins fixtures/tuple.pyi]
2828

29+
[case testTypeIsAndIsinstanceWithGenericAlias]
30+
from typing import Any, Generic, TypeVar
31+
from typing_extensions import TypeAlias, TypeIs
32+
33+
T = TypeVar("T")
34+
class Slice(Generic[T]): pass
35+
36+
SliceInt: TypeAlias = Slice[int | None]
37+
SliceStr: TypeAlias = Slice[str | None]
38+
39+
def is_slice_int(obj: Any) -> TypeIs[SliceInt]: pass
40+
41+
def main(obj: SliceInt | SliceStr) -> None:
42+
if is_slice_int(obj):
43+
pass
44+
elif isinstance(obj, Slice):
45+
reveal_type(obj) # N: Revealed type is "__main__.Slice[builtins.str | None]"
46+
[builtins fixtures/isinstance.pyi]
47+
2948
[case testTypeIsTypeArgsNone]
3049
from typing_extensions import TypeIs
3150
def foo(a: object) -> TypeIs: # E: TypeIs must have exactly one type argument

0 commit comments

Comments
 (0)