blob: 20b5dea9fc8708e9016ddb8b686c4fbb82161ea6 [file] [log] [blame] [edit]
-- Type checker test cases for conditional checks that result in some
-- blocks classified as unreachable (they are not type checked or semantically
-- analyzed).
--
-- For example, we skip blocks that will not be executed on the active
-- Python version.
[case testConditionalTypeAliasPY3]
import typing
def f(): pass
PY3 = f()
if PY3:
t = int
x = object() + 'x' # E: Unsupported left operand type for + ("object")
else:
t = str
y = 'x' / 1
x
z = 1 # type: t
[case testConditionalAssignmentPY2]
import typing
def f(): pass
PY2 = f()
if PY2:
x = object() + 'x'
else:
y = 'x' / 1 # E: Unsupported left operand type for / ("str")
y
[case testConditionalImport]
import typing
def f(): pass
PY2 = f()
if PY2:
import fuzzybar
from barbar import *
from pawwaw import a, bc
else:
import m
[file m.py]
import typing
x = 1
if int():
x = 'a'
[out]
tmp/m.py:4: error: Incompatible types in assignment (expression has type "str", variable has type "int")
[case testNegatedMypyConditional]
import typing
MYPY = 0
if not MYPY:
import xyz753
else:
import pow123 # E
[builtins fixtures/bool.pyi]
[out]
main:6: error: Cannot find implementation or library stub for module named "pow123"
main:6: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
[case testMypyConditional]
import typing
MYPY = 0
if MYPY:
None + 1 # E: Unsupported left operand type for + ("None")
else:
None + ''
[builtins fixtures/bool.pyi]
[case testTypeCheckingConditional]
import typing
if typing.TYPE_CHECKING:
import pow123 # E
else:
import xyz753
[typing fixtures/typing-medium.pyi]
[out]
main:3: error: Cannot find implementation or library stub for module named "pow123"
main:3: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
[case testTypeCheckingConditionalFromImport]
from typing import TYPE_CHECKING
if TYPE_CHECKING:
import pow123 # E
else:
import xyz753
[typing fixtures/typing-medium.pyi]
[out]
main:3: error: Cannot find implementation or library stub for module named "pow123"
main:3: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
[case testNegatedTypeCheckingConditional]
import typing
if not typing.TYPE_CHECKING:
import pow123 # E
else:
import xyz753
[builtins fixtures/bool.pyi]
[typing fixtures/typing-medium.pyi]
[out]
main:5: error: Cannot find implementation or library stub for module named "xyz753"
main:5: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
[case testUndefinedTypeCheckingConditional]
if not TYPE_CHECKING: # E
import pow123
else:
import xyz753
[builtins fixtures/bool.pyi]
[out]
main:1: error: Name "TYPE_CHECKING" is not defined
main:4: error: Cannot find implementation or library stub for module named "xyz753"
main:4: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
[case testConditionalClassDefPY3]
def f(): pass
PY3 = f()
if PY3:
pass
else:
class X(object):
pass
[case testUnreachabilityAndElifPY3]
def f(): pass
PY3 = f()
if PY3:
pass
elif bool():
import nonexistent
1 + ''
else:
import bad_name
1 + ''
[builtins fixtures/bool.pyi]
[out]
[case testSysVersionInfo]
import sys
if sys.version_info[0] >= 3:
def foo() -> int: return 0
else:
def foo() -> str: return ''
reveal_type(foo()) # N: Revealed type is "builtins.int"
[builtins fixtures/ops.pyi]
[out]
[case testSysVersionInfoReversedOperandsOrder]
import sys
if (3,) <= sys.version_info:
def foo() -> int: return 0
else:
def foo() -> str: return ''
reveal_type(foo()) # N: Revealed type is "builtins.int"
[builtins fixtures/ops.pyi]
[out]
[case testSysVersionInfoNegated]
import sys
if not (sys.version_info[0] < 3):
def foo() -> int: return 0
else:
def foo() -> str: return ''
reveal_type(foo()) # N: Revealed type is "builtins.int"
[builtins fixtures/ops.pyi]
[out]
[case testSysVersionInfoSliced1]
import sys
if sys.version_info[:1] >= (3,):
def foo() -> int: return 0
else:
def foo() -> str: return ''
foo() + 0
[builtins fixtures/ops.pyi]
[out]
[case testSysVersionInfoSliced2]
import sys
if sys.version_info[:2] >= (3, 0):
def foo() -> int: return 0
else:
def foo() -> str: return ''
foo() + 0
[builtins fixtures/ops.pyi]
[out]
[case testSysVersionInfoSliced3]
import sys
if sys.version_info[:] >= (3, 0):
def foo() -> int: return 0
else:
def foo() -> str: return ''
foo() + 0
[builtins fixtures/ops.pyi]
[out]
[case testSysVersionInfoSliced4]
import sys
if sys.version_info[0:2] >= (3, 0):
def foo() -> int: return 0
else:
def foo() -> str: return ''
foo() + 0
[builtins fixtures/ops.pyi]
[out]
[case testSysVersionInfoSliced5]
import sys
if sys.version_info[0:] >= (3,):
def foo() -> int: return 0
else:
def foo() -> str: return ''
foo() + 0
[builtins fixtures/ops.pyi]
[out]
[case testSysVersionInfoSliced6]
import sys
if sys.version_info[1:] >= (5,):
def foo() -> int: return 0
else:
def foo() -> str: return ''
foo() + 0
[builtins fixtures/ops.pyi]
[out]
[case testSysVersionInfoSliced7]
import sys
if sys.version_info >= (3, 5):
def foo() -> int: return 0
else:
def foo() -> str: return ''
foo() + 0
[builtins fixtures/ops.pyi]
[out]
[case testSysVersionInfoSliced8]
# Our pyversion only has (major, minor),
# so testing for (major, minor, bugfix) is unsupported.
import sys
if sys.version_info >= (3, 5, 0):
def foo() -> int: return 0
else:
def foo() -> str: return '' # E: All conditional function variants must have identical signatures \
# N: Original: \
# N: def foo() -> int \
# N: Redefinition: \
# N: def foo() -> str
[builtins fixtures/ops.pyi]
[out]
[case testSysVersionInfoSliced9]
# Our pyversion only has (major, minor),
# so testing for (minor, bugfix) is unsupported (also it's silly :-).
import sys
if sys.version_info[1:] >= (5, 0):
def foo() -> int: return 0
else:
def foo() -> str: return '' # E: All conditional function variants must have identical signatures \
# N: Original: \
# N: def foo() -> int \
# N: Redefinition: \
# N: def foo() -> str
[builtins fixtures/ops.pyi]
[out]
[case testSysPlatform1]
import sys
if sys.platform == 'fictional':
def foo() -> int: return 0
else:
def foo() -> str: return ''
foo() + ''
[builtins fixtures/ops.pyi]
[out]
[case testSysPlatform2]
import sys
if sys.platform != 'fictional':
def foo() -> int: return 0
else:
def foo() -> str: return ''
foo() + 0
[builtins fixtures/ops.pyi]
[out]
[case testSysPlatformNegated]
import sys
if not (sys.platform == 'fictional'):
def foo() -> int: return 0
else:
def foo() -> str: return ''
foo() + 0
[builtins fixtures/ops.pyi]
[out]
[case testSysVersionInfoClass]
import sys
if sys.version_info < (3, 5):
class C:
pass
else:
class C:
def foo(self) -> int: return 0
C().foo() + 0
[builtins fixtures/ops.pyi]
[out]
[case testSysVersionInfoImport]
import sys
if sys.version_info >= (3, 5):
import collections
else:
collections = None
Pt = collections.namedtuple('Pt', 'x y z')
[builtins fixtures/ops.pyi]
[out]
[case testSysVersionInfoVariable]
import sys
if sys.version_info >= (3, 5):
x = ''
else:
x = 0
x + ''
[builtins fixtures/ops.pyi]
[out]
[case testSysVersionInfoInClass]
import sys
class C:
if sys.version_info >= (3, 5):
def foo(self) -> int: return 0
else:
def foo(self) -> str: return ''
reveal_type(C().foo()) # N: Revealed type is "builtins.int"
[builtins fixtures/ops.pyi]
[out]
[case testSysVersionInfoInFunction]
import sys
def foo() -> None:
if sys.version_info >= (3, 5):
x = ''
else:
x = 0
reveal_type(x) # N: Revealed type is "builtins.str"
[builtins fixtures/ops.pyi]
[out]
[case testSysPlatformInMethod]
import sys
class C:
def foo(self) -> None:
if sys.platform != 'fictional':
x = ''
else:
x = 0
reveal_type(x) # N: Revealed type is "builtins.str"
[builtins fixtures/ops.pyi]
[out]
[case testSysPlatformInFunctionImport1]
import sys
def foo() -> None:
if sys.platform != 'fictional':
import a
else:
import b as a
a.x
[file a.py]
x = 1
[builtins fixtures/ops.pyi]
[out]
[case testSysPlatformInFunctionImport2]
import sys
def foo() -> None:
if sys.platform == 'fictional':
import b as a
else:
import a
a.x
[file a.py]
x = 1
[builtins fixtures/ops.pyi]
[out]
[case testSysPlatformInFunctionImport3]
from typing import Callable
import sys
def idf(x: Callable[[], None]) -> Callable[[], None]: return x
@idf
def foo() -> None:
if sys.platform == 'fictional':
import b as a
else:
import a
a.x
[file a.py]
x = 1
[builtins fixtures/ops.pyi]
[out]
[case testSysPlatformInMethodImport2]
import sys
class A:
def foo(self) -> None:
if sys.platform == 'fictional':
import b as a
else:
import a
a.x
[file a.py]
x = 1
[builtins fixtures/ops.pyi]
[out]
[case testCustomSysVersionInfo]
# flags: --python-version 3.11
import sys
if sys.version_info == (3, 11):
x = "foo"
else:
x = 3
reveal_type(x) # N: Revealed type is "builtins.str"
[builtins fixtures/ops.pyi]
[out]
[case testCustomSysVersionInfo2]
# flags: --python-version 3.11
import sys
if sys.version_info == (3, 6):
x = "foo"
else:
x = 3
reveal_type(x) # N: Revealed type is "builtins.int"
[builtins fixtures/ops.pyi]
[out]
[case testCustomSysPlatform]
# flags: --platform linux
import sys
if sys.platform == 'linux':
x = "foo"
else:
x = 3
reveal_type(x) # N: Revealed type is "builtins.str"
[builtins fixtures/ops.pyi]
[out]
[case testCustomSysPlatform2]
# flags: --platform win32
import sys
if sys.platform == 'linux':
x = "foo"
else:
x = 3
reveal_type(x) # N: Revealed type is "builtins.int"
[builtins fixtures/ops.pyi]
[out]
[case testCustomSysPlatformStartsWith]
# flags: --platform win32
import sys
if sys.platform.startswith('win'):
x = "foo"
else:
x = 3
reveal_type(x) # N: Revealed type is "builtins.str"
[builtins fixtures/ops.pyi]
[out]
[case testShortCircuitInExpression]
import typing
def make() -> bool: pass
PY2 = PY3 = make()
a = PY2 and 's'
b = PY3 and 's'
c = PY2 or 's'
d = PY3 or 's'
e = (PY2 or PY3) and 's'
f = (PY3 or PY2) and 's'
g = (PY2 or PY3) or 's'
h = (PY3 or PY2) or 's'
reveal_type(a) # N: Revealed type is "builtins.bool"
reveal_type(b) # N: Revealed type is "Literal['s']"
reveal_type(c) # N: Revealed type is "Literal['s']"
reveal_type(d) # N: Revealed type is "builtins.bool"
reveal_type(e) # N: Revealed type is "Literal['s']"
reveal_type(f) # N: Revealed type is "Literal['s']"
reveal_type(g) # N: Revealed type is "builtins.bool"
reveal_type(h) # N: Revealed type is "builtins.bool"
[builtins fixtures/ops.pyi]
[out]
[case testShortCircuitAndWithConditionalAssignment]
# flags: --platform linux
import sys
def f(): pass
PY2 = f()
if PY2 and sys.platform == 'linux':
x = 'foo'
else:
x = 3
reveal_type(x) # N: Revealed type is "builtins.int"
if sys.platform == 'linux' and PY2:
y = 'foo'
else:
y = 3
reveal_type(y) # N: Revealed type is "builtins.int"
[builtins fixtures/ops.pyi]
[case testShortCircuitOrWithConditionalAssignment]
# flags: --platform linux
import sys
def f(): pass
PY2 = f()
if PY2 or sys.platform == 'linux':
x = 'foo'
else:
x = 3
reveal_type(x) # N: Revealed type is "builtins.str"
if sys.platform == 'linux' or PY2:
y = 'foo'
else:
y = 3
reveal_type(y) # N: Revealed type is "builtins.str"
[builtins fixtures/ops.pyi]
[case testShortCircuitNoEvaluation]
# flags: --platform linux --always-false COMPILE_TIME_FALSE
import sys
if sys.platform == 'darwin':
mac_only = 'junk'
# `mac_only` should not be evaluated
if sys.platform == 'darwin' and mac_only:
pass
if sys.platform == 'linux' or mac_only:
pass
COMPILE_TIME_FALSE = 'junk'
if COMPILE_TIME_FALSE:
compile_time_false_only = 'junk'
# `compile_time_false_only` should not be evaluated
if COMPILE_TIME_FALSE and compile_time_false_only:
pass
if not COMPILE_TIME_FALSE or compile_time_false_only:
pass
MYPY = False
if not MYPY:
mypy_only = 'junk'
# `mypy_only` should not be evaluated
if not MYPY and mypy_only:
pass
if MYPY or mypy_only:
pass
[builtins fixtures/ops.pyi]
[case testSemanticAnalysisFalseButTypeNarrowingTrue]
# flags: --always-false COMPILE_TIME_FALSE
from typing import Literal
indeterminate: str
COMPILE_TIME_FALSE: Literal[True] # type-narrowing: mapped in 'if' only
a = COMPILE_TIME_FALSE or indeterminate
reveal_type(a) # N: Revealed type is "builtins.str"
b = indeterminate or COMPILE_TIME_FALSE
reveal_type(b) # N: Revealed type is "Union[builtins.str, Literal[True]]"
[typing fixtures/typing-medium.pyi]
[case testSemanticAnalysisTrueButTypeNarrowingFalse]
# flags: --always-true COMPILE_TIME_TRUE
from typing import Literal
indeterminate: str
COMPILE_TIME_TRUE: Literal[False] # type narrowed to `else` only
a = COMPILE_TIME_TRUE or indeterminate
reveal_type(a) # N: Revealed type is "Literal[False]"
b = indeterminate or COMPILE_TIME_TRUE
reveal_type(b) # N: Revealed type is "Union[builtins.str, Literal[False]]"
[typing fixtures/typing-medium.pyi]
[case testConditionalAssertWithoutElse]
import typing
class A: pass
class B(A): pass
x = A()
reveal_type(x) # N: Revealed type is "__main__.A"
if typing.TYPE_CHECKING:
assert isinstance(x, B)
reveal_type(x) # N: Revealed type is "__main__.B"
reveal_type(x) # N: Revealed type is "__main__.B"
[builtins fixtures/isinstancelist.pyi]
[typing fixtures/typing-medium.pyi]
[case testUnreachableWhenSuperclassIsAny]
from typing import Any
# This can happen if we're importing a class from a missing module
Parent: Any
class Child(Parent):
def foo(self) -> int:
reveal_type(self) # N: Revealed type is "__main__.Child"
if self is None:
reveal_type(self)
return None
reveal_type(self) # N: Revealed type is "__main__.Child"
return 3
def bar(self) -> int:
if 1:
self = super(Child, self).something()
reveal_type(self) # N: Revealed type is "__main__.Child"
if self is None:
reveal_type(self)
return None
reveal_type(self) # N: Revealed type is "__main__.Child"
return 3
[builtins fixtures/isinstance.pyi]
[case testUnreachableWhenSuperclassIsAnyNoStrictOptional]
# flags: --no-strict-optional
from typing import Any
Parent: Any
class Child(Parent):
def foo(self) -> int:
reveal_type(self) # N: Revealed type is "__main__.Child"
if self is None:
reveal_type(self) # N: Revealed type is "None"
return None
reveal_type(self) # N: Revealed type is "__main__.Child"
return 3
[builtins fixtures/isinstance.pyi]
[case testUnreachableAfterToplevelAssert]
import sys
reveal_type(0) # N: Revealed type is "Literal[0]?"
assert sys.platform == 'lol'
reveal_type('') # No error here :-)
[builtins fixtures/ops.pyi]
[case testUnreachableAfterToplevelAssert2]
import sys
reveal_type(0) # N: Revealed type is "Literal[0]?"
assert sys.version_info[0] == 1
reveal_type('') # No error here :-)
[builtins fixtures/ops.pyi]
[case testUnreachableAfterToplevelAssert3]
reveal_type(0) # N: Revealed type is "Literal[0]?"
MYPY = False
assert not MYPY
reveal_type('') # No error here :-)
[builtins fixtures/ops.pyi]
[case testUnreachableAfterToplevelAssert4]
# flags: --always-false NOPE
reveal_type(0) # N: Revealed type is "Literal[0]?"
NOPE = False
assert NOPE
reveal_type('') # No error here :-)
[builtins fixtures/ops.pyi]
[case testUnreachableAfterToplevelAssertImport]
import foo
foo.bar() # E: "object" has no attribute "bar"
[file foo.py]
import sys
assert sys.platform == 'lol'
def bar() -> None: pass
[builtins fixtures/ops.pyi]
[case testUnreachableAfterToplevelAssertImport2]
# flags: --platform lol
import foo
foo.bar() # No error :-)
[file foo.py]
import sys
assert sys.platform == 'lol'
def bar() -> None: pass
[builtins fixtures/ops.pyi]
[case testUnreachableAfterToplevelAssertNotInsideIf]
import sys
if sys.version_info[0] >= 2:
assert sys.platform == 'lol'
reveal_type('') # N: Revealed type is "Literal['']?"
reveal_type('') # N: Revealed type is "Literal['']?"
[builtins fixtures/ops.pyi]
[case testUnreachableFlagWithBadControlFlow1]
# flags: --warn-unreachable
a: int
if isinstance(a, int):
reveal_type(a) # N: Revealed type is "builtins.int"
else:
reveal_type(a) # E: Statement is unreachable
[builtins fixtures/isinstancelist.pyi]
[case testUnreachableFlagWithBadControlFlow2]
# flags: --warn-unreachable
b: int
while isinstance(b, int):
reveal_type(b) # N: Revealed type is "builtins.int"
else:
reveal_type(b) # E: Statement is unreachable
[builtins fixtures/isinstancelist.pyi]
[case testUnreachableFlagWithBadControlFlow3]
# flags: --warn-unreachable
def foo(c: int) -> None:
reveal_type(c) # N: Revealed type is "builtins.int"
assert not isinstance(c, int)
reveal_type(c) # E: Statement is unreachable
[builtins fixtures/isinstancelist.pyi]
[case testUnreachableFlagWithBadControlFlow4]
# flags: --warn-unreachable
d: int
if False:
reveal_type(d) # E: Statement is unreachable
[builtins fixtures/isinstancelist.pyi]
[case testUnreachableFlagWithBadControlFlow5]
# flags: --warn-unreachable
e: int
if True:
reveal_type(e) # N: Revealed type is "builtins.int"
else:
reveal_type(e) # E: Statement is unreachable
[builtins fixtures/isinstancelist.pyi]
[case testUnreachableFlagStatementAfterReturn]
# flags: --warn-unreachable
def foo(x: int) -> None:
reveal_type(x) # N: Revealed type is "builtins.int"
return
reveal_type(x) # E: Statement is unreachable
[case testUnreachableFlagTryBlocks]
# flags: --warn-unreachable
def foo(x: int) -> int:
try:
reveal_type(x) # N: Revealed type is "builtins.int"
return x
reveal_type(x) # E: Statement is unreachable
finally:
reveal_type(x) # N: Revealed type is "builtins.int"
if True:
reveal_type(x) # N: Revealed type is "builtins.int"
else:
reveal_type(x) # E: Statement is unreachable
def bar(x: int) -> int:
try:
if True:
raise Exception()
reveal_type(x) # E: Statement is unreachable
except:
reveal_type(x) # N: Revealed type is "builtins.int"
return x
else:
reveal_type(x) # E: Statement is unreachable
def baz(x: int) -> int:
try:
reveal_type(x) # N: Revealed type is "builtins.int"
except:
# Mypy assumes all lines could throw an exception
reveal_type(x) # N: Revealed type is "builtins.int"
return x
else:
reveal_type(x) # N: Revealed type is "builtins.int"
return x
[builtins fixtures/exception.pyi]
[case testUnreachableFlagIgnoresSemanticAnalysisUnreachable]
# flags: --warn-unreachable --python-version 3.7 --platform win32 --always-false FOOBAR
import sys
from typing import TYPE_CHECKING
x: int
if TYPE_CHECKING:
reveal_type(x) # N: Revealed type is "builtins.int"
else:
reveal_type(x)
if not TYPE_CHECKING:
reveal_type(x)
else:
reveal_type(x) # N: Revealed type is "builtins.int"
if sys.platform == 'darwin':
reveal_type(x)
else:
reveal_type(x) # N: Revealed type is "builtins.int"
if sys.platform == 'win32':
reveal_type(x) # N: Revealed type is "builtins.int"
else:
reveal_type(x)
if sys.version_info == (2, 7):
reveal_type(x)
else:
reveal_type(x) # N: Revealed type is "builtins.int"
if sys.version_info == (3, 7):
reveal_type(x) # N: Revealed type is "builtins.int"
else:
reveal_type(x)
FOOBAR = ""
if FOOBAR:
reveal_type(x)
else:
reveal_type(x) # N: Revealed type is "builtins.int"
[builtins fixtures/ops.pyi]
[typing fixtures/typing-medium.pyi]
[case testUnreachableFlagIgnoresSemanticAnalysisExprUnreachable]
# flags: --warn-unreachable --always-false FOOBAR
import sys
from typing import TYPE_CHECKING
FOOBAR = ""
def foo() -> bool: ...
lst = [1, 2, 3]
a = FOOBAR and foo()
b = (not FOOBAR) or foo()
c = 1 if FOOBAR else 2
d = [x for x in lst if FOOBAR]
[builtins fixtures/list.pyi]
[typing fixtures/typing-medium.pyi]
[case testUnreachableFlagOkWithDeadStatements]
# flags: --warn-unreachable
from typing import NoReturn
def assert_never(x: NoReturn) -> NoReturn:
assert False
def nonthrowing_assert_never(x: NoReturn) -> None: ...
def expect_str(x: str) -> str: pass
x: int
if False:
assert False
reveal_type(x) # E: Statement is unreachable
if False:
raise Exception()
reveal_type(x) # E: Statement is unreachable
if False:
assert_never(x)
reveal_type(x) # E: Statement is unreachable
if False:
nonthrowing_assert_never(x) # E: Statement is unreachable
reveal_type(x)
if False:
# Ignore obvious type errors
assert_never(expect_str(x))
reveal_type(x) # E: Statement is unreachable
[builtins fixtures/exception.pyi]
[case testNeverVariants]
from typing import Never
from typing_extensions import Never as TENever
from typing import NoReturn
from typing_extensions import NoReturn as TENoReturn
from mypy_extensions import NoReturn as MENoReturn
bottom1: Never
reveal_type(bottom1) # N: Revealed type is "<nothing>"
bottom2: TENever
reveal_type(bottom2) # N: Revealed type is "<nothing>"
bottom3: NoReturn
reveal_type(bottom3) # N: Revealed type is "<nothing>"
bottom4: TENoReturn
reveal_type(bottom4) # N: Revealed type is "<nothing>"
bottom5: MENoReturn
reveal_type(bottom5) # N: Revealed type is "<nothing>"
[builtins fixtures/tuple.pyi]
[case testUnreachableFlagExpressions]
# flags: --warn-unreachable
def foo() -> bool: ...
lst = [1, 2, 3, 4]
a = True or foo() # E: Right operand of "or" is never evaluated
b = 42 or False # E: Right operand of "or" is never evaluated
d = False and foo() # E: Right operand of "and" is never evaluated
e = True or (True or (True or foo())) # E: Right operand of "or" is never evaluated
f = (True or foo()) or (True or foo()) # E: Right operand of "or" is never evaluated
k = [x for x in lst if isinstance(x, int) or foo()] # E: Right operand of "or" is never evaluated
[builtins fixtures/isinstancelist.pyi]
[case testUnreachableFlagMiscTestCaseMissingMethod]
# flags: --warn-unreachable
class Case1:
def test1(self) -> bool:
return False and self.missing() # E: Right operand of "and" is never evaluated
def test2(self) -> bool:
return not self.property_decorator_missing and self.missing() # E: Function "property_decorator_missing" could always be true in boolean context \
# E: Right operand of "and" is never evaluated
def property_decorator_missing(self) -> bool:
return True
[builtins fixtures/bool.pyi]
[case testUnreachableFlagWithGenerics]
# flags: --warn-unreachable
from typing import TypeVar, Generic
T1 = TypeVar('T1', bound=int)
T2 = TypeVar('T2', int, str)
T3 = TypeVar('T3', None, str)
def test1(x: T1) -> T1:
if isinstance(x, int):
reveal_type(x) # N: Revealed type is "T1`-1"
else:
reveal_type(x) # E: Statement is unreachable
return x
def test2(x: T2) -> T2:
if isinstance(x, int):
reveal_type(x) # N: Revealed type is "builtins.int"
else:
reveal_type(x) # N: Revealed type is "builtins.str"
if False:
# This is unreachable, but we don't report an error, unfortunately.
# The presence of the TypeVar with values unfortunately currently shuts
# down type-checking for this entire function.
# TODO: Find a way of removing this limitation
reveal_type(x)
return x
class Test3(Generic[T2]):
x: T2
def func(self) -> None:
if isinstance(self.x, int):
reveal_type(self.x) # N: Revealed type is "builtins.int"
else:
reveal_type(self.x) # N: Revealed type is "builtins.str"
if False:
# Same issue as above
reveal_type(self.x)
class Test4(Generic[T3]):
def __init__(self, x: T3):
# https://github.com/python/mypy/issues/9456
# On TypeVars with value restrictions, we currently have no way
# of checking a statement for all the type expansions.
# Thus unreachable warnings are disabled
if x and False:
pass
# This test should fail after this limitation is removed.
if False and x:
pass
[builtins fixtures/isinstancelist.pyi]
[case testUnreachableFlagContextManagersNoSuppress]
# flags: --warn-unreachable
from contextlib import contextmanager
from typing import Optional, Iterator, Any
from typing_extensions import Literal
class DoesNotSuppress1:
def __enter__(self) -> int: ...
def __exit__(self, exctype: object, excvalue: object, traceback: object) -> Optional[bool]: ...
class DoesNotSuppress2:
def __enter__(self) -> int: ...
def __exit__(self, exctype: object, excvalue: object, traceback: object) -> Literal[False]: ...
class DoesNotSuppress3:
def __enter__(self) -> int: ...
def __exit__(self, exctype: object, excvalue: object, traceback: object) -> Any: ...
class DoesNotSuppress4:
def __enter__(self) -> int: ...
def __exit__(self, exctype: object, excvalue: object, traceback: object) -> None: ...
@contextmanager
def simple() -> Iterator[int]:
yield 3
def cond() -> bool: ...
def noop() -> None: ...
def f_no_suppress_1a() -> int:
with DoesNotSuppress1():
return 3
noop() # E: Statement is unreachable
def f_no_suppress_1b() -> int:
with DoesNotSuppress1():
if cond():
return 3
else:
return 3
noop() # E: Statement is unreachable
def f_no_suppress_2() -> int:
with DoesNotSuppress2():
return 3
noop() # E: Statement is unreachable
def f_no_suppress_3() -> int:
with DoesNotSuppress3():
return 3
noop() # E: Statement is unreachable
def f_no_suppress_4() -> int:
with DoesNotSuppress4():
return 3
noop() # E: Statement is unreachable
def f_no_suppress_5() -> int:
with simple():
return 3
noop() # E: Statement is unreachable
[typing fixtures/typing-medium.pyi]
[builtins fixtures/tuple.pyi]
[case testUnreachableFlagContextManagersSuppressed]
# flags: --warn-unreachable
from contextlib import contextmanager
from typing import Optional, Iterator, Any
from typing_extensions import Literal
class DoesNotSuppress:
def __enter__(self) -> int: ...
def __exit__(self, exctype: object, excvalue: object, traceback: object) -> Optional[bool]: ...
class Suppresses1:
def __enter__(self) -> int: ...
def __exit__(self, exctype: object, excvalue: object, traceback: object) -> bool: ...
class Suppresses2:
def __enter__(self) -> int: ...
def __exit__(self, exctype: object, excvalue: object, traceback: object) -> Literal[True]: ...
def cond() -> bool: ...
def noop() -> None: ...
def f_suppress_1a() -> int: # E: Missing return statement
with Suppresses1():
return 3
noop()
def f_suppress_1b() -> int: # E: Missing return statement
with Suppresses1():
if cond():
return 3
else:
return 3
noop()
def f_suppress_2() -> int: # E: Missing return statement
with Suppresses2():
return 3
noop()
def f_mix() -> int: # E: Missing return statement
with DoesNotSuppress(), Suppresses1(), DoesNotSuppress():
return 3
noop()
[typing fixtures/typing-medium.pyi]
[builtins fixtures/tuple.pyi]
[case testUnreachableFlagContextManagersSuppressedNoStrictOptional]
# flags: --warn-unreachable --no-strict-optional
from contextlib import contextmanager
from typing import Optional, Iterator, Any
from typing_extensions import Literal
class DoesNotSuppress1:
def __enter__(self) -> int: ...
def __exit__(self, exctype: object, excvalue: object, traceback: object) -> Optional[bool]: ...
# Normally, this should suppress. But when strict-optional mode is disabled, we can't
# necessarily distinguish between bool and Optional[bool]. So we default to assuming
# no suppression, since that's what most context managers will do.
class DoesNotSuppress2:
def __enter__(self) -> int: ...
def __exit__(self, exctype: object, excvalue: object, traceback: object) -> bool: ...
# But if we see Literal[True], it's pretty unlikely the return type is actually meant to
# be 'Optional[Literal[True]]'. So, we optimistically assume this is meant to be suppressing.
class Suppresses:
def __enter__(self) -> int: ...
def __exit__(self, exctype: object, excvalue: object, traceback: object) -> Literal[True]: ...
def noop() -> None: ...
def f_no_suppress_1() -> int:
with DoesNotSuppress1():
return 3
noop() # E: Statement is unreachable
def f_no_suppress_2() -> int:
with DoesNotSuppress1():
return 3
noop() # E: Statement is unreachable
def f_suppress() -> int: # E: Missing return statement
with Suppresses():
return 3
noop()
[typing fixtures/typing-medium.pyi]
[builtins fixtures/tuple.pyi]
[case testUnreachableFlagContextAsyncManagersNoSuppress]
# flags: --warn-unreachable --python-version 3.7
from contextlib import asynccontextmanager
from typing import Optional, AsyncIterator, Any
from typing_extensions import Literal
class DoesNotSuppress1:
async def __aenter__(self) -> int: ...
async def __aexit__(self, exctype: object, excvalue: object, traceback: object) -> Optional[bool]: ...
class DoesNotSuppress2:
async def __aenter__(self) -> int: ...
async def __aexit__(self, exctype: object, excvalue: object, traceback: object) -> Literal[False]: ...
class DoesNotSuppress3:
async def __aenter__(self) -> int: ...
async def __aexit__(self, exctype: object, excvalue: object, traceback: object) -> Any: ...
class DoesNotSuppress4:
async def __aenter__(self) -> int: ...
async def __aexit__(self, exctype: object, excvalue: object, traceback: object) -> None: ...
@asynccontextmanager
async def simple() -> AsyncIterator[int]:
yield 3
def cond() -> bool: ...
def noop() -> None: ...
async def f_no_suppress_1a() -> int:
async with DoesNotSuppress1():
return 3
noop() # E: Statement is unreachable
async def f_no_suppress_1b() -> int:
async with DoesNotSuppress1():
if cond():
return 3
else:
return 3
noop() # E: Statement is unreachable
async def f_no_suppress_2() -> int:
async with DoesNotSuppress2():
return 3
noop() # E: Statement is unreachable
async def f_no_suppress_3() -> int:
async with DoesNotSuppress3():
return 3
noop() # E: Statement is unreachable
async def f_no_suppress_4() -> int:
async with DoesNotSuppress4():
return 3
noop() # E: Statement is unreachable
async def f_no_suppress_5() -> int:
async with simple():
return 3
noop() # E: Statement is unreachable
[typing fixtures/typing-full.pyi]
[builtins fixtures/tuple.pyi]
[case testUnreachableFlagContextAsyncManagersSuppressed]
# flags: --warn-unreachable --python-version 3.7
from contextlib import asynccontextmanager
from typing import Optional, AsyncIterator, Any
from typing_extensions import Literal
class DoesNotSuppress:
async def __aenter__(self) -> int: ...
async def __aexit__(self, exctype: object, excvalue: object, traceback: object) -> Optional[bool]: ...
class Suppresses1:
async def __aenter__(self) -> int: ...
async def __aexit__(self, exctype: object, excvalue: object, traceback: object) -> bool: ...
class Suppresses2:
async def __aenter__(self) -> int: ...
async def __aexit__(self, exctype: object, excvalue: object, traceback: object) -> Literal[True]: ...
def cond() -> bool: ...
def noop() -> None: ...
async def f_suppress_1() -> int: # E: Missing return statement
async with Suppresses1():
return 3
noop()
async def f_suppress_2() -> int: # E: Missing return statement
async with Suppresses1():
if cond():
return 3
else:
return 3
noop()
async def f_suppress_3() -> int: # E: Missing return statement
async with Suppresses2():
return 3
noop()
async def f_mix() -> int: # E: Missing return statement
async with DoesNotSuppress(), Suppresses1(), DoesNotSuppress():
return 3
noop()
[typing fixtures/typing-full.pyi]
[builtins fixtures/tuple.pyi]
[case testUnreachableFlagContextAsyncManagersAbnormal]
# flags: --warn-unreachable --python-version 3.7
from contextlib import asynccontextmanager
from typing import Optional, AsyncIterator, Any
from typing_extensions import Literal
class RegularManager:
def __enter__(self) -> int: ...
def __exit__(self, exctype: object, excvalue: object, traceback: object) -> bool: ...
class AsyncManager:
async def __aenter__(self) -> int: ...
async def __aexit__(self, exctype: object, excvalue: object, traceback: object) -> bool: ...
def noop() -> None: ...
async def f_bad_1() -> int:
async with RegularManager(): # E: "RegularManager" has no attribute "__aenter__"; maybe "__enter__"? \
# E: "RegularManager" has no attribute "__aexit__"; maybe "__exit__"?
return 3
noop() # E: Statement is unreachable
def f_bad_2() -> int:
with AsyncManager(): # E: "AsyncManager" has no attribute "__enter__"; maybe "__aenter__"? \
# E: "AsyncManager" has no attribute "__exit__"; maybe "__aexit__"?
return 3
noop() # E: Statement is unreachable
# TODO: We should consider reporting an error when the user tries using
# context manager with malformed signatures instead of silently continuing.
class RegularManagerMalformedSignature:
def __enter__(self) -> int: ...
def __exit__(self, exctype: object, excvalue: object, traceback: object) -> object: ...
class AsyncManagerMalformedSignature:
async def __aenter__(self) -> int: ...
async def __aexit__(self, exctype: object, excvalue: object, traceback: object) -> object: ...
def f_malformed_1() -> int:
with RegularManagerMalformedSignature():
return 3
noop() # E: Statement is unreachable
async def f_malformed_2() -> int:
async with AsyncManagerMalformedSignature():
return 3
noop() # E: Statement is unreachable
[typing fixtures/typing-full.pyi]
[builtins fixtures/tuple.pyi]
[case testUnreachableUntypedFunction]
# flags: --warn-unreachable
def test_untyped_fn(obj):
assert obj.prop is True
obj.update(prop=False)
obj.reload()
assert obj.prop is False
reveal_type(obj.prop)
def test_typed_fn(obj) -> None:
assert obj.prop is True
obj.update(prop=False)
obj.reload()
assert obj.prop is False
reveal_type(obj.prop) # E: Statement is unreachable
[case testUnreachableCheckedUntypedFunction]
# flags: --warn-unreachable --check-untyped-defs
def test_untyped_fn(obj):
assert obj.prop is True
obj.update(prop=False)
obj.reload()
assert obj.prop is False
reveal_type(obj.prop) # E: Statement is unreachable
[case testConditionalTypeVarException]
# every part of this test case was necessary to trigger the crash
import sys
from typing import TypeVar
T = TypeVar("T", int, str)
def f(t: T) -> None:
if sys.platform == "lol":
try:
pass
except BaseException as e:
pass
[builtins fixtures/dict.pyi]
[case testUnreachableLiteral]
# flags: --warn-unreachable
from typing_extensions import Literal
def nope() -> Literal[False]: ...
def f() -> None:
if nope():
x = 1 # E: Statement is unreachable
[builtins fixtures/dict.pyi]
[case testUnreachableLiteralFrom__bool__]
# flags: --warn-unreachable
from typing_extensions import Literal
class Truth:
def __bool__(self) -> Literal[True]: ...
class Lie:
def __bool__(self) -> Literal[False]: ...
class Maybe:
def __bool__(self) -> Literal[True | False]: ...
t = Truth()
if t:
x = 1
else:
x = 2 # E: Statement is unreachable
if Lie():
x = 3 # E: Statement is unreachable
if Maybe():
x = 4
def foo() -> bool: ...
y = Truth() or foo() # E: Right operand of "or" is never evaluated
z = Lie() and foo() # E: Right operand of "and" is never evaluated
[builtins fixtures/dict.pyi]
[case testUnreachableModuleBody1]
# flags: --warn-unreachable
from typing import NoReturn
def foo() -> NoReturn:
raise Exception("foo")
foo()
x = 1 # E: Statement is unreachable
[builtins fixtures/exception.pyi]
[case testUnreachableModuleBody2]
# flags: --warn-unreachable
raise Exception
x = 1 # E: Statement is unreachable
[builtins fixtures/exception.pyi]
[case testUnreachableNoReturnBinaryOps]
# flags: --warn-unreachable
from typing import NoReturn
a: NoReturn
a and 1 # E: Right operand of "and" is never evaluated
a or 1 # E: Right operand of "or" is never evaluated
a or a # E: Right operand of "or" is never evaluated
1 and a and 1 # E: Right operand of "and" is never evaluated
a and a # E: Right operand of "and" is never evaluated
[builtins fixtures/exception.pyi]
[case testUnreachableFlagWithTerminalBranchInDeferredNode]
# flags: --warn-unreachable
from typing import NoReturn
def assert_never(x: NoReturn) -> NoReturn: ...
def force_forward_ref() -> int:
return 4
def f(value: None) -> None:
x
if value is not None:
assert_never(value)
x = force_forward_ref()
[builtins fixtures/exception.pyi]
[case testSetitemNoReturn]
# flags: --warn-unreachable
from typing import NoReturn
class Foo:
def __setitem__(self, key: str, value: str) -> NoReturn:
raise Exception
Foo()['a'] = 'a'
x = 0 # E: Statement is unreachable
[builtins fixtures/exception.pyi]
[case TestNoImplicNoReturnFromError]
# flags: --warn-unreachable
from typing import TypeVar
T = TypeVar("T")
class Foo:
def __setitem__(self, key: str, value: str) -> T: # E: A function returning TypeVar should receive at least one argument containing the same TypeVar
raise Exception
def f() -> None:
Foo()['a'] = 'a'
x = 0 # This should not be reported as unreachable
[builtins fixtures/exception.pyi]
[case testIntentionallyEmptyGeneratorFunction]
# flags: --warn-unreachable
from typing import Generator
def f() -> Generator[None, None, None]:
return
yield
[case testIntentionallyEmptyGeneratorFunction_None]
# flags: --warn-unreachable
from typing import Generator
def f() -> Generator[None, None, None]:
return None
yield None