Skip to content

Conversation

@dhruvmanila
Copy link
Member

Summary

This PR adds a new CallableTypeFromFunction special form to allow extracting the abstract signature of a function literal i.e., convert a Type::Function into a Type::Callable (CallableType::General).

This is done to support testing the is_gradual_equivalent_to type relation specifically the case we want to make sure that a function that has parameters with no annotations and does not have a return type annotation is gradual equivalent to Callable[[Any, Any, ...], Any] where the number of parameters should match between the function literal and callable type.

Refer #16634 (comment)

Bikeshedding

The name CallableTypeFromFunction is a bit too verbose. A possibly alternative from Carl is CallableTypeOf but that would be similar to TypeOf albeit with a limitation that the former only accepts function literal types and errors on other types.

Some other alternatives:

  • FunctionSignature
  • SignatureOf (similar issues as TypeOf?)
  • ...

Test Plan

Update type_api.md with a new section that tests this special form, both invalid and valid forms.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 12, 2025

mypy_primer results

No ecosystem changes detected ✅

@sharkdp
Copy link
Contributor

sharkdp commented Mar 12, 2025

More of a high-level comment. I'm not completely convinced that we need a special form in knot_extensions for this. It seems to me like something that could be implemented with core type-system features, once we support generics?

def signature_of[*Ts, R](c: Callable[[*Ts], R]) -> Callable[[*Ts], R]:
    return c

which could be used like this.

@carljm
Copy link
Contributor

carljm commented Mar 12, 2025

something that could be implemented with core type-system features, once we support generics

This approach can still only express callable types that can be spelled with Callable syntax, which is quite limiting (no named/keyword parameters, no optional/defaulted parameters, no omitted annotations, no overloads...). I think we need this special form because our callable type is capable of expressing many signatures that cannot be spelled using core type forms.

I think a more promising way to (partially?) obviate the need for this special form is "callable Protocols" (that is, a Protocol that defines only a __call__ method). But in this case, I'm not sure yet (until we implement protocols) whether we would special-case interpreting that Protocol as a general callable type, or whether it would retain a distinct representation as a Protocol but implement type equivalency with the equivalent callable type. (Or, possibly, we could even transition "general callable type" to simply be one kind of Protocol. Similarly, AlwaysTruthy and AlwaysFalsy could be represented as a Protocol with bool method returning Literal[True] or Literal[False].)

Given the simplicity of this special form, and the fact that we can use it today to help us test callable type relations more thoroughly, I'm still in favor of landing it. We can always consider removing it later (I guess barring the possibility that it sees wide external adoption, but this is unlikely since it doesn't exist at runtime, and if it does see wide adoption despite that, it suggests that it is useful and shouldn't be removed.)

@dhruvmanila
Copy link
Member Author

Additionally, this will also be useful to test out assignability because lambda expressions are limited in that sense. Protocols would be the best in that scenarios but this would at least allow us to write tests for all possible forms of Callable annotations along against various function signatures.

@dhruvmanila dhruvmanila merged commit 08fa9b4 into main Mar 13, 2025
22 checks passed
@dhruvmanila dhruvmanila deleted the dhruv/callable-type-from-function branch March 13, 2025 02:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants