Skip to content

Commit dc2868e

Browse files
committed
Replace "try to extract type from the first overload" with simply using the underlying type
1 parent 5a0fa55 commit dc2868e

File tree

3 files changed

+50
-4
lines changed

3 files changed

+50
-4
lines changed

mypy/checker.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7691,9 +7691,8 @@ def get_isinstance_type(self, expr: Expression) -> list[TypeRange] | None:
76917691
types: list[TypeRange] = []
76927692
for typ in all_types:
76937693
if isinstance(typ, FunctionLike) and typ.is_type_obj():
7694-
# Type variables may be present -- erase them, which is the best
7695-
# we can do (outside disallowing them here).
7696-
erased_type = erase_typevars(typ.items[0].ret_type)
7694+
# If a type is generic, `isinstance` can only narrow its variables to Any.
7695+
erased_type = fill_typevars_with_any(typ.type_object())
76977696
types.append(TypeRange(erased_type, is_upper_bound=False))
76987697
elif isinstance(typ, TypeType):
76997698
# Type[A] means "any type that is a subtype of A" rather than "precisely type A"

test-data/unit/check-narrowing.test

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2463,3 +2463,50 @@ def test(x: T) -> T:
24632463
reveal_type(x.x) # N: Revealed type is "builtins.str"
24642464
return x
24652465
[builtins fixtures/isinstance.pyi]
2466+
2467+
[case testIsinstanceNarrowingWithSelfTypes]
2468+
from typing import Generic, TypeVar, overload
2469+
2470+
T = TypeVar("T")
2471+
2472+
class A(Generic[T]):
2473+
def __init__(self: A[int]) -> None:
2474+
pass
2475+
2476+
def check_a(obj: "A[T] | str") -> None:
2477+
reveal_type(obj) # N: Revealed type is "Union[__main__.A[T`-1], builtins.str]"
2478+
if isinstance(obj, A):
2479+
reveal_type(obj) # N: Revealed type is "__main__.A[T`-1]"
2480+
else:
2481+
reveal_type(obj) # N: Revealed type is "builtins.str"
2482+
2483+
class B(Generic[T]):
2484+
@overload
2485+
def __init__(self, x: T) -> None: ...
2486+
@overload
2487+
def __init__(self: B[int]) -> None: ...
2488+
def __init__(self, x: "T | None" = None) -> None:
2489+
pass
2490+
2491+
def check_b(obj: "B[T] | str") -> None:
2492+
reveal_type(obj) # N: Revealed type is "Union[__main__.B[T`-1], builtins.str]"
2493+
if isinstance(obj, B):
2494+
reveal_type(obj) # N: Revealed type is "__main__.B[T`-1]"
2495+
else:
2496+
reveal_type(obj) # N: Revealed type is "builtins.str"
2497+
2498+
class C(Generic[T]):
2499+
@overload
2500+
def __init__(self: C[int]) -> None: ...
2501+
@overload
2502+
def __init__(self, x: T) -> None: ...
2503+
def __init__(self, x: "T | None" = None) -> None:
2504+
pass
2505+
2506+
def check_c(obj: "C[T] | str") -> None:
2507+
reveal_type(obj) # N: Revealed type is "Union[__main__.C[T`-1], builtins.str]"
2508+
if isinstance(obj, C):
2509+
reveal_type(obj) # N: Revealed type is "__main__.C[T`-1]"
2510+
else:
2511+
reveal_type(obj) # N: Revealed type is "builtins.str"
2512+
[builtins fixtures/isinstance.pyi]

test-data/unit/check-typeddict.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -810,7 +810,7 @@ from typing import TypedDict
810810
D = TypedDict('D', {'x': int})
811811
d: object
812812
if isinstance(d, D): # E: Cannot use isinstance() with TypedDict type
813-
reveal_type(d) # N: Revealed type is "TypedDict('__main__.D', {'x': builtins.int})"
813+
reveal_type(d) # N: Revealed type is "__main__.D"
814814
issubclass(object, D) # E: Cannot use issubclass() with TypedDict type
815815
[builtins fixtures/isinstancelist.pyi]
816816
[typing fixtures/typing-typeddict.pyi]

0 commit comments

Comments
 (0)