Skip to content

[ty] Refactor to support building constraint sets differently#23600

Merged
sharkdp merged 6 commits intomainfrom
dcreager/constraint-builder-refactor
Feb 27, 2026
Merged

[ty] Refactor to support building constraint sets differently#23600
sharkdp merged 6 commits intomainfrom
dcreager/constraint-builder-refactor

Conversation

@dcreager
Copy link
Member

This is a pure refactoring PR that exists solely to set up #23538. That PR will update how we memoize the constraint sets that we build, with hand-rolled cached instead of relying on salsa interning.

To do that, we need a create a new ConstraintSetBuilder type and thread it around through all of the various has_relation_to methods and friends. That's a slog to review, so I've pulled that out into this separate PR to make reviewing easier.

This PR is a pure refactoring. There should be no behavioral changes. In particular, the new ConstraintSetBuilder type is currently empty! We're still using salsa interning at this stage of the migration, and so the builder doesn't need to hold onto any internal state. But don't worry, it will soon.

@dcreager dcreager added internal An internal refactor or improvement ty Multi-file analysis & type inference labels Feb 27, 2026
@astral-sh-bot
Copy link

astral-sh-bot bot commented Feb 27, 2026

Typing conformance results

No changes detected ✅

@astral-sh-bot
Copy link

astral-sh-bot bot commented Feb 27, 2026

Memory usage report

Memory usage unchanged ✅

@astral-sh-bot
Copy link

astral-sh-bot bot commented Feb 27, 2026

mypy_primer results

Changes were detected when running on open source projects
spack (https://github.com/spack/spack)
- lib/spack/spack/llnl/util/filesystem.py:1668:35: error[invalid-argument-type] Argument to function `exists` is incorrect: Expected `int | str | bytes | PathLike[str] | PathLike[bytes]`, found `Sized | Unknown`
+ lib/spack/spack/llnl/util/filesystem.py:1668:35: error[invalid-argument-type] Argument to function `exists` is incorrect: Expected `int | str | bytes | PathLike[str] | PathLike[bytes]`, found `Unknown | Sized`
- lib/spack/spack/llnl/util/filesystem.py:1674:25: error[invalid-argument-type] Argument to function `move` is incorrect: Expected `str | PathLike[str]`, found `Sized | Unknown`
+ lib/spack/spack/llnl/util/filesystem.py:1674:25: error[invalid-argument-type] Argument to function `move` is incorrect: Expected `str | PathLike[str]`, found `Unknown | Sized`

rich (https://github.com/Textualize/rich)
- tests/test_tools.py:17:17: error[invalid-argument-type] Argument to function `next` is incorrect: Expected `SupportsNext[Unknown]`, found `Iterable[tuple[bool, str | Unknown]]`
+ tests/test_tools.py:17:17: error[invalid-argument-type] Argument to function `next` is incorrect: Expected `SupportsNext[Unknown]`, found `Iterable[tuple[bool, Unknown | str]]`
- tests/test_tools.py:18:17: error[invalid-argument-type] Argument to function `next` is incorrect: Expected `SupportsNext[Unknown]`, found `Iterable[tuple[bool, str | Unknown]]`
+ tests/test_tools.py:18:17: error[invalid-argument-type] Argument to function `next` is incorrect: Expected `SupportsNext[Unknown]`, found `Iterable[tuple[bool, Unknown | str]]`
- tests/test_tools.py:19:17: error[invalid-argument-type] Argument to function `next` is incorrect: Expected `SupportsNext[Unknown]`, found `Iterable[tuple[bool, str | Unknown]]`
+ tests/test_tools.py:19:17: error[invalid-argument-type] Argument to function `next` is incorrect: Expected `SupportsNext[Unknown]`, found `Iterable[tuple[bool, Unknown | str]]`
- tests/test_tools.py:20:17: error[invalid-argument-type] Argument to function `next` is incorrect: Expected `SupportsNext[Unknown]`, found `Iterable[tuple[bool, str | Unknown]]`
+ tests/test_tools.py:20:17: error[invalid-argument-type] Argument to function `next` is incorrect: Expected `SupportsNext[Unknown]`, found `Iterable[tuple[bool, Unknown | str]]`

porcupine (https://github.com/Akuli/porcupine)
- porcupine/pluginmanager.py:133:49: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Iterable[Never]`, found `Unknown | str`
- Found 25 diagnostics
+ Found 24 diagnostics

artigraph (https://github.com/artigraph/artigraph)
- tests/arti/types/test_types.py:100:51: error[invalid-argument-type] Argument is incorrect: Expected `frozenset[Any]`, found `frozenset[float | Unknown | int] | list[int | Unknown | float] | tuple[float | Unknown | int, ...]`
+ tests/arti/types/test_types.py:100:51: error[invalid-argument-type] Argument is incorrect: Expected `frozenset[Any]`, found `frozenset[float | Unknown | int] | list[Unknown | int | float] | tuple[float | Unknown | int, ...]`

meson (https://github.com/mesonbuild/meson)
- mesonbuild/dependencies/cuda.py:137:76: error[invalid-argument-type] Argument to function `version_compare_many` is incorrect: Expected `str`, found `str | None | Unknown`
+ mesonbuild/dependencies/cuda.py:137:76: error[invalid-argument-type] Argument to function `version_compare_many` is incorrect: Expected `str`, found `Unknown | str | None`

cloud-init (https://github.com/canonical/cloud-init)
- tests/unittests/distros/test_user_data_normalize.py:24:31: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `dict[Unknown, Unknown]`, found `Unknown | dict[Unknown | str, Unknown | str] | str | ... omitted 3 union elements`
+ tests/unittests/distros/test_user_data_normalize.py:24:31: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `dict[Unknown, Unknown]`, found `Unknown | bool | list[Unknown] | ... omitted 3 union elements`
- tests/unittests/sources/test_gce.py:71:31: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `dict[Unknown, Unknown]`, found `Unknown | dict[Unknown | str, Unknown | str] | str | ... omitted 3 union elements`
+ tests/unittests/sources/test_gce.py:71:31: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `dict[Unknown, Unknown]`, found `Unknown | bool | list[Unknown] | ... omitted 3 union elements`

prefect (https://github.com/PrefectHQ/prefect)
- src/prefect/input/run_input.py:672:20: error[invalid-return-type] Return type does not match returned value: expected `T@GetAutomaticInputHandler | AutomaticRunInput[T@GetAutomaticInputHandler]`, found `Unknown | Coroutine[Any, Any, Unknown]`
+ src/prefect/input/run_input.py:672:20: error[invalid-return-type] Return type does not match returned value: expected `T@GetAutomaticInputHandler | AutomaticRunInput[T@GetAutomaticInputHandler]`, found `T@GetAutomaticInputHandler | AutomaticRunInput[T@GetAutomaticInputHandler] | Coroutine[Any, Any, T@GetAutomaticInputHandler | AutomaticRunInput[T@GetAutomaticInputHandler]]`
+ src/prefect/utilities/asyncutils.py:198:16: error[invalid-return-type] Return type does not match returned value: expected `R@run_coro_as_sync | None`, found `CoroutineType[Any, Any, R@run_coro_as_sync | None] | R@run_coro_as_sync | None`
+ src/prefect/utilities/asyncutils.py:207:20: error[invalid-return-type] Return type does not match returned value: expected `R@run_coro_as_sync | None`, found `CoroutineType[Any, Any, R@run_coro_as_sync | None] | R@run_coro_as_sync | None`
- Found 5781 diagnostics
+ Found 5783 diagnostics

sympy (https://github.com/sympy/sympy)
+ sympy/algebras/tests/test_quaternion.py:423:33: error[unsupported-operator] Operator `-` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/codegen/tests/test_matrix_nodes.py:28:21: error[unsupported-operator] Operator `-` is not supported between two objects of type `MutableDenseMatrix`
- sympy/geometry/tests/test_util.py:129:55: error[invalid-argument-type] Argument to function `subsets` is incorrect: Expected `Sequence[Unknown]`, found `set[Unknown | Point2D]`
+ sympy/geometry/tests/test_util.py:129:55: error[invalid-argument-type] Argument to function `subsets` is incorrect: Expected `Sequence[Unknown]`, found `set[Point2D | Unknown]`
+ sympy/matrices/eigen.py:1202:37: error[unresolved-attribute] Object of type `T1'return@call_highest_priority | T2'return@call_highest_priority` has no attribute `pow`
+ sympy/matrices/expressions/tests/test_blockmatrix.py:236:13: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/expressions/tests/test_blockmatrix.py:236:33: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/expressions/tests/test_blockmatrix.py:236:53: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/expressions/tests/test_blockmatrix.py:460:12: error[unsupported-operator] Operator `-` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/expressions/tests/test_derivatives.py:552:26: error[unsupported-operator] Operator `+` is not supported between two objects of type `MatrixBase | Expr`
+ sympy/matrices/expressions/tests/test_matadd.py:37:12: error[unsupported-operator] Operator `+` is not supported between objects of type `MatrixBase` and `MatrixBase | Expr`
+ sympy/matrices/expressions/tests/test_matpow.py:125:47: error[unsupported-operator] Operator `+` is not supported between two objects of type `ImmutableDenseMatrix`
+ sympy/matrices/inverse.py:385:11: error[unsupported-operator] Operator `-` is not supported between objects of type `MatrixBase` and `MatrixBase | Expr | Unknown`
+ sympy/matrices/inverse.py:393:11: error[unsupported-operator] Operator `+` is not supported between objects of type `MatrixBase` and `MatrixBase | Expr | Unknown`
+ sympy/matrices/matrixbase.py:979:18: error[unsupported-operator] Operator `+` is not supported between two objects of type `Self@_eval_wilkinson`
+ sympy/matrices/matrixbase.py:2957:16: error[invalid-return-type] Return type does not match returned value: expected `Self@_eval_pow_by_cayley`, found `Self@_eval_pow_by_cayley | T1'return@call_highest_priority | T2'return@call_highest_priority | Unknown`
+ sympy/matrices/matrixbase.py:3256:16: error[invalid-return-type] Return type does not match returned value: expected `MatrixBase`, found `T1'return@call_highest_priority | T2'return@call_highest_priority`
+ sympy/matrices/matrixbase.py:3256:29: error[invalid-argument-type] Argument is incorrect: Expected `T1'return@call_highest_priority | T2'return@call_highest_priority`, found `MatrixBase`
+ sympy/matrices/matrixbase.py:3310:16: error[unsupported-operator] Operator `+` is not supported between two objects of type `MatrixBase`
+ sympy/matrices/matrixbase.py:3314:16: error[invalid-return-type] Return type does not match returned value: expected `Tmat@__sub__`, found `MatrixBase`
+ sympy/matrices/matrixbase.py:4386:16: error[unsupported-operator] Operator `+` is not supported between two objects of type `Self@add`
+ sympy/matrices/matrixbase.py:4923:16: error[invalid-return-type] Return type does not match returned value: expected `Self@analytic_func`, found `Self@analytic_func | T1'return@call_highest_priority | T2'return@call_highest_priority | Unknown`
+ sympy/matrices/repmatrix.py:321:17: error[unsupported-operator] Operator `-` is not supported between two objects of type `Self@_eval_is_symmetric`
+ sympy/matrices/solvers.py:741:12: error[invalid-return-type] Return type does not match returned value: expected `Tmat@_pinv_solve`, found `T1'return@call_highest_priority | T2'return@call_highest_priority`
+ sympy/matrices/tests/test_commonmatrix.py:1250:31: error[unsupported-operator] Operator `+` is not supported between objects of type `MutableDenseMatrix` and `ImmutableDenseNDimArray`
+ sympy/matrices/tests/test_eigen.py:407:20: error[invalid-argument-type] Argument to function `max` is incorrect: Expected `Iterable[Unknown]`, found `MatrixBase | Unknown`
+ sympy/matrices/tests/test_immutable.py:106:23: error[unsupported-operator] Operator `+` is not supported between two objects of type `ImmutableDenseMatrix`
+ sympy/matrices/tests/test_matrices.py:122:12: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/tests/test_matrices.py:124:32: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/tests/test_matrices.py:142:12: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/tests/test_matrices.py:2180:22: error[unsupported-operator] Operator `+` is not supported between two objects of type `Unknown | MutableDenseMatrix`
+ sympy/matrices/tests/test_matrices.py:2208:26: error[unsupported-operator] Operator `+` is not supported between two objects of type `Unknown | MutableDenseMatrix`
+ sympy/matrices/tests/test_matrices.py:2909:21: error[unsupported-operator] Operator `-` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/tests/test_matrices.py:2922:13: error[unsupported-operator] Operator `-` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/tests/test_matrices.py:2937:13: error[unsupported-operator] Operator `-` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/tests/test_matrices.py:2938:13: error[unsupported-operator] Operator `-` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/tests/test_matrices.py:2949:14: error[unsupported-operator] Operator `-` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/tests/test_matrices.py:3472:21: error[unsupported-operator] Operator `-` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/tests/test_matrices.py:3479:12: error[unresolved-attribute] Attribute `rank` is not defined on `MatrixExpr` in union `MatrixBase | MatrixExpr | Unknown`
+ sympy/matrices/tests/test_matrices.py:3480:12: error[unresolved-attribute] Attribute `rank` is not defined on `MatrixExpr` in union `MatrixBase | MatrixExpr | Unknown`
+ sympy/matrices/tests/test_matrixbase.py:492:12: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/tests/test_matrixbase.py:494:32: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/tests/test_matrixbase.py:545:12: error[unsupported-operator] Operator `-` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/tests/test_matrixbase.py:824:31: error[unsupported-operator] Operator `+` is not supported between objects of type `MutableDenseMatrix` and `ImmutableDenseNDimArray`
+ sympy/matrices/tests/test_matrixbase.py:877:12: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/tests/test_matrixbase.py:879:32: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/tests/test_matrixbase.py:901:12: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/tests/test_matrixbase.py:2932:22: error[unsupported-operator] Operator `+` is not supported between two objects of type `Unknown | MutableDenseMatrix`
+ sympy/matrices/tests/test_matrixbase.py:2960:26: error[unsupported-operator] Operator `+` is not supported between two objects of type `Unknown | MutableDenseMatrix`
+ sympy/matrices/tests/test_matrixbase.py:3611:21: error[unsupported-operator] Operator `-` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/tests/test_matrixbase.py:3625:13: error[unsupported-operator] Operator `-` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/tests/test_matrixbase.py:3640:13: error[unsupported-operator] Operator `-` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/tests/test_matrixbase.py:3641:13: error[unsupported-operator] Operator `-` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/tests/test_matrixbase.py:3653:14: error[unsupported-operator] Operator `-` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/tests/test_reductions.py:378:21: error[unsupported-operator] Operator `-` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/tests/test_reductions.py:385:12: error[unresolved-attribute] Attribute `rank` is not defined on `MatrixExpr` in union `MatrixBase | MatrixExpr | Unknown`
+ sympy/matrices/tests/test_reductions.py:386:12: error[unresolved-attribute] Attribute `rank` is not defined on `MatrixExpr` in union `MatrixBase | MatrixExpr | Unknown`
+ sympy/matrices/tests/test_solvers.py:69:13: error[unsupported-operator] Operator `-` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/matrices/tests/test_sparse.py:574:12: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableSparseMatrix`
+ sympy/matrices/tests/test_sparse.py:578:52: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableSparseMatrix`
+ sympy/matrices/tests/test_sparse.py:594:17: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableSparseMatrix`
+ sympy/parsing/autolev/test-examples/ruletest5.py:13:6: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/parsing/autolev/test-examples/ruletest5.py:16:38: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/parsing/autolev/test-examples/ruletest5.py:16:84: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/parsing/autolev/test-examples/ruletest5.py:16:131: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/parsing/autolev/test-examples/ruletest5.py:21:44: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/parsing/autolev/test-examples/ruletest5.py:21:90: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/parsing/autolev/test-examples/ruletest5.py:21:137: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/parsing/autolev/test-examples/ruletest5.py:25:37: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/parsing/autolev/test-examples/ruletest5.py:25:83: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/parsing/autolev/test-examples/ruletest5.py:25:130: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/physics/control/tests/test_lti.py:3778:31: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/physics/control/tests/test_lti.py:3778:38: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/physics/mechanics/lagrange.py:223:23: error[unsupported-operator] Operator `-` is not supported between two objects of type `Unknown | MutableDenseMatrix`
+ sympy/physics/mechanics/lagrange.py:347:17: error[unsupported-operator] Operator `+` is not supported between two objects of type `Unknown | MutableDenseMatrix`
+ sympy/physics/mechanics/linearize.py:218:28: error[unsupported-operator] Operator `+` is not supported between two objects of type `Unknown | MutableDenseMatrix`
+ sympy/physics/mechanics/linearize.py:230:29: error[unsupported-operator] Operator `+` is not supported between two objects of type `Unknown | MutableDenseMatrix`
+ sympy/physics/mechanics/linearize.py:242:29: error[unsupported-operator] Operator `+` is not supported between two objects of type `Unknown | MutableDenseMatrix`
+ sympy/physics/mechanics/tests/test_jointsmethod.py:248:17: error[unsupported-operator] Operator `-` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/physics/mechanics/tests/test_jointsmethod.py:250:17: error[unsupported-operator] Operator `-` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/physics/quantum/tests/test_represent.py:90:17: error[unsupported-operator] Operator `+` is not supported between objects of type `MatrixBase | Expr` and `MatrixBase`
+ sympy/physics/quantum/tests/test_represent.py:92:24: error[unsupported-operator] Operator `-` is not supported between two objects of type `MatrixBase | Expr`
+ sympy/physics/quantum/tests/test_represent.py:94:28: error[unsupported-operator] Operator `+` is not supported between two objects of type `MatrixBase | Expr`
+ sympy/physics/vector/functions.py:381:21: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `MatrixBase | Unknown`
+ sympy/solvers/tests/test_numeric.py:138:11: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/solvers/tests/test_solvers.py:723:19: error[unsupported-operator] Operator `-` is not supported between two objects of type `MatrixBase | Expr`
+ sympy/solvers/tests/test_solvers.py:724:19: error[unsupported-operator] Operator `-` is not supported between two objects of type `MatrixBase | Expr`
+ sympy/solvers/tests/test_solvers.py:725:19: error[unsupported-operator] Operator `-` is not supported between two objects of type `MatrixBase | Expr`
+ sympy/solvers/tests/test_solvers.py:725:30: error[unsupported-operator] Operator `-` is not supported between two objects of type `MatrixBase | Expr`
+ sympy/stats/tests/test_symbolic_multivariate.py:85:36: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/stats/tests/test_symbolic_multivariate.py:85:84: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/stats/tests/test_symbolic_multivariate.py:86:36: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/tensor/tests/test_tensor.py:1694:19: error[unsupported-operator] Operator `+` is not supported between two objects of type `MutableDenseMatrix`
+ sympy/tensor/tests/test_tensor.py:1695:23: error[unsupported-operator] Operator `-` is not supported between two objects of type `MutableDenseMatrix`
- Found 16017 diagnostics
+ Found 16109 diagnostics

dd-trace-py (https://github.com/DataDog/dd-trace-py)
- tests/tracer/test_span.py:193:29: error[invalid-argument-type] Argument to bound method `set_metric` is incorrect: Expected `int | float`, found `Span | Unknown | None | ... omitted 6 union elements`
+ tests/tracer/test_span.py:193:29: error[invalid-argument-type] Argument to bound method `set_metric` is incorrect: Expected `int | float`, found `str | Unknown | None | ... omitted 6 union elements`

static-frame (https://github.com/static-frame/static-frame)
- static_frame/test/unit/test_frame_iter.py:1389:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1389:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`
- static_frame/test/unit/test_frame_iter.py:1397:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1397:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`
- static_frame/test/unit/test_frame_iter.py:1408:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1408:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`
- static_frame/test/unit/test_frame_iter.py:1411:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1411:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`
- static_frame/test/unit/test_frame_iter.py:1431:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1431:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`
- static_frame/test/unit/test_frame_iter.py:1439:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1439:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`
- static_frame/test/unit/test_frame_iter.py:1481:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1481:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`
- static_frame/test/unit/test_frame_iter.py:1489:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1489:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`
- static_frame/test/unit/test_frame_iter.py:1549:26: error[unresolved-attribute] Attribute `tolist` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1549:26: error[unresolved-attribute] Attribute `tolist` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`
- static_frame/test/unit/test_frame_iter.py:1550:26: error[unresolved-attribute] Attribute `tolist` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1550:26: error[unresolved-attribute] Attribute `tolist` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`
- static_frame/test/unit/test_frame_iter.py:1553:26: error[unresolved-attribute] Attribute `tolist` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1553:26: error[unresolved-attribute] Attribute `tolist` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`
- static_frame/test/unit/test_frame_iter.py:1554:26: error[unresolved-attribute] Attribute `tolist` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1554:26: error[unresolved-attribute] Attribute `tolist` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`
- static_frame/test/unit/test_frame_iter.py:1684:29: error[unresolved-attribute] Attribute `shape` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1684:29: error[unresolved-attribute] Attribute `shape` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`

scikit-learn (https://github.com/scikit-learn/scikit-learn)
- sklearn/datasets/_lfw.py:469:60: error[invalid-argument-type] Argument to class `str` is incorrect: Expected `bytes | bytearray`, found `Unknown | str`
+ sklearn/datasets/_lfw.py:469:60: error[invalid-argument-type] Argument to class `str` is incorrect: Expected `bytes | bytearray`, found `str | Unknown`

jax (https://github.com/google/jax)
- jax/_src/export/_export.py:1378:45: error[invalid-argument-type] Argument to function `_get_named_sharding` is incorrect: Expected `ShapedArray`, found `Unknown | AbstractValue`
+ jax/_src/export/_export.py:1378:45: error[invalid-argument-type] Argument to function `_get_named_sharding` is incorrect: Expected `ShapedArray`, found `AbstractValue | Unknown`
- jax/_src/pallas/hlo_interpreter.py:433:37: error[invalid-argument-type] Argument is incorrect: Expected `int`, found `int | Unknown | DynamicGridDim`
+ jax/_src/pallas/hlo_interpreter.py:433:37: error[invalid-argument-type] Argument is incorrect: Expected `int`, found `int | DynamicGridDim | Unknown`
- jax/_src/pallas/mosaic/interpret/interpret_pallas_call.py:1900:37: error[invalid-argument-type] Argument is incorrect: Expected `int`, found `int | Unknown | DynamicGridDim`
+ jax/_src/pallas/mosaic/interpret/interpret_pallas_call.py:1900:37: error[invalid-argument-type] Argument is incorrect: Expected `int`, found `int | DynamicGridDim | Unknown`
- jax/_src/pallas/pallas_call.py:862:37: error[invalid-argument-type] Argument is incorrect: Expected `int`, found `int | Unknown | DynamicGridDim`
+ jax/_src/pallas/pallas_call.py:862:37: error[invalid-argument-type] Argument is incorrect: Expected `int`, found `int | DynamicGridDim | Unknown`
- jax/collect_profile.py:110:17: error[unresolved-attribute] Attribute `glob` is not defined on `PathLike[str]`, `int`, `str`, `bytes`, `PathLike[bytes]` in union `PathLike[str] | Unknown | int | ... omitted 3 union elements`
+ jax/collect_profile.py:110:17: error[unresolved-attribute] Attribute `glob` is not defined on `PathLike[str]`, `int`, `str`, `bytes`, `PathLike[bytes]` in union `Unknown | PathLike[str] | int | ... omitted 3 union elements`
- jax/collect_profile.py:113:22: error[unsupported-operator] Operator `/` is not supported between objects of type `PathLike[str] | Unknown | int | ... omitted 3 union elements` and `Literal["remote.trace.json.gz"]`
+ jax/collect_profile.py:113:22: error[unsupported-operator] Operator `/` is not supported between objects of type `Unknown | PathLike[str] | int | ... omitted 3 union elements` and `Literal["remote.trace.json.gz"]`

pandas-stubs (https://github.com/pandas-dev/pandas-stubs)
- tests/series/test_series.py:2441:9: error[type-assertion-failure] Type `Unknown` does not match asserted type `Series[Timestamp]`
- Found 4707 diagnostics
+ Found 4706 diagnostics

colour (https://github.com/colour-science/colour)
+ colour/utilities/verbose.py:1071:69: error[invalid-argument-type] Argument to function `getattr` is incorrect: Expected `str`, found `bool | (Unknown & ~None) | <class 'str'>`
- colour/utilities/verbose.py:1071:69: error[invalid-argument-type] Argument to function `getattr` is incorrect: Expected `str`, found `(Unknown & ~None) | <class 'str'> | bool`

scipy (https://github.com/scipy/scipy)
- subprojects/array_api_compat/array_api_compat/array_api_compat/common/_linalg.py:113:15: error[unresolved-attribute] Attribute `max` is not defined on `tuple[Any, ...]` in union `tuple[Any, ...] | Any`
+ subprojects/array_api_compat/array_api_compat/array_api_compat/common/_linalg.py:113:15: error[unresolved-attribute] Attribute `max` is not defined on `tuple[Any, ...]` in union `Any | tuple[Any, ...]`
- subprojects/array_api_compat/array_api_compat/array_api_compat/common/_linalg.py:113:76: error[unresolved-attribute] Attribute `dtype` is not defined on `tuple[Any, ...]` in union `tuple[Any, ...] | Any`
+ subprojects/array_api_compat/array_api_compat/array_api_compat/common/_linalg.py:113:76: error[unresolved-attribute] Attribute `dtype` is not defined on `tuple[Any, ...]` in union `Any | tuple[Any, ...]`
- subprojects/array_api_compat/array_api_compat/array_api_compat/common/_linalg.py:117:15: error[unresolved-attribute] Attribute `max` is not defined on `tuple[Any, ...]` in union `tuple[Any, ...] | Any`
+ subprojects/array_api_compat/array_api_compat/array_api_compat/common/_linalg.py:117:15: error[unresolved-attribute] Attribute `max` is not defined on `tuple[Any, ...]` in union `Any | tuple[Any, ...]`


fallback: R,

pub(crate) extra: Extra,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This lets us remove a data field from the TypeRelation enum, so that it can be trivially copyable without ConstraintSets needing to be as well.

Comment on lines -192 to +194
SubtypingAssuming(ConstraintSet<'db>),
SubtypingAssuming,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

namely here

Comment on lines +205 to +210
#[derive(Clone, Debug, Eq, Hash, PartialEq, get_size2::GetSize, salsa::Update)]
pub struct OwnedConstraintSet<'db> {
/// The BDD representing this constraint set
node: Node<'db>,
storage: ConstraintSetStorage<'db>,
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only exists to have something internable (for InternedConstraintSet) without having to make all of (eventual, in the later PR) fields of ConstraintSetBuilder implement Hash.

Comment on lines +226 to +227
builder: &'c ConstraintSetBuilder<'db>,
_invariant: PhantomData<fn(&'c ()) -> &'c ()>,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These exist to provide compile- and runtime checks that we're only using ConstraintSets with the builders that created them. I'm considering making the builder field only exist in debug builds, but that would be a follow-on experiment.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my C++ template metaprogramming days, I used to write "should not compile" tests. compile_fail in doctests can achieve something similar, but unfortunately it requires a few things to be pub instead of pub(crate), so I'm not sure if it's worth it. Certainly, adding lots of infrastructure just for this seems unnecessary.

    /// ```compile_fail,E0521
    /// use ty_python_semantic::types::constraints::{ConstraintSetBuilder, ConstraintSet};
    ///
    /// fn wrong_constraint_set<'db>() {
    ///     let builder1 = ConstraintSetBuilder::new();
    ///     let constraints1 = ConstraintSet::always(&builder1);
    ///
    ///     let builder2 = ConstraintSetBuilder::new();
    ///     let _ = builder2.into_owned(|builder2| {
    ///         constraints1  // this is wrong
    ///     });
    /// }
    /// ```

Comment on lines -120 to +125
pub(crate) fn has_relation_to_impl(self, db: &'db dyn Db, other: Self) -> ConstraintSet<'db> {
pub(crate) fn has_relation_to_impl<'c>(
self,
db: &'db dyn Db,
other: Self,
constraints: &'c ConstraintSetBuilder<'db>,
) -> ConstraintSet<'db, 'c> {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good example of the new method shape — we have to take in an additional ConstraintSetBuilder param, and the constraint set that is returned is linked to that builder via the 'c lifetime.

@dcreager dcreager marked this pull request as ready for review February 27, 2026 03:08
Copy link
Contributor

@sharkdp sharkdp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much for pulling it out as an additional refactoring. I think I'm going to merge this right away, both because it could easily accumulate conflicts, and because I'm working on a changeset that also affects has_relation_to and friends, so I might as well just immediately build on top of this.

One thought I had while scrolling through the diff: has_relation_to makes sense as a method on Type (and its sub-variants), but it doesn't need to be attached to it. As we thread more and more parameters through these function calls, I'm wondering if it would make sense to split out these type relations into their own module, and implement them on a TypeRelation struct (or similar) that holds on to those parameters? This would make refactorings like this one easier, but the downside would be that we might have to make some internals of Callable or similar available publicly(?).


pub(crate) fn into_owned(
self,
f: impl for<'c> FnOnce(&'c Self) -> ConstraintSet<'db, 'c>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool. I was aware this existed, but haven't used it myself yet.

@sharkdp sharkdp merged commit bf60289 into main Feb 27, 2026
51 checks passed
@sharkdp sharkdp deleted the dcreager/constraint-builder-refactor branch February 27, 2026 12:40
carljm added a commit that referenced this pull request Feb 27, 2026
* main:
  [ty] Take myself out of the reviewer pool for the next few days (#23618)
  [ty] Fix bug where ty would think that a `Callable` with a variadic positional parameter could be a subtype of a `Callable` with a positional-or-keyword parameter (#23610)
  [`ruff`] Add fix for `none-not-at-end-of-union` (`RUF036`)  (#22829)
  Bump cargo dist to 0.31 (#23614)
  [`pyflakes`] Fix false positive for names shadowing re-exports (`F811`) (#23356)
  [`fastapi`] Handle callable class dependencies with `__call__` method (`FAST003`) (#23553)
  [ty] Recurse into tuples and nested tuples when applying special-cased validation of `isinstance()` and `issubclass()` (#23607)
  Update typing conformance suite commit (#23606)
  [ty] Detect invalid uses of `@final` on non-methods (#23604)
  [ty] Move the type hierarchy request handlers to individual modules
  [ty] Wire up the type hierarchy implementation with the LSP
  [ty] Add routine for mapping from system path to vendored path
  [ty] Implement internal routines for providing the LSP "type hierarchy" feature
  [ty] Add some helper methods on `ClassLiteral`
  [ty] Move some module name helper routines to methods on `ModuleName`
  [ty] Bump version of `lsp-types`
  [ty] Refactor to support building constraint sets differently (#23600)
  [ty] Dataclass transform: neither frozen nor non-frozen (#23366)
  [ty] Add snapshot tests for advanced `invalid-assignment` scenarios (#23581)
  [ty] disallow negative narrowing on SubclassOf types (#23598)
@carljm
Copy link
Contributor

carljm commented Feb 27, 2026

the downside would be that we might have to make some internals of Callable or similar available publicly(?)

Not if the module is a submodule of crate::types?

In fact has_relation_to is already implemented in its own crate::types::relations submodule, even though it is currently an impl on Type.

dcreager added a commit that referenced this pull request Mar 2, 2026
This PR updates how we manage the interning and memoization of our
constraint set BDD implementation. Before we relied on Salsa interning
and tracking. This had the nice property that everything was cached
globally across the entire process, which in theory gives us space
savings when the same constraint sets are created for different regions
of source code.

However, it made us very susceptible to changes in the ordering of salsa
IDs. Salsa IDs are also assigned globally, in the order that interned
structs or tracked method results are created. That means that if e.g. a
particular constraint is created for two unrelated regions of code,
there's no guarantee about how that constraint's salsa ID will compare
to the IDs of the other constraints in the BDD. Since we were using
constraint IDs to define our BDD variable ordering, this would sometimes
give us different BDD structures for different (identical) invocations
of ty. This was leading to a lot of nondeterminism in our CI jobs.

We now rely on a new `ConstraintSetBuilder` type to define _local_
caching of BDD nodes and operations. The type was introduced as a no-op
refactoring in #23600. This PR
updates that type to actually take over responsiblity for the interning
and memoization caches.

This opens up some other potential optimizations, but I've kept this PR
purposefully limited in scope — with one exception, we cache exactly the
same things as before, just in a hand-roll `FxHashMap` instead of via a
magic salsa macro. (That one exception is that we now intern typevars
locally in the new builder, even though they are already salsa-interned
globally. This is needed to give them a stable ID within the builder.)

---------

Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

internal An internal refactor or improvement ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants