From 4a6fa5fc27bd808f9ddc65996ecb8eea7844c6ef Mon Sep 17 00:00:00 2001 From: Matthew Mckee Date: Mon, 31 Mar 2025 16:42:42 +0100 Subject: [PATCH] [red-knot] Add assignability of function literals to callables (#17095) ## Summary Part of #16953 ## Test Plan Update is_assignable_to.md --------- Co-authored-by: Dhruv Manilawala --- .../mdtest/type_properties/is_assignable_to.md | 17 +++++++++++++++++ crates/red_knot_python_semantic/src/types.rs | 6 ++++++ 2 files changed, 23 insertions(+) diff --git a/crates/red_knot_python_semantic/resources/mdtest/type_properties/is_assignable_to.md b/crates/red_knot_python_semantic/resources/mdtest/type_properties/is_assignable_to.md index 3937d2ee08..6f9cf78028 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/type_properties/is_assignable_to.md +++ b/crates/red_knot_python_semantic/resources/mdtest/type_properties/is_assignable_to.md @@ -476,4 +476,21 @@ static_assert(is_assignable_to(CallableTypeOf[keyword_variadic], Callable[..., N static_assert(is_assignable_to(CallableTypeOf[mixed], Callable[..., None])) ``` +### Function types + +```py +from typing import Any, Callable + +def f(x: Any) -> str: + return "" + +def g(x: Any) -> int: + return 1 + +c: Callable[[Any], str] = f + +# error: [invalid-assignment] "Object of type `Literal[g]` is not assignable to `(Any, /) -> str`" +c: Callable[[Any], str] = g +``` + [typing documentation]: https://typing.readthedocs.io/en/latest/spec/concepts.html#the-assignable-to-or-consistent-subtyping-relation diff --git a/crates/red_knot_python_semantic/src/types.rs b/crates/red_knot_python_semantic/src/types.rs index d45ec530d8..d5ed2b6d77 100644 --- a/crates/red_knot_python_semantic/src/types.rs +++ b/crates/red_knot_python_semantic/src/types.rs @@ -900,6 +900,12 @@ impl<'db> Type<'db> { Type::Callable(CallableType::General(target_callable)), ) => self_callable.is_assignable_to(db, target_callable), + (Type::FunctionLiteral(self_function_literal), Type::Callable(_)) => { + self_function_literal + .into_callable_type(db) + .is_assignable_to(db, target) + } + // TODO other types containing gradual forms (e.g. generics containing Any/Unknown) _ => self.is_subtype_of(db, target), }