[red-knot] Check assignability of bound methods to callables (#17430)

## Summary

This is similar to https://github.com/astral-sh/ruff/pull/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`.
This commit is contained in:
Dhruv Manilawala 2025-04-17 00:21:59 +05:30 committed by GitHub
parent 649610cc98
commit 5350288d07
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 22 additions and 0 deletions

View file

@ -504,4 +504,22 @@ c: Callable[[Any], str] = f
c: Callable[[Any], str] = g
```
### Method types
```py
from typing import Any, Callable
class A:
def f(self, x: Any) -> str:
return ""
def g(self, x: Any) -> int:
return 1
c: Callable[[Any], str] = A().f
# error: [invalid-assignment] "Object of type `bound method A.g(x: Any) -> int` is not assignable to `(Any, /) -> str`"
c: Callable[[Any], str] = A().g
```
[typing documentation]: https://typing.python.org/en/latest/spec/concepts.html#the-assignable-to-or-consistent-subtyping-relation

View file

@ -1368,6 +1368,10 @@ impl<'db> Type<'db> {
.is_assignable_to(db, target)
}
(Type::BoundMethod(self_bound_method), Type::Callable(_)) => self_bound_method
.into_callable_type(db)
.is_assignable_to(db, target),
// TODO other types containing gradual forms (e.g. generics containing Any/Unknown)
_ => self.is_subtype_of(db, target),
}