| [case testForcedAssignment] | |
| # flags: --warn-unreachable | |
| x = 1 # type: object | |
| y = 1 | |
| def f(): x, y # Prevent independent redefinition | |
| y = x # E: Incompatible types in assignment (expression has type "object", variable has type "int") | |
| x = 2 | |
| y = x | |
| [builtins fixtures/tuple.pyi] | |
| [case testJoinAny] | |
| # flags: --warn-unreachable | |
| from typing import List, Any | |
| x: List[Any] | |
| def foo() -> List[int]: pass | |
| def bar() -> List[str]: pass | |
| if bool(): | |
| x = foo() | |
| else: | |
| x = bar() | |
| x * 2 | |
| [builtins fixtures/list.pyi] | |
| [case testGeneratorExpressionTypes] | |
| # flags: --warn-unreachable | |
| class A: y = 1 | |
| x = [A()] | |
| y = [x] | |
| z = [1,2] | |
| z = [a.y for b in y for a in b] | |
| [builtins fixtures/list.pyi] | |
| [case testIsinstanceNestedTuple] | |
| # flags: --warn-unreachable | |
| from typing import Union, List, Tuple, Dict | |
| def f(x: Union[int, str, List]) -> None: | |
| if isinstance(x, (str, (int,))): | |
| reveal_type(x) # N: Revealed type is "builtins.int | builtins.str" | |
| x[1] # E: Value of type "int | str" is not indexable | |
| else: | |
| reveal_type(x) # N: Revealed type is "builtins.list[Any]" | |
| x[1] | |
| reveal_type(x) # N: Revealed type is "builtins.int | builtins.str | builtins.list[Any]" | |
| if isinstance(x, (str, (list,))): | |
| reveal_type(x) # N: Revealed type is "builtins.str | builtins.list[Any]" | |
| x[1] | |
| reveal_type(x) # N: Revealed type is "builtins.int | builtins.str | builtins.list[Any]" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsinstanceNarrowsSequenceParentFromElement] | |
| # flags: --warn-unreachable | |
| from __future__ import annotations | |
| def f1(x: list[str] | list[int]) -> None: | |
| if isinstance(x[0], str): | |
| reveal_type(x) # N: Revealed type is "builtins.list[builtins.str]" | |
| reveal_type(x[0]) # N: Revealed type is "builtins.str" | |
| else: | |
| reveal_type(x) # N: Revealed type is "builtins.list[builtins.int]" | |
| reveal_type(x[0]) # N: Revealed type is "builtins.int" | |
| def f2(x: tuple[str, ...] | tuple[int, ...]) -> None: | |
| if isinstance(x[0], str): | |
| reveal_type(x) # N: Revealed type is "builtins.tuple[builtins.str, ...]" | |
| reveal_type(x[0]) # N: Revealed type is "builtins.str" | |
| else: | |
| reveal_type(x) # N: Revealed type is "builtins.tuple[builtins.int, ...]" | |
| reveal_type(x[0]) # N: Revealed type is "builtins.int" | |
| def f3(x: tuple[str, str] | tuple[int, int]) -> None: | |
| if isinstance(x[0], str): | |
| reveal_type(x) # N: Revealed type is "tuple[builtins.str, builtins.str]" | |
| else: | |
| reveal_type(x) # N: Revealed type is "tuple[builtins.int, builtins.int]" | |
| class A: ... | |
| class B: ... | |
| class C(A, B): ... | |
| def f4(x: list[A] | list[B]): | |
| # Technically this is unsound in the presence of multiple inheritance, | |
| # but we already do this kind of narrowing for tuples | |
| if isinstance(x[0], A): | |
| reveal_type(x) # N: Revealed type is "builtins.list[__main__.A]" | |
| else: | |
| reveal_type(x) # N: Revealed type is "builtins.list[__main__.B]" | |
| def f5(x: tuple[A, ...] | tuple[B, ...]): | |
| if isinstance(x[0], A): | |
| reveal_type(x) # N: Revealed type is "builtins.tuple[__main__.A, ...]" | |
| else: | |
| reveal_type(x) # N: Revealed type is "builtins.tuple[__main__.B, ...]" | |
| def f6(x: tuple[A, A] | tuple[B, B]): | |
| if isinstance(x[0], A): | |
| reveal_type(x) # N: Revealed type is "tuple[__main__.A, __main__.A]" | |
| else: | |
| reveal_type(x) # N: Revealed type is "tuple[__main__.B, __main__.B]" | |
| class AA(A): ... | |
| def f7(x: list[A] | list[AA]): | |
| if isinstance(x[0], AA): | |
| reveal_type(x) # N: Revealed type is "builtins.list[__main__.A] | builtins.list[__main__.AA]" | |
| else: | |
| reveal_type(x) # N: Revealed type is "builtins.list[__main__.A] | builtins.list[__main__.AA]" | |
| def f8(x: list[str] | list[str | None]): | |
| if x[0] is not None: | |
| reveal_type(x) # N: Revealed type is "builtins.list[builtins.str] | builtins.list[builtins.str | None]" | |
| else: | |
| reveal_type(x) # N: Revealed type is "builtins.list[builtins.str | None]" | |
| [builtins fixtures/tuple.pyi] | |
| [case testClassAttributeInitialization] | |
| # flags: --warn-unreachable | |
| class A: | |
| x: int | |
| def __init__(self) -> None: | |
| self.y: int | |
| z = self.x | |
| w = self.y | |
| [case testAssignmentSubtypes] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| def foo(x: Union[str, int]): | |
| if isinstance(x, int): | |
| x = 'a' | |
| x + 'a' | |
| z = x | |
| y = [x] | |
| y[0] + 'a' | |
| # TODO: should we allow these two lines? | |
| y + [1] # E: List item 0 has incompatible type "int"; expected "str" | |
| z = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "str") | |
| x: int | |
| y = [x] | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testFunctionDefaultArgs] | |
| # flags: --warn-unreachable | |
| class A: pass | |
| class B(A): y = 1 | |
| x = A() | |
| def foo(x: A = B()): | |
| x.y # E: "A" has no attribute "y" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsinstanceFancyConditionals] | |
| # flags: --warn-unreachable | |
| class A: pass | |
| class B(A): | |
| y = 1 | |
| x = A() | |
| if isinstance(x, B): | |
| x.y | |
| while isinstance(x, B): | |
| x.y | |
| while isinstance(x, B): | |
| x.y | |
| x = B() | |
| [builtins fixtures/isinstance.pyi] | |
| [case testSubtypingWithAny] | |
| # flags: --warn-unreachable | |
| class A: | |
| y = 1 | |
| class B(A): | |
| z = 1 | |
| def foo(): pass | |
| x = A() | |
| if int(): | |
| x = B() | |
| x.z | |
| x = foo() | |
| reveal_type(x) # N: Revealed type is "Any" | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| [case testSingleMultiAssignment] | |
| # flags: --warn-unreachable | |
| x = 'a' | |
| (x,) = ('a',) | |
| [case testUnionMultiAssignment] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| x: Union[int, str] | |
| if int(): | |
| x = 1 | |
| x = 'a' | |
| x + 1 # E: Unsupported operand types for + ("str" and "int") | |
| x = 1 | |
| (x, y) = ('a', 1) | |
| x + 1 # E: Unsupported operand types for + ("str" and "int") | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testUnionIfZigzag] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| def f(x: Union[int, str]) -> None: | |
| if 1: # Without this, the assignment below could create a new variable "x" of type "int" | |
| x = 1 | |
| if x: | |
| x = 'a' | |
| x = 1 | |
| x + 1 | |
| x + 1 | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testTwoLoopsUnion] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| def foo() -> Union[int, str]: pass | |
| def bar() -> None: | |
| x = foo() | |
| if isinstance(x, int): | |
| return | |
| while bool(): | |
| x + 'a' | |
| while bool(): | |
| x = foo() | |
| if bool(): | |
| return | |
| x = 'a' | |
| x + 'a' | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testComplicatedBlocks] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| def foo() -> Union[int, str]: pass | |
| def bar() -> None: | |
| x = foo() | |
| if isinstance(x, int): | |
| return | |
| while bool(): | |
| x + 'a' | |
| while bool(): | |
| x = foo() | |
| if bool(): | |
| return | |
| x = 'a' | |
| x + 'a' | |
| x = foo() | |
| if isinstance(x, int): | |
| return | |
| while bool(): | |
| x + 'a' | |
| while bool(): | |
| x + 'a' # E: Unsupported operand types for + ("int" and "str") \ | |
| # N: Left operand is of type "int | str" | |
| x = foo() | |
| if bool(): | |
| continue | |
| x = 'a' | |
| x = 'a' | |
| x + 'a' | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testUnionTryExcept] | |
| # flags: --warn-unreachable | |
| class A: | |
| y = A() | |
| class B(A): | |
| z = 1 | |
| x = A() | |
| def f(): x # Prevent redefinition of x | |
| x = B() | |
| x.z | |
| try: | |
| x.z | |
| x = A() | |
| x = B() | |
| x.z | |
| except: | |
| pass | |
| x.z # E: "A" has no attribute "z" | |
| [case testUnionTryExcept2] | |
| # flags: --warn-unreachable | |
| class A: | |
| y = A() | |
| class B(A): | |
| z = 1 | |
| x = A() | |
| try: | |
| x.z # E: "A" has no attribute "z" | |
| x = A() | |
| x = B() | |
| x.z | |
| except: | |
| x.z # E: "A" has no attribute "z" | |
| x = B() | |
| x.z | |
| else: | |
| x = B() | |
| x.z | |
| [case testUnionTryExcept3] | |
| # flags: --warn-unreachable | |
| class A: | |
| y = A() | |
| class B(A): | |
| z = 1 | |
| x = A() | |
| def f(): x # Prevent redefinition of x | |
| x = B() | |
| try: | |
| raise BaseException() | |
| x = A() # E: Statement is unreachable | |
| except: | |
| pass | |
| x.z | |
| x = B() | |
| try: | |
| x = A() | |
| raise BaseException() | |
| except: | |
| pass | |
| x.z # E: "A" has no attribute "z" | |
| x = B() | |
| try: | |
| pass | |
| except: | |
| x = A() | |
| raise BaseException() | |
| x.z | |
| try: | |
| x = A() | |
| except: | |
| pass | |
| x.z # E: "A" has no attribute "z" | |
| x = B() | |
| try: | |
| pass | |
| except: | |
| x = A() | |
| x.z # E: "A" has no attribute "z" | |
| [builtins fixtures/exception.pyi] | |
| [case testUnionTryExcept4] | |
| # flags: --warn-unreachable | |
| class A: pass | |
| class B(A): | |
| z = 1 | |
| x = A() | |
| while bool(): | |
| try: | |
| x.z # E: "A" has no attribute "z" | |
| x = A() | |
| except: | |
| x = B() | |
| else: | |
| x = B() | |
| x.z | |
| [builtins fixtures/exception.pyi] | |
| [case testUnionTryFinally] | |
| # flags: --warn-unreachable | |
| class A: pass | |
| class B(A): | |
| b = 1 | |
| x = A() | |
| def f(): x # Prevent redefinition | |
| x = B() | |
| try: | |
| x = A() | |
| x.b # E: "A" has no attribute "b" | |
| x = B() | |
| finally: | |
| x.b # E: "A" has no attribute "b" | |
| x.b | |
| [case testUnionTryFinally2] | |
| # flags: --warn-unreachable | |
| class A: pass | |
| class B(A): | |
| b = 1 | |
| x = A() | |
| def f(): x # Prevent redefinition | |
| x = B() | |
| try: | |
| x = A() | |
| x = B() | |
| except: | |
| pass | |
| finally: | |
| pass | |
| x.b # E: "A" has no attribute "b" | |
| [case testUnionTryFinally3] | |
| # flags: --warn-unreachable | |
| class A: pass | |
| class B(A): | |
| b = 1 | |
| x = A() | |
| def f(): x # Prevent redefinition | |
| x = B() | |
| try: | |
| x = A() | |
| x = B() | |
| except: | |
| pass | |
| finally: | |
| x = B() | |
| x.b | |
| [case testUnionTryFinally4] | |
| # flags: --warn-unreachable | |
| class A: pass | |
| class B(A): | |
| b = 1 | |
| while 2: | |
| x = A() | |
| def f(): x # Prevents redefinition | |
| x = B() | |
| try: | |
| x = A() | |
| x = B() | |
| except: | |
| pass | |
| finally: | |
| x.b # E: "A" has no attribute "b" | |
| if not isinstance(x, B): | |
| break | |
| x.b | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testUnionTryFinally5] | |
| # flags: --warn-unreachable | |
| class A: pass | |
| class B(A): | |
| b = 1 | |
| while 2: | |
| x = A() | |
| try: | |
| x = A() | |
| x = B() | |
| finally: | |
| x.b # E: "A" has no attribute "b" | |
| break | |
| x.b # E: Statement is unreachable | |
| x.b # E: Statement is unreachable | |
| [case testUnionTryFinally6] | |
| # flags: --warn-unreachable | |
| class A: pass | |
| class B(A): | |
| b = 1 | |
| def f() -> int: | |
| x = B() # type: A | |
| try: | |
| x = B() | |
| except: | |
| x = A() | |
| # An exception could occur here | |
| x = B() | |
| finally: | |
| return x.b # E: "A" has no attribute "b" | |
| [case testUnionListIsinstance] | |
| # flags: --warn-unreachable | |
| from typing import Union, List | |
| def f(x: Union[List[int], List[str], int]) -> None: | |
| if isinstance(x, list): | |
| a = x[0] | |
| if isinstance(a, int): | |
| a + 1 | |
| a + 'x' # E: Unsupported operand types for + ("int" and "str") | |
| # type of a? | |
| reveal_type(x) # N: Revealed type is "builtins.list[builtins.int] | builtins.list[builtins.str]" | |
| x + 1 # E: Unsupported operand types for + ("list[int]" and "int") \ | |
| # E: Unsupported operand types for + ("list[str]" and "int") \ | |
| # N: Left operand is of type "list[int] | list[str]" | |
| else: | |
| x[0] # E: Value of type "int" is not indexable | |
| x + 1 | |
| x[0] # E: Value of type "list[int] | list[str] | int" is not indexable | |
| x + 1 # E: Unsupported operand types for + ("list[int]" and "int") \ | |
| # E: Unsupported operand types for + ("list[str]" and "int") \ | |
| # N: Left operand is of type "list[int] | list[str] | int" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testUnionListIsinstance2] | |
| # flags: --warn-unreachable | |
| from typing import Union, List | |
| class A: | |
| a = 1 | |
| class B: pass | |
| class C: pass | |
| def g(x: Union[A, B]) -> A: pass | |
| def h(x: C) -> A: pass | |
| def f(x: Union[A, B, C]) -> None: | |
| if isinstance(x, C): | |
| x = h(x) | |
| else: | |
| x = g(x) | |
| x.a | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testUnionStrictDefnBasic] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| def foo() -> Union[int, str]: pass | |
| x = foo() | |
| if int(): | |
| x = 1 | |
| x = x + 1 | |
| x = foo() | |
| x = x + 1 # E: Unsupported operand types for + ("str" and "int") \ | |
| # N: Left operand is of type "int | str" | |
| if isinstance(x, str): | |
| x = x + 1 # E: Unsupported operand types for + ("str" and "int") | |
| x = 1 | |
| x = x + 1 | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testSubtypeRedefinitionBasic] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| class A: pass | |
| class B(A): | |
| y = 1 | |
| x = A() | |
| x.y # E: "A" has no attribute "y" | |
| x = B() | |
| x.y # OK: x is known to be a B | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsInstanceBasic] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| x: Union[int, str] | |
| if isinstance(x, str): | |
| x = x + 1 # E: Unsupported operand types for + ("str" and "int") | |
| x = x + 'a' | |
| else: | |
| x = x + 'a' # E: Unsupported operand types for + ("int" and "str") | |
| x = x + 1 | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsInstanceIndexing] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| x: Union[int, str] | |
| j = [x] | |
| if isinstance(j[0], str): | |
| j[0] = j[0] + 'a' | |
| j[0] = j[0] + 1 # E: Unsupported operand types for + ("str" and "int") | |
| else: | |
| j[0] = j[0] + 'a' # E: Unsupported operand types for + ("int" and "str") | |
| j[0] = j[0] + 1 | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsInstanceSubClassMember] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| class Animal: pass | |
| class Dog(Animal): | |
| paws = 4 # type: Union[int, str] | |
| def bark(self): pass | |
| class House: | |
| pet: Animal | |
| h = House() | |
| h.pet = Dog() | |
| while bool(): | |
| if isinstance(h.pet, Dog): | |
| if isinstance(h.pet.paws, str): | |
| x = h.pet.paws + 'a' | |
| y = h.pet.paws + 1 # E: Unsupported operand types for + ("str" and "int") \ | |
| # N: Left operand is of type "int | str" | |
| z = h.pet.paws + 'a' # E: Unsupported operand types for + ("int" and "str") \ | |
| # N: Left operand is of type "int | str" | |
| if isinstance(h.pet.paws, str): | |
| x = h.pet.paws + 'a' | |
| break | |
| y = h.pet.paws + 1 | |
| z = h.pet.paws + 'a' # E: Unsupported operand types for + ("int" and "str") | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsInstanceSubClassReset] | |
| # flags: --warn-unreachable | |
| class A: | |
| pass | |
| class B(A): | |
| b = 1 | |
| class C: | |
| a = A() | |
| x = C() | |
| x.a.b # E: "A" has no attribute "b" | |
| if isinstance(x.a, B): | |
| x.a.b | |
| x = C() | |
| x.a.b # E: "A" has no attribute "b" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsinstanceTuple] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| class A: pass | |
| class B: | |
| def method2(self, arg: int): | |
| return 123 | |
| class C: | |
| def method2(self, arg: int): | |
| return 456 | |
| def method3(self, arg: str): | |
| return 'abc' | |
| v = A() # type: Union[A, B, C] | |
| if isinstance(v, (B, C)): | |
| v.method2(123) | |
| v.method3('xyz') # E: Item "B" of "B | C" has no attribute "method3" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsinstanceNeverWidens] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| class A: pass | |
| class B: pass | |
| class C: pass | |
| a = A() # type: A | |
| assert isinstance(a, (A, B)) | |
| reveal_type(a) # N: Revealed type is "__main__.A" | |
| b = A() # type: Union[A, B] | |
| assert isinstance(b, (A, B, C)) | |
| reveal_type(b) # N: Revealed type is "__main__.A | __main__.B" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testMemberAssignmentChanges] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| class Dog: | |
| paws = 1 # type: Union[int, str] | |
| pet = Dog() | |
| pet.paws + 'a' # E: Unsupported operand types for + ("int" and "str") \ | |
| # N: Left operand is of type "int | str" | |
| pet.paws = 'a' | |
| pet.paws + 'a' | |
| pet.paws = 1 | |
| pet.paws + 1 | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsInstanceSubClassMemberHard] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| class Animal: | |
| pass | |
| class Dog(Animal): | |
| paws = 4 # type: Union[int, str] | |
| def bark(self): pass | |
| class House: | |
| pet: Animal | |
| h = House() | |
| h.pet = Dog() | |
| if isinstance(h.pet, Dog): | |
| if isinstance(h.pet.paws, str): | |
| for i in [1]: | |
| # TODO: should we allow this if iterable is of length one or zero? | |
| h.pet.paws + 'a' # E: Unsupported operand types for + ("int" and "str") \ | |
| # N: Left operand is of type "int | str" | |
| if bool(): | |
| break | |
| h.pet.paws = 1 | |
| h.pet.paws + 1 | |
| if isinstance(h.pet.paws, str): | |
| h.pet.paws + 'a' | |
| else: | |
| h.pet.paws + 1 | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsInstanceReturn] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| def foo() -> None: | |
| x = 1 # type: Union[int, str] | |
| if isinstance(x, int): | |
| return | |
| y = x + 'asdad' | |
| def bar() -> None: | |
| x = 1 # type: Union[int, str] | |
| if isinstance(x, int): | |
| return | |
| else: | |
| pass | |
| y = x + 'asdad' | |
| foo() | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsInstanceBadBreak] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| def foo() -> None: | |
| x: Union[int, str] | |
| if isinstance(x, int): | |
| for z in [1,2]: | |
| break | |
| else: | |
| pass | |
| y = x + 'asdad' # E: Unsupported operand types for + ("int" and "str") \ | |
| # N: Left operand is of type "int | str" | |
| foo() | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsInstanceThreeUnion] | |
| # flags: --warn-unreachable | |
| from typing import Union, List | |
| x: Union[int, str, List[int]] | |
| while bool(): | |
| if isinstance(x, int): | |
| x + 1 | |
| elif isinstance(x, str): | |
| x + 'a' | |
| else: | |
| x + [1] | |
| x + 'a' # E: Unsupported operand types for + ("int" and "str") \ | |
| # E: Unsupported operand types for + ("list[int]" and "str") \ | |
| # N: Left operand is of type "int | str | list[int]" | |
| x + [1] # E: Unsupported operand types for + ("int" and "list[int]") \ | |
| # E: Unsupported operand types for + ("str" and "list[int]") \ | |
| # N: Left operand is of type "int | str | list[int]" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsInstanceThreeUnion2] | |
| # flags: --warn-unreachable | |
| from typing import Union, List | |
| x: Union[int, str, List[int]] | |
| while bool(): | |
| if isinstance(x, int): | |
| x + 1 | |
| break | |
| elif isinstance(x, str): | |
| x + 'a' | |
| break | |
| x + [1] | |
| x + 'a' # E: Unsupported operand types for + ("list[int]" and "str") | |
| x + [1] # E: Unsupported operand types for + ("int" and "list[int]") \ | |
| # E: Unsupported operand types for + ("str" and "list[int]") \ | |
| # N: Left operand is of type "int | str | list[int]" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsInstanceThreeUnion3] | |
| # flags: --warn-unreachable | |
| from typing import Union, List | |
| while bool(): | |
| x: Union[int, str, List[int]] | |
| def f(): x # Prevent redefinition | |
| x = 1 | |
| if isinstance(x, int): | |
| x + 1 | |
| break | |
| elif isinstance(x, str): # E: Statement is unreachable | |
| x + 'a' | |
| break | |
| x + [1] # These lines aren't reached because x was an int # E: Statement is unreachable | |
| x + 'a' | |
| x + [1] # E: Unsupported operand types for + ("int" and "list[int]") \ | |
| # E: Unsupported operand types for + ("str" and "list[int]") \ | |
| # N: Left operand is of type "int | str | list[int]" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testRemovingTypeRepeatedly] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| def foo() -> Union[int, str]: pass | |
| for i in [1, 2]: | |
| x = foo() | |
| x + 'a' # E: Unsupported operand types for + ("int" and "str") \ | |
| # N: Left operand is of type "int | str" | |
| if isinstance(x, int): | |
| break | |
| x + 'a' | |
| x = foo() | |
| x + 'a' # E: Unsupported operand types for + ("int" and "str") \ | |
| # N: Left operand is of type "int | str" | |
| if isinstance(x, int): | |
| break | |
| x + 'a' | |
| x = foo() | |
| x + 'a' # E: Unsupported operand types for + ("int" and "str") \ | |
| # N: Left operand is of type "int | str" | |
| if isinstance(x, int): | |
| break | |
| x + 'a' | |
| x + 'a' # E: Unsupported operand types for + ("int" and "str") \ | |
| # N: Left operand is of type "int | str" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testModifyRepeatedly] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| def foo() -> Union[int, str]: pass | |
| x = foo() | |
| def f(): x # Prevent redefinition | |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ | |
| # N: Left operand is of type "int | str" | |
| x + 'a' # E: Unsupported operand types for + ("int" and "str") \ | |
| # N: Left operand is of type "int | str" | |
| x = 1 | |
| x + 1 | |
| x + 'a' # E: Unsupported operand types for + ("int" and "str") | |
| x = 'a' | |
| x + 1 # E: Unsupported operand types for + ("str" and "int") | |
| x + 'a' | |
| x = foo() | |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ | |
| # N: Left operand is of type "int | str" | |
| x + 'a' # E: Unsupported operand types for + ("int" and "str") \ | |
| # N: Left operand is of type "int | str" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testModifyLoop] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| def foo() -> Union[int, str]: pass | |
| x = foo() | |
| def f(): x # Prevent redefinition | |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ | |
| # N: Left operand is of type "int | str" | |
| x = 'a' | |
| x + 1 # E: Unsupported operand types for + ("str" and "int") | |
| x = 1 | |
| x + 1 | |
| while bool(): | |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ | |
| # N: Left operand is of type "int | str" | |
| x = 'a' | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testModifyLoop2] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| def foo() -> Union[int, str]: pass | |
| x = foo() | |
| def f(): x # Prevent redefinition | |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ | |
| # N: Left operand is of type "int | str" | |
| x = 'a' | |
| x + 1 # E: Unsupported operand types for + ("str" and "int") | |
| x = 1 | |
| x + 1 | |
| for i in [1]: | |
| x = 'a' | |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ | |
| # N: Left operand is of type "int | str" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testModifyLoop3] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| def foo() -> Union[int, str]: pass | |
| x = foo() | |
| def f(): x # Prevent redefinition | |
| x = 1 | |
| while bool(): | |
| x + 1 | |
| x = 'a' | |
| break | |
| else: | |
| x + 1 | |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ | |
| # N: Left operand is of type "int | str" | |
| x = 1 | |
| for y in [1]: | |
| x + 1 | |
| x = 'a' | |
| break | |
| else: | |
| x + 1 | |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ | |
| # N: Left operand is of type "int | str" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testModifyLoopWhile4] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| def foo() -> Union[int, str]: pass | |
| x = foo() | |
| def f(): x # Prevent redefinition | |
| x = 1 | |
| while bool(): | |
| x + 1 | |
| if bool(): | |
| x = 'a' | |
| break | |
| else: | |
| x + 1 | |
| x = 'a' | |
| x + 'a' | |
| x = 1 | |
| while bool(): | |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ | |
| # N: Left operand is of type "int | str" | |
| if bool(): | |
| x = 'a' | |
| continue | |
| else: | |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ | |
| # N: Left operand is of type "int | str" | |
| x = 'a' | |
| x + 'a' | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testModifyLoopFor4] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| def foo() -> Union[int, str]: pass | |
| x = foo() | |
| def f(): x # Prevent redefinition | |
| x = 1 | |
| for y in [1]: | |
| x + 1 | |
| if bool(): | |
| x = 'a' | |
| break | |
| else: | |
| x + 1 | |
| x = 'a' | |
| x + 'a' | |
| x = 1 | |
| for y in [1]: | |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ | |
| # N: Left operand is of type "int | str" | |
| if bool(): | |
| x = 'a' | |
| continue | |
| else: | |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ | |
| # N: Left operand is of type "int | str" | |
| x = 'a' | |
| x + 'a' | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testModifyNestedLoop] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| def foo() -> Union[int, str]: pass | |
| x = foo() | |
| def f(): x # Prevent redefinition | |
| x = 1 | |
| for y in [1]: | |
| for z in [1]: | |
| break | |
| else: | |
| x = 'a' | |
| break | |
| else: | |
| x + 1 | |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ | |
| # N: Left operand is of type "int | str" | |
| x = 1 | |
| while bool(): | |
| while bool(): | |
| break | |
| else: | |
| x = 'a' | |
| break | |
| else: | |
| x + 1 | |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ | |
| # N: Left operand is of type "int | str" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testModifyLoopLong] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| class A: a = 1 | |
| def foo() -> Union[int, str, A]: pass | |
| def bar() -> None: | |
| x = foo() | |
| x + 1 # E: Unsupported left operand type for + ("A") \ | |
| # N: Left operand is of type "int | str | A" \ | |
| # E: Unsupported operand types for + ("str" and "int") | |
| if isinstance(x, A): | |
| x.a | |
| else: | |
| if isinstance(x, int): | |
| x + 1 | |
| x + 'a' # E: Unsupported operand types for + ("int" and "str") | |
| else: | |
| x + 'a' | |
| x.a # E: "str" has no attribute "a" | |
| x = A() | |
| if isinstance(x, str): | |
| x + 'a' | |
| else: | |
| while bool(): | |
| if isinstance(x, int): | |
| x + 1 | |
| else: | |
| x.a | |
| break | |
| while bool(): | |
| if isinstance(x, int): | |
| x + 1 | |
| else: | |
| x.a | |
| continue | |
| while bool(): | |
| if isinstance(x, int): | |
| x + 1 | |
| else: | |
| x.a # E: Item "str" of "str | A" has no attribute "a" | |
| x = 'a' | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testWhileExitCondition1] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| x = 1 # type: Union[int, str] | |
| while isinstance(x, int): | |
| if bool(): | |
| continue | |
| x = 'a' | |
| else: | |
| reveal_type(x) # N: Revealed type is "builtins.str" | |
| reveal_type(x) # N: Revealed type is "builtins.str" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testWhileExitCondition2] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| x = 1 # type: Union[int, str] | |
| while isinstance(x, int): | |
| if bool(): | |
| break | |
| x = 'a' | |
| else: | |
| reveal_type(x) # N: Revealed type is "builtins.str" | |
| reveal_type(x) # N: Revealed type is "builtins.int | builtins.str" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testWhileLinkedList] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| LinkedList = Union['Cons', 'Nil'] | |
| class Nil: pass | |
| class Cons: | |
| tail: LinkedList | |
| def last(x: LinkedList) -> Nil: | |
| while isinstance(x, Cons): | |
| x = x.tail | |
| return x | |
| [builtins fixtures/isinstance.pyi] | |
| [case testReturnAndFlow] | |
| # flags: --warn-unreachable | |
| def foo() -> int: | |
| return 1 and 2 | |
| return 'a' # E: Statement is unreachable | |
| [case testCastIsinstance] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| def foo() -> Union[int, str]: pass | |
| x = foo() | |
| y = 1 # type: int | |
| if isinstance(x, str): | |
| x = y | |
| x + 1 | |
| x + 'a' # E: Unsupported operand types for + ("int" and "str") | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testUnreachableCode] | |
| # flags: --warn-unreachable | |
| x = 1 # type: int | |
| while bool(): | |
| x = 'a' # E: Incompatible types in assignment (expression has type "str", variable has type "int") | |
| break | |
| x = 'a' # Note: no error because unreachable code # E: Statement is unreachable | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testUnreachableCode2] | |
| # flags: --warn-unreachable | |
| x = 1 | |
| while bool(): | |
| try: | |
| pass | |
| except: | |
| continue | |
| else: | |
| continue | |
| x + 'a' # E: Statement is unreachable | |
| [builtins fixtures/isinstance.pyi] | |
| [case testUnreachableWhileTrue] | |
| # flags: --warn-unreachable | |
| def f(x: int) -> None: | |
| while True: | |
| if x: | |
| return | |
| 1() # E: Statement is unreachable | |
| [builtins fixtures/bool.pyi] | |
| [case testUnreachableAssertFalse] | |
| # flags: --warn-unreachable | |
| def f() -> None: | |
| assert False | |
| 1() # E: Statement is unreachable | |
| [builtins fixtures/bool.pyi] | |
| [case testUnreachableAssertFalse2] | |
| # flags: --warn-unreachable | |
| def f() -> None: | |
| # The old parser doesn't understand the syntax below | |
| assert False, "hi" | |
| 1() # E: Statement is unreachable | |
| [builtins fixtures/bool.pyi] | |
| [case testUnreachableReturnOrAssertFalse] | |
| # flags: --warn-unreachable | |
| def f(x: int) -> int: | |
| if x: | |
| return x | |
| else: | |
| assert False | |
| 1() # E: Statement is unreachable | |
| [builtins fixtures/bool.pyi] | |
| [case testUnreachableTryExcept] | |
| # flags: --warn-unreachable | |
| def f() -> None: | |
| try: | |
| f() | |
| return | |
| except BaseException: | |
| return | |
| 1() # E: Statement is unreachable | |
| [builtins fixtures/exception.pyi] | |
| [case testUnreachableTryExceptElse] | |
| # flags: --warn-unreachable | |
| def f() -> None: | |
| try: | |
| f() | |
| except BaseException: | |
| return | |
| else: | |
| return | |
| 1() # E: Statement is unreachable | |
| [builtins fixtures/exception.pyi] | |
| [case testUnreachableTryReturnFinally1] | |
| # flags: --warn-unreachable | |
| def f() -> None: | |
| try: | |
| return | |
| finally: | |
| pass | |
| 1() # E: Statement is unreachable | |
| [case testUnreachableTryReturnFinally2] | |
| # flags: --warn-unreachable | |
| def f() -> None: | |
| try: | |
| pass | |
| finally: | |
| return | |
| 1() # E: Statement is unreachable | |
| [case testUnreachableTryReturnExceptRaise] | |
| # flags: --warn-unreachable | |
| def f() -> None: | |
| try: | |
| return | |
| except: | |
| raise | |
| 1() # E: Statement is unreachable | |
| [case testUnreachableReturnLambda] | |
| # flags: --warn-unreachable | |
| from typing import Callable | |
| def g(t: Callable[[int], int]) -> int: pass | |
| def f() -> int: | |
| return g(lambda x: x) | |
| 1() # E: Statement is unreachable | |
| [case testIsinstanceAnd] | |
| # flags: --warn-unreachable | |
| class A: pass | |
| class B(A): | |
| flag = 1 | |
| x = B() # type: A | |
| if isinstance(x, B) and 1: | |
| x.flag | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsinstanceShortcircuit] | |
| # flags: --warn-unreachable | |
| class A: | |
| pass | |
| class B(A): | |
| flag = 1 | |
| x = B() # type: A | |
| if isinstance(x, B) and x.flag: | |
| pass | |
| if isinstance(x, B) or x.flag: # E: "A" has no attribute "flag" | |
| pass | |
| if not isinstance(x, B) or x.flag: | |
| pass | |
| if not isinstance(x, B) and x.flag: # E: "A" has no attribute "flag" | |
| pass | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsinstanceExpression] | |
| # flags: --warn-unreachable | |
| class A: | |
| pass | |
| class B(A): | |
| flag = 1 | |
| x = B() # type: A | |
| x.flag if isinstance(x, B) else 0 | |
| 0 if not isinstance(x, B) else x.flag | |
| 0 if isinstance(x, B) else x.flag # E: "A" has no attribute "flag" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsinstanceMultiAnd] | |
| # flags: --warn-unreachable | |
| class A: pass | |
| class B(A): | |
| flag = 1 | |
| class C(A): | |
| glaf = 1 | |
| x = B() # type: A | |
| y = C() # type: A | |
| if isinstance(x, B) and isinstance(y, C): | |
| x.flag += 1 | |
| y.glaf += 1 | |
| x() # E: "B" not callable | |
| y() # E: "C" not callable | |
| else: | |
| x() # E: "A" not callable | |
| y() # E: "A" not callable | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsinstanceMultiAndSpecialCase] | |
| # flags: --warn-unreachable | |
| class A: | |
| # Ensure A.__add__ and int.__add__ are different to | |
| # force 'isinstance(y, int)' checks below to never succeed. | |
| def __add__(self, other: A) -> A: pass | |
| class B(A): | |
| flag = 1 | |
| class C(A): | |
| glaf = 1 | |
| x = B() # type: A | |
| y = C() # type: A | |
| if isinstance(x, B) and isinstance(y, int): # E: Subclass of "A" and "int" cannot exist: would have incompatible method signatures | |
| 1() # E: Statement is unreachable | |
| if isinstance(y, int) and isinstance(x, B): # E: Subclass of "A" and "int" cannot exist: would have incompatible method signatures \ | |
| # E: Right operand of "and" is never evaluated | |
| 1() # E: Statement is unreachable | |
| if isinstance(y, int) and y > 42: # E: Subclass of "A" and "int" cannot exist: would have incompatible method signatures \ | |
| # E: Right operand of "and" is never evaluated | |
| 1() # E: Statement is unreachable | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testReturnWithCallExprAndIsinstance] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| def f(x: Union[int, str]) -> None: | |
| if not isinstance(x, int): | |
| return foo() | |
| x() # E: "int" not callable | |
| def foo(): pass | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsinstanceOr1] | |
| # flags: --warn-unreachable | |
| from typing import Optional | |
| def f(a: bool, x: object) -> Optional[int]: | |
| if a or not isinstance(x, int): | |
| return None | |
| reveal_type(x) # N: Revealed type is "builtins.int" | |
| return x | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsinstanceOr2] | |
| # flags: --warn-unreachable | |
| from typing import Optional | |
| def g(a: bool, x: object) -> Optional[int]: | |
| if not isinstance(x, int) or a: | |
| return None | |
| reveal_type(x) # N: Revealed type is "builtins.int" | |
| return x | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsinstanceOr3] | |
| # flags: --warn-unreachable | |
| from typing import Optional | |
| def h(a: bool, x: object) -> Optional[int]: | |
| if a or isinstance(x, int): | |
| return None | |
| return x # E: Incompatible return value type (got "object", expected "int | None") | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsinstanceWithOverlappingUnionType] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| def f(x: Union[float, int]) -> None: | |
| if isinstance(x, float): | |
| pass | |
| if not isinstance(x, int): | |
| f(x) | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsinstanceWithOverlappingUnionType2] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| class A: pass | |
| class B(A): pass | |
| def f(x: Union[A, B]) -> None: | |
| if isinstance(x, A): | |
| pass | |
| if not isinstance(x, B): | |
| f(x) | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsinstanceWithOverlappingPromotionTypes] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| def f1(x: Union[float, int]) -> None: | |
| # We ignore promotions in isinstance checks | |
| if isinstance(x, float): | |
| reveal_type(x) # N: Revealed type is "builtins.float" | |
| else: | |
| reveal_type(x) # N: Revealed type is "builtins.int" | |
| class FloatLike: pass | |
| class IntLike(FloatLike): pass | |
| def f2(x: Union[FloatLike, IntLike]) -> None: | |
| if isinstance(x, FloatLike): | |
| reveal_type(x) # N: Revealed type is "__main__.FloatLike" | |
| else: | |
| reveal_type(x) # E: Statement is unreachable | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsinstanceOfSuperclass] | |
| # flags: --warn-unreachable | |
| class A: pass | |
| class B(A): pass | |
| x = B() | |
| if isinstance(x, A): | |
| reveal_type(x) # N: Revealed type is "__main__.B" | |
| if not isinstance(x, A): | |
| reveal_type(x) # E: Statement is unreachable | |
| x = A() | |
| reveal_type(x) # N: Revealed type is "__main__.B" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsinstanceOfNonoverlapping] | |
| # flags: --warn-unreachable | |
| class A: pass | |
| class B: pass | |
| x = B() | |
| if isinstance(x, A): | |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "__main__.B" and "__main__.A">" | |
| else: | |
| reveal_type(x) # N: Revealed type is "__main__.B" | |
| reveal_type(x) # N: Revealed type is "__main__.B" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testAssertIsinstance] | |
| # flags: --warn-unreachable | |
| def f(x: object): | |
| assert isinstance(x, int) | |
| y = 0 # type: int | |
| y = x | |
| [builtins fixtures/isinstance.pyi] | |
| [case testUnionAssertIsinstance] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| def f(x: Union[str, int]): | |
| assert isinstance(x, int) | |
| y = 0 # type: int | |
| y = x | |
| [builtins fixtures/isinstance.pyi] | |
| [case testAnyAssertIsinstance] | |
| # flags: --warn-unreachable | |
| from typing import Any | |
| def f(x: Any): | |
| assert isinstance(x, int) # this should narrow x to type int | |
| x + "foo" # E: Unsupported operand types for + ("int" and "str") | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsinstanceNarrowingAny] | |
| # flags: --warn-unreachable | |
| from typing import Any | |
| class A: pass | |
| class B(A): pass | |
| def f1(x: Any) -> None: | |
| if x and isinstance(x, A): | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| if isinstance(x, A) and x: | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| def f2(x: Any) -> None: | |
| if isinstance(x, A) and not isinstance(x, B): | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| if not isinstance(x, B) and isinstance(x, A): | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsinstanceOfGenericClassRetainsParameters] | |
| # flags: --warn-unreachable | |
| from typing import List, Union | |
| def f(x: Union[List[int], str]) -> None: | |
| if isinstance(x, list): | |
| x[0]() # E: "int" not callable | |
| else: | |
| reveal_type(x) # N: Revealed type is "builtins.str" | |
| reveal_type(x) # N: Revealed type is "builtins.list[builtins.int] | builtins.str" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsinstanceOrIsinstance] | |
| # flags: --warn-unreachable | |
| class A: pass | |
| class B(A): | |
| flag = 1 | |
| class C(A): | |
| flag = 2 | |
| x1 = A() | |
| if isinstance(x1, B) or isinstance(x1, C): | |
| reveal_type(x1) # N: Revealed type is "__main__.B | __main__.C" | |
| f = x1.flag # type: int | |
| else: | |
| reveal_type(x1) # N: Revealed type is "__main__.A" | |
| f = 0 | |
| reveal_type(x1) # N: Revealed type is "__main__.A" | |
| x2 = A() | |
| if isinstance(x2, A) or isinstance(x2, C): # E: Right operand of "or" is never evaluated | |
| reveal_type(x2) # N: Revealed type is "__main__.A" | |
| f = x2.flag # E: "A" has no attribute "flag" | |
| else: | |
| 1() # E: Statement is unreachable | |
| reveal_type(x2) # N: Revealed type is "__main__.A" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testComprehensionIsInstance] | |
| # flags: --warn-unreachable | |
| from typing import List, Union | |
| a = [] # type: List[Union[int, str]] | |
| l = [x for x in a if isinstance(x, int)] | |
| g = (x for x in a if isinstance(x, int)) | |
| d = {0: x for x in a if isinstance(x, int)} | |
| reveal_type(l) # N: Revealed type is "builtins.list[builtins.int]" | |
| 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 testIsinstanceInWrongOrderInBooleanOp] | |
| # flags: --warn-unreachable | |
| class A: | |
| m = 1 | |
| def f(x: object) -> None: | |
| if x.m and isinstance(x, A) or False: # E: "object" has no attribute "m" | |
| pass | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsinstanceAndOr] | |
| # flags: --warn-unreachable | |
| class A: | |
| a: 'A' | |
| def f(x: object) -> None: | |
| b = isinstance(x, A) and x.a or A() | |
| reveal_type(b) # N: Revealed type is "__main__.A" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsInstanceWithUnknownType] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| def f(x: Union[int, str], typ: type) -> None: | |
| if isinstance(x, (typ, int)): | |
| x + 1 # E: Unsupported operand types for + ("str" and "int") \ | |
| # N: Left operand is of type "int | str" | |
| reveal_type(x) # N: Revealed type is "builtins.int | builtins.str" | |
| else: | |
| reveal_type(x) # N: Revealed type is "builtins.str" | |
| reveal_type(x) # N: Revealed type is "builtins.int | builtins.str" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsInstanceWithUnknownTypeMultipleNarrowing] | |
| # flags: --strict-equality --warn-unreachable --python-version 3.10 | |
| from __future__ import annotations | |
| from typing import Iterable | |
| from typing_extensions import TypeAlias | |
| import types | |
| # Regression test for https://github.com/python/mypy/issues/21181 | |
| # We don't have the same type context as with the real stubs, so sort of fake it | |
| _ClassInfoLike: TypeAlias = "type | tuple[_ClassInfoLike, ...]" | |
| class A: ... | |
| class B(A): ... | |
| def fake_type_context(ts: list[type[A]]) -> _ClassInfoLike: | |
| return tuple(ts) # E: Too many arguments for "tuple" | |
| def f1(x: A | None) -> None: | |
| if x is not None: | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| if isinstance(x, object): | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| def f2(x: A | None, ts: list[type[A]]) -> None: | |
| if x is not None: | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| if isinstance(x, fake_type_context(ts)): | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| def f3(x: A | None, t: type | type[A]) -> None: | |
| if x is not None: | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| if isinstance(x, t): | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| def f4(x: A | None, t: type) -> None: | |
| if x is not None: | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| if isinstance(x, t): | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| def f5(x: object | None, ta: type[A], tb: type[B]) -> None: | |
| if x is not None: | |
| reveal_type(x) # N: Revealed type is "builtins.object" | |
| if isinstance(x, ta): | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| if isinstance(x, tb): | |
| reveal_type(x) # N: Revealed type is "__main__.B" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsInstanceWithBoundedType] | |
| # flags: --warn-unreachable | |
| from typing import Union, Type | |
| class A: pass | |
| def f(x: Union[int, A], a: Type[A]) -> None: | |
| if isinstance(x, (a, int)): | |
| reveal_type(x) # N: Revealed type is "builtins.int | __main__.A" | |
| else: | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| reveal_type(x) # N: Revealed type is "builtins.int | __main__.A" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsInstanceWithEmtpy2ndArg] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| def f(x: Union[int, str]) -> None: | |
| if isinstance(x, ()): | |
| reveal_type(x) # E: Statement is unreachable | |
| else: | |
| reveal_type(x) # N: Revealed type is "builtins.int | builtins.str" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsInstanceWithTypeObject] | |
| # flags: --warn-unreachable | |
| from typing import Union, Type | |
| class A: pass | |
| def f(x: Union[int, A], a: Type[A]) -> None: | |
| if isinstance(x, a): | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| elif isinstance(x, int): | |
| reveal_type(x) # N: Revealed type is "builtins.int" | |
| else: | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| reveal_type(x) # N: Revealed type is "builtins.int | __main__.A" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIssubclassUnreachable] | |
| # flags: --warn-unreachable | |
| from typing import Type, Sequence, Union | |
| x: Type[str] | |
| if issubclass(x, int): # E: Subclass of "str" and "int" cannot exist: would have incompatible method signatures | |
| reveal_type(x) # E: Statement is unreachable | |
| class X: pass | |
| class Y(X): pass | |
| class Z(X): pass | |
| a: Union[Type[Y], Type[Z]] | |
| if issubclass(a, X): | |
| reveal_type(a) # N: Revealed type is "type[__main__.Y] | type[__main__.Z]" | |
| else: | |
| reveal_type(a) # E: Statement is unreachable | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIssubclasDestructuringUnions1] | |
| # flags: --warn-unreachable | |
| from typing import Union, List, Tuple, Dict, Type | |
| def f(x: Union[Type[int], Type[str], Type[List]]) -> None: | |
| if issubclass(x, (str, (int,))): | |
| reveal_type(x) # N: Revealed type is "type[builtins.int] | type[builtins.str]" | |
| reveal_type(x()) # N: Revealed type is "builtins.int | builtins.str" | |
| x()[1] # E: Value of type "int | str" is not indexable | |
| else: | |
| reveal_type(x) # N: Revealed type is "type[builtins.list[Any]]" | |
| reveal_type(x()) # N: Revealed type is "builtins.list[Any]" | |
| x()[1] | |
| reveal_type(x) # N: Revealed type is "type[builtins.int] | type[builtins.str] | type[builtins.list[Any]]" | |
| reveal_type(x()) # N: Revealed type is "builtins.int | builtins.str | builtins.list[Any]" | |
| if issubclass(x, (str, (list,))): | |
| reveal_type(x) # N: Revealed type is "type[builtins.str] | type[builtins.list[Any]]" | |
| reveal_type(x()) # N: Revealed type is "builtins.str | builtins.list[Any]" | |
| x()[1] | |
| reveal_type(x) # N: Revealed type is "type[builtins.int] | type[builtins.str] | type[builtins.list[Any]]" | |
| reveal_type(x()) # N: Revealed type is "builtins.int | builtins.str | builtins.list[Any]" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIssubclasDestructuringUnions2] | |
| # flags: --warn-unreachable | |
| from typing import Union, List, Tuple, Dict, Type | |
| def f(x: Type[Union[int, str, List]]) -> None: | |
| if issubclass(x, (str, (int,))): | |
| reveal_type(x) # N: Revealed type is "type[builtins.int] | type[builtins.str]" | |
| reveal_type(x()) # N: Revealed type is "builtins.int | builtins.str" | |
| x()[1] # E: Value of type "int | str" is not indexable | |
| else: | |
| reveal_type(x) # N: Revealed type is "type[builtins.list[Any]]" | |
| reveal_type(x()) # N: Revealed type is "builtins.list[Any]" | |
| x()[1] | |
| reveal_type(x) # N: Revealed type is "type[builtins.int] | type[builtins.str] | type[builtins.list[Any]]" | |
| reveal_type(x()) # N: Revealed type is "builtins.int | builtins.str | builtins.list[Any]" | |
| if issubclass(x, (str, (list,))): | |
| reveal_type(x) # N: Revealed type is "type[builtins.str] | type[builtins.list[Any]]" | |
| reveal_type(x()) # N: Revealed type is "builtins.str | builtins.list[Any]" | |
| x()[1] | |
| reveal_type(x) # N: Revealed type is "type[builtins.int] | type[builtins.str] | type[builtins.list[Any]]" | |
| reveal_type(x()) # N: Revealed type is "builtins.int | builtins.str | builtins.list[Any]" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIssubclasDestructuringUnions3] | |
| # flags: --warn-unreachable | |
| from typing import Union, List, Tuple, Dict, Type | |
| def f(x: Type[Union[int, str, List]]) -> None: | |
| reveal_type(x) # N: Revealed type is "type[builtins.int] | type[builtins.str] | type[builtins.list[Any]]" | |
| reveal_type(x()) # N: Revealed type is "builtins.int | builtins.str | builtins.list[Any]" | |
| if issubclass(x, (str, (int,))): | |
| reveal_type(x) # N: Revealed type is "type[builtins.int] | type[builtins.str]" | |
| reveal_type(x()) # N: Revealed type is "builtins.int | builtins.str" | |
| x()[1] # E: Value of type "int | str" is not indexable | |
| else: | |
| reveal_type(x) # N: Revealed type is "type[builtins.list[Any]]" | |
| reveal_type(x()) # N: Revealed type is "builtins.list[Any]" | |
| x()[1] | |
| reveal_type(x) # N: Revealed type is "type[builtins.int] | type[builtins.str] | type[builtins.list[Any]]" | |
| reveal_type(x()) # N: Revealed type is "builtins.int | builtins.str | builtins.list[Any]" | |
| if issubclass(x, (str, (list,))): | |
| reveal_type(x) # N: Revealed type is "type[builtins.str] | type[builtins.list[Any]]" | |
| reveal_type(x()) # N: Revealed type is "builtins.str | builtins.list[Any]" | |
| x()[1] | |
| reveal_type(x) # N: Revealed type is "type[builtins.int] | type[builtins.str] | type[builtins.list[Any]]" | |
| reveal_type(x()) # N: Revealed type is "builtins.int | builtins.str | builtins.list[Any]" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIssubclass] | |
| # flags: --warn-unreachable | |
| from typing import Type, ClassVar | |
| class Goblin: | |
| level: int | |
| class GoblinAmbusher(Goblin): | |
| job: ClassVar[str] = 'Ranger' | |
| def test_issubclass(cls: Type[Goblin]) -> None: | |
| if issubclass(cls, GoblinAmbusher): | |
| reveal_type(cls) # N: Revealed type is "type[__main__.GoblinAmbusher]" | |
| cls.level | |
| cls.job | |
| ga = cls() | |
| ga.level = 15 | |
| ga.job | |
| ga.job = "Warrior" # E: Cannot assign to class variable "job" via instance | |
| else: | |
| reveal_type(cls) # N: Revealed type is "type[__main__.Goblin]" | |
| cls.level | |
| cls.job # E: "type[Goblin]" has no attribute "job" | |
| g = cls() | |
| g.level = 15 | |
| g.job # E: "Goblin" has no attribute "job" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIssubclassDeepHierarchy] | |
| # flags: --warn-unreachable | |
| from typing import Type, ClassVar | |
| class Mob: pass | |
| class Goblin(Mob): | |
| level: int | |
| class GoblinAmbusher(Goblin): | |
| job: ClassVar[str] = 'Ranger' | |
| def test_issubclass(cls: Type[Mob]) -> None: | |
| if issubclass(cls, Goblin): | |
| reveal_type(cls) # N: Revealed type is "type[__main__.Goblin]" | |
| cls.level | |
| cls.job # E: "type[Goblin]" has no attribute "job" | |
| g = cls() | |
| g.level = 15 | |
| g.job # E: "Goblin" has no attribute "job" | |
| if issubclass(cls, GoblinAmbusher): | |
| reveal_type(cls) # N: Revealed type is "type[__main__.GoblinAmbusher]" | |
| cls.level | |
| cls.job | |
| g = cls() | |
| g.level = 15 | |
| g.job | |
| g.job = 'Warrior' # E: Cannot assign to class variable "job" via instance | |
| else: | |
| reveal_type(cls) # N: Revealed type is "type[__main__.Mob]" | |
| cls.job # E: "type[Mob]" has no attribute "job" | |
| cls.level # E: "type[Mob]" has no attribute "level" | |
| m = cls() | |
| m.level = 15 # E: "Mob" has no attribute "level" | |
| m.job # E: "Mob" has no attribute "job" | |
| if issubclass(cls, GoblinAmbusher): | |
| reveal_type(cls) # N: Revealed type is "type[__main__.GoblinAmbusher]" | |
| cls.job | |
| cls.level | |
| ga = cls() | |
| ga.level = 15 | |
| ga.job | |
| ga.job = 'Warrior' # E: Cannot assign to class variable "job" via instance | |
| if issubclass(cls, GoblinAmbusher): | |
| reveal_type(cls) # N: Revealed type is "type[__main__.GoblinAmbusher]" | |
| cls.level | |
| cls.job | |
| ga = cls() | |
| ga.level = 15 | |
| ga.job | |
| ga.job = "Warrior" # E: Cannot assign to class variable "job" via instance | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIssubclassTuple] | |
| # flags: --warn-unreachable | |
| from typing import Type, ClassVar | |
| class Mob: pass | |
| class Goblin(Mob): | |
| level: int | |
| class GoblinAmbusher(Goblin): | |
| job: ClassVar[str] = 'Ranger' | |
| class GoblinDigger(Goblin): | |
| job: ClassVar[str] = 'Thief' | |
| def test_issubclass(cls: Type[Mob]) -> None: | |
| if issubclass(cls, (Goblin, GoblinAmbusher)): | |
| reveal_type(cls) # N: Revealed type is "type[__main__.Goblin]" | |
| cls.level | |
| cls.job # E: "type[Goblin]" has no attribute "job" | |
| g = cls() | |
| g.level = 15 | |
| g.job # E: "Goblin" has no attribute "job" | |
| if issubclass(cls, GoblinAmbusher): | |
| cls.level | |
| reveal_type(cls) # N: Revealed type is "type[__main__.GoblinAmbusher]" | |
| cls.job | |
| ga = cls() | |
| ga.level = 15 | |
| ga.job | |
| ga.job = "Warrior" # E: Cannot assign to class variable "job" via instance | |
| else: | |
| reveal_type(cls) # N: Revealed type is "type[__main__.Mob]" | |
| cls.job # E: "type[Mob]" has no attribute "job" | |
| cls.level # E: "type[Mob]" has no attribute "level" | |
| m = cls() | |
| m.level = 15 # E: "Mob" has no attribute "level" | |
| m.job # E: "Mob" has no attribute "job" | |
| if issubclass(cls, GoblinAmbusher): | |
| reveal_type(cls) # N: Revealed type is "type[__main__.GoblinAmbusher]" | |
| cls.job | |
| cls.level | |
| ga = cls() | |
| ga.level = 15 | |
| ga.job | |
| ga.job = "Warrior" # E: Cannot assign to class variable "job" via instance | |
| if issubclass(cls, (GoblinDigger, GoblinAmbusher)): | |
| reveal_type(cls) # N: Revealed type is "type[__main__.GoblinDigger] | type[__main__.GoblinAmbusher]" | |
| cls.level | |
| cls.job | |
| g = cls() | |
| g.level = 15 | |
| g.job | |
| g.job = "Warrior" # E: Cannot assign to class variable "job" via instance | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIssubclassBuiltins] | |
| # flags: --warn-unreachable | |
| from typing import List, Type | |
| class MyList(List): pass | |
| class MyIntList(List[int]): pass | |
| def f(cls: Type[object]) -> None: | |
| if issubclass(cls, MyList): | |
| reveal_type(cls) # N: Revealed type is "type[__main__.MyList]" | |
| cls()[0] | |
| else: | |
| reveal_type(cls) # N: Revealed type is "type[builtins.object]" | |
| cls()[0] # E: Value of type "object" is not indexable | |
| if issubclass(cls, MyIntList): | |
| reveal_type(cls) # N: Revealed type is "type[__main__.MyIntList]" | |
| cls()[0] + 1 | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIssubclassTypeVar] | |
| # flags: --strict-equality --warn-unreachable | |
| from __future__ import annotations | |
| from typing import TypeVar | |
| ClassT = TypeVar("ClassT", bound=type) | |
| def directed_meet(cls0: ClassT, cls1: ClassT) -> ClassT | None: | |
| if issubclass(cls1, cls0): | |
| return cls1 | |
| if issubclass(cls0, cls1): | |
| return cls0 | |
| return None | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsinstanceTypeArgs] | |
| # flags: --warn-unreachable | |
| from typing import Iterable, TypeVar | |
| x = 1 | |
| isinstance(x, Iterable) | |
| isinstance(x, Iterable[int]) # E: Parameterized generics cannot be used with class or instance checks | |
| isinstance(x, (int, Iterable[int])) # E: Parameterized generics cannot be used with class or instance checks | |
| isinstance(x, (int, (str, Iterable[int]))) # E: Parameterized generics cannot be used with class or instance checks | |
| [builtins fixtures/isinstancelist.pyi] | |
| [typing fixtures/typing-full.pyi] | |
| [case testIsinstanceAnyAlias] | |
| # flags: --warn-unreachable | |
| from typing import Any | |
| A = Any | |
| isinstance(object(), A) # E: Cannot use isinstance() with Any type | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsinstanceTypeArgsAliases] | |
| # flags: --warn-unreachable | |
| from typing import Iterable, TypeVar | |
| x = 1 | |
| T = TypeVar('T') | |
| It = Iterable | |
| It2 = Iterable[T] | |
| isinstance(x, It[int]) # E: Parameterized generics cannot be used with class or instance checks | |
| isinstance(x, It) | |
| isinstance(x, It2[int]) # E: Parameterized generics cannot be used with class or instance checks | |
| isinstance(x, It2) # E: Parameterized generics cannot be used with class or instance checks | |
| [builtins fixtures/isinstance.pyi] | |
| [typing fixtures/typing-full.pyi] | |
| [case testIssubclassTypeArgs] | |
| # flags: --warn-unreachable | |
| from typing import Iterable, TypeVar | |
| x = int | |
| issubclass(x, Iterable) | |
| issubclass(x, Iterable[int]) # E: Parameterized generics cannot be used with class or instance checks | |
| issubclass(x, (int, Iterable[int])) # E: Parameterized generics cannot be used with class or instance checks | |
| [builtins fixtures/isinstance.pyi] | |
| [typing fixtures/typing-full.pyi] | |
| [case testIssubclassWithMetaclasses] | |
| # flags: --no-strict-optional --warn-unreachable | |
| class FooMetaclass(type): ... | |
| class Foo(metaclass=FooMetaclass): ... | |
| class Bar: ... | |
| fm: FooMetaclass | |
| reveal_type(fm) # N: Revealed type is "__main__.FooMetaclass" | |
| if issubclass(fm, Foo): | |
| reveal_type(fm) # N: Revealed type is "type[__main__.Foo]" | |
| if issubclass(fm, Bar): | |
| reveal_type(fm) # N: Revealed type is "None" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIssubclassWithMetaclassesStrictOptional] | |
| # flags: --warn-unreachable | |
| class FooMetaclass(type): ... | |
| class BarMetaclass(type): ... | |
| class Foo(metaclass=FooMetaclass): ... | |
| class Bar(metaclass=BarMetaclass): ... | |
| class Baz: ... | |
| fm: FooMetaclass | |
| reveal_type(fm) # N: Revealed type is "__main__.FooMetaclass" | |
| if issubclass(fm, Foo): | |
| reveal_type(fm) # N: Revealed type is "type[__main__.Foo]" | |
| if issubclass(fm, Bar): | |
| reveal_type(fm) # N: Revealed type is "type[__main__.Bar]" | |
| if issubclass(fm, Baz): | |
| reveal_type(fm) # N: Revealed type is "type[__main__.Baz]" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsinstanceAndNarrowTypeVariable] | |
| # flags: --warn-unreachable | |
| from typing import TypeVar | |
| class A: pass | |
| class B(A): | |
| attr: int | |
| T = TypeVar('T', bound=A) | |
| def f(x: T) -> None: | |
| if isinstance(x, B): | |
| reveal_type(x) # N: Revealed type is "T`-1" | |
| reveal_type(x.attr) # N: Revealed type is "builtins.int" | |
| else: | |
| reveal_type(x) # N: Revealed type is "T`-1" | |
| x.attr # E: "T" has no attribute "attr" | |
| reveal_type(x) # N: Revealed type is "T`-1" | |
| x.attr # E: "T" has no attribute "attr" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsinstanceAndNegativeNarrowTypeVariableWithUnionBound1] | |
| # flags: --warn-unreachable | |
| from typing import Union, TypeVar | |
| class A: | |
| a: int | |
| class B: | |
| b: int | |
| T = TypeVar("T", bound=Union[A, B]) | |
| def f(x: T) -> T: | |
| if isinstance(x, A): | |
| reveal_type(x) # N: Revealed type is "T`-1" | |
| x.a | |
| x.b # E: "T" has no attribute "b" | |
| if bool(): | |
| return x | |
| else: | |
| reveal_type(x) # N: Revealed type is "T`-1" | |
| x.a # E: "T" has no attribute "a" | |
| x.b | |
| x.a # E: Item "B" of the upper bound "A | B" of type variable "T" has no attribute "a" | |
| x.b # E: Item "A" of the upper bound "A | B" of type variable "T" has no attribute "b" | |
| return x | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsinstanceAndNegativeNarrowTypeVariableWithUnionBound2] | |
| # flags: --warn-unreachable | |
| from typing import Union, TypeVar | |
| class A: | |
| a: int | |
| class B: | |
| b: int | |
| T = TypeVar("T", bound=Union[A, B]) | |
| def f(x: T) -> T: | |
| if isinstance(x, A): | |
| return x | |
| x.a # E: "T" has no attribute "a" | |
| x.b # OK | |
| return x | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsinstanceAndTypeType] | |
| # flags: --warn-unreachable | |
| from typing import Type | |
| def f(x: Type[int]) -> None: | |
| if isinstance(x, type): | |
| reveal_type(x) # N: Revealed type is "type[builtins.int]" | |
| else: | |
| reveal_type(x) # E: Statement is unreachable | |
| reveal_type(x) # N: Revealed type is "type[builtins.int]" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsinstanceVariableSubstitution] | |
| # flags: --warn-unreachable | |
| T = (int, str) | |
| U = (list, T) | |
| x: object = None | |
| if isinstance(x, T): | |
| reveal_type(x) # N: Revealed type is "builtins.int | builtins.str" | |
| if isinstance(x, U): | |
| reveal_type(x) # N: Revealed type is "builtins.list[Any] | builtins.int | builtins.str" | |
| if isinstance(x, (set, (list, T))): | |
| reveal_type(x) # N: Revealed type is "builtins.set[Any] | builtins.list[Any] | builtins.int | builtins.str" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsInstanceTooFewArgs] | |
| # flags: --warn-unreachable | |
| isinstance() # E: Missing positional arguments "x", "t" in call to "isinstance" | |
| x: object | |
| if isinstance(): # E: Missing positional arguments "x", "t" in call to "isinstance" | |
| x = 1 | |
| reveal_type(x) # N: Revealed type is "builtins.int" | |
| if isinstance(x): # E: Missing positional argument "t" in call to "isinstance" | |
| x = 1 | |
| reveal_type(x) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsSubclassTooFewArgs] | |
| # flags: --warn-unreachable | |
| from typing import Type | |
| issubclass() # E: Missing positional arguments "x", "t" in call to "issubclass" | |
| y: Type[object] | |
| if issubclass(): # E: Missing positional arguments "x", "t" in call to "issubclass" | |
| reveal_type(y) # N: Revealed type is "type[builtins.object]" | |
| if issubclass(y): # E: Missing positional argument "t" in call to "issubclass" | |
| reveal_type(y) # N: Revealed type is "type[builtins.object]" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsInstanceTooManyArgs] | |
| # flags: --warn-unreachable | |
| isinstance(1, 1, 1) # E: Too many arguments for "isinstance" \ | |
| # E: Argument 2 to "isinstance" has incompatible type "int"; expected "type | tuple[Any, ...]" | |
| x: object | |
| if isinstance(x, str, 1): # E: Too many arguments for "isinstance" | |
| reveal_type(x) # N: Revealed type is "builtins.object" | |
| x = 1 | |
| reveal_type(x) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsinstanceNarrowAnyExplicit] | |
| # flags: --warn-unreachable | |
| from typing import Any | |
| def narrow_any_to_str_then_reassign_to_int() -> None: | |
| v: Any = 1 | |
| if isinstance(v, str): | |
| reveal_type(v) # N: Revealed type is "builtins.str" | |
| v = 2 | |
| reveal_type(v) # N: Revealed type is "Any" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsinstanceNarrowAnyImplicit] | |
| # flags: --warn-unreachable | |
| def foo(): ... | |
| def narrow_any_to_str_then_reassign_to_int() -> None: | |
| v = foo() | |
| if isinstance(v, str): | |
| reveal_type(v) # N: Revealed type is "builtins.str" | |
| v = 2 | |
| reveal_type(v) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testNarrowTypeAfterInList] | |
| # flags: --warn-unreachable | |
| from typing import List, Optional | |
| x: List[int] | |
| y: Optional[int] | |
| if y in x: | |
| reveal_type(y) # N: Revealed type is "builtins.int" | |
| else: | |
| reveal_type(y) # N: Revealed type is "builtins.int | None" | |
| if y not in x: | |
| reveal_type(y) # N: Revealed type is "builtins.int | None" | |
| else: | |
| reveal_type(y) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/list.pyi] | |
| [case testNarrowTypeAfterInListOfOptional] | |
| # flags: --warn-unreachable | |
| from typing import List, Optional | |
| x: List[Optional[int]] | |
| y: Optional[int] | |
| if y not in x: | |
| reveal_type(y) # N: Revealed type is "builtins.int | None" | |
| else: | |
| reveal_type(y) # N: Revealed type is "builtins.int | None" | |
| [builtins fixtures/list.pyi] | |
| [case testNarrowTypeAfterInListNonOverlapping] | |
| # flags: --warn-unreachable | |
| from typing import List, Optional | |
| def f(x: List[str], y: Optional[int]) -> None: | |
| if y in x: | |
| reveal_type(y) # E: Statement is unreachable | |
| else: | |
| reveal_type(y) # N: Revealed type is "builtins.int | None" | |
| [builtins fixtures/list.pyi] | |
| [case testNarrowTypeAfterInListNested] | |
| # flags: --warn-unreachable | |
| from typing import List, Optional, Any | |
| def f(x: Optional[int], lst: Optional[List[int]], nested_any: List[List[Any]]) -> None: | |
| if lst in nested_any: | |
| reveal_type(lst) # N: Revealed type is "builtins.list[builtins.int]" | |
| if x in nested_any: | |
| reveal_type(x) # E: Statement is unreachable | |
| [builtins fixtures/list.pyi] | |
| [case testNarrowTypeAfterInTuple] | |
| # flags: --warn-unreachable | |
| class A: pass | |
| class B(A): pass | |
| class C(A): pass | |
| def f(y: B | None): | |
| if y in (B(), C()): | |
| reveal_type(y) # N: Revealed type is "__main__.B" | |
| else: | |
| reveal_type(y) # N: Revealed type is "__main__.B | None" | |
| [builtins fixtures/tuple.pyi] | |
| [case testNarrowTypeAfterInNamedTuple] | |
| # flags: --warn-unreachable | |
| from typing import NamedTuple, Optional | |
| class NT(NamedTuple): | |
| x: int | |
| y: int | |
| nt: NT | |
| y: Optional[int] | |
| if y not in nt: | |
| reveal_type(y) # N: Revealed type is "builtins.int | None" | |
| else: | |
| reveal_type(y) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/tuple.pyi] | |
| [case testNarrowTypeAfterInDict] | |
| # flags: --warn-unreachable | |
| from typing import Dict, Optional | |
| x: Dict[str, int] | |
| y: Optional[str] | |
| if y in x: | |
| reveal_type(y) # N: Revealed type is "builtins.str" | |
| else: | |
| reveal_type(y) # N: Revealed type is "builtins.str | None" | |
| if y not in x: | |
| reveal_type(y) # N: Revealed type is "builtins.str | None" | |
| else: | |
| reveal_type(y) # N: Revealed type is "builtins.str" | |
| [builtins fixtures/dict.pyi] | |
| [case testNarrowTypeAfterInNoAnyOrObject] | |
| # flags: --warn-unreachable | |
| from typing import Any, List, Optional | |
| x: List[Any] | |
| z: List[object] | |
| y: Optional[int] | |
| if y in x: | |
| reveal_type(y) # N: Revealed type is "builtins.int | None" | |
| else: | |
| reveal_type(y) # N: Revealed type is "builtins.int | None" | |
| if y not in z: | |
| reveal_type(y) # N: Revealed type is "builtins.int | None" | |
| else: | |
| reveal_type(y) # N: Revealed type is "builtins.int | None" | |
| [typing fixtures/typing-medium.pyi] | |
| [builtins fixtures/list.pyi] | |
| [case testNarrowTypeAfterInUserDefined] | |
| # flags: --warn-unreachable | |
| from typing import Container, Optional | |
| class C(Container[int]): | |
| def __contains__(self, item: object) -> bool: | |
| return item is 'surprise' | |
| y: Optional[int] | |
| # We never trust user defined types | |
| if y in C(): | |
| reveal_type(y) # N: Revealed type is "builtins.int | None" | |
| else: | |
| reveal_type(y) # N: Revealed type is "builtins.int | None" | |
| if y not in C(): | |
| reveal_type(y) # N: Revealed type is "builtins.int | None" | |
| else: | |
| reveal_type(y) # N: Revealed type is "builtins.int | None" | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/list.pyi] | |
| [case testNarrowTypeAfterInSet] | |
| # flags: --warn-unreachable | |
| from typing import Optional, Set | |
| s: Set[str] | |
| y: Optional[str] | |
| if y in {'a', 'b', 'c'}: | |
| reveal_type(y) # N: Revealed type is "builtins.str" | |
| else: | |
| reveal_type(y) # N: Revealed type is "builtins.str | None" | |
| if y not in s: | |
| reveal_type(y) # N: Revealed type is "builtins.str | None" | |
| else: | |
| reveal_type(y) # N: Revealed type is "builtins.str" | |
| [builtins fixtures/set.pyi] | |
| [case testNarrowTypeAfterInTypedDict] | |
| # flags: --warn-unreachable | |
| from typing import Optional, TypedDict | |
| class TD(TypedDict): | |
| a: int | |
| b: str | |
| td: TD | |
| def f() -> None: | |
| x: Optional[str] | |
| if x not in td: | |
| return | |
| reveal_type(x) # N: Revealed type is "builtins.str" | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testIsinstanceWidensWithAnyArg] | |
| # flags: --warn-unreachable | |
| from typing import Any | |
| class A: ... | |
| B: Any | |
| x: A | |
| x.foo() # E: "A" has no attribute "foo" | |
| assert isinstance(x, B) | |
| x.foo() | |
| reveal_type(x) # N: Revealed type is "Any" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsinstanceWidensUnionWithAnyArg] | |
| # flags: --warn-unreachable | |
| from typing import Any, Union | |
| class A: ... | |
| B: Any | |
| x: Union[A, B] | |
| reveal_type(x) # N: Revealed type is "__main__.A | Any" | |
| assert isinstance(x, B) | |
| reveal_type(x) # N: Revealed type is "Any" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsinstanceNarrowsAfterNoneCheckWithAnyUnion] | |
| # flags: --warn-unreachable | |
| from typing import Any, Union | |
| def f(val: Union[Any, str]) -> None: | |
| if val is None or isinstance(val, str): | |
| reveal_type(val) # N: Revealed type is "None | builtins.str" | |
| return | |
| reveal_type(val) # N: Revealed type is "Any" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsinstanceIgnoredImport] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| from foo import A # type: ignore | |
| def f(x: Union[A, str]) -> None: | |
| x.method_only_in_a() # E: Item "str" of "Any | str" has no attribute "method_only_in_a" | |
| if isinstance(x, A): | |
| x.method_only_in_a() | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsinstanceIgnoredImportDualAny] | |
| # flags: --warn-unreachable | |
| from typing import Any | |
| from foo import Bad, OtherBad # type: ignore | |
| x: Any | |
| if isinstance(x, Bad): | |
| reveal_type(x) # N: Revealed type is "Any" | |
| else: | |
| reveal_type(x) # N: Revealed type is "Any" | |
| if isinstance(x, (Bad, OtherBad)): | |
| reveal_type(x) # N: Revealed type is "Any" | |
| else: | |
| reveal_type(x) # N: Revealed type is "Any" | |
| y: object | |
| if isinstance(y, Bad): | |
| reveal_type(y) # N: Revealed type is "Any" | |
| else: | |
| reveal_type(y) # N: Revealed type is "builtins.object" | |
| class Ok: pass | |
| z: Any | |
| if isinstance(z, Ok): | |
| reveal_type(z) # N: Revealed type is "__main__.Ok" | |
| else: | |
| reveal_type(z) # N: Revealed type is "Any" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsInstanceInitialNoneCheckSkipsImpossibleCasesNoStrictOptional] | |
| # flags: --warn-unreachable | |
| from typing import Optional, Union | |
| class A: pass | |
| def foo1(x: Union[A, str, None]) -> None: | |
| if x is None: | |
| reveal_type(x) # N: Revealed type is "None" | |
| elif isinstance(x, A): | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| else: | |
| reveal_type(x) # N: Revealed type is "builtins.str" | |
| def foo2(x: Optional[str]) -> None: | |
| if x is None: | |
| reveal_type(x) # N: Revealed type is "None" | |
| elif isinstance(x, A): | |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "builtins.str" and "__main__.A">" | |
| else: | |
| reveal_type(x) # N: Revealed type is "builtins.str" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsInstanceInitialNoneCheckSkipsImpossibleCasesInNoStrictOptional] | |
| # flags: --no-strict-optional --warn-unreachable | |
| from typing import Optional, Union | |
| class A: pass | |
| def foo1(x: Union[A, str, None]) -> None: | |
| if x is None: | |
| reveal_type(x) # N: Revealed type is "None" | |
| elif isinstance(x, A): | |
| # Note that Union[None, A] == A in no-strict-optional | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| else: | |
| reveal_type(x) # N: Revealed type is "builtins.str" | |
| def foo2(x: Optional[str]) -> None: | |
| if x is None: | |
| reveal_type(x) # N: Revealed type is "None" | |
| elif isinstance(x, A): | |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "builtins.str" and "__main__.A">" | |
| else: | |
| reveal_type(x) # N: Revealed type is "builtins.str" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testNoneCheckDoesNotMakeTypeVarOptional] | |
| # flags: --warn-unreachable | |
| from typing import TypeVar | |
| T = TypeVar('T') | |
| def foo_if(x: T) -> T: | |
| out = None | |
| out = x | |
| if out is None: | |
| pass | |
| return out | |
| def foo_while(x: T) -> T: | |
| out = None | |
| out = x | |
| while out is None: | |
| pass | |
| return out | |
| [builtins fixtures/isinstance.pyi] | |
| [case testNoneCheckDoesNotNarrowWhenUsingTypeVarsNoStrictOptional] | |
| # flags: --no-strict-optional --warn-unreachable | |
| from typing import TypeVar | |
| T = TypeVar('T') | |
| def foo(x: T) -> T: | |
| out = None | |
| out = x | |
| if out is None: | |
| pass | |
| return out | |
| [builtins fixtures/isinstance.pyi] | |
| [case testNoneAndGenericTypesOverlapNoStrictOptional] | |
| # flags: --no-strict-optional --warn-unreachable | |
| from typing import Union, Optional, List | |
| # Note: this test is indirectly making sure meet.is_overlapping_types | |
| # correctly ignores 'None' in unions. | |
| def foo(x: Optional[List[str]]) -> None: | |
| reveal_type(x) # N: Revealed type is "builtins.list[builtins.str] | None" | |
| assert isinstance(x, list) | |
| reveal_type(x) # N: Revealed type is "builtins.list[builtins.str]" | |
| def bar(x: Union[List[str], List[int], None]) -> None: | |
| reveal_type(x) # N: Revealed type is "builtins.list[builtins.str] | builtins.list[builtins.int] | None" | |
| assert isinstance(x, list) | |
| reveal_type(x) # N: Revealed type is "builtins.list[builtins.str] | builtins.list[builtins.int]" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testNoneAndGenericTypesOverlapStrictOptional] | |
| # flags: --warn-unreachable | |
| from typing import Union, Optional, List | |
| # This test is the same as the one above, except for strict-optional. | |
| # It isn't testing anything explicitly and mostly exists for the sake | |
| # of completeness. | |
| def foo(x: Optional[List[str]]) -> None: | |
| reveal_type(x) # N: Revealed type is "builtins.list[builtins.str] | None" | |
| assert isinstance(x, list) | |
| reveal_type(x) # N: Revealed type is "builtins.list[builtins.str]" | |
| def bar(x: Union[List[str], List[int], None]) -> None: | |
| reveal_type(x) # N: Revealed type is "builtins.list[builtins.str] | builtins.list[builtins.int] | None" | |
| assert isinstance(x, list) | |
| reveal_type(x) # N: Revealed type is "builtins.list[builtins.str] | builtins.list[builtins.int]" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsInstanceWithStarExpression] | |
| # flags: --warn-unreachable | |
| from typing import Union, List, Tuple | |
| def f(var: Union[List[str], Tuple[str, str], str]) -> None: | |
| reveal_type(var) # N: Revealed type is "builtins.list[builtins.str] | tuple[builtins.str, builtins.str] | builtins.str" | |
| if isinstance(var, (list, *(str, int))): | |
| reveal_type(var) # N: Revealed type is "builtins.list[builtins.str] | builtins.str" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsInstanceWithStarExpressionAndVariable] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| def f(var: Union[int, str]) -> None: | |
| reveal_type(var) # N: Revealed type is "builtins.int | builtins.str" | |
| some_types = (str, tuple) | |
| another_type = list | |
| if isinstance(var, (*some_types, another_type)): | |
| reveal_type(var) # N: Revealed type is "builtins.str" | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsInstanceWithWrongStarExpression] | |
| # flags: --warn-unreachable | |
| var = 'some string' | |
| if isinstance(var, *(str, int)): # E: Too many arguments for "isinstance" | |
| pass | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testIsInstanceAdHocIntersectionBasic] | |
| # flags: --warn-unreachable | |
| class A: | |
| def f1(self) -> int: ... | |
| class B: | |
| def f2(self) -> int: ... | |
| class C: | |
| def f3(self) -> int: ... | |
| x: A | |
| if isinstance(x, B): | |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "__main__.A" and "__main__.B">" | |
| if isinstance(x, C): | |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "__main__.A", "__main__.B", and "__main__.C">" | |
| reveal_type(x.f1()) # N: Revealed type is "builtins.int" | |
| reveal_type(x.f2()) # N: Revealed type is "builtins.int" | |
| reveal_type(x.f3()) # N: Revealed type is "builtins.int" | |
| x.bad() # E: "<subclass of "__main__.A", "__main__.B", and "__main__.C">" has no attribute "bad" | |
| else: | |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "__main__.A" and "__main__.B">" | |
| else: | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsInstanceAdHocIntersectionRepeatedChecks] | |
| # flags: --warn-unreachable | |
| class A: pass | |
| class B: pass | |
| x: A | |
| if isinstance(x, B): | |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "__main__.A" and "__main__.B">" | |
| if isinstance(x, A): | |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "__main__.A" and "__main__.B">" | |
| if isinstance(x, B): | |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "__main__.A" and "__main__.B">" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsInstanceAdHocIntersectionIncompatibleClasses] | |
| # flags: --warn-unreachable | |
| class A: | |
| def f(self) -> int: ... | |
| class B: | |
| def f(self) -> str: ... | |
| class C: | |
| def f(self) -> str: ... | |
| class Example(A, B): pass # E: Definition of "f" in base class "A" is incompatible with definition in base class "B" | |
| x: A | |
| if isinstance(x, B): # E: Subclass of "A" and "B" cannot exist: would have incompatible method signatures | |
| reveal_type(x) # E: Statement is unreachable | |
| else: | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| y: C | |
| if isinstance(y, B): | |
| reveal_type(y) # N: Revealed type is "__main__.<subclass of "__main__.C" and "__main__.B">" | |
| if isinstance(y, A): # E: Subclass of "C", "B", and "A" cannot exist: would have incompatible method signatures | |
| reveal_type(y) # E: Statement is unreachable | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsInstanceAdHocIntersectionReversed] | |
| # flags: --warn-unreachable | |
| from abc import abstractmethod | |
| from typing import Literal | |
| class A0: | |
| def f(self) -> Literal[0]: | |
| ... | |
| class A1: | |
| def f(self) -> Literal[1]: | |
| ... | |
| class A2: | |
| def f(self) -> Literal[2]: | |
| ... | |
| class B: | |
| @abstractmethod | |
| def f(self) -> Literal[1, 2]: | |
| ... | |
| def t0(self) -> None: | |
| if isinstance(self, A0): # E: Subclass of "B" and "A0" cannot exist: would have incompatible method signatures | |
| x0: Literal[0] = self.f() # E: Statement is unreachable | |
| def t1(self) -> None: | |
| if isinstance(self, A1): | |
| reveal_type(self) # N: Revealed type is "__main__.<subclass of "__main__.A1" and "__main__.B">" | |
| x0: Literal[0] = self.f() # E: Incompatible types in assignment (expression has type "Literal[1]", variable has type "Literal[0]") | |
| x1: Literal[1] = self.f() | |
| def t2(self) -> None: | |
| if isinstance(self, (A0, A1)): | |
| reveal_type(self) # N: Revealed type is "__main__.<subclass of "__main__.A1" and "__main__.B">" | |
| x0: Literal[0] = self.f() # E: Incompatible types in assignment (expression has type "Literal[1]", variable has type "Literal[0]") | |
| x1: Literal[1] = self.f() | |
| def t3(self) -> None: | |
| if isinstance(self, (A1, A2)): | |
| reveal_type(self) # N: Revealed type is "__main__.<subclass of "__main__.A1" and "__main__.B"> | __main__.<subclass of "__main__.A2" and "__main__.B">" | |
| x0: Literal[0] = self.f() # E: Incompatible types in assignment (expression has type "Literal[1, 2]", variable has type "Literal[0]") | |
| x1: Literal[1] = self.f() # E: Incompatible types in assignment (expression has type "Literal[1, 2]", variable has type "Literal[1]") | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsInstanceAdHocIntersectionGenerics] | |
| # flags: --warn-unreachable | |
| from typing import Generic, TypeVar | |
| class Parent: pass | |
| class Child(Parent): pass | |
| T = TypeVar('T') | |
| class A(Generic[T]): | |
| def f(self) -> T: ... | |
| class B: | |
| def f(self) -> Parent: ... | |
| x: A[int] | |
| if isinstance(x, B): # E: Subclass of "A[int]" and "B" cannot exist: would have incompatible method signatures | |
| reveal_type(x) # E: Statement is unreachable | |
| else: | |
| reveal_type(x) # N: Revealed type is "__main__.A[builtins.int]" | |
| y: A[Parent] | |
| if isinstance(y, B): | |
| reveal_type(y) # N: Revealed type is "__main__.<subclass of "__main__.A[__main__.Parent]" and "__main__.B">" | |
| reveal_type(y.f()) # N: Revealed type is "__main__.Parent" | |
| else: | |
| reveal_type(y) # N: Revealed type is "__main__.A[__main__.Parent]" | |
| z: A[Child] | |
| if isinstance(z, B): | |
| reveal_type(z) # N: Revealed type is "__main__.<subclass of "__main__.A[__main__.Child]" and "__main__.B">" | |
| reveal_type(z.f()) # N: Revealed type is "__main__.Child" | |
| else: | |
| reveal_type(z) # N: Revealed type is "__main__.A[__main__.Child]" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsInstanceAdHocIntersectionGenericsWithValues] | |
| # flags: --warn-unreachable | |
| from typing import TypeVar | |
| class A: | |
| attr: int | |
| class B: | |
| attr: int | |
| class C: | |
| attr: str | |
| T1 = TypeVar('T1', A, B) | |
| def f1(x: T1) -> T1: | |
| if isinstance(x, A): | |
| reveal_type(x) # N: Revealed type is "__main__.A" \ | |
| # N: Revealed type is "__main__.<subclass of "__main__.B" and "__main__.A">" | |
| if isinstance(x, B): | |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "__main__.A" and "__main__.B">" \ | |
| # N: Revealed type is "__main__.<subclass of "__main__.B" and "__main__.A">" | |
| else: | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| else: | |
| reveal_type(x) # N: Revealed type is "__main__.B" | |
| return x | |
| T2 = TypeVar('T2', B, C) | |
| def f2(x: T2) -> T2: | |
| if isinstance(x, B): | |
| reveal_type(x) # N: Revealed type is "__main__.B" | |
| # Note: even though --warn-unreachable is set, we don't report | |
| # errors for the below: we don't yet have a way of filtering out | |
| # reachability errors that occur for only one variation of the | |
| # TypeVar yet. | |
| if isinstance(x, C): | |
| reveal_type(x) | |
| else: | |
| reveal_type(x) # N: Revealed type is "__main__.B" | |
| else: | |
| reveal_type(x) # N: Revealed type is "__main__.C" | |
| return x | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsInstanceAdHocIntersectionGenericsWithValuesDirectReturn] | |
| # flags: --warn-unreachable | |
| from typing import TypeVar | |
| class A: | |
| attr: int | |
| class B: | |
| attr: int | |
| class C: | |
| attr: str | |
| T1 = TypeVar('T1', A, B) | |
| def f1(x: T1) -> T1: | |
| if isinstance(x, A): | |
| # The error message is confusing, but we indeed do run into problems if | |
| # 'x' is a subclass of __main__.A and __main__.B | |
| return A() # E: Incompatible return value type (got "A", expected "B") | |
| else: | |
| return B() | |
| T2 = TypeVar('T2', B, C) | |
| def f2(x: T2) -> T2: | |
| if isinstance(x, B): | |
| # In contrast, it's impossible for a subclass of "B" and "C" to | |
| # exist, so this is fine | |
| return B() | |
| else: | |
| return C() | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsInstanceDisjointBase] | |
| # flags: --warn-unreachable | |
| from typing_extensions import disjoint_base | |
| @disjoint_base | |
| class Disjoint1: pass | |
| @disjoint_base | |
| class Disjoint2: pass | |
| @disjoint_base | |
| class Disjoint3(Disjoint1): pass | |
| class Child(Disjoint1): pass | |
| class Unrelated: pass | |
| def f(d1: Disjoint1, u: Unrelated, c: Child) -> object: | |
| if isinstance(d1, Disjoint2): # E: Subclass of "Disjoint1" and "Disjoint2" cannot exist: have distinct disjoint bases | |
| return u # E: Statement is unreachable | |
| if isinstance(u, Disjoint1): # OK | |
| return d1 | |
| if isinstance(c, Disjoint3): # OK | |
| return c | |
| if isinstance(c, Disjoint2): # E: Subclass of "Child" and "Disjoint2" cannot exist: have distinct disjoint bases | |
| return c # E: Statement is unreachable | |
| return d1 | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsInstanceAdHocIntersectionUsage] | |
| # flags: --warn-unreachable | |
| class A: pass | |
| class B: pass | |
| class Concrete(A, B): pass | |
| def accept_a(a: A) -> None: pass | |
| def accept_b(a: B) -> None: pass | |
| def accept_concrete(c: Concrete) -> None: pass | |
| x: A | |
| if isinstance(x, B): | |
| var = x | |
| reveal_type(var) # N: Revealed type is "__main__.<subclass of "__main__.A" and "__main__.B">" | |
| accept_a(var) | |
| accept_b(var) | |
| accept_concrete(var) # E: Argument 1 to "accept_concrete" has incompatible type "<subclass of "__main__.A" and "__main__.B">"; expected "Concrete" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsInstanceAdHocIntersectionReinfer] | |
| # flags: --warn-unreachable | |
| class A: pass | |
| class B: pass | |
| x: A | |
| assert isinstance(x, B) | |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "__main__.A" and "__main__.B">" | |
| y: A | |
| assert isinstance(y, B) | |
| reveal_type(y) # N: Revealed type is "__main__.<subclass of "__main__.A" and "__main__.B">" | |
| x = y | |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "__main__.A" and "__main__.B">" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsInstanceAdHocIntersectionWithUnions] | |
| # flags: --warn-unreachable | |
| from typing import Type, Union | |
| class A: pass | |
| class B: pass | |
| class C: pass | |
| class D: pass | |
| v1: A | |
| if isinstance(v1, (B, C)): | |
| reveal_type(v1) # N: Revealed type is "__main__.<subclass of "__main__.A" and "__main__.B"> | __main__.<subclass of "__main__.A" and "__main__.C">" | |
| v2: Union[A, B] | |
| if isinstance(v2, C): | |
| reveal_type(v2) # N: Revealed type is "__main__.<subclass of "__main__.A" and "__main__.C"> | __main__.<subclass of "__main__.B" and "__main__.C">" | |
| v3: Union[A, B] | |
| if isinstance(v3, (C, D)): | |
| reveal_type(v3) # N: Revealed type is "__main__.<subclass of "__main__.A" and "__main__.C"> | __main__.<subclass of "__main__.A" and "__main__.D"> | __main__.<subclass of "__main__.B" and "__main__.C"> | __main__.<subclass of "__main__.B" and "__main__.D">" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsInstanceAdHocIntersectionSameNames] | |
| # flags: --warn-unreachable | |
| from foo import A as A2 | |
| class A: pass | |
| x: A | |
| if isinstance(x, A2): | |
| reveal_type(x) # N: Revealed type is "__main__.<subclass of "__main__.A" and "foo.A">" | |
| [file foo.py] | |
| class A: pass | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsInstanceAdHocIntersectionBadMro] | |
| # flags: --warn-unreachable | |
| class X: pass | |
| class Y: pass | |
| class A(X, Y): pass | |
| class B(Y, X): pass | |
| foo: A | |
| if isinstance(foo, B): # E: Subclass of "A" and "B" cannot exist: would have inconsistent method resolution order | |
| reveal_type(foo) # E: Statement is unreachable | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsInstanceAdHocIntersectionAmbiguousClass] | |
| # flags: --warn-unreachable | |
| from typing import Any | |
| class Concrete: | |
| x: int | |
| class Ambiguous: | |
| x: Any | |
| # We bias towards assuming these two classes could be overlapping | |
| foo: Concrete | |
| if isinstance(foo, Ambiguous): | |
| reveal_type(foo) # N: Revealed type is "__main__.<subclass of "__main__.Concrete" and "__main__.Ambiguous">" | |
| reveal_type(foo.x) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsSubclassAdHocIntersection] | |
| # flags: --warn-unreachable | |
| from typing import Type | |
| class A: | |
| x: int | |
| class B: | |
| x: int | |
| class C: | |
| x: str | |
| x: Type[A] | |
| if issubclass(x, B): | |
| reveal_type(x) # N: Revealed type is "type[__main__.<subclass of "__main__.A" and "__main__.B">]" | |
| if issubclass(x, C): # E: Subclass of "A", "B", and "C" cannot exist: would have incompatible method signatures | |
| reveal_type(x) # E: Statement is unreachable | |
| else: | |
| reveal_type(x) # N: Revealed type is "type[__main__.<subclass of "__main__.A" and "__main__.B">]" | |
| else: | |
| reveal_type(x) # N: Revealed type is "type[__main__.A]" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testHasAttrExistingAttribute] | |
| # flags: --warn-unreachable | |
| class C: | |
| x: int | |
| c: C | |
| if hasattr(c, "x"): | |
| reveal_type(c.x) # N: Revealed type is "builtins.int" | |
| else: | |
| # We don't mark this unreachable since people may check for deleted attributes | |
| reveal_type(c.x) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testHasAttrMissingAttributeInstance] | |
| # flags: --warn-unreachable | |
| class B: ... | |
| b: B | |
| if hasattr(b, "x"): | |
| reveal_type(b.x) # N: Revealed type is "Any" | |
| else: | |
| b.x # E: "B" has no attribute "x" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testHasAttrMissingAttributeFunction] | |
| # flags: --warn-unreachable | |
| def foo(x: int) -> None: ... | |
| if hasattr(foo, "x"): | |
| reveal_type(foo.x) # N: Revealed type is "Any" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testHasAttrMissingAttributeClassObject] | |
| # flags: --warn-unreachable | |
| class C: ... | |
| if hasattr(C, "x"): | |
| reveal_type(C.x) # N: Revealed type is "Any" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testHasAttrMissingAttributeTypeType] | |
| # flags: --warn-unreachable | |
| from typing import Type | |
| class C: ... | |
| c: Type[C] | |
| if hasattr(c, "x"): | |
| reveal_type(c.x) # N: Revealed type is "Any" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testHasAttrMissingAttributeTypeVar] | |
| # flags: --warn-unreachable | |
| from typing import TypeVar | |
| T = TypeVar("T") | |
| def foo(x: T) -> T: | |
| if hasattr(x, "x"): | |
| reveal_type(x.x) # N: Revealed type is "Any" | |
| return x | |
| else: | |
| return x | |
| [builtins fixtures/isinstance.pyi] | |
| [case testHasAttrMissingAttributeChained] | |
| # flags: --warn-unreachable | |
| class B: ... | |
| b: B | |
| if hasattr(b, "x"): | |
| reveal_type(b.x) # N: Revealed type is "Any" | |
| elif hasattr(b, "y"): | |
| reveal_type(b.y) # N: Revealed type is "Any" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testHasAttrMissingAttributeNested] | |
| # flags: --warn-unreachable | |
| class A: ... | |
| class B: ... | |
| x: A | |
| if hasattr(x, "x"): | |
| if isinstance(x, B): | |
| reveal_type(x.x) # N: Revealed type is "Any" | |
| if hasattr(x, "x") and hasattr(x, "y"): | |
| reveal_type(x.x) # N: Revealed type is "Any" | |
| reveal_type(x.y) # N: Revealed type is "Any" | |
| if hasattr(x, "x"): | |
| if hasattr(x, "y"): | |
| reveal_type(x.x) # N: Revealed type is "Any" | |
| reveal_type(x.y) # N: Revealed type is "Any" | |
| if hasattr(x, "x") or hasattr(x, "y"): | |
| x.x # E: "A" has no attribute "x" | |
| x.y # E: "A" has no attribute "y" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testHasAttrPreciseType] | |
| # flags: --warn-unreachable | |
| class A: ... | |
| x: A | |
| if hasattr(x, "a") and isinstance(x.a, int): | |
| reveal_type(x.a) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testHasAttrMissingAttributeUnion] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| class A: ... | |
| class B: | |
| x: int | |
| xu: Union[A, B] | |
| if hasattr(xu, "x"): | |
| reveal_type(xu) # N: Revealed type is "__main__.A | __main__.B" | |
| reveal_type(xu.x) # N: Revealed type is "Any | builtins.int" | |
| else: | |
| reveal_type(xu) # N: Revealed type is "__main__.A" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testHasAttrMissingAttributeOuterUnion] | |
| # flags: --warn-unreachable | |
| from typing import Union | |
| class A: ... | |
| class B: ... | |
| xu: Union[A, B] | |
| if isinstance(xu, B): | |
| if hasattr(xu, "x"): | |
| reveal_type(xu.x) # N: Revealed type is "Any" | |
| if isinstance(xu, B) and hasattr(xu, "x"): | |
| reveal_type(xu.x) # N: Revealed type is "Any" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testHasAttrDoesntInterfereGetAttr] | |
| # flags: --warn-unreachable | |
| class C: | |
| def __getattr__(self, attr: str) -> str: ... | |
| c: C | |
| if hasattr(c, "foo"): | |
| reveal_type(c.foo) # N: Revealed type is "builtins.str" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testHasAttrMissingAttributeLiteral] | |
| # flags: --warn-unreachable | |
| from typing import Final | |
| class B: ... | |
| b: B | |
| ATTR: Final = "x" | |
| if hasattr(b, ATTR): | |
| reveal_type(b.x) # N: Revealed type is "Any" | |
| else: | |
| b.x # E: "B" has no attribute "x" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testHasAttrDeferred] | |
| # flags: --warn-unreachable | |
| def foo() -> str: ... | |
| class Test: | |
| def stream(self) -> None: | |
| if hasattr(self, "_body"): | |
| reveal_type(self._body) # N: Revealed type is "builtins.str" | |
| def body(self) -> str: | |
| if not hasattr(self, "_body"): | |
| self._body = foo() | |
| return self._body | |
| [builtins fixtures/isinstance.pyi] | |
| [case testHasAttrModule] | |
| # flags: --warn-unreachable | |
| import mod | |
| if hasattr(mod, "y"): | |
| reveal_type(mod.y) # N: Revealed type is "Any" | |
| reveal_type(mod.x) # N: Revealed type is "builtins.int" | |
| else: | |
| mod.y # E: Module has no attribute "y" | |
| reveal_type(mod.x) # N: Revealed type is "builtins.int" | |
| if hasattr(mod, "x"): | |
| mod.y # E: Module has no attribute "y" | |
| reveal_type(mod.x) # N: Revealed type is "builtins.int" | |
| else: | |
| mod.y # E: Module has no attribute "y" | |
| reveal_type(mod.x) # N: Revealed type is "builtins.int" | |
| [file mod.py] | |
| x: int | |
| [builtins fixtures/module.pyi] | |
| [case testHasAttrDoesntInterfereModuleGetAttr] | |
| # flags: --warn-unreachable | |
| import mod | |
| if hasattr(mod, "y"): | |
| reveal_type(mod.y) # N: Revealed type is "builtins.str" | |
| [file mod.py] | |
| def __getattr__(attr: str) -> str: ... | |
| [builtins fixtures/module.pyi] | |
| [case testMultipleHasAttr] | |
| # flags: --warn-unreachable | |
| # https://github.com/python/mypy/issues/20596 | |
| from __future__ import annotations | |
| from typing import Any | |
| def len(obj: object) -> Any: ... | |
| def f(x: type | str): | |
| if ( | |
| hasattr(x, "__origin__") | |
| and x.__origin__ is list | |
| and hasattr(x, "__args__") | |
| and len(x.__args__) == 1 | |
| ): | |
| reveal_type(x.__args__[0]) # N: Revealed type is "Any" | |
| [builtins fixtures/module.pyi] | |
| [case testTypeIsntLostAfterNarrowing] | |
| # flags: --warn-unreachable | |
| from typing import Any | |
| var: Any | |
| reveal_type(var) # N: Revealed type is "Any" | |
| assert isinstance(var, (bool, str)) | |
| reveal_type(var) # N: Revealed type is "builtins.bool | builtins.str" | |
| if isinstance(var, bool): | |
| reveal_type(var) # N: Revealed type is "builtins.bool" | |
| # Type of var shouldn't fall back to Any | |
| reveal_type(var) # N: Revealed type is "builtins.bool | builtins.str" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testReuseIntersectionForRepeatedIsinstanceCalls] | |
| # flags: --warn-unreachable | |
| class A: ... | |
| class B: ... | |
| a: A | |
| if isinstance(a, B): | |
| c = a | |
| if isinstance(a, B): | |
| c = a | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsInstanceTypeAny] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import Any | |
| def foo(x: object, t: type[Any]): | |
| if isinstance(x, t): | |
| reveal_type(x) # N: Revealed type is "Any" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsInstanceObject] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import Any | |
| def foo(x: object, t: object): | |
| if isinstance(x, t): # E: Argument 2 to "isinstance" has incompatible type "object"; expected "type[object] | tuple[type[object], ...]" | |
| reveal_type(x) # N: Revealed type is "builtins.object" | |
| [builtins fixtures/isinstance.pyi] | |
| [case testIsInstanceOrExprInTuple] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import Any | |
| def f1(x: object): | |
| if isinstance(x, str | (int, dict)): # E: Argument 2 to "isinstance" has incompatible type "object"; expected "type | tuple[Any, ...]" | |
| reveal_type(x) # N: Revealed type is "builtins.str" | |
| if type(x) == str | (int, dict): | |
| reveal_type(x) # N: Revealed type is "builtins.object" | |
| def f2(x: Any): | |
| if isinstance(x, str | (int, dict)): # E: Argument 2 to "isinstance" has incompatible type "object"; expected "type | tuple[Any, ...]" | |
| reveal_type(x) # N: Revealed type is "builtins.str" | |
| if type(x) == str | (int, dict): | |
| reveal_type(x) # N: Revealed type is "Any" | |
| [builtins fixtures/primitives.pyi] | |
| [case testIsInstanceUnionOfTuples] | |
| # flags: --strict-equality --warn-unreachable | |
| from __future__ import annotations | |
| from typing import TypeVar, Iterator, final | |
| T1 = TypeVar("T1") | |
| T2 = TypeVar("T2") | |
| T3 = TypeVar("T3") | |
| def extract( | |
| values: object, | |
| ts: ( | |
| tuple[type[T1]] | |
| | tuple[type[T1], type[T2]] | |
| | tuple[type[T1], type[T2], type[T3]] | |
| ) | |
| ) -> Iterator[T1 | T2 | T3]: | |
| if isinstance(values, ts): | |
| reveal_type(values) # N: Revealed type is "T1`-1 | T2`-2 | T3`-3" | |
| yield values | |
| raise | |
| class A: ... | |
| class B: ... | |
| def f1(x: A | B, t: tuple[type[A]] | tuple[type[B]]): | |
| if isinstance(x, t): | |
| reveal_type(x) # N: Revealed type is "__main__.A | __main__.B" | |
| else: | |
| reveal_type(x) # N: Revealed type is "__main__.A | __main__.B" | |
| def f2(x: object, t: tuple[type[A]] | tuple[type[B]]): | |
| if isinstance(x, t): | |
| reveal_type(x) # N: Revealed type is "__main__.A | __main__.B" | |
| else: | |
| reveal_type(x) # N: Revealed type is "builtins.object" | |
| @final | |
| class FA: ... | |
| @final | |
| class FB: ... | |
| def g1(x: FA | FB, t: tuple[type[FA]] | tuple[type[FB]]): | |
| if isinstance(x, t): | |
| reveal_type(x) # N: Revealed type is "__main__.FA | __main__.FB" | |
| else: | |
| reveal_type(x) # N: Revealed type is "__main__.FA | __main__.FB" | |
| def g2(x: object, t: tuple[type[FA]] | tuple[type[FB]]): | |
| if isinstance(x, t): | |
| reveal_type(x) # N: Revealed type is "__main__.FA | __main__.FB" | |
| else: | |
| reveal_type(x) # N: Revealed type is "builtins.object" | |
| [builtins fixtures/primitives.pyi] | |
| [case testIsInstanceTypeVarBoundToType] | |
| # flags: --strict-equality --warn-unreachable | |
| from __future__ import annotations | |
| from typing import TypeVar, Protocol | |
| class A(Protocol): | |
| x: int | |
| T = TypeVar("T", bound=type[A]) | |
| def foo(x: object, t: T): | |
| if isinstance(x, t): | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| reveal_type(x.x) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/primitives.pyi] | |
| [case testIsInstanceFinalTypeObject] | |
| # flags: --strict-equality --warn-unreachable | |
| from __future__ import annotations | |
| from typing import final | |
| @final | |
| class A: ... | |
| def f1(x: A, t: type[A]): | |
| if isinstance(x, A): | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| else: | |
| reveal_type(x) # E: Statement is unreachable | |
| if isinstance(x, t): | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| else: | |
| reveal_type(x) # E: Statement is unreachable | |
| def f2(x: A | None, t: type[A]): | |
| if isinstance(x, A): | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| else: | |
| reveal_type(x) # N: Revealed type is "None" | |
| if isinstance(x, t): | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| else: | |
| reveal_type(x) # N: Revealed type is "None" | |
| [builtins fixtures/isinstancelist.pyi] |