Skip to content

Commit 22ce0d6

Browse files
committed
Mark code after for loops that never end as unreachable
1 parent 8667022 commit 22ce0d6

File tree

2 files changed

+39
-0
lines changed

2 files changed

+39
-0
lines changed

mypy/checker.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5108,12 +5108,31 @@ def visit_for_stmt(self, s: ForStmt) -> None:
51085108
s.inferred_item_type = item_type
51095109
s.inferred_iterator_type = iterator_type
51105110

5111+
proper_iter_type = get_proper_type(iterator_type)
5112+
if isinstance(proper_iter_type, Instance) and proper_iter_type.type.fullname in (
5113+
"typing.Generator",
5114+
"types.GeneratorType",
5115+
):
5116+
supertype = self.named_type("typing.Generator").type
5117+
super_instance = map_instance_to_supertype(proper_iter_type, supertype)
5118+
if isinstance(get_proper_type(super_instance.args[2]), UninhabitedType):
5119+
exit_condition = NameExpr("True")
5120+
exit_condition.fullname = "builtins.True"
5121+
print("woohoo!")
5122+
else:
5123+
exit_condition = NameExpr("False")
5124+
exit_condition.fullname = "builtins.False"
5125+
else:
5126+
exit_condition = NameExpr("False")
5127+
exit_condition.fullname = "builtins.False"
5128+
51115129
self.accept_loop(
51125130
s.body,
51135131
s.else_body,
51145132
on_enter_body=lambda: self.analyze_index_variables(
51155133
s.index, item_type, s.index_type is None, s
51165134
),
5135+
exit_condition=exit_condition,
51175136
)
51185137

51195138
def analyze_async_iterable_item_type(self, expr: Expression) -> tuple[Type, Type]:

test-data/unit/check-unreachable-code.test

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1587,3 +1587,23 @@ x = 0 # not unreachable
15871587

15881588
f2: Callable[[], NoReturn] = lambda: foo()
15891589
x = 0 # not unreachable
1590+
1591+
[case testUnendingForLoop]
1592+
# flags: --warn-unreachable
1593+
from typing import Generator, NoReturn
1594+
1595+
def generator() -> Generator[int, None, NoReturn]:
1596+
while True:
1597+
yield 1
1598+
1599+
def foo() -> int:
1600+
for x in generator():
1601+
return x
1602+
1603+
y = 0 # E: Statement is unreachable
1604+
1605+
def bar() -> int: # E: Missing return statement
1606+
for x in generator():
1607+
break
1608+
1609+
y = 0

0 commit comments

Comments
 (0)