Skip to content
18 changes: 9 additions & 9 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -519,21 +519,21 @@ def allow_unbound_tvars_set(self) -> Iterator[None]:

@contextmanager
def inside_except_star_block_set(
self, value: bool, enteringLoop: bool = False
self, value: bool, entering_loop: bool = False
) -> Iterator[None]:
old = self.inside_except_star_block
self.inside_except_star_block = value

# Return statement would still be in except* scope if entering loops
if not enteringLoop:
if not entering_loop:
old_return_stmt_flag = self.return_stmt_inside_except_star_block
self.return_stmt_inside_except_star_block = value

try:
yield
finally:
self.inside_except_star_block = old
if not enteringLoop:
if not entering_loop:
self.return_stmt_inside_except_star_block = old_return_stmt_flag

#
Expand Down Expand Up @@ -5290,7 +5290,7 @@ def visit_return_stmt(self, s: ReturnStmt) -> None:
if not self.is_func_scope():
self.fail('"return" outside function', s)
if self.return_stmt_inside_except_star_block:
self.fail('"return" not allowed in except* block', s, serious=True, blocker=True)
self.fail('"return" not allowed in except* block', s, serious=True)
if s.expr:
s.expr.accept(self)

Expand Down Expand Up @@ -5324,7 +5324,7 @@ def visit_while_stmt(self, s: WhileStmt) -> None:
self.statement = s
s.expr.accept(self)
self.loop_depth[-1] += 1
with self.inside_except_star_block_set(value=False, enteringLoop=True):
with self.inside_except_star_block_set(value=False, entering_loop=True):
s.body.accept(self)
self.loop_depth[-1] -= 1
self.visit_block_maybe(s.else_body)
Expand All @@ -5349,7 +5349,7 @@ def visit_for_stmt(self, s: ForStmt) -> None:
s.index_type = analyzed

self.loop_depth[-1] += 1
with self.inside_except_star_block_set(value=False, enteringLoop=True):
with self.inside_except_star_block_set(value=False, entering_loop=True):
self.visit_block(s.body)
self.loop_depth[-1] -= 1
self.visit_block_maybe(s.else_body)
Expand All @@ -5359,14 +5359,14 @@ def visit_break_stmt(self, s: BreakStmt) -> None:
if self.loop_depth[-1] == 0:
self.fail('"break" outside loop', s, serious=True, blocker=True)
if self.inside_except_star_block:
self.fail('"break" not allowed in except* block', s, serious=True, blocker=True)
self.fail('"break" not allowed in except* block', s, serious=True)

def visit_continue_stmt(self, s: ContinueStmt) -> None:
self.statement = s
if self.loop_depth[-1] == 0:
self.fail('"continue" outside loop', s, serious=True, blocker=True)
if self.inside_except_star_block:
self.fail('"continue" not allowed in except* block', s, serious=True, blocker=True)
self.fail('"continue" not allowed in except* block', s, serious=True)

def visit_if_stmt(self, s: IfStmt) -> None:
self.statement = s
Expand All @@ -5387,7 +5387,7 @@ def analyze_try_stmt(self, s: TryStmt, visitor: NodeVisitor[None]) -> None:
type.accept(visitor)
if var:
self.analyze_lvalue(var)
with self.inside_except_star_block_set(s.is_star):
with self.inside_except_star_block_set(self.inside_except_star_block or s.is_star):
handler.accept(visitor)
if s.else_body:
s.else_body.accept(visitor)
Expand Down
31 changes: 30 additions & 1 deletion test-data/unit/check-python311.test
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,38 @@ def foo():
return # E: "return" not allowed in except* block
[builtins fixtures/exception.pyi]

[case testContinueInExceptBlockNestedInExceptStarBlock]
# flags: --python-version 3.11
while True:
try:
...
except* Exception:
try:
...
except Exception:
continue # E: "continue" not allowed in except* block
continue # E: "continue" not allowed in except* block
[builtins fixtures/exception.pyi]

[case testReturnInExceptBlockNestedInExceptStarBlock]
# flags: --python-version 3.11
def foo():
try:
...
except* Exception:
try:
...
except Exception:
return # E: "return" not allowed in except* block
return # E: "return" not allowed in except* block
[builtins fixtures/exception.pyi]

[case testBreakContinueReturnInExceptStarBlock1]
# flags: --python-version 3.11
class range: pass
from typing import Sequence
class range(Sequence[int]):
def __init__(self, __x: int, __y: int = ..., __z: int = ...) -> None: pass
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be replaced by a dummy list?


def foo() -> None:
for _ in range(5):
try:
Expand Down
Loading