From 26230b1ed3db02f5c2d5b9ed9d49c70062d66736 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 1 Jan 2026 15:01:00 +0000 Subject: [PATCH] [ty] Use `IntersectionType::from_elements` more (#22329) --- crates/ty_python_semantic/src/types.rs | 30 ++++++------------- crates/ty_python_semantic/src/types/class.rs | 23 ++++++-------- crates/ty_python_semantic/src/types/narrow.rs | 21 ++++--------- .../types/property_tests/type_generation.rs | 10 ++----- 4 files changed, 27 insertions(+), 57 deletions(-) diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index 129af6d7e7..d66e85dc25 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -7631,13 +7631,13 @@ impl<'db> Type<'db> { // but it appears to be what users often expect, and it improves compatibility with // other type checkers such as mypy. // See conversation in https://github.com/astral-sh/ruff/pull/19915. - SpecialFormType::NamedTuple => Ok(IntersectionBuilder::new(db) - .positive_elements([ + SpecialFormType::NamedTuple => Ok(IntersectionType::from_elements( + db, + [ Type::homogeneous_tuple(db, Type::object()), KnownClass::NamedTupleLike.to_instance(db), - ]) - .build()), - + ], + )), SpecialFormType::TypingSelf => { let index = semantic_index(db, scope_id.file(db)); let Some(class) = nearest_enclosing_class(db, index, scope_id) else { @@ -15035,16 +15035,10 @@ pub(crate) mod tests { // salsa, but that would mean we would have to pass in `db` everywhere. // A union of several `Todo` types collapses to a single `Todo` type: - assert!(UnionType::from_elements(&db, vec![todo1, todo2]).is_todo()); + assert!(UnionType::from_elements(&db, [todo1, todo2]).is_todo()); // And similar for intersection types: - assert!( - IntersectionBuilder::new(&db) - .add_positive(todo1) - .add_positive(todo2) - .build() - .is_todo() - ); + assert!(IntersectionType::from_elements(&db, [todo1, todo2]).is_todo()); assert!( IntersectionBuilder::new(&db) .add_positive(todo1) @@ -15129,16 +15123,10 @@ pub(crate) mod tests { assert_eq!(normalized.display(&db).to_string(), "int"); // The same can be said about intersections for the `Never` type. - let intersection = IntersectionBuilder::new(&db) - .add_positive(Type::Never) - .add_positive(div) - .build(); + let intersection = IntersectionType::from_elements(&db, [Type::Never, div]); assert_eq!(intersection.display(&db).to_string(), "Never"); - let intersection = IntersectionBuilder::new(&db) - .add_positive(div) - .add_positive(Type::Never) - .build(); + let intersection = IntersectionType::from_elements(&db, [div, Type::Never]); assert_eq!(intersection.display(&db).to_string(), "Never"); } diff --git a/crates/ty_python_semantic/src/types/class.rs b/crates/ty_python_semantic/src/types/class.rs index 869c82c90f..a3031fb26a 100644 --- a/crates/ty_python_semantic/src/types/class.rs +++ b/crates/ty_python_semantic/src/types/class.rs @@ -4,8 +4,8 @@ use std::sync::{LazyLock, Mutex}; use super::TypeVarVariance; use super::{ - BoundTypeVarInstance, IntersectionBuilder, MemberLookupPolicy, Mro, MroError, MroIterator, - SpecialFormType, SubclassOfType, Truthiness, Type, TypeQualifiers, class_base::ClassBase, + BoundTypeVarInstance, MemberLookupPolicy, Mro, MroError, MroIterator, SpecialFormType, + SubclassOfType, Truthiness, Type, TypeQualifiers, class_base::ClassBase, function::FunctionType, }; use crate::place::TypeOrigin; @@ -37,11 +37,11 @@ use crate::types::visitor::{TypeCollector, TypeVisitor, walk_type_with_recursion use crate::types::{ ApplyTypeMappingVisitor, Binding, BindingContext, BoundSuperType, CallableType, CallableTypeKind, CallableTypes, DATACLASS_FLAGS, DataclassFlags, DataclassParams, - DeprecatedInstance, FindLegacyTypeVarsVisitor, HasRelationToVisitor, IsDisjointVisitor, - IsEquivalentVisitor, KnownInstanceType, ManualPEP695TypeAliasType, MaterializationKind, - NormalizedVisitor, PropertyInstanceType, TypeAliasType, TypeContext, TypeMapping, TypeRelation, - TypedDictParams, UnionBuilder, VarianceInferable, binding_type, declaration_type, - determine_upper_bound, + DeprecatedInstance, FindLegacyTypeVarsVisitor, HasRelationToVisitor, IntersectionType, + IsDisjointVisitor, IsEquivalentVisitor, KnownInstanceType, ManualPEP695TypeAliasType, + MaterializationKind, NormalizedVisitor, PropertyInstanceType, TypeAliasType, TypeContext, + TypeMapping, TypeRelation, TypedDictParams, UnionBuilder, VarianceInferable, binding_type, + declaration_type, determine_upper_bound, }; use crate::{ Db, FxIndexMap, FxIndexSet, FxOrderSet, Program, @@ -2252,13 +2252,8 @@ impl<'db> ClassLiteral<'db> { qualifiers, }, Some(dynamic_type), - ) => Place::bound( - IntersectionBuilder::new(db) - .add_positive(ty) - .add_positive(dynamic_type) - .build(), - ) - .with_qualifiers(qualifiers), + ) => Place::bound(IntersectionType::from_elements(db, [ty, dynamic_type])) + .with_qualifiers(qualifiers), ( PlaceAndQualifiers { diff --git a/crates/ty_python_semantic/src/types/narrow.rs b/crates/ty_python_semantic/src/types/narrow.rs index 19a0087509..26da111527 100644 --- a/crates/ty_python_semantic/src/types/narrow.rs +++ b/crates/ty_python_semantic/src/types/narrow.rs @@ -15,9 +15,9 @@ use crate::types::typed_dict::{ SynthesizedTypedDictType, TypedDictFieldBuilder, TypedDictSchema, TypedDictType, }; use crate::types::{ - CallableType, ClassLiteral, ClassType, IntersectionBuilder, KnownClass, KnownInstanceType, - SpecialFormType, SubclassOfInner, SubclassOfType, Truthiness, Type, TypeContext, - TypeVarBoundOrConstraints, UnionBuilder, infer_expression_types, + CallableType, ClassLiteral, ClassType, IntersectionBuilder, IntersectionType, KnownClass, + KnownInstanceType, SpecialFormType, SubclassOfInner, SubclassOfType, Truthiness, Type, + TypeContext, TypeVarBoundOrConstraints, UnionBuilder, infer_expression_types, }; use ruff_db::parsed::{ParsedModuleRef, parsed_module}; @@ -343,18 +343,12 @@ impl<'db> NarrowingConstraint<'db> { }; let new_regular_disjunct = self.regular_disjunct.map(|regular_disjunct| { - IntersectionBuilder::new(db) - .add_positive(regular_disjunct) - .add_positive(other_regular_disjunct) - .build() + IntersectionType::from_elements(db, [regular_disjunct, other_regular_disjunct]) }); let additional_typeguard_disjuncts = self.typeguard_disjuncts.iter().map(|typeguard_disjunct| { - IntersectionBuilder::new(db) - .add_positive(*typeguard_disjunct) - .add_positive(other_regular_disjunct) - .build() + IntersectionType::from_elements(db, [*typeguard_disjunct, other_regular_disjunct]) }); let mut new_typeguard_disjuncts = other.typeguard_disjuncts; @@ -954,10 +948,7 @@ impl<'db, 'ast> NarrowingConstraintsBuilder<'db, 'ast> { match op { ast::CmpOp::IsNot => { if rhs_ty.is_singleton(self.db) { - let ty = IntersectionBuilder::new(self.db) - .add_negative(rhs_ty) - .build(); - Some(ty) + Some(rhs_ty.negate(self.db)) } else { // Non-singletons cannot be safely narrowed using `is not` None diff --git a/crates/ty_python_semantic/src/types/property_tests/type_generation.rs b/crates/ty_python_semantic/src/types/property_tests/type_generation.rs index 922ebcd5f3..6bfb229c53 100644 --- a/crates/ty_python_semantic/src/types/property_tests/type_generation.rs +++ b/crates/ty_python_semantic/src/types/property_tests/type_generation.rs @@ -4,8 +4,8 @@ use crate::place::{builtins_symbol, known_module_symbol}; use crate::types::enums::is_single_member_enum; use crate::types::tuple::TupleType; use crate::types::{ - BoundMethodType, EnumLiteralType, IntersectionBuilder, KnownClass, Parameter, Parameters, - Signature, SpecialFormType, SubclassOfType, Type, UnionType, + BoundMethodType, EnumLiteralType, IntersectionBuilder, IntersectionType, KnownClass, Parameter, + Parameters, Signature, SpecialFormType, SubclassOfType, Type, UnionType, }; use quickcheck::{Arbitrary, Gen}; use ruff_python_ast::name::Name; @@ -579,11 +579,7 @@ pub(crate) fn intersection<'db>( db: &'db TestDb, tys: impl IntoIterator>, ) -> Type<'db> { - let mut builder = IntersectionBuilder::new(db); - for ty in tys { - builder = builder.add_positive(ty); - } - builder.build() + IntersectionType::from_elements(db, tys) } pub(crate) fn union<'db>(db: &'db TestDb, tys: impl IntoIterator>) -> Type<'db> {