Skip to content

Commit 82f4e88

Browse files
authored
Start propagating end columns/lines through for type-arg errors (#18533)
Fixes #18531
1 parent b82697b commit 82f4e88

File tree

5 files changed

+34
-5
lines changed

5 files changed

+34
-5
lines changed

mypy/fastparse.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2052,13 +2052,16 @@ def visit_Subscript(self, n: ast3.Subscript) -> Type:
20522052

20532053
value = self.visit(n.value)
20542054
if isinstance(value, UnboundType) and not value.args:
2055-
return UnboundType(
2055+
result = UnboundType(
20562056
value.name,
20572057
params,
20582058
line=self.line,
20592059
column=value.column,
20602060
empty_tuple_index=empty_tuple_index,
20612061
)
2062+
result.end_column = getattr(n, "end_col_offset", None)
2063+
result.end_line = getattr(n, "end_lineno", None)
2064+
return result
20622065
else:
20632066
return self.invalid_type(n)
20642067

@@ -2092,7 +2095,7 @@ def visit_Attribute(self, n: Attribute) -> Type:
20922095
before_dot = self.visit(n.value)
20932096

20942097
if isinstance(before_dot, UnboundType) and not before_dot.args:
2095-
return UnboundType(f"{before_dot.name}.{n.attr}", line=self.line)
2098+
return UnboundType(f"{before_dot.name}.{n.attr}", line=self.line, column=n.col_offset)
20962099
else:
20972100
return self.invalid_type(n)
20982101

mypy/semanal.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7218,7 +7218,15 @@ def fail(
72187218
if code is None:
72197219
code = msg.code
72207220
msg = msg.value
7221-
self.errors.report(ctx.line, ctx.column, msg, blocker=blocker, code=code)
7221+
self.errors.report(
7222+
ctx.line,
7223+
ctx.column,
7224+
msg,
7225+
blocker=blocker,
7226+
code=code,
7227+
end_line=ctx.end_line,
7228+
end_column=ctx.end_column,
7229+
)
72227230

72237231
def note(self, msg: str, ctx: Context, code: ErrorCode | None = None) -> None:
72247232
if not self.in_checked_function():

mypy/typeanal.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,8 @@ def analyze_type_with_type_info(
862862
ctx.line,
863863
ctx.column,
864864
)
865+
instance.end_line = ctx.end_line
866+
instance.end_column = ctx.end_column
865867
if len(info.type_vars) == 1 and info.has_param_spec_type:
866868
instance.args = tuple(self.pack_paramspec_args(instance.args))
867869

@@ -2204,6 +2206,8 @@ def instantiate_type_alias(
22042206
tp = Instance(node.target.type, args)
22052207
tp.line = ctx.line
22062208
tp.column = ctx.column
2209+
tp.end_line = ctx.end_line
2210+
tp.end_column = ctx.end_column
22072211
return tp
22082212
if node.tvar_tuple_index is None:
22092213
if any(isinstance(a, UnpackType) for a in args):

test-data/unit/check-columns.test

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,3 +408,17 @@ x[0]
408408
main:2:10:2:17: error: Incompatible types in assignment (expression has type "str", variable has type "int")
409409
main:6:3:7:1: error: Argument 1 to "f" has incompatible type "int"; expected "str"
410410
main:8:1:8:4: error: Value of type "int" is not indexable
411+
412+
[case testEndColumnsWithTooManyTypeVars]
413+
# flags: --pretty
414+
import typing
415+
416+
x1: typing.List[typing.List[int, int]]
417+
x2: list[list[int, int]]
418+
[out]
419+
main:4:17: error: "list" expects 1 type argument, but 2 given
420+
x1: typing.List[typing.List[int, int]]
421+
^~~~~~~~~~~~~~~~~~~~~
422+
main:5:10: error: "list" expects 1 type argument, but 2 given
423+
x2: list[list[int, int]]
424+
^~~~~~~~~~~~~~

test-data/unit/check-parameter-specification.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,8 +1345,8 @@ from typing import Callable, ParamSpec
13451345
P1 = ParamSpec('P1')
13461346
P2 = ParamSpec('P2')
13471347

1348-
def f0(f: Callable[P1, int], *args: P1.args, **kwargs: P2.kwargs): ... # E: ParamSpec "P2" is unbound \
1349-
# E: ParamSpec must have "*args" typed as "P1.args" and "**kwargs" typed as "P1.kwargs"
1348+
def f0(f: Callable[P1, int], *args: P1.args, **kwargs: P2.kwargs): ... # E: ParamSpec must have "*args" typed as "P1.args" and "**kwargs" typed as "P1.kwargs" \
1349+
# E: ParamSpec "P2" is unbound
13501350

13511351
def f1(*args: P1.args): ... # E: ParamSpec "P1" is unbound
13521352
def f2(**kwargs: P1.kwargs): ... # E: ParamSpec "P1" is unbound

0 commit comments

Comments
 (0)