mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-19 01:50:38 +00:00
[ty] Improve invalid method calls for unmatched overloads (#18122)
This makes an easy tweak to allow our diagnostics for unmatched overloads to apply to method calls. Previously, they only worked for function calls. There is at least one other case worth addressing too, namely, class literals. e.g., `type()`. We had a diagnostic snapshot test case to track it. Closes astral-sh/ty#274
This commit is contained in:
parent
c066bf0127
commit
69393b2e6e
4 changed files with 132 additions and 2 deletions
|
@ -278,3 +278,29 @@ def f(
|
|||
|
||||
f(b"foo") # error: [no-matching-overload]
|
||||
```
|
||||
|
||||
## A method call with unmatched overloads
|
||||
|
||||
```py
|
||||
from typing import overload
|
||||
|
||||
class Foo:
|
||||
@overload
|
||||
def bar(self, x: int) -> int: ...
|
||||
@overload
|
||||
def bar(self, x: str) -> str: ...
|
||||
def bar(self, x: int | str) -> int | str:
|
||||
return x
|
||||
|
||||
foo = Foo()
|
||||
foo.bar(b"wat") # error: [no-matching-overload]
|
||||
```
|
||||
|
||||
## A class constructor with unmatched overloads
|
||||
|
||||
TODO: At time of writing (2025-05-15), this has non-ideal diagnostics that doesn't show the
|
||||
unmatched overloads.
|
||||
|
||||
```py
|
||||
type() # error: [no-matching-overload]
|
||||
```
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
---
|
||||
source: crates/ty_test/src/lib.rs
|
||||
expression: snapshot
|
||||
---
|
||||
---
|
||||
mdtest name: no_matching_overload.md - No matching overload diagnostics - A class constructor with unmatched overloads
|
||||
mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/no_matching_overload.md
|
||||
---
|
||||
|
||||
# Python source files
|
||||
|
||||
## mdtest_snippet.py
|
||||
|
||||
```
|
||||
1 | type() # error: [no-matching-overload]
|
||||
```
|
||||
|
||||
# Diagnostics
|
||||
|
||||
```
|
||||
error[no-matching-overload]: No overload of class `type` matches arguments
|
||||
--> src/mdtest_snippet.py:1:1
|
||||
|
|
||||
1 | type() # error: [no-matching-overload]
|
||||
| ^^^^^^
|
||||
|
|
||||
info: rule `no-matching-overload` is enabled by default
|
||||
|
||||
```
|
|
@ -0,0 +1,63 @@
|
|||
---
|
||||
source: crates/ty_test/src/lib.rs
|
||||
expression: snapshot
|
||||
---
|
||||
---
|
||||
mdtest name: no_matching_overload.md - No matching overload diagnostics - A method call with unmatched overloads
|
||||
mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/no_matching_overload.md
|
||||
---
|
||||
|
||||
# Python source files
|
||||
|
||||
## mdtest_snippet.py
|
||||
|
||||
```
|
||||
1 | from typing import overload
|
||||
2 |
|
||||
3 | class Foo:
|
||||
4 | @overload
|
||||
5 | def bar(self, x: int) -> int: ...
|
||||
6 | @overload
|
||||
7 | def bar(self, x: str) -> str: ...
|
||||
8 | def bar(self, x: int | str) -> int | str:
|
||||
9 | return x
|
||||
10 |
|
||||
11 | foo = Foo()
|
||||
12 | foo.bar(b"wat") # error: [no-matching-overload]
|
||||
```
|
||||
|
||||
# Diagnostics
|
||||
|
||||
```
|
||||
error[no-matching-overload]: No overload of bound method `bar` matches arguments
|
||||
--> src/mdtest_snippet.py:12:1
|
||||
|
|
||||
11 | foo = Foo()
|
||||
12 | foo.bar(b"wat") # error: [no-matching-overload]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
info: First overload defined here
|
||||
--> src/mdtest_snippet.py:5:9
|
||||
|
|
||||
3 | class Foo:
|
||||
4 | @overload
|
||||
5 | def bar(self, x: int) -> int: ...
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
6 | @overload
|
||||
7 | def bar(self, x: str) -> str: ...
|
||||
|
|
||||
info: Possible overloads for bound method `bar`:
|
||||
info: (self, x: int) -> int
|
||||
info: (self, x: str) -> str
|
||||
info: Overload implementation defined here
|
||||
--> src/mdtest_snippet.py:8:9
|
||||
|
|
||||
6 | @overload
|
||||
7 | def bar(self, x: str) -> str: ...
|
||||
8 | def bar(self, x: int | str) -> int | str:
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
9 | return x
|
||||
|
|
||||
info: rule `no-matching-overload` is enabled by default
|
||||
|
||||
```
|
|
@ -1120,7 +1120,19 @@ impl<'db> CallableBinding<'db> {
|
|||
String::new()
|
||||
}
|
||||
));
|
||||
if let Some(function) = self.signature_type.into_function_literal() {
|
||||
// TODO: This should probably be adapted to handle more
|
||||
// types of callables[1]. At present, it just handles
|
||||
// standard function and method calls.
|
||||
//
|
||||
// [1]: https://github.com/astral-sh/ty/issues/274#issuecomment-2881856028
|
||||
let function_type_and_kind = match self.signature_type {
|
||||
Type::FunctionLiteral(function) => Some(("function", function)),
|
||||
Type::BoundMethod(bound_method) => {
|
||||
Some(("bound method", bound_method.function(context.db())))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
if let Some((kind, function)) = function_type_and_kind {
|
||||
if let Some(overloaded_function) = function.to_overloaded(context.db()) {
|
||||
if let Some(spans) = overloaded_function
|
||||
.overloads
|
||||
|
@ -1134,7 +1146,7 @@ impl<'db> CallableBinding<'db> {
|
|||
}
|
||||
|
||||
diag.info(format_args!(
|
||||
"Possible overloads for function `{}`:",
|
||||
"Possible overloads for {kind} `{}`:",
|
||||
function.name(context.db())
|
||||
));
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue