Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
4e5994c
Rename bindings types
dcreager Mar 11, 2025
90e4b9b
Move Bindings into bind module
dcreager Mar 11, 2025
adede59
Make bind_call/overload constructor methods
dcreager Mar 11, 2025
57b400c
Add dunder_call to callable signature
dcreager Mar 11, 2025
e611d6f
Mostly working
dcreager Mar 12, 2025
c3a3659
There we go
dcreager Mar 13, 2025
453dbfa
Remove unused stuff
dcreager Mar 13, 2025
61a1cea
clippy
dcreager Mar 13, 2025
1266d0f
lint
dcreager Mar 13, 2025
0bf32e3
Clean up error types more
dcreager Mar 13, 2025
06825f2
Merge branch 'main' into dcreager/union-callables
dcreager Mar 14, 2025
a85b6d5
Fix merge conflicts
dcreager Mar 14, 2025
88ad36f
clippy
dcreager Mar 14, 2025
903bfde
Track call signatures
dcreager Mar 14, 2025
71fe9ff
Back to `try_call`
dcreager Mar 14, 2025
a1596da
Better comment for `Type::signatures`
dcreager Mar 14, 2025
da5eef3
Remove all mut use of Signatures
dcreager Mar 14, 2025
fb9fd6e
Track signatures structs
dcreager Mar 14, 2025
d0a07fc
Simplify signatures a bit
dcreager Mar 14, 2025
9d525c7
Store signature in callable binding too
dcreager Mar 14, 2025
b6af683
Change to iter/iter_mut
dcreager Mar 14, 2025
834d4aa
fix doc links
dcreager Mar 14, 2025
675e496
lint
dcreager Mar 14, 2025
19a1e53
Untrack signatures
dcreager Mar 14, 2025
b2b943c
Back to mut
dcreager Mar 14, 2025
fd3d579
Remove (some) stutter from call errors
dcreager Mar 14, 2025
d279145
Apply suggestions from code review
dcreager Mar 14, 2025
dda63db
Fewer is_known calls
dcreager Mar 14, 2025
d997944
Only iterate errors if there are any
dcreager Mar 14, 2025
b4103ab
CallableDescriptor → Description
dcreager Mar 14, 2025
9cf9e28
Doesn't panic anymore
dcreager Mar 14, 2025
00891ae
ty → type
dcreager Mar 14, 2025
aa2d77c
Merge branch 'main' into dcreager/union-callables
dcreager Mar 14, 2025
3357df6
Apply suggestions from code review
dcreager Mar 15, 2025
9957879
Panic again
dcreager Mar 15, 2025
aed2a87
Remove unneeded lifetime params
dcreager Mar 15, 2025
e770680
Comment empty overloads vec
dcreager Mar 15, 2025
0cf9acd
Better comments
dcreager Mar 15, 2025
1cd9df8
Use bool for dunder_call_is_possibly_unbound
dcreager Mar 15, 2025
11951dd
callable_descriptor → description
dcreager Mar 15, 2025
86be76a
Clarify CallError comments
dcreager Mar 15, 2025
6d00d40
Bring back replace_type
dcreager Mar 15, 2025
9082b4b
Don't intern signatures
dcreager Mar 15, 2025
edc8c1d
Add with_bound_type
dcreager Mar 15, 2025
bb17715
clippy
dcreager Mar 15, 2025
50f4bd3
Match on the binding type
dcreager Mar 15, 2025
3946f37
replace iter methods with IntoIterator impls
dcreager Mar 15, 2025
9677ec5
reduce indentation
dcreager Mar 15, 2025
f7b8247
Clarify boxed bindings in `CallError`
dcreager Mar 15, 2025
608ad34
clippy
dcreager Mar 15, 2025
2e317e1
Use SmallVec to optimize non-union and non-overloads
dcreager Mar 15, 2025
1d5c021
Remove into_result for real I guess
dcreager Mar 15, 2025
23c311d
clippy
dcreager Mar 15, 2025
c794612
Remove some identation
dcreager Mar 15, 2025
c9499b7
Merge branch 'main' into dcreager/union-callables
dcreager Mar 15, 2025
fd1ccd8
todo half done
dcreager Mar 15, 2025
28c2c62
Remove multiple class is_known calls
dcreager Mar 15, 2025
e57f986
Fix test assertions
dcreager Mar 15, 2025
7c88a34
Update crates/red_knot_python_semantic/src/types.rs
dcreager Mar 17, 2025
6dc3dcf
Update tests
dcreager Mar 17, 2025
e460c80
Merge branch 'main' into dcreager/union-callables
dcreager Mar 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ reveal_type(X() + Y()) # revealed: int

```py
class NotBoolable:
__bool__ = 3
__bool__: int = 3

a = NotBoolable()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def _(flag: bool):

a = NonCallable()
# error: [call-non-callable] "Object of type `Literal[1]` is not callable"
reveal_type(a()) # revealed: int | Unknown
reveal_type(a()) # revealed: Unknown | int
```

## Call binding errors
Expand Down
17 changes: 15 additions & 2 deletions crates/red_knot_python_semantic/resources/mdtest/call/union.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def _(flag: bool):
def f() -> int:
return 1
x = f() # error: [call-non-callable] "Object of type `Literal[1]` is not callable"
reveal_type(x) # revealed: int | Unknown
reveal_type(x) # revealed: Unknown | int
```

## Multiple non-callable elements in a union
Expand All @@ -58,7 +58,7 @@ def _(flag: bool, flag2: bool):
return 1
# TODO we should mention all non-callable elements of the union
# error: [call-non-callable] "Object of type `Literal[1]` is not callable"
# revealed: int | Unknown
# revealed: Unknown | int
reveal_type(f())
```

Expand Down Expand Up @@ -148,3 +148,16 @@ def _(flag: bool):
x = f(3)
reveal_type(x) # revealed: Unknown
```

## Union including a special-cased function

```py
def _(flag: bool):
if flag:
f = str
else:
f = repr
reveal_type(str("string")) # revealed: Literal["string"]
reveal_type(repr("string")) # revealed: Literal["'string'"]
reveal_type(f("string")) # revealed: Literal["string", "'string'"]
```
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ It may also be more appropriate to use `unsupported-operator` as the error code.

```py
class NotBoolable:
__bool__ = 3
__bool__: int = 3

class WithContains:
def __contains__(self, item) -> NotBoolable:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ element) of a chained comparison.

```py
class NotBoolable:
__bool__ = 3
__bool__: int = 3

class Comparable:
def __lt__(self, item) -> NotBoolable:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ def compute_chained_comparison():

```py
class NotBoolable:
__bool__ = 5
__bool__: int = 5

class Comparable:
def __lt__(self, other) -> NotBoolable:
Expand Down Expand Up @@ -387,7 +387,7 @@ class A:
return NotBoolable()

class NotBoolable:
__bool__ = None
__bool__: None = None

# error: [unsupported-bool-conversion]
(A(),) == (A(),)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def _(target: int):

```py
class NotBoolable:
__bool__ = 3
__bool__: int = 3
Copy link
Member Author

Choose a reason for hiding this comment

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

Without these changes, we infer the type of __bool__ to be int | Unknown. Only one of the union branches is non-callable, which changes the content of the error message below. I decided to add the type annotations instead of updating the expected error messages, since this seems to more accurately reflect the intent of these NotBoolable types.


def _(target: int, flag: NotBoolable):
y = 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

```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"
assert NotBoolable()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ if NotBoolable():

```py
class NotBoolable:
__bool__ = None
__bool__: None = None

# error: [unsupported-bool-conversion] "Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable"
if NotBoolable():
Expand All @@ -133,9 +133,9 @@ if NotBoolable():
```py
def test(cond: bool):
class NotBoolable:
__bool__ = None if cond else 3
__bool__: int | None = None if cond else 3

# error: [unsupported-bool-conversion] "Boolean conversion is unsupported for type `NotBoolable`; it incorrectly implements `__bool__`"
# error: [unsupported-bool-conversion] "Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable"
Copy link
Member Author

Choose a reason for hiding this comment

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

Here __bool__ is a union, but unlike above, both elements are non-callable, so we treat the union as a whole as non-callable.

if NotBoolable():
...
```
Expand All @@ -145,7 +145,7 @@ def test(cond: bool):
```py
def test(cond: bool):
class NotBoolable:
__bool__ = None
__bool__: None = None

a = 10 if cond else NotBoolable()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def _(flag: bool, flag2: 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"
while NotBoolable():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,7 @@ error: lint:not-iterable
|
35 | # error: [not-iterable]
36 | for y in Iterable2():
| ^^^^^^^^^^^ Object of type `Iterable2` may not be iterable because it may not have an `__iter__` method and its `__getitem__` method (with type `<bound method `__getitem__` of `Iterable2`> | <bound method `__getitem__` of `Iterable2`>`)
may have an incorrect signature for the old-style iteration protocol (expected a signature at least as permissive as `def __getitem__(self, key: int): ...`)
| ^^^^^^^^^^^ Object of type `Iterable2` may not be iterable because it may not have an `__iter__` method and its `__getitem__` method (with type `<bound method `__getitem__` of `Iterable2`> | <bound method `__getitem__` of `Iterable2`>`) may have an incorrect signature for the old-style iteration protocol (expected a signature at least as permissive as `def __getitem__(self, key: int): ...`)
37 | reveal_type(y) # revealed: bytes | str | int
|

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/binary/instances.m

```
1 | class NotBoolable:
2 | __bool__ = 3
2 | __bool__: int = 3
3 |
4 | a = NotBoolable()
5 |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/comparison/instanc

```
1 | class NotBoolable:
2 | __bool__ = 3
2 | __bool__: int = 3
3 |
4 | class WithContains:
5 | def __contains__(self, item) -> NotBoolable:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/unary/not.md

```
1 | class NotBoolable:
2 | __bool__ = 3
2 | __bool__: int = 3
3 |
4 | # error: [unsupported-bool-conversion]
5 | not NotBoolable()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/comparison/instanc

```
1 | class NotBoolable:
2 | __bool__ = 3
2 | __bool__: int = 3
3 |
4 | class Comparable:
5 | def __lt__(self, item) -> NotBoolable:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/comparison/tuples.

```
1 | class NotBoolable:
2 | __bool__ = 5
2 | __bool__: int = 5
3 |
4 | class Comparable:
5 | def __lt__(self, other) -> NotBoolable:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/comparison/tuples.
3 | return NotBoolable()
4 |
5 | class NotBoolable:
6 | __bool__ = None
6 | __bool__: None = None
7 |
8 | # error: [unsupported-bool-conversion]
9 | (A(),) == (A(),)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ reveal_type(not PossiblyUnboundBool())

```py
class NotBoolable:
__bool__ = 3
__bool__: int = 3

# error: [unsupported-bool-conversion]
not NotBoolable()
Expand Down
2 changes: 1 addition & 1 deletion crates/red_knot_python_semantic/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::{resolve_module, Db, KnownModule, Module, Program};

pub(crate) use implicit_globals::module_type_implicit_global_symbol;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub(crate) enum Boundness {
Bound,
PossiblyUnbound,
Expand Down
Loading
Loading