[red-knot] Handle unions of callables better (#16716)

This cleans up how we handle calling unions of types. #16568 adding a
three-level structure for callable signatures (`Signatures`,
`CallableSignature`, and `Signature`) to handle unions and overloads.

This PR updates the bindings side to mimic that structure. What used to
be called `CallOutcome` is now `Bindings`, and represents the result of
binding actual arguments against a possible union of callables.
`CallableBinding` is the result of binding a single, possibly
overloaded, callable type. `Binding` is the result of binding a single
overload.

While we're here, this also cleans up `CallError` greatly. It was
previously extracting error information from the bindings and storing it
in the error result. It is now a simple enum, carrying no data, that's
used as a status code to talk about whether the overall binding was
successful or not. We are now more consistent about walking the binding
itself to get detailed information about _how_ the binding was
unsucessful.

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Co-authored-by: Carl Meyer <carl@astral.sh>
This commit is contained in:
Douglas Creager
2025-03-17 10:35:52 -04:00
committed by GitHub
parent 3ccc8dbbf9
commit 23ccb52fa6
27 changed files with 1301 additions and 1251 deletions

View File

@@ -40,7 +40,7 @@ def _(flag: bool):
```py
class NotBoolable:
__bool__ = 3
__bool__: int = 3
# error: [unsupported-bool-conversion] "Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable"
3 if NotBoolable() else 4

View File

@@ -152,7 +152,7 @@ def _(flag: bool):
```py
class NotBoolable:
__bool__ = 3
__bool__: int = 3
# error: [unsupported-bool-conversion] "Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable"
if NotBoolable():

View File

@@ -48,7 +48,7 @@ def _(target: int):
```py
class NotBoolable:
__bool__ = 3
__bool__: int = 3
def _(target: int, flag: NotBoolable):
y = 1