[ty] add doc-comments for some variance stuff (#20189)

This commit is contained in:
Eric Mark Martin 2025-09-05 10:03:10 -04:00 committed by GitHub
parent fdfb51b595
commit eb6154f792
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 31 additions and 1 deletions

View file

@ -6551,6 +6551,7 @@ impl<'db> VarianceInferable<'db> for Type<'db> {
}
Type::GenericAlias(generic_alias) => generic_alias.variance_of(db, typevar),
Type::Callable(callable_type) => callable_type.signatures(db).variance_of(db, typevar),
// A type variable is always covariant in itself.
Type::TypeVar(other_typevar) | Type::NonInferableTypeVar(other_typevar)
if other_typevar == typevar =>
{
@ -6560,11 +6561,19 @@ impl<'db> VarianceInferable<'db> for Type<'db> {
Type::ProtocolInstance(protocol_instance_type) => {
protocol_instance_type.variance_of(db, typevar)
}
// unions are covariant in their disjuncts
Type::Union(union_type) => union_type
.elements(db)
.iter()
.map(|ty| ty.variance_of(db, typevar))
.collect(),
// Products are covariant in their conjuncts. For negative
// conjuncts, they're contravariant. To see this, suppose we have
// `B` a subtype of `A`. A value of type `~B` could be some non-`B`
// `A`, and so is not assignable to `~A`. On the other hand, a value
// of type `~A` excludes all `A`s, and thus all `B`s, and so _is_
// assignable to `~B`.
Type::Intersection(intersection_type) => intersection_type
.positive(db)
.iter()

View file

@ -108,9 +108,30 @@ impl std::iter::FromIterator<Self> for TypeVarVariance {
}
pub(crate) trait VarianceInferable<'db>: Sized {
/// The variance of `typevar` in `self`
///
/// Generally, one will implement this by traversing any types within `self`
/// in which `typevar` could occur, and calling `variance_of` recursively on
/// them.
///
/// Sometimes the recursive calls will be in positions where you need to
/// specify a non-covariant polarity. See `with_polarity` for more details.
fn variance_of(self, db: &'db dyn Db, typevar: BoundTypeVarInstance<'db>) -> TypeVarVariance;
fn with_polarity(self, polarity: TypeVarVariance) -> WithPolarity<Self> {
/// Creates a `VarianceInferable` that applies `polarity` (see
/// `TypeVarVariance::compose`) to the result of variance inference on the
/// underlying value.
///
/// In some cases, we need to apply a polarity to the recursive call.
/// You can do this with `ty.with_polarity(polarity).variance_of(typevar)`.
/// Generally, this will be whenever the type occurs in argument-position,
/// in which case you will want `TypeVarVariance::Contravariant`, or
/// `TypeVarVariance::Invariant` if the value(s) being annotated is known to
/// be mutable, such as `T` in `list[T]`. See the [typing spec][typing-spec]
/// for more details.
///
/// [typing-spec]: https://typing.python.org/en/latest/spec/generics.html#variance
fn with_polarity(self, polarity: TypeVarVariance) -> impl VarianceInferable<'db> {
WithPolarity {
variance_inferable: self,
polarity,