Skip to content

Commit 9cd1954

Browse files
rwbartonJukkaL
authored andcommitted
Make 'break' outside loop and similar errors blockers (#1714)
The type checker isn't equipped to deal with such errors currently, and having it ignore these errors silently on the basis that they should have been caught by semantic analysis is a bit sketchy. Fixes #1571.
1 parent 9b71668 commit 9cd1954

File tree

2 files changed

+20
-6
lines changed

2 files changed

+20
-6
lines changed

mypy/semanal.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1651,11 +1651,11 @@ def visit_for_stmt(self, s: ForStmt) -> None:
16511651

16521652
def visit_break_stmt(self, s: BreakStmt) -> None:
16531653
if self.loop_depth == 0:
1654-
self.fail("'break' outside loop", s, True)
1654+
self.fail("'break' outside loop", s, True, blocker=True)
16551655

16561656
def visit_continue_stmt(self, s: ContinueStmt) -> None:
16571657
if self.loop_depth == 0:
1658-
self.fail("'continue' outside loop", s, True)
1658+
self.fail("'continue' outside loop", s, True, blocker=True)
16591659

16601660
def visit_if_stmt(self, s: IfStmt) -> None:
16611661
infer_reachability_of_if_statement(s, pyversion=self.pyversion)
@@ -1783,7 +1783,7 @@ def visit_star_expr(self, expr: StarExpr) -> None:
17831783

17841784
def visit_yield_from_expr(self, e: YieldFromExpr) -> None:
17851785
if not self.is_func_scope(): # not sure
1786-
self.fail("'yield from' outside function", e)
1786+
self.fail("'yield from' outside function", e, True, blocker=True)
17871787
else:
17881788
self.function_stack[-1].is_generator = True
17891789
if e.expr:
@@ -2036,7 +2036,7 @@ def visit__promote_expr(self, expr: PromoteExpr) -> None:
20362036

20372037
def visit_yield_expr(self, expr: YieldExpr) -> None:
20382038
if not self.is_func_scope():
2039-
self.fail("'yield' outside function", expr)
2039+
self.fail("'yield' outside function", expr, True, blocker=True)
20402040
else:
20412041
self.function_stack[-1].is_generator = True
20422042
if expr.expr:
@@ -2250,13 +2250,14 @@ def name_not_defined(self, name: str, ctx: Context) -> None:
22502250
def name_already_defined(self, name: str, ctx: Context) -> None:
22512251
self.fail("Name '{}' already defined".format(name), ctx)
22522252

2253-
def fail(self, msg: str, ctx: Context, serious: bool = False) -> None:
2253+
def fail(self, msg: str, ctx: Context, serious: bool = False, *,
2254+
blocker: bool = False) -> None:
22542255
if (not serious and
22552256
not self.check_untyped_defs and
22562257
self.function_stack and
22572258
self.function_stack[-1].is_dynamic()):
22582259
return
2259-
self.errors.report(ctx.get_line(), msg)
2260+
self.errors.report(ctx.get_line(), msg, blocker=blocker)
22602261

22612262
def note(self, msg: str, ctx: Context) -> None:
22622263
if (not self.check_untyped_defs and

test-data/unit/check-semanal-error.test

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,16 @@ T = TypeVar('T')
6666
class C: # Forgot to add type params here
6767
def __init__(self, t: T) -> None: pass
6868
c = C(t=3) # type: C[int] # E: "C" expects no type arguments, but 1 given
69+
70+
[case testBreakOutsideLoop]
71+
break # E: 'break' outside loop
72+
73+
[case testContinueOutsideLoop]
74+
continue # E: 'continue' outside loop
75+
76+
[case testYieldOutsideFunction]
77+
yield # E: 'yield' outside function
78+
79+
[case testYieldFromOutsideFunction]
80+
x = 1
81+
yield from x # E: 'yield from' outside function

0 commit comments

Comments
 (0)