Move the check in `Signature::has_relation_to_inner`

This commit is contained in:
Dhruv Manilawala 2025-12-15 10:41:07 +05:30
parent b2b76f4a3c
commit f305b4b8cf
3 changed files with 26 additions and 17 deletions

View File

@ -711,6 +711,9 @@ class Child2(Parent):
### One `ParamSpec` not inferable ### One `ParamSpec` not inferable
Here, `P` is in a non-inferable position while `Q` is inferable. So, they are not considered
assignable.
```py ```py
from typing import Callable from typing import Callable

View File

@ -2174,23 +2174,6 @@ impl<'db> Type<'db> {
ConstraintSet::from(true) ConstraintSet::from(true)
} }
// Two ParamSpec attributes (P.args/P.kwargs and Q.args/Q.kwargs) are assignable to
// each other if they have the same attribute kind and both underlying ParamSpecs are
// inferable.
(Type::TypeVar(lhs_bound_typevar), Type::TypeVar(rhs_bound_typevar))
if lhs_bound_typevar.paramspec_attr(db).is_some()
&& lhs_bound_typevar.paramspec_attr(db)
== rhs_bound_typevar.paramspec_attr(db)
&& lhs_bound_typevar
.without_paramspec_attr(db)
.is_inferable(db, inferable)
&& rhs_bound_typevar
.without_paramspec_attr(db)
.is_inferable(db, inferable) =>
{
ConstraintSet::from(true)
}
// `type[T]` is a subtype of the class object `A` if every instance of `T` is a subtype of an instance // `type[T]` is a subtype of the class object `A` if every instance of `T` is a subtype of an instance
// of `A`, and vice versa. // of `A`, and vice versa.
(Type::SubclassOf(subclass_of), _) (Type::SubclassOf(subclass_of), _)

View File

@ -1072,6 +1072,29 @@ impl<'db> Signature<'db> {
let mut check_types = |type1: Option<Type<'db>>, type2: Option<Type<'db>>| { let mut check_types = |type1: Option<Type<'db>>, type2: Option<Type<'db>>| {
let type1 = type1.unwrap_or(Type::unknown()); let type1 = type1.unwrap_or(Type::unknown());
let type2 = type2.unwrap_or(Type::unknown()); let type2 = type2.unwrap_or(Type::unknown());
match (type1, type2) {
// This is a special case where the _same_ components of two different `ParamSpec`
// type variables are assignable to each other when they're both in an inferable
// position.
//
// `ParamSpec` type variables can only occur in parameter lists so this special case
// is present here instead of in `Type::has_relation_to_impl`.
(Type::TypeVar(typevar1), Type::TypeVar(typevar2))
if typevar1.paramspec_attr(db).is_some()
&& typevar1.paramspec_attr(db) == typevar2.paramspec_attr(db)
&& typevar1
.without_paramspec_attr(db)
.is_inferable(db, inferable)
&& typevar2
.without_paramspec_attr(db)
.is_inferable(db, inferable) =>
{
return true;
}
_ => {}
}
!result !result
.intersect( .intersect(
db, db,