Skip to content

[ty] Track constraint set "support" separately; go back to fully reduced BDDs#22578

Draft
dcreager wants to merge 11 commits intomainfrom
dcreager/support
Draft

[ty] Track constraint set "support" separately; go back to fully reduced BDDs#22578
dcreager wants to merge 11 commits intomainfrom
dcreager/support

Conversation

@dcreager
Copy link
Member

This reverts our short-lived experiment with quasi-reduced BDDs. We introduced quasi-reduction in #21744 in an attempt to remove some non-determinism in our tests. This non-determinism came about because a constraint set BDD might contain different sets of individual constraints depending on the (arbitrary) BDD variable ordering that is in force for a particular run of ty. Quasi-reduction ensured that all of the constraints explicitly mentioned when constructing a constraint set actually appeared in the BDD structure, giving us a deterministic set of constraints to iterate over.

However, that came at the cost of much bigger BDDs! Large enough, in fact, that it was causing untenable performance regressions on #21902.

This PR is a different take on the problem. We now explicitly track the set of constraints that are mentioned when constructing a constraint set. This is called the constraint set's support, and is an additional (salsa-interned) field in ConstraintSet. Tracking that separately means that we can go back to fully reduced BDDs, since have a different way to iterate through the constraint set's support when we need to.

This depends on #22577.

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

astral-sh-bot bot commented Jan 14, 2026

Typing conformance results

No changes detected ✅

@astral-sh-bot
Copy link

astral-sh-bot bot commented Jan 14, 2026

mypy_primer results

Changes were detected when running on open source projects
attrs (https://github.com/python-attrs/attrs)
- tests/test_validators.py:1257:20: error[invalid-argument-type] Argument is incorrect: Expected `float | int`, found `Literal["spam"]`
+ tests/test_validators.py:1257:20: error[invalid-argument-type] Argument is incorrect: Expected `int | float`, found `Literal["spam"]`

tornado (https://github.com/tornadoweb/tornado)
- tornado/gen.py:255:62: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `None | Awaitable[Unknown] | list[Awaitable[Unknown]] | dict[Any, Awaitable[Unknown]] | Future[Unknown]`, found `_T@next | _T@next | _VT@next`
+ tornado/gen.py:255:62: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `None | Awaitable[Unknown] | list[Awaitable[Unknown]] | dict[Any, Awaitable[Unknown]] | Future[Unknown]`, found `_T@next | _VT@next | _T@next`

discord.py (https://github.com/Rapptz/discord.py)
+ discord/app_commands/checks.py:390:42: error[invalid-assignment] Object of type `Coroutine[Any, Any, Cooldown | None] | Cooldown | None` is not assignable to `Cooldown | None`
- Found 536 diagnostics
+ Found 537 diagnostics

prefect (https://github.com/PrefectHQ/prefect)
- src/integrations/prefect-dbt/prefect_dbt/core/settings.py:94:28: error[invalid-assignment] Object of type `dict[Any, Any] | int | dict[str, Any] | ... omitted 4 union elements` is not assignable to `dict[str, Any]`
- src/integrations/prefect-dbt/prefect_dbt/core/settings.py:99:28: error[invalid-assignment] Object of type `int | dict[Any, Any] | float | ... omitted 3 union elements` is not assignable to `dict[str, Any]`
+ src/integrations/prefect-dbt/prefect_dbt/core/settings.py:94:28: error[invalid-assignment] Object of type `dict[Any, Any] | dict[str, Any] | str | ... omitted 4 union elements` is not assignable to `dict[str, Any]`
+ src/integrations/prefect-dbt/prefect_dbt/core/settings.py:99:28: error[invalid-assignment] Object of type `dict[Any, Any] | str | int | ... omitted 3 union elements` is not assignable to `dict[str, Any]`
+ src/prefect/_internal/concurrency/api.py:83:29: error[invalid-argument-type] Argument to function `cast_to_call` is incorrect: Expected `() -> Awaitable[T@call_soon_in_new_thread]`, found `() -> T@call_soon_in_new_thread | Awaitable[T@call_soon_in_new_thread]`
+ src/prefect/_internal/concurrency/api.py:87:16: error[invalid-return-type] Return type does not match returned value: expected `Call[T@call_soon_in_new_thread]`, found `Call[Awaitable[T@call_soon_in_new_thread]]`
+ src/prefect/_internal/concurrency/api.py:99:29: error[invalid-argument-type] Argument to function `cast_to_call` is incorrect: Expected `() -> Awaitable[T@call_soon_in_loop_thread]`, found `() -> T@call_soon_in_loop_thread | Awaitable[T@call_soon_in_loop_thread]`
+ src/prefect/_internal/concurrency/api.py:103:16: error[invalid-return-type] Return type does not match returned value: expected `Call[T@call_soon_in_loop_thread]`, found `Call[Awaitable[T@call_soon_in_loop_thread]]`
+ src/prefect/_internal/concurrency/api.py:137:29: error[invalid-argument-type] Argument to function `cast_to_call` is incorrect: Expected `() -> Awaitable[T@wait_for_call_in_loop_thread]`, found `(() -> Awaitable[T@wait_for_call_in_loop_thread]) | Call[T@wait_for_call_in_loop_thread]`
+ src/prefect/_internal/concurrency/api.py:146:20: error[invalid-return-type] Return type does not match returned value: expected `T@wait_for_call_in_loop_thread`, found `Awaitable[T@wait_for_call_in_loop_thread]`
+ src/prefect/_internal/concurrency/api.py:154:29: error[invalid-argument-type] Argument to function `cast_to_call` is incorrect: Expected `() -> Awaitable[T@wait_for_call_in_new_thread]`, found `(() -> T@wait_for_call_in_new_thread) | Call[T@wait_for_call_in_new_thread]`
+ src/prefect/_internal/concurrency/api.py:160:16: error[invalid-return-type] Return type does not match returned value: expected `T@wait_for_call_in_new_thread`, found `Awaitable[T@wait_for_call_in_new_thread]`
+ src/prefect/_internal/concurrency/api.py:166:46: error[invalid-argument-type] Argument to function `call_soon_in_new_thread` is incorrect: Expected `() -> Awaitable[T@call_in_new_thread]`, found `(() -> T@call_in_new_thread) | Call[T@call_in_new_thread]`
+ src/prefect/_internal/concurrency/api.py:174:47: error[invalid-argument-type] Argument to function `call_soon_in_loop_thread` is incorrect: Expected `() -> Awaitable[T@call_in_loop_thread]`, found `(() -> Awaitable[T@call_in_loop_thread]) | Call[T@call_in_loop_thread]`
+ src/prefect/_internal/concurrency/api.py:189:29: error[invalid-argument-type] Argument to function `cast_to_call` is incorrect: Expected `() -> Awaitable[T@wait_for_call_in_loop_thread]`, found `(() -> Awaitable[T@wait_for_call_in_loop_thread]) | Call[T@wait_for_call_in_loop_thread]`
+ src/prefect/_internal/concurrency/api.py:198:20: error[invalid-return-type] Return type does not match returned value: expected `T@wait_for_call_in_loop_thread`, found `Awaitable[T@wait_for_call_in_loop_thread]`
+ src/prefect/_internal/concurrency/api.py:206:29: error[invalid-argument-type] Argument to function `cast_to_call` is incorrect: Expected `() -> Awaitable[T@wait_for_call_in_new_thread]`, found `(() -> T@wait_for_call_in_new_thread) | Call[T@wait_for_call_in_new_thread]`
+ src/prefect/_internal/concurrency/api.py:212:16: error[invalid-return-type] Return type does not match returned value: expected `T@wait_for_call_in_new_thread`, found `Awaitable[T@wait_for_call_in_new_thread]`
+ src/prefect/_internal/concurrency/api.py:219:46: error[invalid-argument-type] Argument to function `call_soon_in_new_thread` is incorrect: Expected `() -> Awaitable[T@call_in_new_thread]`, found `() -> T@call_in_new_thread | Awaitable[T@call_in_new_thread]`
+ src/prefect/_internal/concurrency/api.py:220:16: error[invalid-return-type] Return type does not match returned value: expected `T@call_in_new_thread`, found `Awaitable[T@call_in_new_thread]`
+ src/prefect/_internal/concurrency/api.py:230:33: error[invalid-argument-type] Argument to function `cast_to_call` is incorrect: Expected `() -> Awaitable[T@call_in_loop_thread]`, found `() -> T@call_in_loop_thread | Awaitable[T@call_in_loop_thread]`
+ src/prefect/_internal/concurrency/api.py:233:47: error[invalid-argument-type] Argument to function `call_soon_in_loop_thread` is incorrect: Expected `() -> Awaitable[T@call_in_loop_thread]`, found `() -> T@call_in_loop_thread | Awaitable[T@call_in_loop_thread]`
- src/prefect/cli/deploy/_core.py:86:21: error[invalid-assignment] Object of type `dict[Any, Any] | int | dict[str, Any] | ... omitted 4 union elements` is not assignable to `dict[str, Any]`
- src/prefect/cli/deploy/_core.py:87:21: error[invalid-assignment] Object of type `int | dict[Any, Any] | float | ... omitted 3 union elements` is not assignable to `dict[str, Any]`
+ src/prefect/cli/deploy/_core.py:86:21: error[invalid-assignment] Object of type `dict[Any, Any] | dict[str, Any] | str | ... omitted 4 union elements` is not assignable to `dict[str, Any]`
+ src/prefect/cli/deploy/_core.py:87:21: error[invalid-assignment] Object of type `dict[Any, Any] | str | int | ... omitted 3 union elements` is not assignable to `dict[str, Any]`
+ src/prefect/concurrency/_leases.py:89:53: error[invalid-argument-type] Argument to bound method `add_done_callback` is incorrect: Expected `(Future[CoroutineType[Any, Any, None]], /) -> object`, found `def handle_lease_renewal_failure(future: Future[None]) -> Unknown`
- src/prefect/deployments/steps/core.py:137:38: error[invalid-argument-type] Argument is incorrect: Argument type `dict[Any, Any] | int | dict[str, Any] | ... omitted 4 union elements` does not satisfy constraints (`str`, `int`, `int | float`, `bool`, `dict[Any, Any]`, `list[Any]`, `None`) of type variable `T`
+ src/prefect/deployments/steps/core.py:137:38: error[invalid-argument-type] Argument is incorrect: Argument type `dict[Any, Any] | dict[str, Any] | str | ... omitted 4 union elements` does not satisfy constraints (`str`, `int`, `int | float`, `bool`, `dict[Any, Any]`, `list[Any]`, `None`) of type variable `T`
+ 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]`
+ 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]`
- src/prefect/utilities/templating.py:320:13: error[invalid-assignment] Invalid subscript assignment with key of type `object` and value of type `Unknown | int | dict[str, Any] | ... omitted 4 union elements` on object of type `dict[str, Any]`
+ src/prefect/utilities/templating.py:320:13: error[invalid-assignment] Invalid subscript assignment with key of type `object` and value of type `Unknown | dict[str, Any] | str | ... omitted 4 union elements` on object of type `dict[str, Any]`
- src/prefect/utilities/templating.py:323:16: error[invalid-return-type] Return type does not match returned value: expected `T@resolve_block_document_references | dict[str, Any]`, found `list[Unknown | int | dict[str, Any] | ... omitted 4 union elements]`
+ src/prefect/utilities/templating.py:323:16: error[invalid-return-type] Return type does not match returned value: expected `T@resolve_block_document_references | dict[str, Any]`, found `list[Unknown | dict[str, Any] | str | ... omitted 4 union elements]`
- src/prefect/utilities/templating.py:437:16: error[invalid-return-type] Return type does not match returned value: expected `T@resolve_variables`, found `dict[object, Unknown | int | float | ... omitted 4 union elements]`
+ src/prefect/utilities/templating.py:437:16: error[invalid-return-type] Return type does not match returned value: expected `T@resolve_variables`, found `dict[object, Unknown | str | int | ... omitted 4 union elements]`
- src/prefect/utilities/templating.py:442:16: error[invalid-return-type] Return type does not match returned value: expected `T@resolve_variables`, found `list[Unknown | int | float | ... omitted 4 union elements]`
+ src/prefect/utilities/templating.py:442:16: error[invalid-return-type] Return type does not match returned value: expected `T@resolve_variables`, found `list[Unknown | str | int | ... omitted 4 union elements]`
- src/prefect/workers/base.py:232:13: error[invalid-argument-type] Argument is incorrect: Argument type `str | int | dict[str, Any] | ... omitted 3 union elements` does not satisfy constraints (`str`, `int`, `int | float`, `bool`, `dict[Any, Any]`, `list[Any]`, `None`) of type variable `T`
+ src/prefect/workers/base.py:232:13: error[invalid-argument-type] Argument is incorrect: Argument type `str | dict[str, Any] | int | ... omitted 3 union elements` does not satisfy constraints (`str`, `int`, `int | float`, `bool`, `dict[Any, Any]`, `list[Any]`, `None`) of type variable `T`
- src/prefect/workers/base.py:234:20: error[invalid-argument-type] Argument expression after ** must be a mapping type: Found `int | Unknown | float | ... omitted 4 union elements`
+ src/prefect/workers/base.py:234:20: error[invalid-argument-type] Argument expression after ** must be a mapping type: Found `Unknown | str | int | ... omitted 4 union elements`
- Found 5368 diagnostics
+ Found 5389 diagnostics

pwndbg (https://github.com/pwndbg/pwndbg)
- pwndbg/aglib/kernel/__init__.py:264:20: error[unsupported-operator] Operator `+` is not supported between objects of type `None | Unknown` and `Literal[1]`
+ pwndbg/aglib/kernel/__init__.py:264:20: error[unsupported-operator] Operator `+` is not supported between objects of type `Unknown | None` and `Literal[1]`
- pwndbg/aglib/kernel/__init__.py:270:22: error[unsupported-operator] Operator `+` is not supported between objects of type `None | Unknown` and `int`
+ pwndbg/aglib/kernel/__init__.py:270:22: error[unsupported-operator] Operator `+` is not supported between objects of type `Unknown | None` and `int`

static-frame (https://github.com/static-frame/static-frame)
- static_frame/core/batch.py:774:16: error[invalid-return-type] Return type does not match returned value: expected `InterGetItemLocCompound[Batch]`, found `InterGetItemLocCompound[Batch | Bottom[Series[Any, Any]]]`
- static_frame/core/batch.py:778:16: error[invalid-return-type] Return type does not match returned value: expected `InterGetItemILocCompound[Batch]`, found `InterGetItemILocCompound[Batch | Bottom[Series[Any, Any]]]`
- static_frame/core/batch.py:782:16: error[invalid-return-type] Return type does not match returned value: expected `InterfaceGetItemBLoc[Batch]`, found `InterfaceGetItemBLoc[Batch | Bottom[Series[Any, Any]]]`
+ static_frame/core/frame.py:3707:16: error[invalid-return-type] Return type does not match returned value: expected `InterfaceGetItemBLoc[Series[Any, Any]]`, found `InterfaceGetItemBLoc[Series[Any, Any] | @Todo | Bottom[Index[Any]]]`
- static_frame/core/index.py:580:16: error[invalid-return-type] Return type does not match returned value: expected `InterGetItemLocReduces[TVContainer_co@loc, TVDtype@Index]`, found `InterGetItemLocReduces[Any | Bottom[Series[Any, Any]], TVDtype@Index]`
+ static_frame/core/index.py:580:16: error[invalid-return-type] Return type does not match returned value: expected `InterGetItemLocReduces[TVContainer_co@loc, TVDtype@Index]`, found `InterGetItemLocReduces[Any | Bottom[Index[Any]] | Bottom[Series[Any, Any]], TVDtype@Index]`
- static_frame/core/index.py:763:16: error[invalid-return-type] Return type does not match returned value: expected `InterfaceString[ndarray[Any, Any]]`, found `InterfaceString[ndarray[Any, Any] | Bottom[Series[Any, Any]]]`
- static_frame/core/index.py:781:16: error[invalid-return-type] Return type does not match returned value: expected `InterfaceDatetime[ndarray[Any, Any]]`, found `InterfaceDatetime[ndarray[Any, Any] | Bottom[Series[Any, Any]]]`
- static_frame/core/index.py:801:16: error[invalid-return-type] Return type does not match returned value: expected `InterfaceRe[ndarray[Any, Any]]`, found `InterfaceRe[ndarray[Any, Any] | Bottom[Series[Any, Any]]]`
- static_frame/core/node_fill_value.py:534:16: error[invalid-return-type] Return type does not match returned value: expected `InterGetItemLocReduces[Batch, Any]`, found `InterGetItemLocReduces[Batch | Bottom[Series[Any, Any]], Any]`
- static_frame/core/node_selector.py:526:16: error[invalid-return-type] Return type does not match returned value: expected `InterGetItemLocReduces[TVContainer_co@InterfaceSelectQuartet, Any]`, found `InterGetItemLocReduces[Unknown | Bottom[Series[Any, Any]], Any]`
+ static_frame/core/node_selector.py:526:16: error[invalid-return-type] Return type does not match returned value: expected `InterGetItemLocReduces[TVContainer_co@InterfaceSelectQuartet, Any]`, found `InterGetItemLocReduces[Unknown | Bottom[Index[Any]] | Bottom[Series[Any, Any]], Any]`
- static_frame/core/series.py:765:59: warning[unused-ignore-comment] Unused blanket `type: ignore` directive
+ static_frame/core/yarn.py:414:59: warning[unused-ignore-comment] Unused blanket `type: ignore` directive
- Found 1819 diagnostics
+ Found 1813 diagnostics

rotki (https://github.com/rotki/rotki)
- rotkehlchen/chain/decoding/tools.py:96:44: warning[unused-ignore-comment] Unused blanket `type: ignore` directive
- rotkehlchen/chain/decoding/tools.py:99:13: error[invalid-argument-type] Argument to function `decode_transfer_direction` is incorrect: Expected `Sequence[A@BaseDecoderTools]`, found `Unknown | tuple[BTCAddress, ...] | tuple[ChecksumAddress, ...] | tuple[SubstrateAddress, ...] | tuple[SolanaAddress, ...]`
- rotkehlchen/chain/decoding/tools.py:100:62: warning[unused-ignore-comment] Unused blanket `type: ignore` directive
+ rotkehlchen/chain/decoding/tools.py:97:13: error[invalid-argument-type] Argument to function `decode_transfer_direction` is incorrect: Expected `BTCAddress | ChecksumAddress | SubstrateAddress | SolanaAddress`, found `A@BaseDecoderTools`
+ rotkehlchen/chain/decoding/tools.py:98:13: error[invalid-argument-type] Argument to function `decode_transfer_direction` is incorrect: Expected `BTCAddress | ChecksumAddress | SubstrateAddress | SolanaAddress | None`, found `A@BaseDecoderTools | None`
- Found 2054 diagnostics
+ Found 2053 diagnostics

core (https://github.com/home-assistant/core)
- homeassistant/util/variance.py:47:12: error[invalid-return-type] Return type does not match returned value: expected `(**_P@ignore_variance) -> _R@ignore_variance`, found `_Wrapped[_P@ignore_variance, int | _R@ignore_variance | float | datetime, _P@ignore_variance, _R@ignore_variance | int | float | datetime]`
+ homeassistant/util/variance.py:47:12: error[invalid-return-type] Return type does not match returned value: expected `(**_P@ignore_variance) -> _R@ignore_variance`, found `_Wrapped[_P@ignore_variance, _R@ignore_variance | int | float | datetime, _P@ignore_variance, _R@ignore_variance | int | float | datetime]`

No memory usage changes detected ✅

@codspeed-hq
Copy link

codspeed-hq bot commented Jan 14, 2026

CodSpeed Performance Report

Merging this PR will not alter performance

Comparing dcreager/support (73e182d) with main (e43efd0)

Summary

✅ 53 untouched benchmarks

@dcreager dcreager force-pushed the dcreager/support branch 2 times, most recently from dcf8097 to 33bd081 Compare January 14, 2026 19:10
@dcreager dcreager force-pushed the dcreager/lazy-sequent-map branch from 5b240fb to 6555491 Compare January 17, 2026 17:53
Base automatically changed from dcreager/lazy-sequent-map to main January 20, 2026 21:15
@astral-sh-bot
Copy link

astral-sh-bot bot commented Jan 27, 2026

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

Formatter (stable)

✅ ecosystem check detected no format changes.

Formatter (preview)

✅ ecosystem check detected no format changes.

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.

1 participant