mirror of https://github.com/astral-sh/ruff
Fix assignability of P[int] to type[P] and type[P[int]]
This commit is contained in:
parent
ece01a1cb6
commit
f0f60805de
|
|
@ -356,8 +356,16 @@ def expects_type_p_of_int(x: type[P[int]]):
|
|||
# OK, the default specialization of `P` is assignable to `type[P[Unknown]]`
|
||||
expects_type_p(P)
|
||||
|
||||
# also OK, because the default specialization is `P[Unknown]` which is assignable to `P[int]`
|
||||
# Also OK, because `P[int]` and `P[str]` are both assignable to `P[Unknown]`
|
||||
expects_type_p(P[int])
|
||||
expects_type_p(P[str])
|
||||
|
||||
# Also OK, because the default specialization is `P[Unknown]` which is assignable to `P[int]`
|
||||
expects_type_p_of_int(P)
|
||||
expects_type_p_of_int(P[int])
|
||||
|
||||
# Not OK, because `P[str]` is not assignable to `P[int]`
|
||||
expects_type_p_of_int(P[str]) # error: [invalid-argument-type]
|
||||
```
|
||||
|
||||
The same principles apply when typevar defaults are used, but the results are a bit different
|
||||
|
|
@ -390,3 +398,54 @@ expects_type_p(P[int]) # error: [invalid-argument-type]
|
|||
expects_type_p_of_int(P[str]) # error: [invalid-argument-type]
|
||||
expects_type_p_of_str(P[int]) # error: [invalid-argument-type]
|
||||
```
|
||||
|
||||
This also works with `ParamSpec`:
|
||||
|
||||
```py
|
||||
@final
|
||||
class C[**P]: ...
|
||||
|
||||
def expects_type_c(f: type[C]): ...
|
||||
def expects_type_c_of_int_and_str(x: type[C[int, str]]): ...
|
||||
|
||||
# OK, the unspecialized `C` is assignable to `type[C[...]]`
|
||||
expects_type_c(C)
|
||||
|
||||
# Also OK, any specialization is assignable to the unspecialized `C`
|
||||
expects_type_c(C[int])
|
||||
expects_type_c(C[str, int, bytes])
|
||||
|
||||
# Ok, the unspecialized `C` is assignable to `type[C[int, str]]`
|
||||
expects_type_c_of_int_and_str(C)
|
||||
|
||||
# Also OK, the specialized `C[int, str]` is assignable to `type[C[int, str]]`
|
||||
expects_type_c_of_int_and_str(C[int, str])
|
||||
|
||||
# TODO: these should be errors
|
||||
expects_type_c_of_int_and_str(C[str])
|
||||
expects_type_c_of_int_and_str(C[int, str, bytes])
|
||||
expects_type_c_of_int_and_str(C[str, int])
|
||||
```
|
||||
|
||||
And with a `ParamSpec` that has a default:
|
||||
|
||||
```py
|
||||
@final
|
||||
class C[**P = [int, str]]: ...
|
||||
|
||||
def expects_type_c_default(f: type[C]): ...
|
||||
def expects_type_c_default_of_int(f: type[C[int]]): ...
|
||||
def expects_type_c_default_of_int_str(f: type[C[int, str]]): ...
|
||||
|
||||
expects_type_c_default(C)
|
||||
expects_type_c_default(C[int, str])
|
||||
expects_type_c_default_of_int(C)
|
||||
expects_type_c_default_of_int(C[int])
|
||||
expects_type_c_default_of_int_str(C)
|
||||
expects_type_c_default_of_int_str(C[int, str])
|
||||
|
||||
# TODO: these should be errors
|
||||
expects_type_c_default(C[int])
|
||||
expects_type_c_default_of_int(C[str])
|
||||
expects_type_c_default_of_int_str(C[str, int])
|
||||
```
|
||||
|
|
|
|||
|
|
@ -2725,6 +2725,18 @@ impl<'db> Type<'db> {
|
|||
)
|
||||
}
|
||||
|
||||
// For generic aliases, we delegate to the underlying class type.
|
||||
(Type::GenericAlias(self_alias), Type::GenericAlias(target_alias)) => {
|
||||
ClassType::from(self_alias).has_relation_to_impl(
|
||||
db,
|
||||
ClassType::from(target_alias),
|
||||
inferable,
|
||||
relation,
|
||||
relation_visitor,
|
||||
disjointness_visitor,
|
||||
)
|
||||
}
|
||||
|
||||
(Type::GenericAlias(alias), Type::SubclassOf(target_subclass_ty)) => target_subclass_ty
|
||||
.subclass_of()
|
||||
.into_class(db)
|
||||
|
|
|
|||
Loading…
Reference in New Issue