From d9a613e91d9543d52e112200aae5628a1b992807 Mon Sep 17 00:00:00 2001 From: avins Date: Fri, 8 Nov 2024 23:56:42 -0500 Subject: [PATCH 1/7] Added checks for invalid usage of continue/break/return in except* block --- mypy/semanal.py | 30 +++++++++++++++++++++- test-data/unit/check-except-star.test | 36 +++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 test-data/unit/check-except-star.test diff --git a/mypy/semanal.py b/mypy/semanal.py index 59e4594353f0..5f9fbb2f2465 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -484,6 +484,10 @@ def __init__( # Used to pass information about current overload index to visit_func_def(). self.current_overload_item: int | None = None + # Used to track whether currently inside an except* block. This helps + # to invoke errors when continue/break/return is used inside except * block. + self.is_in_except_block: bool = False + # mypyc doesn't properly handle implementing an abstractproperty # with a regular attribute so we make them properties @property @@ -854,6 +858,9 @@ def file_context( def visit_func_def(self, defn: FuncDef) -> None: self.statement = defn + was_in_except_block: bool = self.is_in_except_block + self.is_in_except_block = False + # Visit default values because they may contain assignment expressions. for arg in defn.arguments: if arg.initializer: @@ -874,11 +881,14 @@ def visit_func_def(self, defn: FuncDef) -> None: self.add_function_to_symbol_table(defn) if not self.recurse_into_functions: + self.is_in_except_block = was_in_except_block return with self.scope.function_scope(defn): self.analyze_func_def(defn) + self.is_in_except_block = was_in_except_block + def function_fullname(self, fullname: str) -> str: if self.current_overload_item is None: return fullname @@ -5263,6 +5273,8 @@ def visit_return_stmt(self, s: ReturnStmt) -> None: self.statement = s if not self.is_func_scope(): self.fail('"return" outside function', s) + if self.is_in_except_block: + self.fail('"return" not allowed in except* block', s, serious=True, blocker=True) if s.expr: s.expr.accept(self) @@ -5295,9 +5307,12 @@ def visit_operator_assignment_stmt(self, s: OperatorAssignmentStmt) -> None: def visit_while_stmt(self, s: WhileStmt) -> None: self.statement = s s.expr.accept(self) + was_in_except_block: bool = self.is_in_except_block + self.is_in_except_block = False self.loop_depth[-1] += 1 s.body.accept(self) self.loop_depth[-1] -= 1 + self.is_in_except_block = was_in_except_block self.visit_block_maybe(s.else_body) def visit_for_stmt(self, s: ForStmt) -> None: @@ -5319,9 +5334,12 @@ def visit_for_stmt(self, s: ForStmt) -> None: self.store_declared_types(s.index, analyzed) s.index_type = analyzed + was_in_except_block: bool = self.is_in_except_block + self.is_in_except_block = False self.loop_depth[-1] += 1 self.visit_block(s.body) self.loop_depth[-1] -= 1 + self.is_in_except_block = was_in_except_block self.visit_block_maybe(s.else_body) @@ -5329,11 +5347,15 @@ def visit_break_stmt(self, s: BreakStmt) -> None: self.statement = s if self.loop_depth[-1] == 0: self.fail('"break" outside loop', s, serious=True, blocker=True) + if self.is_in_except_block: + self.fail('"break" not allowed in except* block', s, serious=True, blocker=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.is_in_except_block: + self.fail('"continue" not allowed in except* block', s, serious=True, blocker=True) def visit_if_stmt(self, s: IfStmt) -> None: self.statement = s @@ -5354,7 +5376,13 @@ def analyze_try_stmt(self, s: TryStmt, visitor: NodeVisitor[None]) -> None: type.accept(visitor) if var: self.analyze_lvalue(var) - handler.accept(visitor) + if s.is_star: + was_in_except_block: bool = self.is_in_except_block + self.is_in_except_block = True + handler.accept(visitor) + self.is_in_except_block = was_in_except_block + else: + handler.accept(visitor) if s.else_body: s.else_body.accept(visitor) if s.finally_body: diff --git a/test-data/unit/check-except-star.test b/test-data/unit/check-except-star.test new file mode 100644 index 000000000000..bdd1a730f911 --- /dev/null +++ b/test-data/unit/check-except-star.test @@ -0,0 +1,36 @@ +[case testExceptStarForbiddenBasic] +# flags: --python-version 3.11 +[builtins fixtures/exception.pyi] +def foo() -> None: + for _ in range(5): + try: + ... + except* Exception: + continue # E: "continue" not allowed in except* block + except* ValueError: + for _ in range(2): + continue + break # E: "break" not allowed in except* block + except* TypeError: + return # E: "return" not allowed in except* block + +[case testExceptStarForbiddenEdgeCases] +# flags: --python-version 3.11 +[builtins fixtures/exception.pyi] +def foo2(): + while True: + try: + ... + except* ValueError: + def inner(): + while True: + if 1 < 1: + continue + else: + break + return + if 1 < 2: + break # E: "break" not allowed in except* block + if 1 < 2: + continue # E: "continue" not allowed in except* block + return # E: "return" not allowed in except* block From c947ec79ed9b26e9702cb00f46f2bb25ec736a1e Mon Sep 17 00:00:00 2001 From: avins Date: Sat, 9 Nov 2024 23:47:53 -0500 Subject: [PATCH 2/7] used context manager to manage flag, updated unit tests --- mypy/semanal.py | 48 ++++++++++++-------------- test-data/unit/check-except-star.test | 36 -------------------- test-data/unit/check-python311.test | 49 +++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 63 deletions(-) delete mode 100644 test-data/unit/check-except-star.test diff --git a/mypy/semanal.py b/mypy/semanal.py index 5f9fbb2f2465..7d01c3b9c1ac 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -485,8 +485,8 @@ def __init__( self.current_overload_item: int | None = None # Used to track whether currently inside an except* block. This helps - # to invoke errors when continue/break/return is used inside except * block. - self.is_in_except_block: bool = False + # to invoke errors when continue/break/return is used inside except* block. + self.inside_except_star_block: bool = False # mypyc doesn't properly handle implementing an abstractproperty # with a regular attribute so we make them properties @@ -515,6 +515,15 @@ def allow_unbound_tvars_set(self) -> Iterator[None]: finally: self.allow_unbound_tvars = old + @contextmanager + def inside_except_star_block_set(self, value: bool) -> Iterator[None]: + old = self.inside_except_star_block + self.inside_except_star_block = value + try: + yield + finally: + self.inside_except_star_block = old + # # Preparing module (performed before semantic analysis) # @@ -858,9 +867,6 @@ def file_context( def visit_func_def(self, defn: FuncDef) -> None: self.statement = defn - was_in_except_block: bool = self.is_in_except_block - self.is_in_except_block = False - # Visit default values because they may contain assignment expressions. for arg in defn.arguments: if arg.initializer: @@ -881,13 +887,11 @@ def visit_func_def(self, defn: FuncDef) -> None: self.add_function_to_symbol_table(defn) if not self.recurse_into_functions: - self.is_in_except_block = was_in_except_block return with self.scope.function_scope(defn): - self.analyze_func_def(defn) - - self.is_in_except_block = was_in_except_block + with self.inside_except_star_block_set(False): + self.analyze_func_def(defn) def function_fullname(self, fullname: str) -> str: if self.current_overload_item is None: @@ -5273,7 +5277,7 @@ def visit_return_stmt(self, s: ReturnStmt) -> None: self.statement = s if not self.is_func_scope(): self.fail('"return" outside function', s) - if self.is_in_except_block: + if self.inside_except_star_block: self.fail('"return" not allowed in except* block', s, serious=True, blocker=True) if s.expr: s.expr.accept(self) @@ -5307,12 +5311,10 @@ def visit_operator_assignment_stmt(self, s: OperatorAssignmentStmt) -> None: def visit_while_stmt(self, s: WhileStmt) -> None: self.statement = s s.expr.accept(self) - was_in_except_block: bool = self.is_in_except_block - self.is_in_except_block = False self.loop_depth[-1] += 1 - s.body.accept(self) + with self.inside_except_star_block_set(False): + s.body.accept(self) self.loop_depth[-1] -= 1 - self.is_in_except_block = was_in_except_block self.visit_block_maybe(s.else_body) def visit_for_stmt(self, s: ForStmt) -> None: @@ -5334,27 +5336,24 @@ def visit_for_stmt(self, s: ForStmt) -> None: self.store_declared_types(s.index, analyzed) s.index_type = analyzed - was_in_except_block: bool = self.is_in_except_block - self.is_in_except_block = False self.loop_depth[-1] += 1 - self.visit_block(s.body) + with self.inside_except_star_block_set(False): + self.visit_block(s.body) self.loop_depth[-1] -= 1 - self.is_in_except_block = was_in_except_block - self.visit_block_maybe(s.else_body) def visit_break_stmt(self, s: BreakStmt) -> None: self.statement = s if self.loop_depth[-1] == 0: self.fail('"break" outside loop', s, serious=True, blocker=True) - if self.is_in_except_block: + if self.inside_except_star_block: self.fail('"break" not allowed in except* block', s, serious=True, blocker=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.is_in_except_block: + if self.inside_except_star_block: self.fail('"continue" not allowed in except* block', s, serious=True, blocker=True) def visit_if_stmt(self, s: IfStmt) -> None: @@ -5376,12 +5375,7 @@ def analyze_try_stmt(self, s: TryStmt, visitor: NodeVisitor[None]) -> None: type.accept(visitor) if var: self.analyze_lvalue(var) - if s.is_star: - was_in_except_block: bool = self.is_in_except_block - self.is_in_except_block = True - handler.accept(visitor) - self.is_in_except_block = was_in_except_block - else: + with self.inside_except_star_block_set(s.is_star): handler.accept(visitor) if s.else_body: s.else_body.accept(visitor) diff --git a/test-data/unit/check-except-star.test b/test-data/unit/check-except-star.test deleted file mode 100644 index bdd1a730f911..000000000000 --- a/test-data/unit/check-except-star.test +++ /dev/null @@ -1,36 +0,0 @@ -[case testExceptStarForbiddenBasic] -# flags: --python-version 3.11 -[builtins fixtures/exception.pyi] -def foo() -> None: - for _ in range(5): - try: - ... - except* Exception: - continue # E: "continue" not allowed in except* block - except* ValueError: - for _ in range(2): - continue - break # E: "break" not allowed in except* block - except* TypeError: - return # E: "return" not allowed in except* block - -[case testExceptStarForbiddenEdgeCases] -# flags: --python-version 3.11 -[builtins fixtures/exception.pyi] -def foo2(): - while True: - try: - ... - except* ValueError: - def inner(): - while True: - if 1 < 1: - continue - else: - break - return - if 1 < 2: - break # E: "break" not allowed in except* block - if 1 < 2: - continue # E: "continue" not allowed in except* block - return # E: "return" not allowed in except* block diff --git a/test-data/unit/check-python311.test b/test-data/unit/check-python311.test index 28951824999f..1362c3ac950d 100644 --- a/test-data/unit/check-python311.test +++ b/test-data/unit/check-python311.test @@ -173,3 +173,52 @@ Alias4 = Callable[[*IntList], int] # E: "List[int]" cannot be unpacked (must be x4: Alias4[int] # E: Bad number of arguments for type alias, expected 0, given 1 reveal_type(x4) # N: Revealed type is "def (*Any) -> builtins.int" [builtins fixtures/tuple.pyi] + +[case testReturnInExceptStarBlock] +# flags: --python-version 3.11 +def foo() -> None: + try: + pass + except* Exception: + return # E: "return" not allowed in except* block + finally: + return +[builtins fixtures/exception.pyi] + +[case testBreakContinueReturnInExceptStarBlock1] +# flags: --python-version 3.11 +class range: pass +def foo() -> None: + for _ in range(5): + try: + pass + except* Exception: + continue # E: "continue" not allowed in except* block + except* Exception: + for _ in range(2): + continue + break # E: "break" not allowed in except* block + except* Exception: + return # E: "return" not allowed in except* block +[builtins fixtures/exception.pyi] + +[case testBreakContinueReturnInExceptStarBlock2] +# flags: --python-version 3.11 +def foo(): + while True: + try: + pass + except* Exception: + def inner(): + while True: + if 1 < 1: + continue + else: + break + return + if 1 < 2: + break # E: "break" not allowed in except* block + if 1 < 2: + continue # E: "continue" not allowed in except* block + return # E: "return" not allowed in except* block +[builtins fixtures/exception.pyi] \ No newline at end of file From d65b1b8c688b35c14aac11e280d8111f317eb597 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 10 Nov 2024 04:48:32 +0000 Subject: [PATCH 3/7] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- test-data/unit/check-python311.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/unit/check-python311.test b/test-data/unit/check-python311.test index 1362c3ac950d..dcc5bc46a3d4 100644 --- a/test-data/unit/check-python311.test +++ b/test-data/unit/check-python311.test @@ -221,4 +221,4 @@ def foo(): if 1 < 2: continue # E: "continue" not allowed in except* block return # E: "return" not allowed in except* block -[builtins fixtures/exception.pyi] \ No newline at end of file +[builtins fixtures/exception.pyi] From bde474958a18866efa52130690ce4ff603e209be Mon Sep 17 00:00:00 2001 From: avins Date: Sun, 10 Nov 2024 10:32:29 -0500 Subject: [PATCH 4/7] added check for edge case when return stmt inside loop can affect control flow in except* block --- mypy/semanal.py | 22 +++++++++++++++++----- test-data/unit/check-python311.test | 13 ++++++++++++- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/mypy/semanal.py b/mypy/semanal.py index 7d01c3b9c1ac..384510525dc0 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -487,6 +487,8 @@ def __init__( # Used to track whether currently inside an except* block. This helps # to invoke errors when continue/break/return is used inside except* block. self.inside_except_star_block: bool = False + # Used to track edge case when return is still inside except* if it enters a loop + self.return_stmt_inside_except_star_block: bool = False # mypyc doesn't properly handle implementing an abstractproperty # with a regular attribute so we make them properties @@ -516,13 +518,23 @@ def allow_unbound_tvars_set(self) -> Iterator[None]: self.allow_unbound_tvars = old @contextmanager - def inside_except_star_block_set(self, value: bool) -> Iterator[None]: + def inside_except_star_block_set( + self, value: bool, enteringLoop: 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: + 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: + self.return_stmt_inside_except_star_block = old_return_stmt_flag # # Preparing module (performed before semantic analysis) @@ -890,7 +902,7 @@ def visit_func_def(self, defn: FuncDef) -> None: return with self.scope.function_scope(defn): - with self.inside_except_star_block_set(False): + with self.inside_except_star_block_set(value=False): self.analyze_func_def(defn) def function_fullname(self, fullname: str) -> str: @@ -5277,7 +5289,7 @@ def visit_return_stmt(self, s: ReturnStmt) -> None: self.statement = s if not self.is_func_scope(): self.fail('"return" outside function', s) - if self.inside_except_star_block: + if self.return_stmt_inside_except_star_block: self.fail('"return" not allowed in except* block', s, serious=True, blocker=True) if s.expr: s.expr.accept(self) @@ -5312,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(False): + with self.inside_except_star_block_set(value=False, enteringLoop=True): s.body.accept(self) self.loop_depth[-1] -= 1 self.visit_block_maybe(s.else_body) @@ -5337,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(False): + with self.inside_except_star_block_set(value=False, enteringLoop=True): self.visit_block(s.body) self.loop_depth[-1] -= 1 self.visit_block_maybe(s.else_body) diff --git a/test-data/unit/check-python311.test b/test-data/unit/check-python311.test index dcc5bc46a3d4..20cf968b6c77 100644 --- a/test-data/unit/check-python311.test +++ b/test-data/unit/check-python311.test @@ -174,7 +174,7 @@ x4: Alias4[int] # E: Bad number of arguments for type alias, expected 0, given reveal_type(x4) # N: Revealed type is "def (*Any) -> builtins.int" [builtins fixtures/tuple.pyi] -[case testReturnInExceptStarBlock] +[case testReturnInExceptStarBlock1] # flags: --python-version 3.11 def foo() -> None: try: @@ -185,6 +185,17 @@ def foo() -> None: return [builtins fixtures/exception.pyi] +[case testReturnInExceptStarBlock2] +# flags: --python-version 3.11 +def foo(): + while True: + try: + pass + except* Exception: + while True: + return # E: "return" not allowed in except* block +[builtins fixtures/exception.pyi] + [case testBreakContinueReturnInExceptStarBlock1] # flags: --python-version 3.11 class range: pass From 13d88a22a1bd55b17dd12d018da826a623c4ca2c Mon Sep 17 00:00:00 2001 From: avins Date: Tue, 12 Nov 2024 14:19:35 -0500 Subject: [PATCH 5/7] Added edge case for invalid control flow in except block nested inside except* block, other minor fixes --- mypy/semanal.py | 18 ++++++++--------- test-data/unit/check-python311.test | 31 ++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/mypy/semanal.py b/mypy/semanal.py index 384510525dc0..1f5f31d59e32 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -519,13 +519,13 @@ 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 @@ -533,7 +533,7 @@ def inside_except_star_block_set( 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 # @@ -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) @@ -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) @@ -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) @@ -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 @@ -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) diff --git a/test-data/unit/check-python311.test b/test-data/unit/check-python311.test index 20cf968b6c77..7e9907460db7 100644 --- a/test-data/unit/check-python311.test +++ b/test-data/unit/check-python311.test @@ -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 + def foo() -> None: for _ in range(5): try: From 3b765f237ffa1c84fe414e12fc7489977e6b5f3a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 12 Nov 2024 19:20:12 +0000 Subject: [PATCH 6/7] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- test-data/unit/check-python311.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/unit/check-python311.test b/test-data/unit/check-python311.test index 7e9907460db7..6c66548a269a 100644 --- a/test-data/unit/check-python311.test +++ b/test-data/unit/check-python311.test @@ -225,7 +225,7 @@ def foo(): [case testBreakContinueReturnInExceptStarBlock1] # flags: --python-version 3.11 from typing import Sequence -class range(Sequence[int]): +class range(Sequence[int]): def __init__(self, __x: int, __y: int = ..., __z: int = ...) -> None: pass def foo() -> None: From 9ee65f3596577844d32bfc25072c24097c4a5ea5 Mon Sep 17 00:00:00 2001 From: avins Date: Wed, 13 Nov 2024 20:41:41 -0500 Subject: [PATCH 7/7] Updated unit test to use dummy iterable --- test-data/unit/check-python311.test | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/test-data/unit/check-python311.test b/test-data/unit/check-python311.test index 7e9907460db7..6f4c540572b0 100644 --- a/test-data/unit/check-python311.test +++ b/test-data/unit/check-python311.test @@ -224,18 +224,15 @@ def foo(): [case testBreakContinueReturnInExceptStarBlock1] # flags: --python-version 3.11 -from typing import Sequence -class range(Sequence[int]): - def __init__(self, __x: int, __y: int = ..., __z: int = ...) -> None: pass - -def foo() -> None: - for _ in range(5): +from typing import Iterable +def foo(x: Iterable[int]) -> None: + for _ in x: try: pass except* Exception: continue # E: "continue" not allowed in except* block except* Exception: - for _ in range(2): + for _ in x: continue break # E: "break" not allowed in except* block except* Exception: