mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-03 18:28:56 +00:00
[red-knot] Support calling a typing.Callable
(#16888)
## Summary Part of #15382, this PR adds support for calling a variable that's annotated with `typing.Callable`. ## Test Plan Add test cases in a new `call/annotation.md` file.
This commit is contained in:
parent
1cffb323bc
commit
0360c6b219
3 changed files with 47 additions and 2 deletions
|
@ -29,8 +29,6 @@ def i(callback: Callable[Concatenate[int, P], R_co], *args: P.args, **kwargs: P.
|
|||
# TODO: should understand the annotation
|
||||
reveal_type(kwargs) # revealed: dict
|
||||
|
||||
# TODO: not an error; remove once `call` is implemented for `Callable`
|
||||
# error: [call-non-callable]
|
||||
return callback(42, *args, **kwargs)
|
||||
|
||||
class Foo:
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
# `typing.Callable`
|
||||
|
||||
```py
|
||||
from typing import Callable
|
||||
|
||||
def _(c: Callable[[], int]):
|
||||
reveal_type(c()) # revealed: 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`"
|
||||
reveal_type(c("a", 1)) # revealed: int
|
||||
```
|
||||
|
||||
The `Callable` annotation can only be used to describe positional-only parameters.
|
||||
|
||||
```py
|
||||
def _(c: Callable[[int, str], None]):
|
||||
# error: [unknown-argument] "Argument `a` does not match any known parameter"
|
||||
# error: [unknown-argument] "Argument `b` does not match any known parameter"
|
||||
# error: [missing-argument] "No arguments provided for required parameters 1, 2"
|
||||
reveal_type(c(a=1, b="b")) # revealed: None
|
||||
```
|
||||
|
||||
If the annotation uses a gradual form (`...`) for the parameter list, then it can accept any kind of
|
||||
parameter with any type.
|
||||
|
||||
```py
|
||||
def _(c: Callable[..., int]):
|
||||
reveal_type(c()) # revealed: int
|
||||
reveal_type(c(1)) # revealed: int
|
||||
reveal_type(c(1, "str", False, a=[1, 2], b=(3, 4))) # revealed: int
|
||||
```
|
||||
|
||||
An invalid `Callable` form can accept any parameters and will return `Unknown`.
|
||||
|
||||
```py
|
||||
# error: [invalid-type-form]
|
||||
def _(c: Callable[42, str]):
|
||||
reveal_type(c()) # revealed: Unknown
|
||||
```
|
|
@ -2340,6 +2340,10 @@ impl<'db> Type<'db> {
|
|||
/// [`CallErrorKind::NotCallable`].
|
||||
fn signatures(self, db: &'db dyn Db) -> Signatures<'db> {
|
||||
match self {
|
||||
Type::Callable(CallableType::General(callable)) => Signatures::single(
|
||||
CallableSignature::single(self, callable.signature(db).clone()),
|
||||
),
|
||||
|
||||
Type::Callable(CallableType::BoundMethod(bound_method)) => {
|
||||
let signature = bound_method.function(db).signature(db);
|
||||
let signature = CallableSignature::single(self, signature.clone())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue