calculate variance from parameter type

This commit is contained in:
Douglas Creager 2025-12-11 16:34:03 -05:00
parent 73acf0a926
commit 2950af4fd9
1 changed files with 11 additions and 2 deletions

View File

@ -15,6 +15,7 @@ use crate::types::constraints::{ConstraintSet, IteratorConstraintsExtension};
use crate::types::instance::{Protocol, ProtocolInstanceType}; use crate::types::instance::{Protocol, ProtocolInstanceType};
use crate::types::signatures::Parameters; use crate::types::signatures::Parameters;
use crate::types::tuple::{TupleSpec, TupleType, walk_tuple_type}; use crate::types::tuple::{TupleSpec, TupleType, walk_tuple_type};
use crate::types::variance::VarianceInferable;
use crate::types::visitor::{TypeCollector, TypeVisitor, walk_type_with_recursion_guard}; use crate::types::visitor::{TypeCollector, TypeVisitor, walk_type_with_recursion_guard};
use crate::types::{ use crate::types::{
ApplyTypeMappingVisitor, BindingContext, BoundTypeVarIdentity, BoundTypeVarInstance, ApplyTypeMappingVisitor, BindingContext, BoundTypeVarIdentity, BoundTypeVarInstance,
@ -1553,6 +1554,10 @@ impl<'db> SpecializationBuilder<'db> {
/// Finds all of the valid specializations of a constraint set, and adds their type mappings to /// Finds all of the valid specializations of a constraint set, and adds their type mappings to
/// the specialization that this builder is building up. /// the specialization that this builder is building up.
/// ///
/// `formal` should be the top-level formal parameter type that we are inferring. This is used
/// by our literal promotion logic, which needs to know which typevars are affected by each
/// argument, and the variance of those typevars in the corresponding parameter.
///
/// TODO: This is a stopgap! Eventually, the builder will maintain a single constraint set for /// TODO: This is a stopgap! Eventually, the builder will maintain a single constraint set for
/// the main specialization that we are building, and [`build`][Self::build] will build the /// the main specialization that we are building, and [`build`][Self::build] will build the
/// specialization directly from that constraint set. This method lets us migrate to that brave /// specialization directly from that constraint set. This method lets us migrate to that brave
@ -1560,8 +1565,8 @@ impl<'db> SpecializationBuilder<'db> {
/// type comparisons. /// type comparisons.
fn add_type_mappings_from_constraint_set( fn add_type_mappings_from_constraint_set(
&mut self, &mut self,
formal: Type<'db>,
constraints: ConstraintSet<'db>, constraints: ConstraintSet<'db>,
variance: TypeVarVariance,
mut f: impl FnMut(TypeVarAssignment<'db>) -> Option<Type<'db>>, mut f: impl FnMut(TypeVarAssignment<'db>) -> Option<Type<'db>>,
) { ) {
constraints.for_each_path(self.db, |path| { constraints.for_each_path(self.db, |path| {
@ -1570,11 +1575,14 @@ impl<'db> SpecializationBuilder<'db> {
let lower = constraint.lower(self.db); let lower = constraint.lower(self.db);
let upper = constraint.upper(self.db); let upper = constraint.upper(self.db);
if !upper.is_object() { if !upper.is_object() {
let variance = formal.variance_of(self.db, typevar);
self.add_type_mapping(typevar, upper, variance, &mut f); self.add_type_mapping(typevar, upper, variance, &mut f);
} else if !lower.is_never() { } else if !lower.is_never() {
let variance = formal.variance_of(self.db, typevar);
self.add_type_mapping(typevar, lower, variance, &mut f); self.add_type_mapping(typevar, lower, variance, &mut f);
} }
if let Type::TypeVar(lower_bound_typevar) = lower { if let Type::TypeVar(lower_bound_typevar) = lower {
let variance = formal.variance_of(self.db, lower_bound_typevar);
self.add_type_mapping( self.add_type_mapping(
lower_bound_typevar, lower_bound_typevar,
Type::TypeVar(typevar), Type::TypeVar(typevar),
@ -1583,6 +1591,7 @@ impl<'db> SpecializationBuilder<'db> {
); );
} }
if let Type::TypeVar(upper_bound_typevar) = upper { if let Type::TypeVar(upper_bound_typevar) = upper {
let variance = formal.variance_of(self.db, upper_bound_typevar);
self.add_type_mapping( self.add_type_mapping(
upper_bound_typevar, upper_bound_typevar,
Type::TypeVar(typevar), Type::TypeVar(typevar),
@ -1899,7 +1908,7 @@ impl<'db> SpecializationBuilder<'db> {
formal_callable.signatures(self.db), formal_callable.signatures(self.db),
self.inferable, self.inferable,
); );
self.add_type_mappings_from_constraint_set(when, polarity, &mut f); self.add_type_mappings_from_constraint_set(formal, when, &mut f);
} }
} }