diff --git a/crates/red_knot_python_semantic/resources/mdtest/annotations/unsupported_special_forms.md b/crates/red_knot_python_semantic/resources/mdtest/annotations/unsupported_special_forms.md index f81c230b0b..bed5c4a56f 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/annotations/unsupported_special_forms.md +++ b/crates/red_knot_python_semantic/resources/mdtest/annotations/unsupported_special_forms.md @@ -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: diff --git a/crates/red_knot_python_semantic/resources/mdtest/call/annotation.md b/crates/red_knot_python_semantic/resources/mdtest/call/annotation.md new file mode 100644 index 0000000000..1899baafe6 --- /dev/null +++ b/crates/red_knot_python_semantic/resources/mdtest/call/annotation.md @@ -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 +``` diff --git a/crates/red_knot_python_semantic/src/types.rs b/crates/red_knot_python_semantic/src/types.rs index 810e5ae18f..61d6b147e3 100644 --- a/crates/red_knot_python_semantic/src/types.rs +++ b/crates/red_knot_python_semantic/src/types.rs @@ -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())