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]]`
|
# OK, the default specialization of `P` is assignable to `type[P[Unknown]]`
|
||||||
expects_type_p(P)
|
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)
|
||||||
|
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
|
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_int(P[str]) # error: [invalid-argument-type]
|
||||||
expects_type_p_of_str(P[int]) # 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
|
(Type::GenericAlias(alias), Type::SubclassOf(target_subclass_ty)) => target_subclass_ty
|
||||||
.subclass_of()
|
.subclass_of()
|
||||||
.into_class(db)
|
.into_class(db)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue