red_knot_python_semantic: replace one use of "old" secondary diagnostic messages

This is the first use of the new `lint()` reporter.

I somewhat skipped a step here and also modified the actual diagnostic
message itself. The snapshots should tell the story.

We couldn't do this before because we had no way of differentiating
between "message for the diagnostic as a whole" and "message for a
specific code annotation." Now we can, so we can write more precise
messages based on the assumption that users are also seeing the code
snippet.

The downside here is that the actual message text can become quite vague
in the absence of the code snippet. This occurs, for example, with
concise diagnostic formatting. It's unclear if we should do anything
about it. I don't really see a way to make it better that doesn't
involve creating diagnostics with messages for each mode, which I think
would be a major PITA.

The upside is that this code gets a bit simpler, and we very
specifically avoid doing extra work if this specific lint is disabled.
This commit is contained in:
Andrew Gallant 2025-04-08 15:01:19 -04:00 committed by Andrew Gallant
parent ba408f4231
commit 7e2eb591bc
31 changed files with 151 additions and 142 deletions

View file

@ -12,7 +12,7 @@ X = GenericAlias(type, ())
A = NewType("A", int)
# TODO: typeshed for `typing.GenericAlias` uses `type` for the first argument. `NewType` should be special-cased
# to be compatible with `type`
# error: [invalid-argument-type] "Object of type `NewType` cannot be assigned to parameter 2 (`origin`) of function `__new__`; expected type `type`"
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `type`, found `NewType`"
B = GenericAlias(A, ())
def _(

View file

@ -9,8 +9,8 @@ def _(c: Callable[[], int]):
def _(c: Callable[[int, str], int]):
reveal_type(c(1, "a")) # revealed: int
# error: [invalid-argument-type] "Object of type `Literal["a"]` cannot be assigned to parameter 1; expected type `int`"
# error: [invalid-argument-type] "Object of type `Literal[1]` cannot be assigned to parameter 2; expected type `str`"
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["a"]`"
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `str`, found `Literal[1]`"
reveal_type(c("a", 1)) # revealed: int
```

View file

@ -85,7 +85,7 @@ class C:
c = C()
# error: 15 [invalid-argument-type] "Object of type `Literal["foo"]` cannot be assigned to parameter 2 (`x`) of bound method `__call__`; expected type `int`"
# error: 15 [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["foo"]`"
reveal_type(c("foo")) # revealed: int
```
@ -99,7 +99,7 @@ class C:
c = C()
# error: 13 [invalid-argument-type] "Object of type `C` cannot be assigned to parameter 1 (`self`) of bound method `__call__`; expected type `int`"
# error: 13 [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `C`"
reveal_type(c()) # revealed: int
```

View file

@ -98,7 +98,7 @@ def _(flag: bool) -> None:
def __new__(cls, x: int, y: int = 1): ...
reveal_type(Foo(1)) # revealed: Foo
# error: [invalid-argument-type] "Object of type `Literal["1"]` cannot be assigned to parameter 2 (`x`) of function `__new__`; expected type `int`"
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["1"]`"
reveal_type(Foo("1")) # revealed: Foo
# error: [missing-argument] "No argument provided for required parameter `x` of function `__new__`"
reveal_type(Foo()) # revealed: Foo
@ -210,7 +210,7 @@ def _(flag: bool) -> None:
def __init__(self, x: int, y: int = 1): ...
reveal_type(Foo(1)) # revealed: Foo
# error: [invalid-argument-type] "Object of type `Literal["1"]` cannot be assigned to parameter 2 (`x`) of bound method `__init__`; expected type `int`"
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["1"]`"
reveal_type(Foo("1")) # revealed: Foo
# error: [missing-argument] "No argument provided for required parameter `x` of bound method `__init__`"
reveal_type(Foo()) # revealed: Foo

View file

@ -72,7 +72,7 @@ def _(flag: bool):
def f(x: int) -> int:
return 1
# error: 15 [invalid-argument-type] "Object of type `Literal["foo"]` cannot be assigned to parameter 1 (`x`) of function `f`; expected type `int`"
# error: 15 [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["foo"]`"
reveal_type(f("foo")) # revealed: int
```
@ -82,7 +82,7 @@ reveal_type(f("foo")) # revealed: int
def f(x: int, /) -> int:
return 1
# error: 15 [invalid-argument-type] "Object of type `Literal["foo"]` cannot be assigned to parameter 1 (`x`) of function `f`; expected type `int`"
# error: 15 [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["foo"]`"
reveal_type(f("foo")) # revealed: int
```
@ -92,7 +92,7 @@ reveal_type(f("foo")) # revealed: int
def f(*args: int) -> int:
return 1
# error: 15 [invalid-argument-type] "Object of type `Literal["foo"]` cannot be assigned to parameter `*args` of function `f`; expected type `int`"
# error: 15 [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["foo"]`"
reveal_type(f("foo")) # revealed: int
```
@ -102,7 +102,7 @@ reveal_type(f("foo")) # revealed: int
def f(x: int) -> int:
return 1
# error: 15 [invalid-argument-type] "Object of type `Literal["foo"]` cannot be assigned to parameter `x` of function `f`; expected type `int`"
# error: 15 [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["foo"]`"
reveal_type(f(x="foo")) # revealed: int
```
@ -112,7 +112,7 @@ reveal_type(f(x="foo")) # revealed: int
def f(*, x: int) -> int:
return 1
# error: 15 [invalid-argument-type] "Object of type `Literal["foo"]` cannot be assigned to parameter `x` of function `f`; expected type `int`"
# error: 15 [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["foo"]`"
reveal_type(f(x="foo")) # revealed: int
```
@ -122,7 +122,7 @@ reveal_type(f(x="foo")) # revealed: int
def f(**kwargs: int) -> int:
return 1
# error: 15 [invalid-argument-type] "Object of type `Literal["foo"]` cannot be assigned to parameter `**kwargs` of function `f`; expected type `int`"
# error: 15 [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["foo"]`"
reveal_type(f(x="foo")) # revealed: int
```
@ -132,8 +132,8 @@ reveal_type(f(x="foo")) # revealed: int
def f(x: int = 1, y: str = "foo") -> int:
return 1
# error: 15 [invalid-argument-type] "Object of type `Literal[2]` cannot be assigned to parameter `y` of function `f`; expected type `str`"
# error: 20 [invalid-argument-type] "Object of type `Literal["bar"]` cannot be assigned to parameter `x` of function `f`; expected type `int`"
# error: 15 [invalid-argument-type] "Argument to this function is incorrect: Expected `str`, found `Literal[2]`"
# error: 20 [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["bar"]`"
reveal_type(f(y=2, x="bar")) # revealed: int
```

View file

@ -114,7 +114,7 @@ inspect.getattr_static()
# error: [missing-argument] "No argument provided for required parameter `attr`"
inspect.getattr_static(C())
# error: [invalid-argument-type] "Object of type `Literal[1]` cannot be assigned to parameter 2 (`attr`) of function `getattr_static`; expected type `str`"
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `str`, found `Literal[1]`"
inspect.getattr_static(C(), 1)
# error: [too-many-positional-arguments] "Too many positional arguments to function `getattr_static`: expected 3, got 4"

View file

@ -24,7 +24,7 @@ to the valid order:
def f(**kw: int, x: str) -> int:
return 1
# error: 15 [invalid-argument-type] "Object of type `Literal[1]` cannot be assigned to parameter 1 (`x`) of function `f`; expected type `str`"
# error: 15 [invalid-argument-type] "Argument to this function is incorrect: Expected `str`, found `Literal[1]`"
reveal_type(f(1)) # revealed: int
```
@ -38,7 +38,7 @@ def f(x: int = 1, y: str) -> int:
return 1
reveal_type(f(y="foo")) # revealed: int
# error: [invalid-argument-type] "Object of type `Literal["foo"]` cannot be assigned to parameter 1 (`x`) of function `f`; expected type `int`"
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["foo"]`"
# error: [missing-argument] "No argument provided for required parameter `y` of function `f`"
reveal_type(f("foo")) # revealed: int
```

View file

@ -350,7 +350,7 @@ class D:
# This function is wrongly annotated, it should be `type[D]` instead of `D`
pass
# error: [invalid-argument-type] "Object of type `Literal[D]` cannot be assigned to parameter 1 (`cls`) of bound method `f`; expected type `D`"
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `D`, found `Literal[D]`"
D.f()
```

View file

@ -20,7 +20,7 @@ class C:
def _(subclass_of_c: type[C]):
reveal_type(subclass_of_c(1)) # revealed: C
# error: [invalid-argument-type] "Object of type `Literal["a"]` cannot be assigned to parameter 2 (`x`) of bound method `__init__`; expected type `int`"
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["a"]`"
reveal_type(subclass_of_c("a")) # revealed: C
# error: [missing-argument] "No argument provided for required parameter `x` of bound method `__init__`"
reveal_type(subclass_of_c()) # revealed: C

View file

@ -94,7 +94,7 @@ def _(flag: bool):
else:
f = f2
# error: [invalid-argument-type] "Object of type `Literal[3]` cannot be assigned to parameter 1 (`a`) of function `f2`; expected type `str`"
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `str`, found `Literal[3]`"
x = f(3)
reveal_type(x) # revealed: int | str
```

View file

@ -207,7 +207,7 @@ first argument:
def wrong_signature(f: int) -> str:
return "a"
# error: [invalid-argument-type] "Object of type `Literal[f]` cannot be assigned to parameter 1 (`f`) of function `wrong_signature`; expected type `int`"
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal[f]`"
@wrong_signature
def f(x): ...

View file

@ -42,7 +42,7 @@ def f(w: Wrapper) -> None:
v: int | None = w.value
# This function call is incorrect, because `w.value` could be `None`. We therefore emit the following
# error: "`Unknown | None` cannot be assigned to parameter 1 (`i`) of function `accepts_int`; expected type `int`"
# error: "Argument to this function is incorrect: Expected `int`, found `Unknown | None`"
c = accepts_int(w.value)
```

View file

@ -81,10 +81,10 @@ class IntSubclass(int): ...
reveal_type(Bounded[int]()) # revealed: Bounded[int]
reveal_type(Bounded[IntSubclass]()) # revealed: Bounded[IntSubclass]
# error: [invalid-argument-type] "Object of type `str` cannot be assigned to parameter 1 (`T`) of class `Bounded`; expected type `int`"
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `str`"
reveal_type(Bounded[str]()) # revealed: Unknown
# error: [invalid-argument-type] "Object of type `int | str` cannot be assigned to parameter 1 (`T`) of class `Bounded`; expected type `int`"
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `int | str`"
reveal_type(Bounded[int | str]()) # revealed: Unknown
reveal_type(BoundedByUnion[int]()) # revealed: BoundedByUnion[int]
@ -110,7 +110,7 @@ reveal_type(Constrained[str]()) # revealed: Constrained[str]
# TODO: revealed: Unknown
reveal_type(Constrained[int | str]()) # revealed: Constrained[int | str]
# error: [invalid-argument-type] "Object of type `object` cannot be assigned to parameter 1 (`T`) of class `Constrained`; expected type `int | str`"
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int | str`, found `object`"
reveal_type(Constrained[object]()) # revealed: Unknown
```

View file

@ -85,7 +85,7 @@ class C[T]:
c: C[int] = C[int]()
c.m1(1)
c.m2(1)
# error: [invalid-argument-type] "Object of type `Literal["string"]` cannot be assigned to parameter 2 (`x`) of bound method `m2`; expected type `int`"
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["string"]`"
c.m2("string")
```

View file

@ -146,7 +146,7 @@ class C:
@property
def attr(self) -> int:
return 1
# error: [invalid-argument-type] "Object of type `Literal[attr]` cannot be assigned to parameter 2 (`fset`) of bound method `setter`; expected type `(Any, Any, /) -> None`"
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `(Any, Any, /) -> None`, found `Literal[attr]`"
@attr.setter
def attr(self) -> None:
pass
@ -156,7 +156,7 @@ class C:
```py
class C:
# error: [invalid-argument-type] "Object of type `Literal[attr]` cannot be assigned to parameter 1 (`fget`) of class `property`; expected type `((Any, /) -> Any) | None`"
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `((Any, /) -> Any) | None`, found `Literal[attr]`"
@property
def attr(self, x: int) -> int:
return 1

View file

@ -21,19 +21,19 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/diagnostics/invali
# Diagnostics
```
error: lint:invalid-argument-type
error: lint:invalid-argument-type: Argument to this function is incorrect
--> /src/mdtest_snippet.py:4:5
|
2 | return x * x
3 |
4 | foo("hello") # error: [invalid-argument-type]
| ^^^^^^^ Object of type `Literal["hello"]` cannot be assigned to parameter 1 (`x`) of function `foo`; expected type `int`
| ^^^^^^^ Expected `int`, found `Literal["hello"]`
|
info
--> /src/mdtest_snippet.py:1:9
info: Function defined here
--> /src/mdtest_snippet.py:1:5
|
1 | def foo(x: int) -> int:
| ------ parameter declared in function definition here
| ^^^ ------ Parameter declared here
2 | return x * x
|

View file

@ -23,19 +23,19 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/diagnostics/invali
# Diagnostics
```
error: lint:invalid-argument-type
error: lint:invalid-argument-type: Argument to this function is incorrect
--> /src/mdtest_snippet.py:6:10
|
5 | c = C()
6 | c.square("hello") # error: [invalid-argument-type]
| ^^^^^^^ Object of type `Literal["hello"]` cannot be assigned to parameter 2 (`x`) of bound method `square`; expected type `int`
| ^^^^^^^ Expected `int`, found `Literal["hello"]`
|
info
--> /src/mdtest_snippet.py:2:22
info: Function defined here
--> /src/mdtest_snippet.py:2:9
|
1 | class C:
2 | def square(self, x: int) -> int:
| ------ parameter declared in function definition here
| ^^^^^^ ------ Parameter declared here
3 | return x * x
|

View file

@ -27,19 +27,19 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/diagnostics/invali
# Diagnostics
```
error: lint:invalid-argument-type
error: lint:invalid-argument-type: Argument to this function is incorrect
--> /src/mdtest_snippet.py:3:13
|
1 | import package
2 |
3 | package.foo("hello") # error: [invalid-argument-type]
| ^^^^^^^ Object of type `Literal["hello"]` cannot be assigned to parameter 1 (`x`) of function `foo`; expected type `int`
| ^^^^^^^ Expected `int`, found `Literal["hello"]`
|
info
--> /src/package.py:1:9
info: Function defined here
--> /src/package.py:1:5
|
1 | def foo(x: int) -> int:
| ------ parameter declared in function definition here
| ^^^ ------ Parameter declared here
2 | return x * x
|

View file

@ -22,22 +22,22 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/diagnostics/invali
# Diagnostics
```
error: lint:invalid-argument-type
error: lint:invalid-argument-type: Argument to this function is incorrect
--> /src/mdtest_snippet.py:2:9
|
1 | def bar():
2 | foo("hello") # error: [invalid-argument-type]
| ^^^^^^^ Object of type `Literal["hello"]` cannot be assigned to parameter 1 (`x`) of function `foo`; expected type `int`
| ^^^^^^^ Expected `int`, found `Literal["hello"]`
3 |
4 | def foo(x: int) -> int:
|
info
--> /src/mdtest_snippet.py:4:9
info: Function defined here
--> /src/mdtest_snippet.py:4:5
|
2 | foo("hello") # error: [invalid-argument-type]
3 |
4 | def foo(x: int) -> int:
| ------ parameter declared in function definition here
| ^^^ ------ Parameter declared here
5 | return x * x
|

View file

@ -21,19 +21,19 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/diagnostics/invali
# Diagnostics
```
error: lint:invalid-argument-type
error: lint:invalid-argument-type: Argument to this function is incorrect
--> /src/mdtest_snippet.py:4:8
|
2 | return x * y * z
3 |
4 | foo(1, "hello", 3) # error: [invalid-argument-type]
| ^^^^^^^ Object of type `Literal["hello"]` cannot be assigned to parameter 2 (`y`) of function `foo`; expected type `int`
| ^^^^^^^ Expected `int`, found `Literal["hello"]`
|
info
--> /src/mdtest_snippet.py:1:17
info: Function defined here
--> /src/mdtest_snippet.py:1:5
|
1 | def foo(x: int, y: int, z: int) -> int:
| ------ parameter declared in function definition here
| ^^^ ------ Parameter declared here
2 | return x * y * z
|

View file

@ -25,21 +25,22 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/diagnostics/invali
# Diagnostics
```
error: lint:invalid-argument-type
error: lint:invalid-argument-type: Argument to this function is incorrect
--> /src/mdtest_snippet.py:8:8
|
6 | return x * y * z
7 |
8 | foo(1, "hello", 3) # error: [invalid-argument-type]
| ^^^^^^^ Object of type `Literal["hello"]` cannot be assigned to parameter 2 (`y`) of function `foo`; expected type `int`
| ^^^^^^^ Expected `int`, found `Literal["hello"]`
|
info
--> /src/mdtest_snippet.py:3:5
info: Function defined here
--> /src/mdtest_snippet.py:1:5
|
1 | def foo(
| ^^^
2 | x: int,
3 | y: int,
| ------ parameter declared in function definition here
| ------ Parameter declared here
4 | z: int,
5 | ) -> int:
|

View file

@ -24,57 +24,57 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/diagnostics/invali
# Diagnostics
```
error: lint:invalid-argument-type
error: lint:invalid-argument-type: Argument to this function is incorrect
--> /src/mdtest_snippet.py:7:5
|
5 | # error: [invalid-argument-type]
6 | # error: [invalid-argument-type]
7 | foo("a", "b", "c")
| ^^^ Object of type `Literal["a"]` cannot be assigned to parameter 1 (`x`) of function `foo`; expected type `int`
| ^^^ Expected `int`, found `Literal["a"]`
|
info
--> /src/mdtest_snippet.py:1:9
info: Function defined here
--> /src/mdtest_snippet.py:1:5
|
1 | def foo(x: int, y: int, z: int) -> int:
| ------ parameter declared in function definition here
| ^^^ ------ Parameter declared here
2 | return x * y * z
|
```
```
error: lint:invalid-argument-type
error: lint:invalid-argument-type: Argument to this function is incorrect
--> /src/mdtest_snippet.py:7:10
|
5 | # error: [invalid-argument-type]
6 | # error: [invalid-argument-type]
7 | foo("a", "b", "c")
| ^^^ Object of type `Literal["b"]` cannot be assigned to parameter 2 (`y`) of function `foo`; expected type `int`
| ^^^ Expected `int`, found `Literal["b"]`
|
info
--> /src/mdtest_snippet.py:1:17
info: Function defined here
--> /src/mdtest_snippet.py:1:5
|
1 | def foo(x: int, y: int, z: int) -> int:
| ------ parameter declared in function definition here
| ^^^ ------ Parameter declared here
2 | return x * y * z
|
```
```
error: lint:invalid-argument-type
error: lint:invalid-argument-type: Argument to this function is incorrect
--> /src/mdtest_snippet.py:7:15
|
5 | # error: [invalid-argument-type]
6 | # error: [invalid-argument-type]
7 | foo("a", "b", "c")
| ^^^ Object of type `Literal["c"]` cannot be assigned to parameter 3 (`z`) of function `foo`; expected type `int`
| ^^^ Expected `int`, found `Literal["c"]`
|
info
--> /src/mdtest_snippet.py:1:25
info: Function defined here
--> /src/mdtest_snippet.py:1:5
|
1 | def foo(x: int, y: int, z: int) -> int:
| ------ parameter declared in function definition here
| ^^^ ------ Parameter declared here
2 | return x * y * z
|

View file

@ -20,21 +20,23 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/diagnostics/invali
# Diagnostics
```
error: lint:invalid-argument-type
error: lint:invalid-argument-type: Argument to this function is incorrect
--> /src/mdtest_snippet.py:3:12
|
1 | import json
2 |
3 | json.loads(5) # error: [invalid-argument-type]
| ^ Object of type `Literal[5]` cannot be assigned to parameter 1 (`s`) of function `loads`; expected type `str | bytes | bytearray`
| ^ Expected `str | bytes | bytearray`, found `Literal[5]`
|
info
--> stdlib/json/__init__.pyi:40:5
info: Function defined here
--> stdlib/json/__init__.pyi:39:5
|
37 | **kwds: Any,
38 | ) -> None: ...
39 | def loads(
| ^^^^^
40 | s: str | bytes | bytearray,
| -------------------------- parameter declared in function definition here
| -------------------------- Parameter declared here
41 | *,
42 | cls: type[JSONDecoder] | None = None,
|

View file

@ -21,19 +21,19 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/diagnostics/invali
# Diagnostics
```
error: lint:invalid-argument-type
error: lint:invalid-argument-type: Argument to this function is incorrect
--> /src/mdtest_snippet.py:4:11
|
2 | return x * y * z
3 |
4 | foo(1, 2, z="hello") # error: [invalid-argument-type]
| ^^^^^^^^^ Object of type `Literal["hello"]` cannot be assigned to parameter `z` of function `foo`; expected type `int`
| ^^^^^^^^^ Expected `int`, found `Literal["hello"]`
|
info
--> /src/mdtest_snippet.py:1:28
info: Function defined here
--> /src/mdtest_snippet.py:1:5
|
1 | def foo(x: int, y: int, *, z: int = 0) -> int:
| ---------- parameter declared in function definition here
| ^^^ ---------- Parameter declared here
2 | return x * y * z
|

View file

@ -21,19 +21,19 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/diagnostics/invali
# Diagnostics
```
error: lint:invalid-argument-type
error: lint:invalid-argument-type: Argument to this function is incorrect
--> /src/mdtest_snippet.py:4:11
|
2 | return x * y * z
3 |
4 | foo(1, 2, z="hello") # error: [invalid-argument-type]
| ^^^^^^^^^ Object of type `Literal["hello"]` cannot be assigned to parameter `z` of function `foo`; expected type `int`
| ^^^^^^^^^ Expected `int`, found `Literal["hello"]`
|
info
--> /src/mdtest_snippet.py:1:31
info: Function defined here
--> /src/mdtest_snippet.py:1:5
|
1 | def foo(x: int, /, y: int, *, z: int = 0) -> int:
| ---------- parameter declared in function definition here
| ^^^ ---------- Parameter declared here
2 | return x * y * z
|

View file

@ -21,19 +21,19 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/diagnostics/invali
# Diagnostics
```
error: lint:invalid-argument-type
error: lint:invalid-argument-type: Argument to this function is incorrect
--> /src/mdtest_snippet.py:4:11
|
2 | return x * y * z
3 |
4 | foo(1, 2, "hello") # error: [invalid-argument-type]
| ^^^^^^^ Object of type `Literal["hello"]` cannot be assigned to parameter 3 (`z`) of function `foo`; expected type `int`
| ^^^^^^^ Expected `int`, found `Literal["hello"]`
|
info
--> /src/mdtest_snippet.py:1:25
info: Function defined here
--> /src/mdtest_snippet.py:1:5
|
1 | def foo(x: int, y: int, z: int = 0) -> int:
| ---------- parameter declared in function definition here
| ^^^ ---------- Parameter declared here
2 | return x * y * z
|

View file

@ -21,19 +21,19 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/diagnostics/invali
# Diagnostics
```
error: lint:invalid-argument-type
error: lint:invalid-argument-type: Argument to this function is incorrect
--> /src/mdtest_snippet.py:4:8
|
2 | return x * y * z
3 |
4 | foo(1, "hello", 3) # error: [invalid-argument-type]
| ^^^^^^^ Object of type `Literal["hello"]` cannot be assigned to parameter 2 (`y`) of function `foo`; expected type `int`
| ^^^^^^^ Expected `int`, found `Literal["hello"]`
|
info
--> /src/mdtest_snippet.py:1:17
info: Function defined here
--> /src/mdtest_snippet.py:1:5
|
1 | def foo(x: int, y: int, z: int, /) -> int:
| ------ parameter declared in function definition here
| ^^^ ------ Parameter declared here
2 | return x * y * z
|

View file

@ -23,19 +23,19 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/diagnostics/invali
# Diagnostics
```
error: lint:invalid-argument-type
error: lint:invalid-argument-type: Argument to this function is incorrect
--> /src/mdtest_snippet.py:6:3
|
5 | c = C()
6 | c("wrong") # error: [invalid-argument-type]
| ^^^^^^^ Object of type `Literal["wrong"]` cannot be assigned to parameter 2 (`x`) of bound method `__call__`; expected type `int`
| ^^^^^^^ Expected `int`, found `Literal["wrong"]`
|
info
--> /src/mdtest_snippet.py:2:24
info: Function defined here
--> /src/mdtest_snippet.py:2:9
|
1 | class C:
2 | def __call__(self, x: int) -> int:
| ------ parameter declared in function definition here
| ^^^^^^^^ ------ Parameter declared here
3 | return 1
|

View file

@ -21,19 +21,19 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/diagnostics/invali
# Diagnostics
```
error: lint:invalid-argument-type
error: lint:invalid-argument-type: Argument to this function is incorrect
--> /src/mdtest_snippet.py:4:14
|
2 | return len(numbers)
3 |
4 | foo(1, 2, 3, "hello", 5) # error: [invalid-argument-type]
| ^^^^^^^ Object of type `Literal["hello"]` cannot be assigned to parameter `*numbers` of function `foo`; expected type `int`
| ^^^^^^^ Expected `int`, found `Literal["hello"]`
|
info
--> /src/mdtest_snippet.py:1:9
info: Function defined here
--> /src/mdtest_snippet.py:1:5
|
1 | def foo(*numbers: int) -> int:
| ------------- parameter declared in function definition here
| ^^^ ------------- Parameter declared here
2 | return len(numbers)
|

View file

@ -21,19 +21,19 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/diagnostics/invali
# Diagnostics
```
error: lint:invalid-argument-type
error: lint:invalid-argument-type: Argument to this function is incorrect
--> /src/mdtest_snippet.py:4:20
|
2 | return len(numbers)
3 |
4 | foo(a=1, b=2, c=3, d="hello", e=5) # error: [invalid-argument-type]
| ^^^^^^^^^ Object of type `Literal["hello"]` cannot be assigned to parameter `**numbers` of function `foo`; expected type `int`
| ^^^^^^^^^ Expected `int`, found `Literal["hello"]`
|
info
--> /src/mdtest_snippet.py:1:9
info: Function defined here
--> /src/mdtest_snippet.py:1:5
|
1 | def foo(**numbers: int) -> int:
| -------------- parameter declared in function definition here
| ^^^ -------------- Parameter declared here
2 | return len(numbers)
|

View file

@ -21,7 +21,7 @@ use crate::types::{
todo_type, BoundMethodType, FunctionDecorators, KnownClass, KnownFunction, KnownInstanceType,
MethodWrapperKind, PropertyInstanceType, UnionType, WrapperDescriptorKind,
};
use ruff_db::diagnostic::{OldSecondaryDiagnosticMessage, Span};
use ruff_db::diagnostic::{Annotation, Severity, Span, SubDiagnostic};
use ruff_python_ast as ast;
use ruff_text_size::Ranged;
@ -1183,15 +1183,23 @@ pub(crate) enum BindingError<'db> {
}
impl<'db> BindingError<'db> {
/// Returns a tuple of two spans. The first is
/// the span for the identifier of the function
/// definition for `callable_ty`. The second is
/// the span for the parameter in the function
/// definition for `callable_ty`.
///
/// If there are no meaningful spans, then this
/// returns `None`.
fn parameter_span_from_index(
db: &'db dyn Db,
callable_ty: Type<'db>,
parameter_index: usize,
) -> Option<Span> {
) -> Option<(Span, Span)> {
match callable_ty {
Type::FunctionLiteral(function) => {
let function_scope = function.body_scope(db);
let mut span = Span::from(function_scope.file(db));
let span = Span::from(function_scope.file(db));
let node = function_scope.node(db);
if let Some(func_def) = node.as_function() {
let range = func_def
@ -1200,8 +1208,9 @@ impl<'db> BindingError<'db> {
.nth(parameter_index)
.map(|param| param.range())
.unwrap_or(func_def.parameters.range);
span = span.with_range(range);
Some(span)
let name_span = span.clone().with_range(func_def.name.range);
let parameter_span = span.with_range(range);
Some((name_span, parameter_span))
} else {
None
}
@ -1229,32 +1238,29 @@ impl<'db> BindingError<'db> {
expected_ty,
provided_ty,
} => {
let mut messages = vec![];
if let Some(span) =
Self::parameter_span_from_index(context.db(), callable_ty, parameter.index)
{
messages.push(OldSecondaryDiagnosticMessage::new(
span,
"parameter declared in function definition here",
));
}
let Some(builder) = context.lint(&INVALID_ARGUMENT_TYPE) else {
return;
};
let provided_ty_display = provided_ty.display(context.db());
let expected_ty_display = expected_ty.display(context.db());
context.report_lint_with_secondary_messages(
&INVALID_ARGUMENT_TYPE,
Self::get_node(node, *argument_index),
format_args!(
"Object of type `{provided_ty_display}` cannot be assigned to \
parameter {parameter}{}; expected type `{expected_ty_display}`",
if let Some(CallableDescription { kind, name }) = callable_description {
format!(" of {kind} `{name}`")
} else {
String::new()
}
),
&messages,
);
let mut reporter = builder.build("Argument to this function is incorrect");
let diag = reporter.diagnostic();
let span = context.span(Self::get_node(node, *argument_index));
diag.annotate(Annotation::primary(span).message(format_args!(
"Expected `{expected_ty_display}`, found `{provided_ty_display}`"
)));
if let Some((name_span, parameter_span)) =
Self::parameter_span_from_index(context.db(), callable_ty, parameter.index)
{
let mut sub = SubDiagnostic::new(Severity::Info, "Function defined here");
sub.annotate(Annotation::primary(name_span));
sub.annotate(
Annotation::secondary(parameter_span).message("Parameter declared here"),
);
diag.sub(sub);
}
}
Self::TooManyPositionalArguments {