From 0b971463aec6b0b543f8a7392d85210246e4a7af Mon Sep 17 00:00:00 2001 From: Sean Doherty Date: Sat, 16 May 2026 23:57:27 -0500 Subject: [PATCH 1/3] Use nested subscript line numbers in fastparse --- mypy/fastparse.py | 2 +- test-data/unit/check-errorcodes.test | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/mypy/fastparse.py b/mypy/fastparse.py index d9e2d5df8f4c1..3c9b8971ffbb7 100644 --- a/mypy/fastparse.py +++ b/mypy/fastparse.py @@ -2112,7 +2112,7 @@ def visit_Subscript(self, n: ast3.Subscript) -> Type: result = UnboundType( value.name, params, - line=self.line, + line=n.lineno, column=value.column, empty_tuple_index=empty_tuple_index, ) diff --git a/test-data/unit/check-errorcodes.test b/test-data/unit/check-errorcodes.test index 85a2264c2088b..802ae722dadb4 100644 --- a/test-data/unit/check-errorcodes.test +++ b/test-data/unit/check-errorcodes.test @@ -1087,6 +1087,15 @@ def f(arg: int) -> int: def f(arg: str) -> str: ... +[case testNestedSubscriptWrongArityLineNumber] +# flags: --python-version 3.12 +def foo() -> dict[ + str, + dict[int, int, int], # E: "dict" expects 2 type arguments, but 3 given [type-arg] +]: + return {} +[builtins fixtures/dict.pyi] + [case testSliceInDictBuiltin_no_native_parse] # flags: --show-column-numbers b: dict[int, x:y] From 8dee2d29755dd1876837c3dfa2f9aca5ccf22fc1 Mon Sep 17 00:00:00 2001 From: Sean Doherty Date: Sun, 17 May 2026 00:28:52 -0500 Subject: [PATCH 2/3] Preserve source offsets for parsed type comments --- mypy/fastparse.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/mypy/fastparse.py b/mypy/fastparse.py index 3c9b8971ffbb7..1a273f9412cae 100644 --- a/mypy/fastparse.py +++ b/mypy/fastparse.py @@ -323,7 +323,7 @@ def parse_type_comment( ignored = None assert isinstance(typ, ast3.Expression) converted = TypeConverter( - errors, line=line, override_column=column, is_evaluated=False + errors, line=line, override_column=column, line_offset=line - 1, is_evaluated=False ).visit(typ.body) return ignored, converted @@ -966,11 +966,16 @@ def do_func_def( blocker=False, ) translated_args: list[Type] = TypeConverter( - self.errors, line=lineno, override_column=n.col_offset + self.errors, + line=lineno, + override_column=n.col_offset, + line_offset=lineno - 1, ).translate_expr_list(func_type_ast.argtypes) # Use a cast to work around `list` invariance arg_types = cast(list[Type | None], translated_args) - return_type = TypeConverter(self.errors, line=lineno).visit(func_type_ast.returns) + return_type = TypeConverter( + self.errors, line=lineno, line_offset=lineno - 1 + ).visit(func_type_ast.returns) # add implicit self type in_method_scope = self.class_and_function_stack[-2:] == ["C", "D"] @@ -1877,11 +1882,13 @@ def __init__( errors: Errors | None, line: int = -1, override_column: int = -1, + line_offset: int = 0, is_evaluated: bool = True, ) -> None: self.errors = errors self.line = line self.override_column = override_column + self.line_offset = line_offset self.node_stack: list[AST] = [] self.is_evaluated = is_evaluated @@ -1896,6 +1903,10 @@ def convert_column(self, column: int) -> int: else: return self.override_column + def convert_lineno(self, line: int) -> int: + """Map relative line numbers from synthetic parses back to source lines.""" + return line + self.line_offset + def invalid_type(self, node: AST, note: str | None = None) -> RawExpressionType: """Constructs a type representing some expression that normally forms an invalid type. For example, if we see a type hint that says "3 + 4", we would transform that @@ -2112,12 +2123,13 @@ def visit_Subscript(self, n: ast3.Subscript) -> Type: result = UnboundType( value.name, params, - line=n.lineno, + line=self.convert_lineno(n.lineno), column=value.column, empty_tuple_index=empty_tuple_index, ) result.end_column = n.end_col_offset - result.end_line = n.end_lineno + if n.end_lineno is not None: + result.end_line = self.convert_lineno(n.end_lineno) return result else: return self.invalid_type(n) From cf126cdeb6db5969b82b71ec70657608767c9ddc Mon Sep 17 00:00:00 2001 From: Sean Doherty Date: Sun, 17 May 2026 00:37:36 -0500 Subject: [PATCH 3/3] Cover type-comment subscript line offsets --- test-data/unit/check-errorcodes.test | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test-data/unit/check-errorcodes.test b/test-data/unit/check-errorcodes.test index 802ae722dadb4..c11f615bb4f60 100644 --- a/test-data/unit/check-errorcodes.test +++ b/test-data/unit/check-errorcodes.test @@ -1096,6 +1096,12 @@ def foo() -> dict[ return {} [builtins fixtures/dict.pyi] +[case testTypeCommentNestedSubscriptWrongArityLineNumber] +# flags: --python-version 3.12 +x = 0 +y = {} # type: dict[int, int, int] # E: "dict" expects 2 type arguments, but 3 given [type-arg] +[builtins fixtures/dict.pyi] + [case testSliceInDictBuiltin_no_native_parse] # flags: --show-column-numbers b: dict[int, x:y]