Skip to content

Conversation

@dhruvmanila
Copy link
Member

@dhruvmanila dhruvmanila commented Mar 4, 2025

Summary

Part of #15382

This PR implements a general callable type that wraps around a Signature and it uses that new type to represent typing.Callable.

It also implements Display support for Callable. The format is as:

([<arg name>][: <arg type>][ = <default type>], ...) -> <return type>

The / and * separators are added at the correct boundary for positional-only and keyword-only parameters. Now, as typing.Callable only has positional-only parameters, the rendered signature would be:

Callable[[int, str], None]
# (int, str, /) -> None

The / separator represents that all the arguments are positional-only.

The relationship methods that check assignability, subtype relationship, etc. are not yet implemented and will be done so as a follow-up.

Test Plan

Add test cases for display support for Signature and various mdtest for typing.Callable.

@dhruvmanila dhruvmanila added the ty Multi-file analysis & type inference label Mar 4, 2025
@dhruvmanila dhruvmanila force-pushed the dhruv/callable-type branch from e71d87b to dbae500 Compare March 5, 2025 08:44
@dhruvmanila dhruvmanila force-pushed the dhruv/callable-type branch from dbae500 to 05a7a5b Compare March 5, 2025 10:35
@github-actions
Copy link
Contributor

github-actions bot commented Mar 5, 2025

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

Formatter (stable)

✅ ecosystem check detected no format changes.

Formatter (preview)

✅ ecosystem check detected no format changes.

Copy link
Contributor

@carljm carljm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very cool! Great work.

@dhruvmanila
Copy link
Member Author

dhruvmanila commented Mar 6, 2025

Post review changes

  • Use (...) -> Unknown consistently
  • Display ... for gradual form. This is done using an additional flag on Parameters to indicate the gradual form.
  • Use Any for gradual form while Unknown for invalid forms
  • Avoid special casing for param spec variable
  • Don't error on bare Callable, infer it as (...) -> Unknown
  • Remove various todos, add a couple more
  • Improve display handling of Signature

Regarding the relation implementation, I think I'd prefer to add it in a follow-up PR to keep the changes separate and easier to review. I implemented is_single_valued and is_singleton but not member and static_member yet.

@dhruvmanila dhruvmanila requested a review from carljm March 6, 2025 15:57
Copy link
Contributor

@carljm carljm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@dhruvmanila dhruvmanila enabled auto-merge (squash) March 8, 2025 03:53
@dhruvmanila dhruvmanila merged commit 0361021 into main Mar 8, 2025
20 checks passed
@dhruvmanila dhruvmanila deleted the dhruv/callable-type branch March 8, 2025 03:58
@dhruvmanila dhruvmanila linked an issue Mar 8, 2025 that may be closed by this pull request
19 tasks
dcreager added a commit that referenced this pull request Mar 8, 2025
* main:
  [red-knot] Understand `typing.Callable` (#16493)
  [red-knot] Support unpacking `with` target (#16469)
  [red-knot] Attribute access and the descriptor protocol (#16416)
  [`pep8-naming`] Add links to `ignore-names` options in various rules' documentation (#16557)
  [red-knot] avoid inferring types if unpacking fails (#16530)
Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

two tiny nits I spotted that probably don't warrant their own PR, but could maybe be addressed if you're doing further followup work on Callable types

Comment on lines +350 to +354
pub(crate) fn is_keyword_only(&self) -> bool {
matches!(self.kind, ParameterKind::KeywordOnly { .. })
}

pub(crate) fn is_positional_only(&self) -> bool {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit

Suggested change
pub(crate) fn is_keyword_only(&self) -> bool {
matches!(self.kind, ParameterKind::KeywordOnly { .. })
}
pub(crate) fn is_positional_only(&self) -> bool {
pub(crate) const fn is_keyword_only(&self) -> bool {
matches!(self.kind, ParameterKind::KeywordOnly { .. })
}
pub(crate) const fn is_positional_only(&self) -> bool {

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be wrong but I'm not sure if this is going to make any difference as we don't use any of these functions in the const context and I don't know we'll ever be able to (?) because parameters are always going to be dynamic i.e., we cannot statically determine during compile time whether a parameter is positional or not.

dhruvmanila added a commit that referenced this pull request Mar 12, 2025
## Summary

This PR is a follow-up to #16493
that implements member lookup for the general callable type.

Based on the discussion around [member lookup
here](#16493 (comment))
and [`.to_meta_type()`
here](#16493 (comment)).

## Test Plan

Add a new test cases.
AlexWaygood added a commit that referenced this pull request May 3, 2025
## Summary

Currently this assertion fails on `main`, because we do not synthesize a
`__call__` attribute for Callable types:

```py
from typing import Protocol, Callable
from knot_extensions import static_assert, is_assignable_to

class Foo(Protocol):
    def __call__(self, x: int, /) -> str: ...

static_assert(is_assignable_to(Callable[[int], str], Foo))
```

This PR fixes that.

See previous discussion about this in
#16493 (comment) and
#17682 (comment)

## Test Plan

Existing mdtests updated; a couple of new ones added.
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.

[red-knot] Support callable types and typing.Callable

5 participants