mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 10:48:32 +00:00
ty_python_semantic: add union type context to function call type errors
This context gets added only when calling a function through a union type.
This commit is contained in:
parent
5ea3a52c8a
commit
346e82b572
42 changed files with 235 additions and 101 deletions
|
@ -59,26 +59,37 @@ type KeyDiagnosticFields = (
|
|||
Severity,
|
||||
);
|
||||
|
||||
// left: [
|
||||
// (Lint(LintName("invalid-argument-type")), Some("/src/tomllib/_parser.py"), Some(8224..8254), "Argument to function `skip_until` is incorrect", Error),
|
||||
// (Lint(LintName("invalid-argument-type")), Some("/src/tomllib/_parser.py"), Some(16914..16948), "Argument to function `skip_until` is incorrect", Error),
|
||||
// (Lint(LintName("invalid-argument-type")), Some("/src/tomllib/_parser.py"), Some(17319..17363), "Argument to function `skip_until` is incorrect", Error),
|
||||
// ]
|
||||
//right: [
|
||||
// (Lint(LintName("invalid-argument-type")), Some("/src/tomllib/_parser.py"), Some(8224..8254), "Argument to this function is incorrect", Error),
|
||||
// (Lint(LintName("invalid-argument-type")), Some("/src/tomllib/_parser.py"), Some(16914..16948), "Argument to this function is incorrect", Error),
|
||||
// (Lint(LintName("invalid-argument-type")), Some("/src/tomllib/_parser.py"), Some(17319..17363), "Argument to this function is incorrect", Error),
|
||||
// ]
|
||||
|
||||
static EXPECTED_TOMLLIB_DIAGNOSTICS: &[KeyDiagnosticFields] = &[
|
||||
(
|
||||
DiagnosticId::lint("invalid-argument-type"),
|
||||
Some("/src/tomllib/_parser.py"),
|
||||
Some(8224..8254),
|
||||
"Argument to this function is incorrect",
|
||||
"Argument to function `skip_until` is incorrect",
|
||||
Severity::Error,
|
||||
),
|
||||
(
|
||||
DiagnosticId::lint("invalid-argument-type"),
|
||||
Some("/src/tomllib/_parser.py"),
|
||||
Some(16914..16948),
|
||||
"Argument to this function is incorrect",
|
||||
"Argument to function `skip_until` is incorrect",
|
||||
Severity::Error,
|
||||
),
|
||||
(
|
||||
DiagnosticId::lint("invalid-argument-type"),
|
||||
Some("/src/tomllib/_parser.py"),
|
||||
Some(17319..17363),
|
||||
"Argument to this function is incorrect",
|
||||
"Argument to function `skip_until` is incorrect",
|
||||
Severity::Error,
|
||||
),
|
||||
];
|
||||
|
|
|
@ -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] "Argument to this function is incorrect: Expected `type`, found `NewType`"
|
||||
# error: [invalid-argument-type] "Argument to function `__new__` is incorrect: Expected `type`, found `NewType`"
|
||||
B = GenericAlias(A, ())
|
||||
|
||||
def _(
|
||||
|
|
|
@ -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] "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]`"
|
||||
# error: [invalid-argument-type] "Argument is incorrect: Expected `int`, found `Literal["a"]`"
|
||||
# error: [invalid-argument-type] "Argument is incorrect: Expected `str`, found `Literal[1]`"
|
||||
reveal_type(c("a", 1)) # revealed: int
|
||||
```
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ class C:
|
|||
|
||||
c = C()
|
||||
|
||||
# error: 15 [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["foo"]`"
|
||||
# error: 15 [invalid-argument-type] "Argument to bound method `__call__` 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] "Argument to this function is incorrect: Expected `int`, found `C`"
|
||||
# error: 13 [invalid-argument-type] "Argument to bound method `__call__` is incorrect: Expected `int`, found `C`"
|
||||
reveal_type(c()) # revealed: int
|
||||
```
|
||||
|
||||
|
|
|
@ -99,8 +99,8 @@ def _(flag: bool) -> None:
|
|||
def __new__(cls, x: int, y: int = 1): ...
|
||||
|
||||
reveal_type(Foo(1)) # revealed: Foo
|
||||
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["1"]`"
|
||||
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["1"]`"
|
||||
# error: [invalid-argument-type] "Argument to function `__new__` is incorrect: Expected `int`, found `Literal["1"]`"
|
||||
# error: [invalid-argument-type] "Argument to function `__new__` 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__`"
|
||||
# error: [missing-argument] "No argument provided for required parameter `x` of function `__new__`"
|
||||
|
@ -232,8 +232,8 @@ def _(flag: bool) -> None:
|
|||
def __init__(self, x: int, y: int = 1): ...
|
||||
|
||||
reveal_type(Foo(1)) # revealed: Foo
|
||||
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["1"]`"
|
||||
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["1"]`"
|
||||
# error: [invalid-argument-type] "Argument to bound method `__init__` is incorrect: Expected `int`, found `Literal["1"]`"
|
||||
# error: [invalid-argument-type] "Argument to bound method `__init__` 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__`"
|
||||
# error: [missing-argument] "No argument provided for required parameter `x` of bound method `__init__`"
|
||||
|
|
|
@ -77,7 +77,7 @@ def _(flag: bool):
|
|||
def f(x: int) -> int:
|
||||
return 1
|
||||
|
||||
# error: 15 [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["foo"]`"
|
||||
# error: 15 [invalid-argument-type] "Argument to function `f` is incorrect: Expected `int`, found `Literal["foo"]`"
|
||||
reveal_type(f("foo")) # revealed: int
|
||||
```
|
||||
|
||||
|
@ -87,7 +87,7 @@ reveal_type(f("foo")) # revealed: int
|
|||
def f(x: int, /) -> int:
|
||||
return 1
|
||||
|
||||
# error: 15 [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["foo"]`"
|
||||
# error: 15 [invalid-argument-type] "Argument to function `f` is incorrect: Expected `int`, found `Literal["foo"]`"
|
||||
reveal_type(f("foo")) # revealed: int
|
||||
```
|
||||
|
||||
|
@ -97,7 +97,7 @@ reveal_type(f("foo")) # revealed: int
|
|||
def f(*args: int) -> int:
|
||||
return 1
|
||||
|
||||
# error: 15 [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["foo"]`"
|
||||
# error: 15 [invalid-argument-type] "Argument to function `f` is incorrect: Expected `int`, found `Literal["foo"]`"
|
||||
reveal_type(f("foo")) # revealed: int
|
||||
```
|
||||
|
||||
|
@ -107,7 +107,7 @@ reveal_type(f("foo")) # revealed: int
|
|||
def f(x: int) -> int:
|
||||
return 1
|
||||
|
||||
# error: 15 [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["foo"]`"
|
||||
# error: 15 [invalid-argument-type] "Argument to function `f` is incorrect: Expected `int`, found `Literal["foo"]`"
|
||||
reveal_type(f(x="foo")) # revealed: int
|
||||
```
|
||||
|
||||
|
@ -117,7 +117,7 @@ reveal_type(f(x="foo")) # revealed: int
|
|||
def f(*, x: int) -> int:
|
||||
return 1
|
||||
|
||||
# error: 15 [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["foo"]`"
|
||||
# error: 15 [invalid-argument-type] "Argument to function `f` is incorrect: Expected `int`, found `Literal["foo"]`"
|
||||
reveal_type(f(x="foo")) # revealed: int
|
||||
```
|
||||
|
||||
|
@ -127,7 +127,7 @@ reveal_type(f(x="foo")) # revealed: int
|
|||
def f(**kwargs: int) -> int:
|
||||
return 1
|
||||
|
||||
# error: 15 [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["foo"]`"
|
||||
# error: 15 [invalid-argument-type] "Argument to function `f` is incorrect: Expected `int`, found `Literal["foo"]`"
|
||||
reveal_type(f(x="foo")) # revealed: int
|
||||
```
|
||||
|
||||
|
@ -137,8 +137,8 @@ reveal_type(f(x="foo")) # revealed: int
|
|||
def f(x: int = 1, y: str = "foo") -> int:
|
||||
return 1
|
||||
|
||||
# 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"]`"
|
||||
# error: 15 [invalid-argument-type] "Argument to function `f` is incorrect: Expected `str`, found `Literal[2]`"
|
||||
# error: 20 [invalid-argument-type] "Argument to function `f` is incorrect: Expected `int`, found `Literal["bar"]`"
|
||||
reveal_type(f(y=2, x="bar")) # revealed: int
|
||||
```
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ inspect.getattr_static()
|
|||
# error: [missing-argument] "No argument provided for required parameter `attr`"
|
||||
inspect.getattr_static(C())
|
||||
|
||||
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `str`, found `Literal[1]`"
|
||||
# error: [invalid-argument-type] "Argument to function `getattr_static` 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"
|
||||
|
|
|
@ -24,7 +24,7 @@ to the valid order:
|
|||
def f(**kw: int, x: str) -> int:
|
||||
return 1
|
||||
|
||||
# error: 15 [invalid-argument-type] "Argument to this function is incorrect: Expected `str`, found `Literal[1]`"
|
||||
# error: 15 [invalid-argument-type] "Argument to function `f` 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] "Argument to this function is incorrect: Expected `int`, found `Literal["foo"]`"
|
||||
# error: [invalid-argument-type] "Argument to function `f` 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
|
||||
```
|
||||
|
|
|
@ -350,7 +350,7 @@ class D:
|
|||
# This function is wrongly annotated, it should be `type[D]` instead of `D`
|
||||
pass
|
||||
|
||||
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `D`, found `<class 'D'>`"
|
||||
# error: [invalid-argument-type] "Argument to bound method `f` is incorrect: Expected `D`, found `<class 'D'>`"
|
||||
D.f()
|
||||
```
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ class C:
|
|||
def _(subclass_of_c: type[C]):
|
||||
reveal_type(subclass_of_c(1)) # revealed: C
|
||||
|
||||
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["a"]`"
|
||||
# error: [invalid-argument-type] "Argument to bound method `__init__` 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
|
||||
|
|
|
@ -94,7 +94,7 @@ def _(flag: bool):
|
|||
else:
|
||||
f = f2
|
||||
|
||||
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `str`, found `Literal[3]`"
|
||||
# error: [invalid-argument-type] "Argument to function `f2` is incorrect: Expected `str`, found `Literal[3]`"
|
||||
x = f(3)
|
||||
reveal_type(x) # revealed: int | str
|
||||
```
|
||||
|
|
|
@ -207,7 +207,7 @@ first argument:
|
|||
def wrong_signature(f: int) -> str:
|
||||
return "a"
|
||||
|
||||
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `def f(x) -> Unknown`"
|
||||
# error: [invalid-argument-type] "Argument to function `wrong_signature` is incorrect: Expected `int`, found `def f(x) -> Unknown`"
|
||||
@wrong_signature
|
||||
def f(x): ...
|
||||
|
||||
|
|
|
@ -99,9 +99,9 @@ def _(n: int):
|
|||
else:
|
||||
f = PossiblyNotCallable()
|
||||
# error: [too-many-positional-arguments]
|
||||
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `str`, found `Literal[3]`"
|
||||
# error: [invalid-argument-type] "Argument to function `f2` is incorrect: Expected `str`, found `Literal[3]`"
|
||||
# error: [missing-argument]
|
||||
# error: [invalid-argument-type] "Argument to this function is incorrect: Argument type `Literal[3]` does not satisfy upper bound of type variable `T`"
|
||||
# error: [invalid-argument-type] "Argument to function `f4` is incorrect: Argument type `Literal[3]` does not satisfy upper bound of type variable `T`"
|
||||
# error: [call-non-callable] "Object of type `Literal[5]` is not callable"
|
||||
# error: [no-matching-overload]
|
||||
# error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)"
|
||||
|
|
|
@ -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: "Argument to this function is incorrect: Expected `int`, found `Unknown | None`"
|
||||
# error: "Argument to function `accepts_int` is incorrect: Expected `int`, found `Unknown | None`"
|
||||
c = accepts_int(w.value)
|
||||
```
|
||||
|
||||
|
|
|
@ -123,11 +123,11 @@ reveal_type(Bounded[int]()) # revealed: Bounded[int]
|
|||
reveal_type(Bounded[IntSubclass]()) # revealed: Bounded[IntSubclass]
|
||||
|
||||
# TODO: update this diagnostic to talk about type parameters and specializations
|
||||
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `str`"
|
||||
# error: [invalid-argument-type] "Argument to class `Bounded` is incorrect: Expected `int`, found `str`"
|
||||
reveal_type(Bounded[str]()) # revealed: Unknown
|
||||
|
||||
# TODO: update this diagnostic to talk about type parameters and specializations
|
||||
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `int | str`"
|
||||
# error: [invalid-argument-type] "Argument to class `Bounded` is incorrect: Expected `int`, found `int | str`"
|
||||
reveal_type(Bounded[int | str]()) # revealed: Unknown
|
||||
|
||||
reveal_type(BoundedByUnion[int]()) # revealed: BoundedByUnion[int]
|
||||
|
@ -156,7 +156,7 @@ reveal_type(Constrained[str]()) # revealed: Constrained[str]
|
|||
reveal_type(Constrained[int | str]()) # revealed: Constrained[int | str]
|
||||
|
||||
# TODO: update this diagnostic to talk about type parameters and specializations
|
||||
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int | str`, found `object`"
|
||||
# error: [invalid-argument-type] "Argument to class `Constrained` is incorrect: Expected `int | str`, found `object`"
|
||||
reveal_type(Constrained[object]()) # revealed: Unknown
|
||||
```
|
||||
|
||||
|
|
|
@ -98,11 +98,11 @@ reveal_type(Bounded[int]()) # revealed: Bounded[int]
|
|||
reveal_type(Bounded[IntSubclass]()) # revealed: Bounded[IntSubclass]
|
||||
|
||||
# TODO: update this diagnostic to talk about type parameters and specializations
|
||||
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `str`"
|
||||
# error: [invalid-argument-type] "Argument to class `Bounded` is incorrect: Expected `int`, found `str`"
|
||||
reveal_type(Bounded[str]()) # revealed: Unknown
|
||||
|
||||
# TODO: update this diagnostic to talk about type parameters and specializations
|
||||
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `int | str`"
|
||||
# error: [invalid-argument-type] "Argument to class `Bounded` is incorrect: Expected `int`, found `int | str`"
|
||||
reveal_type(Bounded[int | str]()) # revealed: Unknown
|
||||
|
||||
reveal_type(BoundedByUnion[int]()) # revealed: BoundedByUnion[int]
|
||||
|
@ -129,7 +129,7 @@ reveal_type(Constrained[str]()) # revealed: Constrained[str]
|
|||
reveal_type(Constrained[int | str]()) # revealed: Constrained[int | str]
|
||||
|
||||
# TODO: update this diagnostic to talk about type parameters and specializations
|
||||
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int | str`, found `object`"
|
||||
# error: [invalid-argument-type] "Argument to class `Constrained` is incorrect: Expected `int | str`, found `object`"
|
||||
reveal_type(Constrained[object]()) # revealed: Unknown
|
||||
```
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ class C[T]:
|
|||
c: C[int] = C[int]()
|
||||
c.m1(1)
|
||||
c.m2(1)
|
||||
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["string"]`"
|
||||
# error: [invalid-argument-type] "Argument to bound method `m2` is incorrect: Expected `int`, found `Literal["string"]`"
|
||||
c.m2("string")
|
||||
```
|
||||
|
||||
|
|
|
@ -146,7 +146,7 @@ class C:
|
|||
@property
|
||||
def attr(self) -> int:
|
||||
return 1
|
||||
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `(Any, Any, /) -> None`, found `def attr(self) -> None`"
|
||||
# error: [invalid-argument-type] "Argument to bound method `setter` is incorrect: Expected `(Any, Any, /) -> None`, found `def attr(self) -> None`"
|
||||
@attr.setter
|
||||
def attr(self) -> None:
|
||||
pass
|
||||
|
@ -156,7 +156,7 @@ class C:
|
|||
|
||||
```py
|
||||
class C:
|
||||
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `((Any, /) -> Any) | None`, found `def attr(self, x: int) -> int`"
|
||||
# error: [invalid-argument-type] "Argument to class `property` is incorrect: Expected `((Any, /) -> Any) | None`, found `def attr(self, x: int) -> int`"
|
||||
@property
|
||||
def attr(self, x: int) -> int:
|
||||
return 1
|
||||
|
|
|
@ -68,7 +68,7 @@ info[revealed-type]: Revealed type
|
|||
```
|
||||
|
||||
```
|
||||
error[invalid-argument-type]: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to function `f` is incorrect
|
||||
--> src/mdtest_snippet.py:12:15
|
||||
|
|
||||
10 | reveal_type(f(True)) # revealed: Literal[True]
|
||||
|
|
|
@ -83,7 +83,7 @@ info[revealed-type]: Revealed type
|
|||
```
|
||||
|
||||
```
|
||||
error[invalid-argument-type]: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to function `f` is incorrect
|
||||
--> src/mdtest_snippet.py:13:15
|
||||
|
|
||||
11 | reveal_type(f(None)) # revealed: None
|
||||
|
|
|
@ -65,7 +65,7 @@ info[revealed-type]: Revealed type
|
|||
```
|
||||
|
||||
```
|
||||
error[invalid-argument-type]: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to function `f` is incorrect
|
||||
--> src/mdtest_snippet.py:9:15
|
||||
|
|
||||
7 | reveal_type(f(True)) # revealed: Literal[True]
|
||||
|
|
|
@ -80,7 +80,7 @@ info[revealed-type]: Revealed type
|
|||
```
|
||||
|
||||
```
|
||||
error[invalid-argument-type]: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to function `f` is incorrect
|
||||
--> src/mdtest_snippet.py:10:15
|
||||
|
|
||||
8 | reveal_type(f(None)) # revealed: None
|
||||
|
|
|
@ -21,7 +21,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_argu
|
|||
# Diagnostics
|
||||
|
||||
```
|
||||
error[invalid-argument-type]: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to function `foo` is incorrect
|
||||
--> src/mdtest_snippet.py:4:5
|
||||
|
|
||||
2 | return x * x
|
||||
|
|
|
@ -23,7 +23,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_argu
|
|||
# Diagnostics
|
||||
|
||||
```
|
||||
error[invalid-argument-type]: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to bound method `square` is incorrect
|
||||
--> src/mdtest_snippet.py:6:10
|
||||
|
|
||||
5 | c = C()
|
||||
|
|
|
@ -27,7 +27,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_argu
|
|||
# Diagnostics
|
||||
|
||||
```
|
||||
error[invalid-argument-type]: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to function `foo` is incorrect
|
||||
--> src/mdtest_snippet.py:3:13
|
||||
|
|
||||
1 | import package
|
||||
|
|
|
@ -22,7 +22,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_argu
|
|||
# Diagnostics
|
||||
|
||||
```
|
||||
error[invalid-argument-type]: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to function `foo` is incorrect
|
||||
--> src/mdtest_snippet.py:2:9
|
||||
|
|
||||
1 | def bar():
|
||||
|
|
|
@ -21,7 +21,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_argu
|
|||
# Diagnostics
|
||||
|
||||
```
|
||||
error[invalid-argument-type]: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to function `foo` is incorrect
|
||||
--> src/mdtest_snippet.py:4:8
|
||||
|
|
||||
2 | return x * y * z
|
||||
|
|
|
@ -25,7 +25,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_argu
|
|||
# Diagnostics
|
||||
|
||||
```
|
||||
error[invalid-argument-type]: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to function `foo` is incorrect
|
||||
--> src/mdtest_snippet.py:8:8
|
||||
|
|
||||
6 | return x * y * z
|
||||
|
|
|
@ -24,7 +24,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_argu
|
|||
# Diagnostics
|
||||
|
||||
```
|
||||
error[invalid-argument-type]: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to function `foo` is incorrect
|
||||
--> src/mdtest_snippet.py:7:5
|
||||
|
|
||||
5 | # error: [invalid-argument-type]
|
||||
|
@ -44,7 +44,7 @@ info: `invalid-argument-type` is enabled by default
|
|||
```
|
||||
|
||||
```
|
||||
error[invalid-argument-type]: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to function `foo` is incorrect
|
||||
--> src/mdtest_snippet.py:7:10
|
||||
|
|
||||
5 | # error: [invalid-argument-type]
|
||||
|
@ -64,7 +64,7 @@ info: `invalid-argument-type` is enabled by default
|
|||
```
|
||||
|
||||
```
|
||||
error[invalid-argument-type]: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to function `foo` is incorrect
|
||||
--> src/mdtest_snippet.py:7:15
|
||||
|
|
||||
5 | # error: [invalid-argument-type]
|
||||
|
|
|
@ -20,7 +20,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_argu
|
|||
# Diagnostics
|
||||
|
||||
```
|
||||
error[invalid-argument-type]: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to function `loads` is incorrect
|
||||
--> src/mdtest_snippet.py:3:12
|
||||
|
|
||||
1 | import json
|
||||
|
|
|
@ -21,7 +21,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_argu
|
|||
# Diagnostics
|
||||
|
||||
```
|
||||
error[invalid-argument-type]: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to function `foo` is incorrect
|
||||
--> src/mdtest_snippet.py:4:11
|
||||
|
|
||||
2 | return x * y * z
|
||||
|
|
|
@ -21,7 +21,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_argu
|
|||
# Diagnostics
|
||||
|
||||
```
|
||||
error[invalid-argument-type]: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to function `foo` is incorrect
|
||||
--> src/mdtest_snippet.py:4:11
|
||||
|
|
||||
2 | return x * y * z
|
||||
|
|
|
@ -21,7 +21,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_argu
|
|||
# Diagnostics
|
||||
|
||||
```
|
||||
error[invalid-argument-type]: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to function `foo` is incorrect
|
||||
--> src/mdtest_snippet.py:4:11
|
||||
|
|
||||
2 | return x * y * z
|
||||
|
|
|
@ -21,7 +21,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_argu
|
|||
# Diagnostics
|
||||
|
||||
```
|
||||
error[invalid-argument-type]: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to function `foo` is incorrect
|
||||
--> src/mdtest_snippet.py:4:8
|
||||
|
|
||||
2 | return x * y * z
|
||||
|
|
|
@ -23,7 +23,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_argu
|
|||
# Diagnostics
|
||||
|
||||
```
|
||||
error[invalid-argument-type]: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to bound method `__call__` is incorrect
|
||||
--> src/mdtest_snippet.py:6:3
|
||||
|
|
||||
5 | c = C()
|
||||
|
|
|
@ -21,7 +21,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_argu
|
|||
# Diagnostics
|
||||
|
||||
```
|
||||
error[invalid-argument-type]: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to function `foo` is incorrect
|
||||
--> src/mdtest_snippet.py:4:14
|
||||
|
|
||||
2 | return len(numbers)
|
||||
|
|
|
@ -21,7 +21,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_argu
|
|||
# Diagnostics
|
||||
|
||||
```
|
||||
error[invalid-argument-type]: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to function `foo` is incorrect
|
||||
--> src/mdtest_snippet.py:4:20
|
||||
|
|
||||
2 | return len(numbers)
|
||||
|
|
|
@ -31,7 +31,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.m
|
|||
# Diagnostics
|
||||
|
||||
```
|
||||
error: lint:invalid-argument-type: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to function `f2` is incorrect
|
||||
--> src/mdtest_snippet.py:14:11
|
||||
|
|
||||
12 | # error: [too-many-positional-arguments]
|
||||
|
@ -48,12 +48,14 @@ info: Function defined here
|
|||
| ^^ --------- Parameter declared here
|
||||
5 | return 0
|
||||
|
|
||||
info: `lint:invalid-argument-type` is enabled by default
|
||||
info: Union variant `def f2(name: str) -> int` is incompatible with this call site
|
||||
info: Attempted to call union type `(def f1() -> int) | (def f2(name: str) -> int)`
|
||||
info: `invalid-argument-type` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error: lint:too-many-positional-arguments: Too many positional arguments to function `f1`: expected 0, got 1
|
||||
error[too-many-positional-arguments]: Too many positional arguments to function `f1`: expected 0, got 1
|
||||
--> src/mdtest_snippet.py:14:11
|
||||
|
|
||||
12 | # error: [too-many-positional-arguments]
|
||||
|
@ -61,6 +63,8 @@ error: lint:too-many-positional-arguments: Too many positional arguments to func
|
|||
14 | x = f(3)
|
||||
| ^
|
||||
|
|
||||
info: `lint:too-many-positional-arguments` is enabled by default
|
||||
info: Union variant `def f1() -> int` is incompatible with this call site
|
||||
info: Attempted to call union type `(def f1() -> int) | (def f2(name: str) -> int)`
|
||||
info: `too-many-positional-arguments` is enabled by default
|
||||
|
||||
```
|
||||
|
|
|
@ -30,7 +30,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.m
|
|||
# Diagnostics
|
||||
|
||||
```
|
||||
error: lint:invalid-argument-type: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to function `f2` is incorrect
|
||||
--> src/mdtest_snippet.py:13:11
|
||||
|
|
||||
11 | f = f2
|
||||
|
@ -47,6 +47,8 @@ info: Function defined here
|
|||
| ^^ --------- Parameter declared here
|
||||
5 | return 0
|
||||
|
|
||||
info: `lint:invalid-argument-type` is enabled by default
|
||||
info: Union variant `def f2(name: str) -> int` is incompatible with this call site
|
||||
info: Attempted to call union type `(def f1(a: int) -> int) | (def f2(name: str) -> int)`
|
||||
info: `invalid-argument-type` is enabled by default
|
||||
|
||||
```
|
||||
|
|
|
@ -31,7 +31,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.m
|
|||
# Diagnostics
|
||||
|
||||
```
|
||||
error: lint:parameter-already-assigned: Multiple values provided for parameter `name` of function `f1`
|
||||
error[parameter-already-assigned]: Multiple values provided for parameter `name` of function `f1`
|
||||
--> src/mdtest_snippet.py:14:18
|
||||
|
|
||||
12 | # error: [parameter-already-assigned]
|
||||
|
@ -39,12 +39,14 @@ error: lint:parameter-already-assigned: Multiple values provided for parameter `
|
|||
14 | y = f("foo", name="bar", unknown="quux")
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
info: `lint:parameter-already-assigned` is enabled by default
|
||||
info: Union variant `def f1(name: str) -> int` is incompatible with this call site
|
||||
info: Attempted to call union type `(def f1(name: str) -> int) | (def any(*args, **kwargs) -> int)`
|
||||
info: `parameter-already-assigned` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error: lint:unknown-argument: Argument `unknown` does not match any known parameter of function `f1`
|
||||
error[unknown-argument]: Argument `unknown` does not match any known parameter of function `f1`
|
||||
--> src/mdtest_snippet.py:14:30
|
||||
|
|
||||
12 | # error: [parameter-already-assigned]
|
||||
|
@ -52,6 +54,8 @@ error: lint:unknown-argument: Argument `unknown` does not match any known parame
|
|||
14 | y = f("foo", name="bar", unknown="quux")
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
info: `lint:unknown-argument` is enabled by default
|
||||
info: Union variant `def f1(name: str) -> int` is incompatible with this call site
|
||||
info: Attempted to call union type `(def f1(name: str) -> int) | (def any(*args, **kwargs) -> int)`
|
||||
info: `unknown-argument` is enabled by default
|
||||
|
||||
```
|
||||
|
|
|
@ -53,9 +53,9 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.m
|
|||
39 | else:
|
||||
40 | f = PossiblyNotCallable()
|
||||
41 | # error: [too-many-positional-arguments]
|
||||
42 | # error: [invalid-argument-type] "Argument to this function is incorrect: Expected `str`, found `Literal[3]`"
|
||||
42 | # error: [invalid-argument-type] "Argument to function `f2` is incorrect: Expected `str`, found `Literal[3]`"
|
||||
43 | # error: [missing-argument]
|
||||
44 | # error: [invalid-argument-type] "Argument to this function is incorrect: Argument type `Literal[3]` does not satisfy upper bound of type variable `T`"
|
||||
44 | # error: [invalid-argument-type] "Argument to function `f4` is incorrect: Argument type `Literal[3]` does not satisfy upper bound of type variable `T`"
|
||||
45 | # error: [call-non-callable] "Object of type `Literal[5]` is not callable"
|
||||
46 | # error: [no-matching-overload]
|
||||
47 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)"
|
||||
|
@ -65,7 +65,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.m
|
|||
# Diagnostics
|
||||
|
||||
```
|
||||
error: lint:call-non-callable: Object of type `Literal[5]` is not callable
|
||||
error[call-non-callable]: Object of type `Literal[5]` is not callable
|
||||
--> src/mdtest_snippet.py:48:9
|
||||
|
|
||||
46 | # error: [no-matching-overload]
|
||||
|
@ -73,12 +73,14 @@ error: lint:call-non-callable: Object of type `Literal[5]` is not callable
|
|||
48 | x = f(3)
|
||||
| ^^^^
|
||||
|
|
||||
info: `lint:call-non-callable` is enabled by default
|
||||
info: Union variant `Literal[5]` is incompatible with this call site
|
||||
info: Attempted to call union type `(def f1() -> int) | (def f2(name: str) -> int) | (def f3(a: int, b: int) -> int) | (def f4(x: T) -> int) | Literal[5] | Unknown | (<method-wrapper `__get__` of `f`>) | PossiblyNotCallable`
|
||||
info: `call-non-callable` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error: lint:call-non-callable: Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)
|
||||
error[call-non-callable]: Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)
|
||||
--> src/mdtest_snippet.py:48:9
|
||||
|
|
||||
46 | # error: [no-matching-overload]
|
||||
|
@ -86,12 +88,14 @@ error: lint:call-non-callable: Object of type `PossiblyNotCallable` is not calla
|
|||
48 | x = f(3)
|
||||
| ^^^^
|
||||
|
|
||||
info: `lint:call-non-callable` is enabled by default
|
||||
info: Union variant `PossiblyNotCallable` is incompatible with this call site
|
||||
info: Attempted to call union type `(def f1() -> int) | (def f2(name: str) -> int) | (def f3(a: int, b: int) -> int) | (def f4(x: T) -> int) | Literal[5] | Unknown | (<method-wrapper `__get__` of `f`>) | PossiblyNotCallable`
|
||||
info: `call-non-callable` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error: lint:missing-argument: No argument provided for required parameter `b` of function `f3`
|
||||
error[missing-argument]: No argument provided for required parameter `b` of function `f3`
|
||||
--> src/mdtest_snippet.py:48:9
|
||||
|
|
||||
46 | # error: [no-matching-overload]
|
||||
|
@ -99,12 +103,14 @@ error: lint:missing-argument: No argument provided for required parameter `b` of
|
|||
48 | x = f(3)
|
||||
| ^^^^
|
||||
|
|
||||
info: `lint:missing-argument` is enabled by default
|
||||
info: Union variant `def f3(a: int, b: int) -> int` is incompatible with this call site
|
||||
info: Attempted to call union type `(def f1() -> int) | (def f2(name: str) -> int) | (def f3(a: int, b: int) -> int) | (def f4(x: T) -> int) | Literal[5] | Unknown | (<method-wrapper `__get__` of `f`>) | PossiblyNotCallable`
|
||||
info: `missing-argument` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error: lint:no-matching-overload: No overload of method wrapper `__get__` of function `f` matches arguments
|
||||
error[no-matching-overload]: No overload of method wrapper `__get__` of function `f` matches arguments
|
||||
--> src/mdtest_snippet.py:48:9
|
||||
|
|
||||
46 | # error: [no-matching-overload]
|
||||
|
@ -112,12 +118,14 @@ error: lint:no-matching-overload: No overload of method wrapper `__get__` of fun
|
|||
48 | x = f(3)
|
||||
| ^^^^
|
||||
|
|
||||
info: `lint:no-matching-overload` is enabled by default
|
||||
info: Union variant `<method-wrapper `__get__` of `f`>` is incompatible with this call site
|
||||
info: Attempted to call union type `(def f1() -> int) | (def f2(name: str) -> int) | (def f3(a: int, b: int) -> int) | (def f4(x: T) -> int) | Literal[5] | Unknown | (<method-wrapper `__get__` of `f`>) | PossiblyNotCallable`
|
||||
info: `no-matching-overload` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error: lint:invalid-argument-type: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to function `f2` is incorrect
|
||||
--> src/mdtest_snippet.py:48:11
|
||||
|
|
||||
46 | # error: [no-matching-overload]
|
||||
|
@ -134,12 +142,14 @@ info: Function defined here
|
|||
| ^^ --------- Parameter declared here
|
||||
7 | return 0
|
||||
|
|
||||
info: `lint:invalid-argument-type` is enabled by default
|
||||
info: Union variant `def f2(name: str) -> int` is incompatible with this call site
|
||||
info: Attempted to call union type `(def f1() -> int) | (def f2(name: str) -> int) | (def f3(a: int, b: int) -> int) | (def f4(x: T) -> int) | Literal[5] | Unknown | (<method-wrapper `__get__` of `f`>) | PossiblyNotCallable`
|
||||
info: `invalid-argument-type` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error: lint:invalid-argument-type: Argument to this function is incorrect
|
||||
error[invalid-argument-type]: Argument to function `f4` is incorrect
|
||||
--> src/mdtest_snippet.py:48:11
|
||||
|
|
||||
46 | # error: [no-matching-overload]
|
||||
|
@ -156,12 +166,14 @@ info: Type variable defined here
|
|||
| ^^^^^^
|
||||
13 | return 0
|
||||
|
|
||||
info: `lint:invalid-argument-type` is enabled by default
|
||||
info: Union variant `def f4(x: T) -> int` is incompatible with this call site
|
||||
info: Attempted to call union type `(def f1() -> int) | (def f2(name: str) -> int) | (def f3(a: int, b: int) -> int) | (def f4(x: T) -> int) | Literal[5] | Unknown | (<method-wrapper `__get__` of `f`>) | PossiblyNotCallable`
|
||||
info: `invalid-argument-type` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error: lint:too-many-positional-arguments: Too many positional arguments to function `f1`: expected 0, got 1
|
||||
error[too-many-positional-arguments]: Too many positional arguments to function `f1`: expected 0, got 1
|
||||
--> src/mdtest_snippet.py:48:11
|
||||
|
|
||||
46 | # error: [no-matching-overload]
|
||||
|
@ -169,6 +181,8 @@ error: lint:too-many-positional-arguments: Too many positional arguments to func
|
|||
48 | x = f(3)
|
||||
| ^
|
||||
|
|
||||
info: `lint:too-many-positional-arguments` is enabled by default
|
||||
info: Union variant `def f1() -> int` is incompatible with this call site
|
||||
info: Attempted to call union type `(def f1() -> int) | (def f2(name: str) -> int) | (def f3(a: int, b: int) -> int) | (def f4(x: T) -> int) | Literal[5] | Unknown | (<method-wrapper `__get__` of `f`>) | PossiblyNotCallable`
|
||||
info: `too-many-positional-arguments` is enabled by default
|
||||
|
||||
```
|
||||
|
|
|
@ -24,7 +24,7 @@ use crate::types::{
|
|||
FunctionType, KnownClass, KnownFunction, KnownInstanceType, MethodWrapperKind,
|
||||
PropertyInstanceType, TupleType, UnionType, WrapperDescriptorKind,
|
||||
};
|
||||
use ruff_db::diagnostic::{Annotation, Severity, SubDiagnostic};
|
||||
use ruff_db::diagnostic::{Annotation, Diagnostic, Severity, SubDiagnostic};
|
||||
use ruff_python_ast as ast;
|
||||
|
||||
/// Binding information for a possible union of callables. At a call site, the arguments must be
|
||||
|
@ -199,8 +199,19 @@ impl<'db> Bindings<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
// If this is not a union, then report a diagnostic for any
|
||||
// errors as normal.
|
||||
if let Some(binding) = self.single_element() {
|
||||
binding.report_diagnostics(context, node, None);
|
||||
return;
|
||||
}
|
||||
|
||||
for binding in self {
|
||||
binding.report_diagnostics(context, node);
|
||||
let union_diag = UnionDiagnostic {
|
||||
callable_type: self.callable_type(),
|
||||
binding,
|
||||
};
|
||||
binding.report_diagnostics(context, node, Some(&union_diag));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1043,23 +1054,34 @@ impl<'db> CallableBinding<'db> {
|
|||
Type::unknown()
|
||||
}
|
||||
|
||||
fn report_diagnostics(&self, context: &InferContext<'db>, node: ast::AnyNodeRef) {
|
||||
fn report_diagnostics(
|
||||
&self,
|
||||
context: &InferContext<'db>,
|
||||
node: ast::AnyNodeRef,
|
||||
union_diag: Option<&UnionDiagnostic<'_, '_>>,
|
||||
) {
|
||||
if !self.is_callable() {
|
||||
if let Some(builder) = context.report_lint(&CALL_NON_CALLABLE, node) {
|
||||
builder.into_diagnostic(format_args!(
|
||||
let mut diag = builder.into_diagnostic(format_args!(
|
||||
"Object of type `{}` is not callable",
|
||||
self.callable_type.display(context.db()),
|
||||
));
|
||||
if let Some(union_diag) = union_diag {
|
||||
union_diag.add_union_context(context.db(), &mut diag);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if self.dunder_call_is_possibly_unbound {
|
||||
if let Some(builder) = context.report_lint(&CALL_NON_CALLABLE, node) {
|
||||
builder.into_diagnostic(format_args!(
|
||||
let mut diag = builder.into_diagnostic(format_args!(
|
||||
"Object of type `{}` is not callable (possibly unbound `__call__` method)",
|
||||
self.callable_type.display(context.db()),
|
||||
));
|
||||
if let Some(union_diag) = union_diag {
|
||||
union_diag.add_union_context(context.db(), &mut diag);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -1067,7 +1089,7 @@ impl<'db> CallableBinding<'db> {
|
|||
let callable_description = CallableDescription::new(context.db(), self.callable_type);
|
||||
if self.overloads.len() > 1 {
|
||||
if let Some(builder) = context.report_lint(&NO_MATCHING_OVERLOAD, node) {
|
||||
builder.into_diagnostic(format_args!(
|
||||
let mut diag = builder.into_diagnostic(format_args!(
|
||||
"No overload{} matches arguments",
|
||||
if let Some(CallableDescription { kind, name }) = callable_description {
|
||||
format!(" of {kind} `{name}`")
|
||||
|
@ -1075,6 +1097,9 @@ impl<'db> CallableBinding<'db> {
|
|||
String::new()
|
||||
}
|
||||
));
|
||||
if let Some(union_diag) = union_diag {
|
||||
union_diag.add_union_context(context.db(), &mut diag);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -1086,6 +1111,7 @@ impl<'db> CallableBinding<'db> {
|
|||
node,
|
||||
self.signature_type,
|
||||
callable_description.as_ref(),
|
||||
union_diag,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1385,9 +1411,10 @@ impl<'db> Binding<'db> {
|
|||
node: ast::AnyNodeRef,
|
||||
callable_ty: Type<'db>,
|
||||
callable_description: Option<&CallableDescription>,
|
||||
union_diag: Option<&UnionDiagnostic<'_, '_>>,
|
||||
) {
|
||||
for error in &self.errors {
|
||||
error.report_diagnostic(context, node, callable_ty, callable_description);
|
||||
error.report_diagnostic(context, node, callable_ty, callable_description, union_diag);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1539,12 +1566,13 @@ pub(crate) enum BindingError<'db> {
|
|||
}
|
||||
|
||||
impl<'db> BindingError<'db> {
|
||||
pub(super) fn report_diagnostic(
|
||||
fn report_diagnostic(
|
||||
&self,
|
||||
context: &InferContext<'db>,
|
||||
node: ast::AnyNodeRef,
|
||||
callable_ty: Type<'db>,
|
||||
callable_description: Option<&CallableDescription>,
|
||||
union_diag: Option<&UnionDiagnostic<'_, '_>>,
|
||||
) {
|
||||
match self {
|
||||
Self::InvalidArgumentType {
|
||||
|
@ -1561,7 +1589,14 @@ impl<'db> BindingError<'db> {
|
|||
let provided_ty_display = provided_ty.display(context.db());
|
||||
let expected_ty_display = expected_ty.display(context.db());
|
||||
|
||||
let mut diag = builder.into_diagnostic("Argument to this function is incorrect");
|
||||
let mut diag = builder.into_diagnostic(format_args!(
|
||||
"Argument{} is incorrect",
|
||||
if let Some(CallableDescription { kind, name }) = callable_description {
|
||||
format!(" to {kind} `{name}`")
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
));
|
||||
diag.set_primary_message(format_args!(
|
||||
"Expected `{expected_ty_display}`, found `{provided_ty_display}`"
|
||||
));
|
||||
|
@ -1575,6 +1610,9 @@ impl<'db> BindingError<'db> {
|
|||
);
|
||||
diag.sub(sub);
|
||||
}
|
||||
if let Some(union_diag) = union_diag {
|
||||
union_diag.add_union_context(context.db(), &mut diag);
|
||||
}
|
||||
}
|
||||
|
||||
Self::TooManyPositionalArguments {
|
||||
|
@ -1584,7 +1622,7 @@ impl<'db> BindingError<'db> {
|
|||
} => {
|
||||
let node = Self::get_node(node, *first_excess_argument_index);
|
||||
if let Some(builder) = context.report_lint(&TOO_MANY_POSITIONAL_ARGUMENTS, node) {
|
||||
builder.into_diagnostic(format_args!(
|
||||
let mut diag = builder.into_diagnostic(format_args!(
|
||||
"Too many positional arguments{}: expected \
|
||||
{expected_positional_count}, got {provided_positional_count}",
|
||||
if let Some(CallableDescription { kind, name }) = callable_description {
|
||||
|
@ -1593,13 +1631,16 @@ impl<'db> BindingError<'db> {
|
|||
String::new()
|
||||
}
|
||||
));
|
||||
if let Some(union_diag) = union_diag {
|
||||
union_diag.add_union_context(context.db(), &mut diag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Self::MissingArguments { parameters } => {
|
||||
if let Some(builder) = context.report_lint(&MISSING_ARGUMENT, node) {
|
||||
let s = if parameters.0.len() == 1 { "" } else { "s" };
|
||||
builder.into_diagnostic(format_args!(
|
||||
let mut diag = builder.into_diagnostic(format_args!(
|
||||
"No argument{s} provided for required parameter{s} {parameters}{}",
|
||||
if let Some(CallableDescription { kind, name }) = callable_description {
|
||||
format!(" of {kind} `{name}`")
|
||||
|
@ -1607,6 +1648,9 @@ impl<'db> BindingError<'db> {
|
|||
String::new()
|
||||
}
|
||||
));
|
||||
if let Some(union_diag) = union_diag {
|
||||
union_diag.add_union_context(context.db(), &mut diag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1616,7 +1660,7 @@ impl<'db> BindingError<'db> {
|
|||
} => {
|
||||
let node = Self::get_node(node, *argument_index);
|
||||
if let Some(builder) = context.report_lint(&UNKNOWN_ARGUMENT, node) {
|
||||
builder.into_diagnostic(format_args!(
|
||||
let mut diag = builder.into_diagnostic(format_args!(
|
||||
"Argument `{argument_name}` does not match any known parameter{}",
|
||||
if let Some(CallableDescription { kind, name }) = callable_description {
|
||||
format!(" of {kind} `{name}`")
|
||||
|
@ -1624,6 +1668,9 @@ impl<'db> BindingError<'db> {
|
|||
String::new()
|
||||
}
|
||||
));
|
||||
if let Some(union_diag) = union_diag {
|
||||
union_diag.add_union_context(context.db(), &mut diag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1633,7 +1680,7 @@ impl<'db> BindingError<'db> {
|
|||
} => {
|
||||
let node = Self::get_node(node, *argument_index);
|
||||
if let Some(builder) = context.report_lint(&PARAMETER_ALREADY_ASSIGNED, node) {
|
||||
builder.into_diagnostic(format_args!(
|
||||
let mut diag = builder.into_diagnostic(format_args!(
|
||||
"Multiple values provided for parameter {parameter}{}",
|
||||
if let Some(CallableDescription { kind, name }) = callable_description {
|
||||
format!(" of {kind} `{name}`")
|
||||
|
@ -1641,6 +1688,9 @@ impl<'db> BindingError<'db> {
|
|||
String::new()
|
||||
}
|
||||
));
|
||||
if let Some(union_diag) = union_diag {
|
||||
union_diag.add_union_context(context.db(), &mut diag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1657,7 +1707,14 @@ impl<'db> BindingError<'db> {
|
|||
let argument_type = error.argument_type();
|
||||
let argument_ty_display = argument_type.display(context.db());
|
||||
|
||||
let mut diag = builder.into_diagnostic("Argument to this function is incorrect");
|
||||
let mut diag = builder.into_diagnostic(format_args!(
|
||||
"Argument{} is incorrect",
|
||||
if let Some(CallableDescription { kind, name }) = callable_description {
|
||||
format!(" to {kind} `{name}`")
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
));
|
||||
diag.set_primary_message(format_args!(
|
||||
"Argument type `{argument_ty_display}` does not satisfy {} of type variable `{}`",
|
||||
match error {
|
||||
|
@ -1671,12 +1728,15 @@ impl<'db> BindingError<'db> {
|
|||
let mut sub = SubDiagnostic::new(Severity::Info, "Type variable defined here");
|
||||
sub.annotate(Annotation::primary(typevar_range.into()));
|
||||
diag.sub(sub);
|
||||
if let Some(union_diag) = union_diag {
|
||||
union_diag.add_union_context(context.db(), &mut diag);
|
||||
}
|
||||
}
|
||||
|
||||
Self::InternalCallError(reason) => {
|
||||
let node = Self::get_node(node, None);
|
||||
if let Some(builder) = context.report_lint(&CALL_NON_CALLABLE, node) {
|
||||
builder.into_diagnostic(format_args!(
|
||||
let mut diag = builder.into_diagnostic(format_args!(
|
||||
"Call{} failed: {reason}",
|
||||
if let Some(CallableDescription { kind, name }) = callable_description {
|
||||
format!(" of {kind} `{name}`")
|
||||
|
@ -1684,6 +1744,9 @@ impl<'db> BindingError<'db> {
|
|||
String::new()
|
||||
}
|
||||
));
|
||||
if let Some(union_diag) = union_diag {
|
||||
union_diag.add_union_context(context.db(), &mut diag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1708,3 +1771,39 @@ impl<'db> BindingError<'db> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Contains additional context for union specific diagnostics.
|
||||
///
|
||||
/// This is used when a function call is inconsistent with one or more variants
|
||||
/// of a union. This can be used to attach sub-diagnostics that clarify that
|
||||
/// the error is part of a union.
|
||||
struct UnionDiagnostic<'b, 'db> {
|
||||
/// The type of the union.
|
||||
callable_type: Type<'db>,
|
||||
/// The specific binding that failed.
|
||||
binding: &'b CallableBinding<'db>,
|
||||
}
|
||||
|
||||
impl UnionDiagnostic<'_, '_> {
|
||||
/// Adds context about any relevant union function types to the given
|
||||
/// diagnostic.
|
||||
fn add_union_context(&self, db: &'_ dyn Db, diag: &mut Diagnostic) {
|
||||
let sub = SubDiagnostic::new(
|
||||
Severity::Info,
|
||||
format_args!(
|
||||
"Union variant `{callable_ty}` is incompatible with this call site",
|
||||
callable_ty = self.binding.callable_type.display(db),
|
||||
),
|
||||
);
|
||||
diag.sub(sub);
|
||||
|
||||
let sub = SubDiagnostic::new(
|
||||
Severity::Info,
|
||||
format_args!(
|
||||
"Attempted to call union type `{}`",
|
||||
self.callable_type.display(db)
|
||||
),
|
||||
);
|
||||
diag.sub(sub);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue