diff --git a/crates/ty_python_semantic/src/types/constraints.rs b/crates/ty_python_semantic/src/types/constraints.rs index 2e9e4e12fa..25c86958d0 100644 --- a/crates/ty_python_semantic/src/types/constraints.rs +++ b/crates/ty_python_semantic/src/types/constraints.rs @@ -441,19 +441,6 @@ impl<'db> Node<'db> { matches!(self, Node::AlwaysFalse) } - /// Returns the `or` or union of two BDDs. - fn or(self, db: &'db dyn Db, other: Self) -> Self { - match (self, other) { - (Node::AlwaysTrue, _) | (_, Node::AlwaysTrue) => Node::AlwaysTrue, - (Node::AlwaysFalse, other) | (other, Node::AlwaysFalse) => other, - (Node::Interior(a), Node::Interior(b)) => { - // OR is commutative, which lets us halve the cache requirements - let (a, b) = if b < a { (b, a) } else { (a, b) }; - a.or(db, b) - } - } - } - /// Returns the `and` or intersection of two BDDs. fn and(self, db: &'db dyn Db, other: Self) -> Self { match (self, other) { @@ -574,32 +561,6 @@ impl get_size2::GetSize for InteriorNode<'_> {} #[salsa::tracked] impl<'db> InteriorNode<'db> { - #[salsa::tracked(heap_size=ruff_memory_usage::heap_size)] - fn or(self, db: &'db dyn Db, other: Self) -> Node<'db> { - let self_constraint = self.constraint(db); - let other_constraint = other.constraint(db); - match self_constraint.cmp(&other_constraint) { - Ordering::Equal => Node::new( - db, - self_constraint, - self.if_true(db).or(db, other.if_true(db)), - self.if_false(db).or(db, other.if_false(db)), - ), - Ordering::Less => Node::new( - db, - self_constraint, - self.if_true(db).or(db, Node::Interior(other)), - self.if_false(db).or(db, Node::Interior(other)), - ), - Ordering::Greater => Node::new( - db, - other_constraint, - Node::Interior(self).or(db, other.if_true(db)), - Node::Interior(self).or(db, other.if_false(db)), - ), - } - } - #[salsa::tracked(heap_size=ruff_memory_usage::heap_size)] fn and(self, db: &'db dyn Db, other: Self) -> Node<'db> { let self_constraint = self.constraint(db); @@ -802,7 +763,6 @@ impl<'db> UnderspecifiedNode<'db> { /// Returns the `or` or union of two BDDs. fn or(self, db: &'db dyn Db, other: Self) -> Self { match (self, other) { - // both(ish) operands terminal (UnderspecifiedNode::Impossible, _) | (_, UnderspecifiedNode::Impossible) => { UnderspecifiedNode::Impossible } @@ -812,32 +772,24 @@ impl<'db> UnderspecifiedNode<'db> { (UnderspecifiedNode::AlwaysTrue, UnderspecifiedNode::AlwaysTrue) => { UnderspecifiedNode::AlwaysTrue } - - // both operands fully specified - (UnderspecifiedNode::AlwaysTrue, UnderspecifiedNode::FullySpecified(other)) - | (UnderspecifiedNode::FullySpecified(other), UnderspecifiedNode::AlwaysTrue) => { - Node::new( - db, - other.constraint(db), - Node::AlwaysTrue.or(db, other.if_true(db)), - Node::AlwaysTrue.or(db, other.if_false(db)), - ) - .into() - } (UnderspecifiedNode::FullySpecified(a), UnderspecifiedNode::FullySpecified(b)) => { // OR is commutative, which lets us halve the cache requirements let (a, b) = if b < a { (b, a) } else { (a, b) }; - a.or(db, b).into() + PossiblySpecifiedInteriorNode::from(a).or(db, UnderspecifiedNode::FullySpecified(b)) } - - // at least one operand underspecified (UnderspecifiedNode::Interior(a), UnderspecifiedNode::Interior(b)) => { // OR is commutative, which lets us halve the cache requirements let (a, b) = if b < a { (b, a) } else { (a, b) }; - a.or(db, UnderspecifiedNode::Interior(b)) + PossiblySpecifiedInteriorNode::from(a).or(db, UnderspecifiedNode::Interior(b)) + } + (other, UnderspecifiedNode::FullySpecified(interior)) + | (UnderspecifiedNode::FullySpecified(interior), other) => { + PossiblySpecifiedInteriorNode::from(interior).or(db, other) } (other, UnderspecifiedNode::Interior(interior)) - | (UnderspecifiedNode::Interior(interior), other) => interior.or(db, other), + | (UnderspecifiedNode::Interior(interior), other) => { + PossiblySpecifiedInteriorNode::from(interior).or(db, other) + } } } @@ -1173,30 +1125,6 @@ impl<'db> UnderspecifiedInteriorNode<'db> { } } - #[salsa::tracked(heap_size=ruff_memory_usage::heap_size)] - fn or(self, db: &'db dyn Db, other: UnderspecifiedNode<'db>) -> UnderspecifiedNode<'db> { - match self.cmp_constraints(db, other) { - NodeOrdering::Equal(constraint, other) => UnderspecifiedNode::new( - db, - constraint, - self.if_true(db).or(db, other.if_true(db)), - self.if_false(db).or(db, other.if_false(db)), - ), - NodeOrdering::Less(constraint) => UnderspecifiedNode::new( - db, - constraint, - self.if_true(db).or(db, other), - self.if_false(db).or(db, other), - ), - NodeOrdering::Greater(constraint, other) => UnderspecifiedNode::new( - db, - constraint, - self.or(db, other.if_true(db)), - self.or(db, other.if_false(db)), - ), - } - } - #[salsa::tracked(heap_size=ruff_memory_usage::heap_size)] fn and(self, db: &'db dyn Db, other: UnderspecifiedNode<'db>) -> UnderspecifiedNode<'db> { match self.cmp_constraints(db, other) { @@ -1299,6 +1227,22 @@ impl<'db> PossiblySpecifiedInteriorNode<'db> { } } + fn cmp_constraints(self, db: &'db dyn Db, other: UnderspecifiedNode<'db>) -> NodeOrdering<'db> { + let self_constraint = self.constraint(db); + match other { + // Terminal nodes come after all interior nodes + UnderspecifiedNode::AlwaysTrue + | UnderspecifiedNode::AlwaysFalse + | UnderspecifiedNode::Impossible => NodeOrdering::Less(self_constraint), + UnderspecifiedNode::FullySpecified(other) => { + NodeOrdering::from_constraints(db, self_constraint, other.into()) + } + UnderspecifiedNode::Interior(other) => { + NodeOrdering::from_constraints(db, self_constraint, other.into()) + } + } + } + #[salsa::tracked(heap_size=ruff_memory_usage::heap_size)] fn negate(self, db: &'db dyn Db) -> UnderspecifiedNode<'db> { UnderspecifiedNode::new( @@ -1309,6 +1253,30 @@ impl<'db> PossiblySpecifiedInteriorNode<'db> { ) } + #[salsa::tracked(heap_size=ruff_memory_usage::heap_size)] + fn or(self, db: &'db dyn Db, other: UnderspecifiedNode<'db>) -> UnderspecifiedNode<'db> { + match self.cmp_constraints(db, other) { + NodeOrdering::Equal(constraint, other) => UnderspecifiedNode::new( + db, + constraint, + self.if_true(db).or(db, other.if_true(db)), + self.if_false(db).or(db, other.if_false(db)), + ), + NodeOrdering::Less(constraint) => UnderspecifiedNode::new( + db, + constraint, + self.if_true(db).or(db, other), + self.if_false(db).or(db, other), + ), + NodeOrdering::Greater(constraint, other) => UnderspecifiedNode::new( + db, + constraint, + self.or(db, other.if_true(db)), + self.or(db, other.if_false(db)), + ), + } + } + #[salsa::tracked(heap_size=ruff_memory_usage::heap_size)] fn restrict_one( self,