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
|
### 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
|
```py
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from ty_extensions import TypeOf, static_assert, is_subtype_of
|
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(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(not is_subtype_of(TypeOf[A.g], Callable[[], int]))
|
||||||
|
|
||||||
static_assert(is_subtype_of(TypeOf[A.f], Callable[[A, int], 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
|
### Overloads
|
||||||
|
|
||||||
#### Subtype overloaded
|
#### Subtype overloaded
|
||||||
|
|
|
||||||
|
|
@ -9165,20 +9165,16 @@ impl<'db> BoundMethodType<'db> {
|
||||||
relation: TypeRelation,
|
relation: TypeRelation,
|
||||||
visitor: &HasRelationToVisitor<'db>,
|
visitor: &HasRelationToVisitor<'db>,
|
||||||
) -> ConstraintSet<'db> {
|
) -> ConstraintSet<'db> {
|
||||||
// A bound method is a typically a subtype of itself. However, we must explicitly verify
|
// Note that we do not consider `self_instance`, and we use `into_callable_type` to compare
|
||||||
// the subtyping of the underlying function signatures (since they might be specialized
|
// the signatures of the bound methods _after_ the `self` parameter has been bound. The
|
||||||
// differently), and of the bound self parameter (taking care that parameters, including a
|
// bound `self` is no longer available as a parameter to callers, and should therefore not
|
||||||
// bound self parameter, are contravariant.)
|
// influence the result of the check.
|
||||||
self.function(db)
|
self.into_callable_type(db).has_relation_to_impl(
|
||||||
.has_relation_to_impl(db, other.function(db), relation, visitor)
|
db,
|
||||||
.and(db, || {
|
other.into_callable_type(db),
|
||||||
other.self_instance(db).has_relation_to_impl(
|
relation,
|
||||||
db,
|
visitor,
|
||||||
self.self_instance(db),
|
)
|
||||||
relation,
|
|
||||||
visitor,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_equivalent_to_impl(
|
fn is_equivalent_to_impl(
|
||||||
|
|
@ -9187,13 +9183,12 @@ impl<'db> BoundMethodType<'db> {
|
||||||
other: Self,
|
other: Self,
|
||||||
visitor: &IsEquivalentVisitor<'db>,
|
visitor: &IsEquivalentVisitor<'db>,
|
||||||
) -> ConstraintSet<'db> {
|
) -> ConstraintSet<'db> {
|
||||||
self.function(db)
|
// Note that we do not consider `self_instance`, and we use `into_callable_type` to compare
|
||||||
.is_equivalent_to_impl(db, other.function(db), visitor)
|
// the signatures of the bound methods _after_ the `self` parameter has been bound. The
|
||||||
.and(db, || {
|
// bound `self` is no longer available as a parameter to callers, and should therefore not
|
||||||
other
|
// influence the result of the check.
|
||||||
.self_instance(db)
|
self.into_callable_type(db)
|
||||||
.is_equivalent_to_impl(db, self.self_instance(db), visitor)
|
.is_equivalent_to_impl(db, other.into_callable_type(db), visitor)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue