mirror of https://github.com/astral-sh/ruff
better predicate for skipping typevars
This commit is contained in:
parent
745f4d95ba
commit
dbab2c43c4
|
|
@ -1903,6 +1903,20 @@ impl<'db> Type<'db> {
|
||||||
self.has_relation_to(db, target, inferable, TypeRelation::Assignability)
|
self.has_relation_to(db, target, inferable, TypeRelation::Assignability)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn when_constraint_set_assignable_to(
|
||||||
|
self,
|
||||||
|
db: &'db dyn Db,
|
||||||
|
target: Type<'db>,
|
||||||
|
inferable: InferableTypeVars<'_, 'db>,
|
||||||
|
) -> ConstraintSet<'db> {
|
||||||
|
self.has_relation_to(
|
||||||
|
db,
|
||||||
|
target,
|
||||||
|
inferable,
|
||||||
|
TypeRelation::ConstraintSetAssignability,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Return `true` if it would be redundant to add `self` to a union that already contains `other`.
|
/// Return `true` if it would be redundant to add `self` to a union that already contains `other`.
|
||||||
///
|
///
|
||||||
/// See [`TypeRelation::Redundancy`] for more details.
|
/// See [`TypeRelation::Redundancy`] for more details.
|
||||||
|
|
|
||||||
|
|
@ -3017,7 +3017,7 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> {
|
||||||
FxHashMap::default();
|
FxHashMap::default();
|
||||||
|
|
||||||
let parameters = self.signature.parameters();
|
let parameters = self.signature.parameters();
|
||||||
for (argument_index, adjusted_argument_index, argument, argument_type) in
|
for (argument_index, adjusted_argument_index, _, argument_type) in
|
||||||
self.enumerate_argument_types()
|
self.enumerate_argument_types()
|
||||||
{
|
{
|
||||||
for (parameter_index, variadic_argument_type) in
|
for (parameter_index, variadic_argument_type) in
|
||||||
|
|
@ -3029,28 +3029,25 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Below, we will possibly perform literal promotion on the types that we infer for
|
// Below, we will possibly perform literal promotion on the types that we infer for
|
||||||
// each typevar. Whether we do so will depend on the variance of the typevar in the
|
// each typevar. Whether we do so will depend on which arguments affect the
|
||||||
// parameter type that each argument is mapped to.
|
// specialization of the typevar, and what variance the typevar has in the
|
||||||
//
|
// corresponding parameter type.
|
||||||
// Note that we do not track the variance for synthetic `self` arguments. Those
|
let when_assignable = argument_type.when_constraint_set_assignable_to(
|
||||||
// only exist for generic methods of a (possibly generic) class. The class instance
|
self.db,
|
||||||
// is fixed for any generic method call, and shouldn't affect literal promotion.
|
expected_type,
|
||||||
// (This is true even for the constructors of a generic class: a `self` annotation
|
self.inferable_typevars,
|
||||||
// on `__init__` limits which specializations the constructor overload applies to,
|
);
|
||||||
// but we rely on occurrences of a typevar in other parameters to determine whether
|
for bound_typevar in generic_context_variables.clone() {
|
||||||
// to promote literals in the specialized generic class type.)
|
let identity = bound_typevar.identity(self.db);
|
||||||
if !matches!(argument, Argument::Synthetic)
|
if !when_assignable.mentions_typevar(self.db, identity) {
|
||||||
&& parameter.form == ParameterForm::Value
|
continue;
|
||||||
&& expected_type.has_typevar(self.db)
|
}
|
||||||
{
|
let variance = expected_type.variance_of(self.db, bound_typevar);
|
||||||
for bound_typevar in generic_context_variables.clone() {
|
if variance != TypeVarVariance::Bivariant {
|
||||||
let variance = expected_type.variance_of(self.db, bound_typevar);
|
variance_in_arguments
|
||||||
if variance != TypeVarVariance::Bivariant {
|
.entry(identity)
|
||||||
variance_in_arguments
|
.and_modify(|current| *current = current.join(variance))
|
||||||
.entry(bound_typevar.identity(self.db))
|
.or_insert(variance);
|
||||||
.and_modify(|current| *current = current.join(variance))
|
|
||||||
.or_insert(variance);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -322,6 +322,18 @@ impl<'db> ConstraintSet<'db> {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn mentions_typevar(
|
||||||
|
self,
|
||||||
|
db: &'db dyn Db,
|
||||||
|
bound_typevar: BoundTypeVarIdentity<'db>,
|
||||||
|
) -> bool {
|
||||||
|
let mut found = false;
|
||||||
|
self.node.for_each_constraint(db, &mut |constraint| {
|
||||||
|
found |= constraint.typevar(db).identity(db) == bound_typevar;
|
||||||
|
});
|
||||||
|
found
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the constraints under which `lhs` is a subtype of `rhs`, assuming that the
|
/// Returns the constraints under which `lhs` is a subtype of `rhs`, assuming that the
|
||||||
/// constraints in this constraint set hold. Panics if neither of the types being compared are
|
/// constraints in this constraint set hold. Panics if neither of the types being compared are
|
||||||
/// a typevar. (That case is handled by `Type::has_relation_to`.)
|
/// a typevar. (That case is handled by `Type::has_relation_to`.)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue