From 0a436d3c2519c8aa62bc182bb198720d9ffad790 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Sat, 13 Sep 2025 02:11:39 +0000 Subject: [PATCH 01/14] feat: index range err code --- mypy/checkexpr.py | 39 ++++++++++ mypy/errorcodes.py | 7 ++ mypy/exprlength.py | 154 +++++++++++++++++++++++++++++++++++++++ mypy/message_registry.py | 5 ++ 4 files changed, 205 insertions(+) create mode 100644 mypy/exprlength.py diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 73282c94be4eb..d3621ede7ffa1 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -26,6 +26,7 @@ freshen_all_functions_type_vars, freshen_function_type_vars, ) +from mypy.exprlength import get_static_expr_length from mypy.infer import ArgumentInferContext, infer_function_type_arguments, infer_type_arguments from mypy.literals import literal from mypy.maptype import map_instance_to_supertype @@ -4450,6 +4451,7 @@ def visit_index_with_type( # Allow special forms to be indexed and used to create union types return self.named_type("typing._SpecialForm") else: + self.static_index_range_check(left_type, e, index) result, method_type = self.check_method_call_by_name( "__getitem__", left_type, @@ -4472,6 +4474,43 @@ def min_tuple_length(self, left: TupleType) -> int: return left.length() - 1 + unpack.type.min_len return left.length() - 1 + def static_index_range_check(self, left_type: Type, e: IndexExpr, index: Expression): + if isinstance(left_type, Instance) and left_type.type.fullname in ( + "builtins.list", "builtins.set", "builtins.dict", "builtins.str", "builtins.bytes" + ): + idx_val = None + # Try to extract integer literal index + if isinstance(index, IntExpr): + idx_val = index.value + elif isinstance(index, UnaryExpr): + if index.op == "-": + operand = index.expr + if isinstance(operand, IntExpr): + idx_val = -operand.value + elif index.op == "+": + operand = index.expr + if isinstance(operand, IntExpr): + idx_val = operand.value + # Could add more cases (e.g. LiteralType) if desired + if idx_val is not None: + length = get_static_expr_length(e.base) + if length is not None: + # For negative indices, Python counts from the end + check_idx = idx_val + if check_idx < 0: + check_idx += length + if not (0 <= check_idx < length): + name = "" + if isinstance(e.base, NameExpr): + name = e.base.name + self.chk.fail( + message_registry.SEQUENCE_INDEX_OUT_OF_RANGE.format( + name=name or "", length=length + ), + e, + code=message_registry.SEQUENCE_INDEX_OUT_OF_RANGE.code, + ) + def visit_tuple_index_helper(self, left: TupleType, n: int) -> Type | None: unpack_index = find_unpack_in_list(left.items) if unpack_index is None: diff --git a/mypy/errorcodes.py b/mypy/errorcodes.py index bcfdbf6edc2bf..601b823f18268 100644 --- a/mypy/errorcodes.py +++ b/mypy/errorcodes.py @@ -326,5 +326,12 @@ def __hash__(self) -> int: default_enabled=False, ) +INDEX_RANGE = ErrorCode( + "index-range", + "index out of statically known range", + "Index Range", + True, +) + # This copy will not include any error codes defined later in the plugins. mypy_error_codes = error_codes.copy() diff --git a/mypy/exprlength.py b/mypy/exprlength.py new file mode 100644 index 0000000000000..ef1168c89e51d --- /dev/null +++ b/mypy/exprlength.py @@ -0,0 +1,154 @@ +"""Static expression length analysis utilities for mypy. + +Provides helpers for statically determining the length of expressions, +when possible. +""" + +from typing import List, Optional, Tuple +from mypy.nodes import ( + Expression, + ExpressionStmt, + ForStmt, + GeneratorExpr, + IfStmt, + ListComprehension, + ListExpr, + TupleExpr, + SetExpr, + WhileStmt, + DictExpr, + MemberExpr, + StrExpr, + StarExpr, + BytesExpr, + CallExpr, + NameExpr, + TryStmt, + Block, + AssignmentStmt, + is_IntExpr_list, +) +from mypy.nodes import WithStmt, FuncDef, OverloadedFuncDef, ClassDef, GlobalDecl, NonlocalDecl +from mypy.nodes import ARG_POS + +def get_static_expr_length(expr: Expression, context: Optional[Block] = None) -> Optional[int]: + """Try to statically determine the length of an expression. + + Returns the length if it can be determined at type-check time, + otherwise returns None. + + If context is provided, will attempt to resolve NameExpr/Var assignments. + """ + # NOTE: currently only used for indexing but could be extended to flag + # fun things like list.pop or to allow len([1, 2, 3]) to type check as Literal[3] + + # List, tuple literals (with possible star expressions) + if isinstance(expr, (ListExpr, TupleExpr)): + # if there are no star expressions, or we know the length of them, + # we know the length of the expression + stars = [get_static_expr_length(i, context) for i in expr.items if isinstance(i, StarExpr)] + other = sum(not isinstance(i, StarExpr) for i in expr.items) + return other + sum(star for star in stars if star is not None) + elif isinstance(expr, SetExpr): + # TODO: set expressions are more complicated, you need to know the + # actual value of each item in order to confidently state its length + pass + elif isinstance(expr, DictExpr): + # TODO: same as with sets, dicts are more complicated since you need + # to know the specific value of each key, and ensure they don't collide + pass + # String or bytes literal + elif isinstance(expr, (StrExpr, BytesExpr)): + return len(expr.value) + elif isinstance(expr, ListComprehension): + # If the generator's length is known, the list's length is known + return get_static_expr_length(expr.generator, context) + elif isinstance(expr, GeneratorExpr): + # If there is only one sequence and no conditions, and we know + # the sequence length, we know the max number of items yielded + # from the genexp and can pass that info forward + if len(expr.sequences) == 1 and len(expr.condlists) == 0: + return get_static_expr_length(expr.sequences[0], context) + # range() with constant arguments + elif isinstance(expr, CallExpr): + callee = expr.callee + if isinstance(callee, NameExpr) and callee.fullname == "builtins.range": + args = expr.args + if is_IntExpr_list(args) and all(kind == ARG_POS for kind in expr.arg_kinds): + if len(args) == 1: + # range(stop) + stop = args[0].value + return max(0, stop) + elif len(args) == 2: + # range(start, stop) + start, stop = args[0].value, args[1].value + return max(0, stop - start) + elif len(args) == 3: + # range(start, stop, step) + start, stop, step = args[0].value, args[1].value, args[2].value + if step == 0: + return None + n = (stop - start + (step - (1 if step > 0 else -1))) // step + return max(0, n) + # We have a big spaghetti monster of special case logic to resolve name expressions + elif isinstance(expr, NameExpr): + # Try to resolve the value of a local variable if possible + if context is None: + # Cannot resolve without context + return None + assignments: List[Tuple[AssignmentStmt, int]] = [] + + # Iterate thru all statements in the block + for stmt in context.body: + if isinstance(stmt, (IfStmt, ForStmt, WhileStmt, TryStmt, WithStmt, FuncDef, OverloadedFuncDef, ClassDef)): + # These statements complicate things and render the whole block useless + return None + elif isinstance(stmt, (GlobalDecl, NonlocalDecl)) and expr.name in stmt.names: + # We cannot assure the value of a global or nonlocal + return None + elif stmt.line >= expr.line: + # We can stop our analysis at the line where the name is used + break + # Check for any assignments + elif isinstance(stmt, AssignmentStmt): + # First, exit if any assignment has a rhs expression that + # could mutate the name + # TODO Write logic to recursively unwrap statements to see + # if any internal statements mess with our var + + # Iterate thru lvalues in the assignment + for idx, lval in enumerate(stmt.lvalues): + # Check if any of them matches our variable + if isinstance(lval, NameExpr) and lval.name == expr.name: + assignments.append((stmt, idx)) + elif isinstance(stmt, ExpressionStmt): + if isinstance(stmt.expr, CallExpr): + callee = stmt.expr.callee + for arg in stmt.expr.args: + if isinstance(arg, NameExpr) and arg.name == expr.name: + # our var was passed to a function as an input, + # it could be mutated now + return None + if ( + isinstance(callee, MemberExpr) + and isinstance(callee.expr, NameExpr) + and callee.expr.name == expr.name + ): + return None + + # For now, we only attempt to resolve the length + # when the name was only ever assigned to once + if len(assignments) != 1: + return None + stmt, idx = assignments[0] + rvalue = stmt.rvalue + # If single lvalue, just use rvalue + if len(stmt.lvalues) == 1: + return get_static_expr_length(rvalue, context) + # If multiple lvalues, try to extract the corresponding value + elif isinstance(rvalue, (TupleExpr, ListExpr)): + if len(rvalue.items) == len(stmt.lvalues): + return get_static_expr_length(rvalue.items[idx], context) + # Otherwise, cannot determine + # Could add more cases (e.g. dicts, sets) in the future + return None diff --git a/mypy/message_registry.py b/mypy/message_registry.py index 09004322aee9f..861aab5f8808f 100644 --- a/mypy/message_registry.py +++ b/mypy/message_registry.py @@ -370,3 +370,8 @@ def with_additional_msg(self, info: str) -> ErrorMessage: TYPE_ALIAS_WITH_AWAIT_EXPRESSION: Final = ErrorMessage( "Await expression cannot be used within a type alias", codes.SYNTAX ) + +SEQUENCE_INDEX_OUT_OF_RANGE = ErrorMessage( + "Sequence index out of range: {name!r} only has {length} items", + code=codes.INDEX_RANGE, +) From 264c4e2678969a9251f4126aa2de507125adf0e8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 13 Sep 2025 02:11:39 +0000 Subject: [PATCH 02/14] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypy/checkexpr.py | 6 +++++- mypy/errorcodes.py | 7 +------ mypy/exprlength.py | 45 ++++++++++++++++++++++++++++------------ mypy/message_registry.py | 3 +-- 4 files changed, 39 insertions(+), 22 deletions(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index d3621ede7ffa1..7de9688be5c74 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -4476,7 +4476,11 @@ def min_tuple_length(self, left: TupleType) -> int: def static_index_range_check(self, left_type: Type, e: IndexExpr, index: Expression): if isinstance(left_type, Instance) and left_type.type.fullname in ( - "builtins.list", "builtins.set", "builtins.dict", "builtins.str", "builtins.bytes" + "builtins.list", + "builtins.set", + "builtins.dict", + "builtins.str", + "builtins.bytes", ): idx_val = None # Try to extract integer literal index diff --git a/mypy/errorcodes.py b/mypy/errorcodes.py index 601b823f18268..07323ae7f227e 100644 --- a/mypy/errorcodes.py +++ b/mypy/errorcodes.py @@ -326,12 +326,7 @@ def __hash__(self) -> int: default_enabled=False, ) -INDEX_RANGE = ErrorCode( - "index-range", - "index out of statically known range", - "Index Range", - True, -) +INDEX_RANGE = ErrorCode("index-range", "index out of statically known range", "Index Range", True) # This copy will not include any error codes defined later in the plugins. mypy_error_codes = error_codes.copy() diff --git a/mypy/exprlength.py b/mypy/exprlength.py index ef1168c89e51d..53032bc86af4d 100644 --- a/mypy/exprlength.py +++ b/mypy/exprlength.py @@ -5,31 +5,38 @@ """ from typing import List, Optional, Tuple + from mypy.nodes import ( + ARG_POS, + AssignmentStmt, + Block, + BytesExpr, + CallExpr, + ClassDef, + DictExpr, Expression, ExpressionStmt, ForStmt, + FuncDef, GeneratorExpr, + GlobalDecl, IfStmt, ListComprehension, ListExpr, - TupleExpr, - SetExpr, - WhileStmt, - DictExpr, MemberExpr, - StrExpr, - StarExpr, - BytesExpr, - CallExpr, NameExpr, + NonlocalDecl, + OverloadedFuncDef, + SetExpr, + StarExpr, + StrExpr, TryStmt, - Block, - AssignmentStmt, + TupleExpr, + WhileStmt, + WithStmt, is_IntExpr_list, ) -from mypy.nodes import WithStmt, FuncDef, OverloadedFuncDef, ClassDef, GlobalDecl, NonlocalDecl -from mypy.nodes import ARG_POS + def get_static_expr_length(expr: Expression, context: Optional[Block] = None) -> Optional[int]: """Try to statically determine the length of an expression. @@ -100,7 +107,19 @@ def get_static_expr_length(expr: Expression, context: Optional[Block] = None) -> # Iterate thru all statements in the block for stmt in context.body: - if isinstance(stmt, (IfStmt, ForStmt, WhileStmt, TryStmt, WithStmt, FuncDef, OverloadedFuncDef, ClassDef)): + if isinstance( + stmt, + ( + IfStmt, + ForStmt, + WhileStmt, + TryStmt, + WithStmt, + FuncDef, + OverloadedFuncDef, + ClassDef, + ), + ): # These statements complicate things and render the whole block useless return None elif isinstance(stmt, (GlobalDecl, NonlocalDecl)) and expr.name in stmt.names: diff --git a/mypy/message_registry.py b/mypy/message_registry.py index 861aab5f8808f..a6fcb9b4e267e 100644 --- a/mypy/message_registry.py +++ b/mypy/message_registry.py @@ -372,6 +372,5 @@ def with_additional_msg(self, info: str) -> ErrorMessage: ) SEQUENCE_INDEX_OUT_OF_RANGE = ErrorMessage( - "Sequence index out of range: {name!r} only has {length} items", - code=codes.INDEX_RANGE, + "Sequence index out of range: {name!r} only has {length} items", code=codes.INDEX_RANGE ) From e1e1b241db3c995ffb97652655523dd3bd5efcdb Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Sat, 13 Sep 2025 02:11:39 +0000 Subject: [PATCH 03/14] Update nodes.py --- mypy/nodes.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mypy/nodes.py b/mypy/nodes.py index 040f3fc28dce0..426c8e04f185b 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -8,7 +8,7 @@ from collections import defaultdict from collections.abc import Iterator, Sequence from enum import Enum, unique -from typing import TYPE_CHECKING, Any, Callable, Final, Optional, TypeVar, Union, cast +from typing import TYPE_CHECKING, Any, Callable, Final, List, Optional, TypeVar, Union, cast from typing_extensions import TypeAlias as _TypeAlias, TypeGuard from mypy_extensions import trait @@ -1971,6 +1971,7 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: return visitor.visit_int_expr(self) +def is_IntExpr_list(items: List[Expression]) -> TypeGuard[List[IntExpr]]: # How mypy uses StrExpr and BytesExpr: # # b'x' -> BytesExpr From 4deb1f7e89759abdda1586bdf36a2ea49a42f65b Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Sat, 13 Sep 2025 02:11:39 +0000 Subject: [PATCH 04/14] Update checkexpr.py --- mypy/checkexpr.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 7de9688be5c74..469ed8070a050 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -4477,8 +4477,7 @@ def min_tuple_length(self, left: TupleType) -> int: def static_index_range_check(self, left_type: Type, e: IndexExpr, index: Expression): if isinstance(left_type, Instance) and left_type.type.fullname in ( "builtins.list", - "builtins.set", - "builtins.dict", + "builtins.tuple", "builtins.str", "builtins.bytes", ): From 7867a0ebb4589460c7c6c88f31d02ab02fe3d93f Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Sat, 13 Sep 2025 02:11:39 +0000 Subject: [PATCH 05/14] Update nodes.py --- mypy/nodes.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mypy/nodes.py b/mypy/nodes.py index 426c8e04f185b..c74016721c674 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -1972,6 +1972,9 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: def is_IntExpr_list(items: List[Expression]) -> TypeGuard[List[IntExpr]]: + return all(isinstance(item, IntExpr) for item in items) + + # How mypy uses StrExpr and BytesExpr: # # b'x' -> BytesExpr From 30d6e67200c2576f3700c45188f6c5bf39bd3bc8 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Sat, 13 Sep 2025 02:11:39 +0000 Subject: [PATCH 06/14] Update errorcodes.py --- mypy/errorcodes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy/errorcodes.py b/mypy/errorcodes.py index 07323ae7f227e..bded9f733dcbf 100644 --- a/mypy/errorcodes.py +++ b/mypy/errorcodes.py @@ -326,7 +326,7 @@ def __hash__(self) -> int: default_enabled=False, ) -INDEX_RANGE = ErrorCode("index-range", "index out of statically known range", "Index Range", True) +INDEX_RANGE: Final[ErrorCode] = ErrorCode("index-range", "index out of statically known range", "Index Range", True) # This copy will not include any error codes defined later in the plugins. mypy_error_codes = error_codes.copy() From cf53f1daa506c13f6f5b22779ca3062585f37f38 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 13 Sep 2025 02:11:39 +0000 Subject: [PATCH 07/14] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypy/errorcodes.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mypy/errorcodes.py b/mypy/errorcodes.py index bded9f733dcbf..875ffbca1b6e4 100644 --- a/mypy/errorcodes.py +++ b/mypy/errorcodes.py @@ -326,7 +326,9 @@ def __hash__(self) -> int: default_enabled=False, ) -INDEX_RANGE: Final[ErrorCode] = ErrorCode("index-range", "index out of statically known range", "Index Range", True) +INDEX_RANGE: Final[ErrorCode] = ErrorCode( + "index-range", "index out of statically known range", "Index Range", True +) # This copy will not include any error codes defined later in the plugins. mypy_error_codes = error_codes.copy() From d2c540b90d21fc6a5e77bb64d8094c4391a51f84 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Sat, 13 Sep 2025 02:11:39 +0000 Subject: [PATCH 08/14] Update checkexpr.py --- mypy/checkexpr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 469ed8070a050..de84a7a56a225 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -4474,7 +4474,7 @@ def min_tuple_length(self, left: TupleType) -> int: return left.length() - 1 + unpack.type.min_len return left.length() - 1 - def static_index_range_check(self, left_type: Type, e: IndexExpr, index: Expression): + def static_index_range_check(self, left_type: Type, e: IndexExpr, index: Expression) -> None: if isinstance(left_type, Instance) and left_type.type.fullname in ( "builtins.list", "builtins.tuple", From 667ae47cc6f5710d2c41bc33df2839d8d0f6d19b Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Sat, 13 Sep 2025 02:11:39 +0000 Subject: [PATCH 09/14] Update exprlength.py --- mypy/exprlength.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/mypy/exprlength.py b/mypy/exprlength.py index 53032bc86af4d..286a2da563eba 100644 --- a/mypy/exprlength.py +++ b/mypy/exprlength.py @@ -51,11 +51,12 @@ def get_static_expr_length(expr: Expression, context: Optional[Block] = None) -> # List, tuple literals (with possible star expressions) if isinstance(expr, (ListExpr, TupleExpr)): - # if there are no star expressions, or we know the length of them, - # we know the length of the expression stars = [get_static_expr_length(i, context) for i in expr.items if isinstance(i, StarExpr)] - other = sum(not isinstance(i, StarExpr) for i in expr.items) - return other + sum(star for star in stars if star is not None) + if None not in stars: + # if there are no star expressions, or we know the + # length of them, we know the length of the expression + other = sum(not isinstance(i, StarExpr) for i in expr.items) + return other + sum(star for star in stars if star is not None) elif isinstance(expr, SetExpr): # TODO: set expressions are more complicated, you need to know the # actual value of each item in order to confidently state its length From 8342457a1835988a33dae142e5edf08360b7d046 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Sat, 13 Sep 2025 02:11:39 +0000 Subject: [PATCH 10/14] Update run-misc.test --- mypyc/test-data/run-misc.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/test-data/run-misc.test b/mypyc/test-data/run-misc.test index 129946a4c3300..59a977f93088e 100644 --- a/mypyc/test-data/run-misc.test +++ b/mypyc/test-data/run-misc.test @@ -25,7 +25,7 @@ def f(a: bool, b: bool) -> None: def g() -> None: try: - [0][1] + [0][1] # type: ignore [index-range] y = 1 except Exception: pass From 7b36e2d98610b5897a4610034966988e5d5c7288 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Sat, 13 Sep 2025 02:11:39 +0000 Subject: [PATCH 11/14] Update run-exceptions.test --- mypyc/test-data/run-exceptions.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/test-data/run-exceptions.test b/mypyc/test-data/run-exceptions.test index 1b180b9331971..6567760fb913e 100644 --- a/mypyc/test-data/run-exceptions.test +++ b/mypyc/test-data/run-exceptions.test @@ -125,7 +125,7 @@ def g(b: bool) -> None: try: if b: x = [0] - x[1] + x[1] # type: ignore [index-range] else: raise Exception('hi') except: From 4a98befbf411d6962538bb1de64a7f56ac37b642 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Sat, 13 Sep 2025 02:11:39 +0000 Subject: [PATCH 12/14] Update run-exceptions.test --- mypyc/test-data/run-exceptions.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/test-data/run-exceptions.test b/mypyc/test-data/run-exceptions.test index 6567760fb913e..c1efa3ef98b46 100644 --- a/mypyc/test-data/run-exceptions.test +++ b/mypyc/test-data/run-exceptions.test @@ -371,7 +371,7 @@ def b(b1: int, b2: int) -> str: if b1 == 1: raise Exception('hi') elif b1 == 2: - [0][1] + [0][1] # type: ignore [index-range] elif b1 == 3: return 'try' except IndexError: From 6e93317a69fde90239d344cad4e8ddb3e2dbbc2d Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Sat, 13 Sep 2025 02:11:39 +0000 Subject: [PATCH 13/14] Update run-exceptions.test --- mypyc/test-data/run-exceptions.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/test-data/run-exceptions.test b/mypyc/test-data/run-exceptions.test index c1efa3ef98b46..c8037be27c76d 100644 --- a/mypyc/test-data/run-exceptions.test +++ b/mypyc/test-data/run-exceptions.test @@ -133,7 +133,7 @@ def g(b: bool) -> None: def r(x: int) -> None: if x == 0: - [0][1] + [0][1] # type: ignore [index-range] elif x == 1: raise Exception('hi') elif x == 2: From 5b9e8607c2a48d9a0793568de0a93db8abab324e Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Sat, 13 Sep 2025 02:11:39 +0000 Subject: [PATCH 14/14] Update run-exceptions.test --- mypyc/test-data/run-exceptions.test | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mypyc/test-data/run-exceptions.test b/mypyc/test-data/run-exceptions.test index c8037be27c76d..89ad2240431b6 100644 --- a/mypyc/test-data/run-exceptions.test +++ b/mypyc/test-data/run-exceptions.test @@ -263,7 +263,7 @@ Traceback (most recent call last): File "native.py", line 44, in i r(0) File "native.py", line 15, in r - [0][1] + [0][1] # type: ignore [index-range] IndexError: list index out of range == k == Traceback (most recent call last): @@ -281,7 +281,7 @@ Traceback (most recent call last): File "native.py", line 61, in k r(0) File "native.py", line 15, in r - [0][1] + [0][1] # type: ignore [index-range] IndexError: list index out of range == g == caught! @@ -330,7 +330,7 @@ Traceback (most recent call last): File "native.py", line 61, in k r(0) File "native.py", line 15, in r - [0][1] + [0][1] # type: ignore [index-range] IndexError: list index out of range == g == caught!