Same trick for tuples

This commit is contained in:
David Peter 2025-10-21 15:30:53 +02:00
parent be94796e6d
commit a3f8f60e1e
5 changed files with 32 additions and 18 deletions

View File

@ -2583,6 +2583,23 @@ class C:
reveal_type(C().x) # revealed: Unknown | tuple[Divergent, Literal[1]]
```
That also works if the tuple is not constructed directly:
```py
# from typing import TypeVar, Literal
#
# T = TypeVar("T")
#
# def make_tuple(a: T) -> tuple[T, Literal[1]]:
# return (a, 1)
#
# class D:
# def f(self, other: "D"):
# self.x = make_tuple(other.x)
#
# reveal_type(D().x) # revealed: Unknown | tuple[Divergent, Literal[1]]
```
## Attributes of standard library modules that aren't yet defined
For attributes of stdlib modules that exist in future versions, we can give better diagnostics.

View File

@ -301,7 +301,7 @@ fn expand_type<'db>(db: &'db dyn Db, ty: Type<'db>) -> Option<Vec<Type<'db>>> {
}
})
.multi_cartesian_product()
.map(|types| Type::tuple(TupleType::heterogeneous(db, types)))
.map(|types| Type::heterogeneous_tuple(db, types))
.collect::<Vec<_>>();
if expanded.len() == 1 {

View File

@ -5968,16 +5968,9 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
let mut annotated_elt_tys = annotated_tuple.as_ref().map(Tuple::all_elements);
let db = self.db();
let divergent = Type::divergent(Some(self.scope()));
let element_types = elts.iter().map(|element| {
let annotated_elt_ty = annotated_elt_tys.as_mut().and_then(Iterator::next).copied();
let element_type = self.infer_expression(element, TypeContext::new(annotated_elt_ty));
if element_type.has_divergent_type(self.db(), divergent) {
divergent
} else {
element_type
}
self.infer_expression(element, TypeContext::new(annotated_elt_ty))
});
Type::heterogeneous_tuple(db, element_types)

View File

@ -73,13 +73,7 @@ impl<'db> Type<'db> {
{
Type::tuple(TupleType::heterogeneous(
db,
elements.into_iter().map(Into::into).map(|ty| {
if specialization_depth(db, ty) > MAX_SPECIALIZATION_DEPTH {
Type::divergent(None)
} else {
ty
}
}),
elements.into_iter().map(Into::into),
))
}

View File

@ -26,10 +26,11 @@ use crate::subscript::{Nth, OutOfBoundsError, PyIndex, PySlice, StepSizeZeroErro
use crate::types::class::{ClassType, KnownClass};
use crate::types::constraints::{ConstraintSet, IteratorConstraintsExtension};
use crate::types::generics::InferableTypeVars;
use crate::types::visitor::MAX_SPECIALIZATION_DEPTH;
use crate::types::{
ApplyTypeMappingVisitor, BoundTypeVarInstance, FindLegacyTypeVarsVisitor, HasRelationToVisitor,
IsDisjointVisitor, IsEquivalentVisitor, NormalizedVisitor, Type, TypeMapping, TypeRelation,
UnionBuilder, UnionType,
UnionBuilder, UnionType, specialization_depth,
};
use crate::types::{Truthiness, TypeContext};
use crate::{Db, FxOrderSet, Program};
@ -178,7 +179,16 @@ impl<'db> TupleType<'db> {
db: &'db dyn Db,
types: impl IntoIterator<Item = Type<'db>>,
) -> Option<Self> {
TupleType::new(db, &TupleSpec::heterogeneous(types))
TupleType::new(
db,
&TupleSpec::heterogeneous(types.into_iter().map(|ty| {
if specialization_depth(db, ty) > MAX_SPECIALIZATION_DEPTH {
Type::divergent(None)
} else {
ty
}
})),
)
}
#[cfg(test)]