Skip to content

Commit 2344f41

Browse files
committed
Handle 'while True', 'assert False'
1 parent 01fed1a commit 2344f41

File tree

3 files changed

+115
-3
lines changed

3 files changed

+115
-3
lines changed

mypy/checker.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,9 @@ def accept_loop(self, body: Node, else_body: Node = None, *,
246246
_, else_map = find_isinstance_check(
247247
exit_condition, self.type_map, self.typing_mode_weak()
248248
)
249-
if else_map:
249+
if else_map is None:
250+
self.binder.unreachable()
251+
else:
250252
for var, type in else_map.items():
251253
self.binder.push(var, type)
252254
if else_body:
@@ -1500,7 +1502,9 @@ def visit_assert_stmt(self, s: AssertStmt) -> Type:
15001502
self.typing_mode_weak()
15011503
)
15021504

1503-
if true_map:
1505+
if true_map is None:
1506+
self.binder.unreachable()
1507+
else:
15041508
for var, type in true_map.items():
15051509
self.binder.push(var, type)
15061510

@@ -2183,6 +2187,16 @@ def conditional_type_map(expr: Node,
21832187
return {}, {}
21842188

21852189

2190+
def is_true_literal(n: Node) -> bool:
2191+
return (refers_to_fullname(n, 'builtins.True')
2192+
or isinstance(n, IntExpr) and n.value == 1)
2193+
2194+
2195+
def is_false_literal(n: Node) -> bool:
2196+
return (refers_to_fullname(n, 'builtins.False')
2197+
or isinstance(n, IntExpr) and n.value == 0)
2198+
2199+
21862200
def is_literal_none(n: Node) -> bool:
21872201
return isinstance(n, NameExpr) and n.fullname == 'builtins.None'
21882202

@@ -2246,7 +2260,11 @@ def find_isinstance_check(node: Node,
22462260
22472261
Guaranteed to not return None, None. (But may return {}, {})
22482262
"""
2249-
if isinstance(node, CallExpr):
2263+
if is_true_literal(node):
2264+
return {}, None
2265+
elif is_false_literal(node):
2266+
return None, {}
2267+
elif isinstance(node, CallExpr):
22502268
if refers_to_fullname(node.callee, 'builtins.isinstance'):
22512269
expr = node.args[0]
22522270
if expr.literal == LITERAL_TYPE:

test-data/unit/check-isinstance.test

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -985,6 +985,89 @@ while bool():
985985
x + 'a'
986986
[builtins fixtures/isinstance.py]
987987

988+
[case testUnreachableWhileTrue]
989+
def f(x: int) -> None:
990+
while True:
991+
if x:
992+
return
993+
1()
994+
[builtins fixtures/bool.py]
995+
996+
[case testUnreachableAssertFalse]
997+
def f() -> None:
998+
assert False
999+
1()
1000+
[builtins fixtures/bool.py]
1001+
1002+
[case testUnreachableAssertFalse2]
1003+
# flags: fast-parser
1004+
def f() -> None:
1005+
# The old parser doesn't understand the syntax below
1006+
assert False, "hi"
1007+
1()
1008+
[builtins fixtures/bool.py]
1009+
1010+
[case testUnreachableReturnOrAssertFalse]
1011+
def f(x: int) -> int:
1012+
if x:
1013+
return x
1014+
else:
1015+
assert False
1016+
1()
1017+
[builtins fixtures/bool.py]
1018+
1019+
[case testUnreachableTryExcept]
1020+
def f() -> None:
1021+
try:
1022+
f()
1023+
return
1024+
except BaseException:
1025+
return
1026+
1()
1027+
[builtins fixtures/exception.py]
1028+
1029+
[case testUnreachableTryExceptElse]
1030+
def f() -> None:
1031+
try:
1032+
f()
1033+
except BaseException:
1034+
return
1035+
else:
1036+
return
1037+
1()
1038+
[builtins fixtures/exception.py]
1039+
1040+
[case testUnreachableTryReturnFinally1]
1041+
def f() -> None:
1042+
try:
1043+
return
1044+
finally:
1045+
pass
1046+
1()
1047+
1048+
[case testUnreachableTryReturnFinally2]
1049+
def f() -> None:
1050+
try:
1051+
pass
1052+
finally:
1053+
return
1054+
1()
1055+
1056+
[case testUnreachableTryReturnExceptRaise]
1057+
def f() -> None:
1058+
try:
1059+
return
1060+
except:
1061+
raise
1062+
1()
1063+
1064+
[case testUnreachableReturnLambda]
1065+
from typing import Callable
1066+
def g(t: Callable[[int], int]) -> int: pass
1067+
def f() -> int:
1068+
return g(lambda x: x)
1069+
1()
1070+
9881071
[case testIsinstanceAnd]
9891072
class A:
9901073
pass

test-data/unit/check-modules.test

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,17 @@ from a import x
812812
x = 0
813813
[out]
814814

815+
[case testIfFalseImport]
816+
if False:
817+
import a
818+
def f(x: 'a.A') -> int:
819+
return x.f()
820+
[file a.py]
821+
class A:
822+
def f(self) -> int:
823+
return 0
824+
[builtins fixtures/bool.py]
825+
815826

816827
-- Test stability under import cycles
817828
-- ----------------------------------

0 commit comments

Comments
 (0)