Skip to content

Commit 5350288

Browse files
authored
[red-knot] Check assignability of bound methods to callables (#17430)
## Summary This is similar to #17095, it adds assignability check for bound methods to callables. ## Test Plan Add test cases to for assignability; specifically it uses gradual types because otherwise it would just delegate to `is_subtype_of`.
1 parent 649610c commit 5350288

File tree

2 files changed

+22
-0
lines changed

2 files changed

+22
-0
lines changed

crates/red_knot_python_semantic/resources/mdtest/type_properties/is_assignable_to.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,4 +504,22 @@ c: Callable[[Any], str] = f
504504
c: Callable[[Any], str] = g
505505
```
506506

507+
### Method types
508+
509+
```py
510+
from typing import Any, Callable
511+
512+
class A:
513+
def f(self, x: Any) -> str:
514+
return ""
515+
516+
def g(self, x: Any) -> int:
517+
return 1
518+
519+
c: Callable[[Any], str] = A().f
520+
521+
# error: [invalid-assignment] "Object of type `bound method A.g(x: Any) -> int` is not assignable to `(Any, /) -> str`"
522+
c: Callable[[Any], str] = A().g
523+
```
524+
507525
[typing documentation]: https://typing.python.org/en/latest/spec/concepts.html#the-assignable-to-or-consistent-subtyping-relation

crates/red_knot_python_semantic/src/types.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1368,6 +1368,10 @@ impl<'db> Type<'db> {
13681368
.is_assignable_to(db, target)
13691369
}
13701370

1371+
(Type::BoundMethod(self_bound_method), Type::Callable(_)) => self_bound_method
1372+
.into_callable_type(db)
1373+
.is_assignable_to(db, target),
1374+
13711375
// TODO other types containing gradual forms (e.g. generics containing Any/Unknown)
13721376
_ => self.is_subtype_of(db, target),
13731377
}

0 commit comments

Comments
 (0)