diff --git a/crates/ty_python_semantic/src/types/builder.rs b/crates/ty_python_semantic/src/types/builder.rs index b7cc49497a..abe6a2b3f3 100644 --- a/crates/ty_python_semantic/src/types/builder.rs +++ b/crates/ty_python_semantic/src/types/builder.rs @@ -325,6 +325,9 @@ impl<'db> UnionBuilder<'db> { } }; + let mut ty_negated_cache = None; + let mut ty_negated = || *ty_negated_cache.get_or_insert_with(|| ty.negate(self.db)); + match ty { Type::Union(union) => { let new_elements = union.elements(self.db); @@ -365,7 +368,6 @@ impl<'db> UnionBuilder<'db> { Type::StringLiteral(literal) => { let mut found = None; let mut to_remove = None; - let mut ty_negated = None; for (index, element) in self.elements.iter_mut().enumerate() { match element { UnionElement::StringLiterals(literals) => { @@ -387,8 +389,7 @@ impl<'db> UnionBuilder<'db> { to_remove = Some(index); continue; } - let negated = ty_negated.get_or_insert_with(|| ty.negate(self.db)); - if negated.is_subtype_of(self.db, *existing) { + if ty_negated().is_subtype_of(self.db, *existing) { // The type that includes both this new element, and its negation // (or a supertype of its negation), must be simply `object`. self.collapse_to_object(); @@ -414,7 +415,6 @@ impl<'db> UnionBuilder<'db> { Type::BytesLiteral(literal) => { let mut found = None; let mut to_remove = None; - let mut ty_negated = None; for (index, element) in self.elements.iter_mut().enumerate() { match element { UnionElement::BytesLiterals(literals) => { @@ -430,13 +430,13 @@ impl<'db> UnionBuilder<'db> { if ty.is_subtype_of(self.db, *existing) { return; } + // e.g. `existing` could be `Literal[b""] & Any`, + // and `ty` could be `Literal[b""]` if existing.is_subtype_of(self.db, ty) { to_remove = Some(index); continue; } - - let negated = ty_negated.get_or_insert_with(|| ty.negate(self.db)); - if negated.is_subtype_of(self.db, *existing) { + if ty_negated().is_subtype_of(self.db, *existing) { // The type that includes both this new element, and its negation // (or a supertype of its negation), must be simply `object`. self.collapse_to_object(); @@ -462,7 +462,6 @@ impl<'db> UnionBuilder<'db> { Type::IntLiteral(literal) => { let mut found = None; let mut to_remove = None; - let mut ty_negated = None; for (index, element) in self.elements.iter_mut().enumerate() { match element { UnionElement::IntLiterals(literals) => { @@ -478,13 +477,13 @@ impl<'db> UnionBuilder<'db> { if ty.is_subtype_of(self.db, *existing) { return; } + // e.g. `existing` could be `Literal[1] & Any`, + // and `ty` could be `Literal[1]` if existing.is_subtype_of(self.db, ty) { to_remove = Some(index); continue; } - - let negated = ty_negated.get_or_insert_with(|| ty.negate(self.db)); - if negated.is_subtype_of(self.db, *existing) { + if ty_negated().is_subtype_of(self.db, *existing) { // The type that includes both this new element, and its negation // (or a supertype of its negation), must be simply `object`. self.collapse_to_object();