diff --git a/crates/ty_python_semantic/resources/mdtest/attributes.md b/crates/ty_python_semantic/resources/mdtest/attributes.md index e8d5132f60..5acd9fbec3 100644 --- a/crates/ty_python_semantic/resources/mdtest/attributes.md +++ b/crates/ty_python_semantic/resources/mdtest/attributes.md @@ -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. diff --git a/crates/ty_python_semantic/src/types/call/arguments.rs b/crates/ty_python_semantic/src/types/call/arguments.rs index fc8bf871e5..58c459e214 100644 --- a/crates/ty_python_semantic/src/types/call/arguments.rs +++ b/crates/ty_python_semantic/src/types/call/arguments.rs @@ -301,7 +301,7 @@ fn expand_type<'db>(db: &'db dyn Db, ty: Type<'db>) -> Option>> { } }) .multi_cartesian_product() - .map(|types| Type::tuple(TupleType::heterogeneous(db, types))) + .map(|types| Type::heterogeneous_tuple(db, types)) .collect::>(); if expanded.len() == 1 { diff --git a/crates/ty_python_semantic/src/types/infer/builder.rs b/crates/ty_python_semantic/src/types/infer/builder.rs index 419b85fda6..5e313ac7cf 100644 --- a/crates/ty_python_semantic/src/types/infer/builder.rs +++ b/crates/ty_python_semantic/src/types/infer/builder.rs @@ -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) diff --git a/crates/ty_python_semantic/src/types/instance.rs b/crates/ty_python_semantic/src/types/instance.rs index 76dc447fd0..a043e62b59 100644 --- a/crates/ty_python_semantic/src/types/instance.rs +++ b/crates/ty_python_semantic/src/types/instance.rs @@ -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), )) } diff --git a/crates/ty_python_semantic/src/types/tuple.rs b/crates/ty_python_semantic/src/types/tuple.rs index f091c99ea5..bd15053a0c 100644 --- a/crates/ty_python_semantic/src/types/tuple.rs +++ b/crates/ty_python_semantic/src/types/tuple.rs @@ -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>, ) -> Option { - 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)]