mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 18:58:04 +00:00
[ty] Ensure that a function-literal type is always equivalent to itself (#18227)
This commit is contained in:
parent
60b486abce
commit
e8d4f6d891
3 changed files with 38 additions and 10 deletions
|
@ -334,4 +334,30 @@ static_assert(is_equivalent_to(CallableTypeOf[pg], CallableTypeOf[cpg]))
|
|||
static_assert(is_equivalent_to(CallableTypeOf[cpg], CallableTypeOf[pg]))
|
||||
```
|
||||
|
||||
## Function-literal types and bound-method types
|
||||
|
||||
Function-literal types and bound-method types are always considered self-equivalent, even if they
|
||||
have unannotated parameters, or parameters with not-fully-static annotations.
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
python-version = "3.12"
|
||||
```
|
||||
|
||||
```py
|
||||
from ty_extensions import is_equivalent_to, TypeOf, static_assert
|
||||
|
||||
def f(): ...
|
||||
|
||||
static_assert(is_equivalent_to(TypeOf[f], TypeOf[f]))
|
||||
|
||||
class A:
|
||||
def method(self) -> int:
|
||||
return 42
|
||||
|
||||
static_assert(is_equivalent_to(TypeOf[A.method], TypeOf[A.method]))
|
||||
type X = TypeOf[A.method]
|
||||
static_assert(is_equivalent_to(X, X))
|
||||
```
|
||||
|
||||
[the equivalence relation]: https://typing.python.org/en/latest/spec/glossary.html#term-equivalent
|
||||
|
|
|
@ -7146,10 +7146,11 @@ impl<'db> FunctionType<'db> {
|
|||
// However, our representation of a function literal includes any specialization that
|
||||
// should be applied to the signature. Different specializations of the same function
|
||||
// literal are only subtypes of each other if they result in subtype signatures.
|
||||
self.body_scope(db) == other.body_scope(db)
|
||||
&& self
|
||||
.into_callable_type(db)
|
||||
.is_subtype_of(db, other.into_callable_type(db))
|
||||
self.normalized(db) == other.normalized(db)
|
||||
|| (self.body_scope(db) == other.body_scope(db)
|
||||
&& self
|
||||
.into_callable_type(db)
|
||||
.is_subtype_of(db, other.into_callable_type(db)))
|
||||
}
|
||||
|
||||
fn is_assignable_to(self, db: &'db dyn Db, other: Self) -> bool {
|
||||
|
@ -7164,10 +7165,11 @@ impl<'db> FunctionType<'db> {
|
|||
}
|
||||
|
||||
fn is_equivalent_to(self, db: &'db dyn Db, other: Self) -> bool {
|
||||
self.body_scope(db) == other.body_scope(db)
|
||||
&& self
|
||||
.into_callable_type(db)
|
||||
.is_equivalent_to(db, other.into_callable_type(db))
|
||||
self.normalized(db) == other.normalized(db)
|
||||
|| (self.body_scope(db) == other.body_scope(db)
|
||||
&& self
|
||||
.into_callable_type(db)
|
||||
.is_equivalent_to(db, other.into_callable_type(db)))
|
||||
}
|
||||
|
||||
fn is_gradual_equivalent_to(self, db: &'db dyn Db, other: Self) -> bool {
|
||||
|
|
|
@ -302,8 +302,8 @@ impl<'db> Signature<'db> {
|
|||
|
||||
pub(crate) fn normalized(&self, db: &'db dyn Db) -> Self {
|
||||
Self {
|
||||
generic_context: self.generic_context,
|
||||
inherited_generic_context: self.inherited_generic_context,
|
||||
generic_context: self.generic_context.map(|ctx| ctx.normalized(db)),
|
||||
inherited_generic_context: self.inherited_generic_context.map(|ctx| ctx.normalized(db)),
|
||||
parameters: self
|
||||
.parameters
|
||||
.iter()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue