better predicate for skipping typevars

This commit is contained in:
Douglas Creager 2025-12-11 11:21:45 -05:00
parent 745f4d95ba
commit dbab2c43c4
3 changed files with 46 additions and 23 deletions

View File

@ -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.

View File

@ -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);
}
} }
} }

View File

@ -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`.)