mirror of https://github.com/astral-sh/ruff
don't consider self
This commit is contained in:
parent
ebfb33c30b
commit
40600821ea
|
|
@ -1963,6 +1963,10 @@ static_assert(not is_subtype_of(type[A], Callable[[int], A]))
|
|||
|
||||
### Bound methods
|
||||
|
||||
The bound `self` or `cls` parameter of a bound method has been curried away, and is no longer
|
||||
available as a parameter when calling it. It therefore is not considered when checking subtyping
|
||||
involving the bound method.
|
||||
|
||||
```py
|
||||
from typing import Callable
|
||||
from ty_extensions import TypeOf, static_assert, is_subtype_of
|
||||
|
|
@ -1981,12 +1985,131 @@ static_assert(is_subtype_of(TypeOf[a.f], Callable[[int], int]))
|
|||
static_assert(is_subtype_of(TypeOf[a.g], Callable[[int], int]))
|
||||
static_assert(is_subtype_of(TypeOf[A.g], Callable[[int], int]))
|
||||
|
||||
static_assert(not is_subtype_of(TypeOf[a.f], Callable[[float], int]))
|
||||
static_assert(not is_subtype_of(TypeOf[A.g], Callable[[], int]))
|
||||
|
||||
static_assert(is_subtype_of(TypeOf[A.f], Callable[[A, int], int]))
|
||||
```
|
||||
|
||||
Return types are in covariant position:
|
||||
|
||||
```py
|
||||
static_assert(is_subtype_of(TypeOf[a.f], Callable[[int], object]))
|
||||
static_assert(is_subtype_of(TypeOf[a.g], Callable[[int], object]))
|
||||
static_assert(is_subtype_of(TypeOf[A.g], Callable[[int], object]))
|
||||
|
||||
static_assert(not is_subtype_of(TypeOf[a.f], Callable[[int], bool]))
|
||||
static_assert(not is_subtype_of(TypeOf[a.g], Callable[[int], bool]))
|
||||
static_assert(not is_subtype_of(TypeOf[A.g], Callable[[int], bool]))
|
||||
```
|
||||
|
||||
Parameter types are in contravariant position:
|
||||
|
||||
```py
|
||||
static_assert(not is_subtype_of(TypeOf[a.f], Callable[[object], int]))
|
||||
static_assert(not is_subtype_of(TypeOf[a.g], Callable[[object], int]))
|
||||
static_assert(not is_subtype_of(TypeOf[A.g], Callable[[object], int]))
|
||||
|
||||
static_assert(is_subtype_of(TypeOf[a.f], Callable[[bool], int]))
|
||||
static_assert(is_subtype_of(TypeOf[a.g], Callable[[bool], int]))
|
||||
static_assert(is_subtype_of(TypeOf[A.g], Callable[[bool], int]))
|
||||
```
|
||||
|
||||
We should get the same results when comparing with a bound method of a different class.
|
||||
|
||||
```py
|
||||
class B:
|
||||
def returns_int(self, a: int) -> int:
|
||||
return 0
|
||||
|
||||
def returns_object(self, a: int) -> object:
|
||||
return a
|
||||
|
||||
def returns_bool(self, a: int) -> bool:
|
||||
return True
|
||||
|
||||
def takes_object(self, a: object) -> int:
|
||||
return 0
|
||||
|
||||
def takes_bool(self, a: bool) -> int:
|
||||
return 0
|
||||
|
||||
@classmethod
|
||||
def class_returns_int(cls, a: int) -> int:
|
||||
return 0
|
||||
|
||||
@classmethod
|
||||
def class_returns_object(cls, a: int) -> object:
|
||||
return a
|
||||
|
||||
@classmethod
|
||||
def class_returns_bool(cls, a: int) -> bool:
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def class_takes_object(cls, a: object) -> int:
|
||||
return 0
|
||||
|
||||
@classmethod
|
||||
def class_takes_bool(cls, a: bool) -> int:
|
||||
return 0
|
||||
|
||||
b = B()
|
||||
|
||||
static_assert(is_subtype_of(TypeOf[a.f], TypeOf[b.returns_object]))
|
||||
static_assert(is_subtype_of(TypeOf[a.f], TypeOf[b.returns_int]))
|
||||
static_assert(not is_subtype_of(TypeOf[a.f], TypeOf[b.returns_bool]))
|
||||
static_assert(not is_subtype_of(TypeOf[a.f], TypeOf[b.takes_object]))
|
||||
static_assert(is_subtype_of(TypeOf[a.f], TypeOf[b.takes_bool]))
|
||||
|
||||
static_assert(is_subtype_of(TypeOf[a.f], TypeOf[b.class_returns_object]))
|
||||
static_assert(is_subtype_of(TypeOf[a.f], TypeOf[b.class_returns_int]))
|
||||
static_assert(not is_subtype_of(TypeOf[a.f], TypeOf[b.class_returns_bool]))
|
||||
static_assert(not is_subtype_of(TypeOf[a.f], TypeOf[b.class_takes_object]))
|
||||
static_assert(is_subtype_of(TypeOf[a.f], TypeOf[b.class_takes_bool]))
|
||||
|
||||
static_assert(is_subtype_of(TypeOf[a.f], TypeOf[B.class_returns_object]))
|
||||
static_assert(is_subtype_of(TypeOf[a.f], TypeOf[B.class_returns_int]))
|
||||
static_assert(not is_subtype_of(TypeOf[a.f], TypeOf[B.class_returns_bool]))
|
||||
static_assert(not is_subtype_of(TypeOf[a.f], TypeOf[B.class_takes_object]))
|
||||
static_assert(is_subtype_of(TypeOf[a.f], TypeOf[B.class_takes_bool]))
|
||||
|
||||
static_assert(is_subtype_of(TypeOf[a.g], TypeOf[b.returns_object]))
|
||||
static_assert(is_subtype_of(TypeOf[a.g], TypeOf[b.returns_int]))
|
||||
static_assert(not is_subtype_of(TypeOf[a.g], TypeOf[b.returns_bool]))
|
||||
static_assert(not is_subtype_of(TypeOf[a.g], TypeOf[b.takes_object]))
|
||||
static_assert(is_subtype_of(TypeOf[a.g], TypeOf[b.takes_bool]))
|
||||
|
||||
static_assert(is_subtype_of(TypeOf[a.g], TypeOf[b.class_returns_object]))
|
||||
static_assert(is_subtype_of(TypeOf[a.g], TypeOf[b.class_returns_int]))
|
||||
static_assert(not is_subtype_of(TypeOf[a.g], TypeOf[b.class_returns_bool]))
|
||||
static_assert(not is_subtype_of(TypeOf[a.g], TypeOf[b.class_takes_object]))
|
||||
static_assert(is_subtype_of(TypeOf[a.g], TypeOf[b.class_takes_bool]))
|
||||
|
||||
static_assert(is_subtype_of(TypeOf[a.g], TypeOf[B.class_returns_object]))
|
||||
static_assert(is_subtype_of(TypeOf[a.g], TypeOf[B.class_returns_int]))
|
||||
static_assert(not is_subtype_of(TypeOf[a.g], TypeOf[B.class_returns_bool]))
|
||||
static_assert(not is_subtype_of(TypeOf[a.g], TypeOf[B.class_takes_object]))
|
||||
static_assert(is_subtype_of(TypeOf[a.g], TypeOf[B.class_takes_bool]))
|
||||
|
||||
static_assert(is_subtype_of(TypeOf[A.g], TypeOf[b.returns_object]))
|
||||
static_assert(is_subtype_of(TypeOf[A.g], TypeOf[b.returns_int]))
|
||||
static_assert(not is_subtype_of(TypeOf[A.g], TypeOf[b.returns_bool]))
|
||||
static_assert(not is_subtype_of(TypeOf[A.g], TypeOf[b.takes_object]))
|
||||
static_assert(is_subtype_of(TypeOf[A.g], TypeOf[b.takes_bool]))
|
||||
|
||||
static_assert(is_subtype_of(TypeOf[A.g], TypeOf[b.class_returns_object]))
|
||||
static_assert(is_subtype_of(TypeOf[A.g], TypeOf[b.class_returns_int]))
|
||||
static_assert(not is_subtype_of(TypeOf[A.g], TypeOf[b.class_returns_bool]))
|
||||
static_assert(not is_subtype_of(TypeOf[A.g], TypeOf[b.class_takes_object]))
|
||||
static_assert(is_subtype_of(TypeOf[A.g], TypeOf[b.class_takes_bool]))
|
||||
|
||||
static_assert(is_subtype_of(TypeOf[A.g], TypeOf[B.class_returns_object]))
|
||||
static_assert(is_subtype_of(TypeOf[A.g], TypeOf[B.class_returns_int]))
|
||||
static_assert(not is_subtype_of(TypeOf[A.g], TypeOf[B.class_returns_bool]))
|
||||
static_assert(not is_subtype_of(TypeOf[A.g], TypeOf[B.class_takes_object]))
|
||||
static_assert(is_subtype_of(TypeOf[A.g], TypeOf[B.class_takes_bool]))
|
||||
```
|
||||
|
||||
### Overloads
|
||||
|
||||
#### Subtype overloaded
|
||||
|
|
|
|||
|
|
@ -9165,20 +9165,16 @@ impl<'db> BoundMethodType<'db> {
|
|||
relation: TypeRelation,
|
||||
visitor: &HasRelationToVisitor<'db>,
|
||||
) -> ConstraintSet<'db> {
|
||||
// A bound method is a typically a subtype of itself. However, we must explicitly verify
|
||||
// the subtyping of the underlying function signatures (since they might be specialized
|
||||
// differently), and of the bound self parameter (taking care that parameters, including a
|
||||
// bound self parameter, are contravariant.)
|
||||
self.function(db)
|
||||
.has_relation_to_impl(db, other.function(db), relation, visitor)
|
||||
.and(db, || {
|
||||
other.self_instance(db).has_relation_to_impl(
|
||||
// Note that we do not consider `self_instance`, and we use `into_callable_type` to compare
|
||||
// the signatures of the bound methods _after_ the `self` parameter has been bound. The
|
||||
// bound `self` is no longer available as a parameter to callers, and should therefore not
|
||||
// influence the result of the check.
|
||||
self.into_callable_type(db).has_relation_to_impl(
|
||||
db,
|
||||
self.self_instance(db),
|
||||
other.into_callable_type(db),
|
||||
relation,
|
||||
visitor,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn is_equivalent_to_impl(
|
||||
|
|
@ -9187,13 +9183,12 @@ impl<'db> BoundMethodType<'db> {
|
|||
other: Self,
|
||||
visitor: &IsEquivalentVisitor<'db>,
|
||||
) -> ConstraintSet<'db> {
|
||||
self.function(db)
|
||||
.is_equivalent_to_impl(db, other.function(db), visitor)
|
||||
.and(db, || {
|
||||
other
|
||||
.self_instance(db)
|
||||
.is_equivalent_to_impl(db, self.self_instance(db), visitor)
|
||||
})
|
||||
// Note that we do not consider `self_instance`, and we use `into_callable_type` to compare
|
||||
// the signatures of the bound methods _after_ the `self` parameter has been bound. The
|
||||
// bound `self` is no longer available as a parameter to callers, and should therefore not
|
||||
// influence the result of the check.
|
||||
self.into_callable_type(db)
|
||||
.is_equivalent_to_impl(db, other.into_callable_type(db), visitor)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue