From 86271d605dddb7167aaa70f90257266c1bfbcd6c Mon Sep 17 00:00:00 2001 From: Douglas Creager Date: Sun, 14 Dec 2025 13:10:51 -0500 Subject: [PATCH] codex 2 --- .../mdtest/generics/specialize_constrained.md | 8 +-- .../src/types/constraints.rs | 58 +++++++++++++++---- 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/crates/ty_python_semantic/resources/mdtest/generics/specialize_constrained.md b/crates/ty_python_semantic/resources/mdtest/generics/specialize_constrained.md index da1882b375..4dad6d3090 100644 --- a/crates/ty_python_semantic/resources/mdtest/generics/specialize_constrained.md +++ b/crates/ty_python_semantic/resources/mdtest/generics/specialize_constrained.md @@ -43,7 +43,7 @@ def unbounded[T](): # revealed: None reveal_type(generic_context(unbounded).specialize_constrained(ConstraintSet.range(bool, T, bool) & ConstraintSet.range(Never, T, str))) - # revealed: ty_extensions.Specialization[T@unbounded = int] + # revealed: ty_extensions.Specialization[T@unbounded = bool] reveal_type(generic_context(unbounded).specialize_constrained(ConstraintSet.range(Never, T, int) | ConstraintSet.range(Never, T, bool))) # revealed: ty_extensions.Specialization[T@unbounded = Never] reveal_type(generic_context(unbounded).specialize_constrained(ConstraintSet.range(Never, T, int) | ConstraintSet.range(Never, T, str))) @@ -310,18 +310,18 @@ def constrained_by_gradual_list[T: (list[Base], list[Any])](): # Same tests as above, but with the typevar constraints in a different order, to make sure the # results do not depend on our BDD variable ordering. def constrained_by_gradual_list_reverse[T: (list[Any], list[Base])](): - # revealed: ty_extensions.Specialization[T@constrained_by_gradual_list_reverse = Top[list[Any]]] + # revealed: ty_extensions.Specialization[T@constrained_by_gradual_list_reverse = list[Base]] reveal_type(generic_context(constrained_by_gradual_list_reverse).specialize_constrained(ConstraintSet.always())) # revealed: ty_extensions.Specialization[T@constrained_by_gradual_list_reverse = list[object]] reveal_type(generic_context(constrained_by_gradual_list_reverse).specialize_constrained(ConstraintSet.range(Never, T, list[object]))) - # revealed: ty_extensions.Specialization[T@constrained_by_gradual_list_reverse = list[Any]] + # revealed: ty_extensions.Specialization[T@constrained_by_gradual_list_reverse = list[Base] & list[Any]] reveal_type(generic_context(constrained_by_gradual_list_reverse).specialize_constrained(ConstraintSet.range(Never, T, list[Any]))) # revealed: None reveal_type(generic_context(constrained_by_gradual_list_reverse).specialize_constrained(ConstraintSet.never())) # revealed: ty_extensions.Specialization[T@constrained_by_gradual_list_reverse = list[Base]] reveal_type(generic_context(constrained_by_gradual_list_reverse).specialize_constrained(ConstraintSet.range(Never, T, list[Base]))) - # revealed: ty_extensions.Specialization[T@constrained_by_gradual_list_reverse = Top[list[Any]]] + # revealed: ty_extensions.Specialization[T@constrained_by_gradual_list_reverse = list[Base]] reveal_type(generic_context(constrained_by_gradual_list_reverse).specialize_constrained(ConstraintSet.range(list[Base], T, object))) # TODO: revealed: ty_extensions.Specialization[T@constrained_by_gradual = list[Any]] diff --git a/crates/ty_python_semantic/src/types/constraints.rs b/crates/ty_python_semantic/src/types/constraints.rs index 8f9c34dfd5..31a7465522 100644 --- a/crates/ty_python_semantic/src/types/constraints.rs +++ b/crates/ty_python_semantic/src/types/constraints.rs @@ -1079,8 +1079,21 @@ impl<'db> Node<'db> { fn or_with_rhs_offset(self, db: &'db dyn Db, other: Self, rhs_offset: usize) -> Self { match (self, other) { - (Node::AlwaysTrue, _) => Node::AlwaysTrue, - (_, Node::AlwaysTrue) => Node::AlwaysTrue, + (Node::AlwaysTrue, Node::AlwaysTrue) => Node::AlwaysTrue, + (Node::AlwaysTrue, Node::Interior(rhs)) => Node::new( + db, + rhs.constraint(db), + Node::AlwaysTrue, + Node::AlwaysTrue, + rhs.source_order(db) + rhs_offset, + ), + (Node::Interior(lhs), Node::AlwaysTrue) => Node::new( + db, + lhs.constraint(db), + Node::AlwaysTrue, + Node::AlwaysTrue, + lhs.source_order(db), + ), (Node::AlwaysFalse, rhs) => rhs.with_source_order_offset(db, rhs_offset), (lhs, Node::AlwaysFalse) => lhs, (Node::Interior(lhs), Node::Interior(rhs)) => lhs.or(db, rhs, rhs_offset), @@ -1095,8 +1108,21 @@ impl<'db> Node<'db> { fn and_with_rhs_offset(self, db: &'db dyn Db, other: Self, rhs_offset: usize) -> Self { match (self, other) { - (Node::AlwaysFalse, _) => Node::AlwaysFalse, - (_, Node::AlwaysFalse) => Node::AlwaysFalse, + (Node::AlwaysFalse, Node::AlwaysFalse) => Node::AlwaysFalse, + (Node::AlwaysFalse, Node::Interior(rhs)) => Node::new( + db, + rhs.constraint(db), + Node::AlwaysFalse, + Node::AlwaysFalse, + rhs.source_order(db) + rhs_offset, + ), + (Node::Interior(lhs), Node::AlwaysFalse) => Node::new( + db, + lhs.constraint(db), + Node::AlwaysFalse, + Node::AlwaysFalse, + lhs.source_order(db), + ), (Node::AlwaysTrue, rhs) => rhs.with_source_order_offset(db, rhs_offset), (lhs, Node::AlwaysTrue) => lhs, (Node::Interior(lhs), Node::Interior(rhs)) => lhs.and(db, rhs, rhs_offset), @@ -3676,14 +3702,26 @@ mod tests { fn test_display_graph_output() { let expected = indoc! {r#" (T = str) - ┡━₁ (U = str) - │ ┡━₁ always - │ └─₀ (U = bool) - │ ┡━₁ always - │ └─₀ never + ┡━₁ (T = bool) + │ ┡━₁ (U = str) + │ │ ┡━₁ (U = bool) + │ │ │ ┡━₁ always + │ │ │ └─₀ always + │ │ └─₀ (U = bool) + │ │ ┡━₁ always + │ │ └─₀ never + │ └─₀ (U = str) + │ ┡━₁ (U = bool) + │ │ ┡━₁ always + │ │ └─₀ always + │ └─₀ (U = bool) + │ ┡━₁ always + │ └─₀ never └─₀ (T = bool) ┡━₁ (U = str) - │ ┡━₁ always + │ ┡━₁ (U = bool) + │ │ ┡━₁ always + │ │ └─₀ always │ └─₀ (U = bool) │ ┡━₁ always │ └─₀ never