Skip to content

[ty] Add mdtests that exercise constraint sets#20319

Merged
dcreager merged 22 commits intomainfrom
dcreager/constraint-mdtest
Sep 10, 2025
Merged

[ty] Add mdtests that exercise constraint sets#20319
dcreager merged 22 commits intomainfrom
dcreager/constraint-mdtest

Conversation

@dcreager
Copy link
Member

@dcreager dcreager commented Sep 9, 2025

This PR adds a new ty_extensions.ConstraintSet class, which is used to expose constraint sets to our mdtest framework. This lets us write a large collection of unit tests that exercise the invariants and rewrite rules of our constraint set implementation.

As part of this, is_assignable_to and friends are updated to return a ConstraintSet instead of a bool, and we implement ConstraintSet.__bool__ to return when a constraint set is always satisfied. That lets us still use static_assert(is_assignable_to(...)), since the assertion will coerce the constraint set to a bool, and also lets us reveal_type(is_assignable_to(...)) to see more detail about whether/when the two types are assignable. That lets us get rid of reveal_when_assignable_to and friends, since they are now redundant with the expanded capabilities of is_assignable_to.

@dcreager dcreager changed the base branch from main to dcreager/incomparable September 9, 2025 18:10
@dcreager dcreager force-pushed the dcreager/constraint-mdtest branch from 1779737 to 9192e06 Compare September 9, 2025 18:16
@github-actions
Copy link
Contributor

github-actions bot commented Sep 9, 2025

Diagnostic diff on typing conformance tests

No changes detected when running ty on typing conformance tests ✅

@github-actions
Copy link
Contributor

github-actions bot commented Sep 9, 2025

mypy_primer results

No ecosystem changes detected ✅
No memory usage changes detected ✅

Base automatically changed from dcreager/incomparable to main September 9, 2025 19:54
@dcreager dcreager force-pushed the dcreager/constraint-mdtest branch from 9192e06 to a8e2919 Compare September 9, 2025 19:56
@dcreager dcreager force-pushed the dcreager/constraint-mdtest branch from a8e2919 to 65f13e5 Compare September 10, 2025 01:01
@dcreager dcreager marked this pull request as ready for review September 10, 2025 01:03
Copy link
Contributor

@carljm carljm left a comment

Choose a reason for hiding this comment

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

Nice!


```py
def _[T]() -> None:
# revealed: ty_extensions.ConstraintSet[(SubSub ≤ T@_ ≤ Base) ∨ (Sub ≤ T@_ ≤ Super)]
Copy link
Contributor

Choose a reason for hiding this comment

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

Why doesn't this union simplify to SubSub <= T <= Super?

Copy link
Member Author

Choose a reason for hiding this comment

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

There can be types that satisfy SubSub ≤ T ≤ Super but which aren't comparable to Sub or Base, and which therefore shouldn't be included in the union.

So with just set theory, if the possible values are 0, 1, and 2, you get a type lattice of

   012
01  02  12
 0   1   2
     ∅

Then we might have

SubSub = ∅
Sub    = 1
Base   = 12
Super  = 012

SubSub ≤ T ≤ Base  = {∅, 1, 2, 12}
Sub ≤ T ≤ Super    = {1, 01, 12, 012}

The union should be

(SubSub ≤ T ≤ Base) ∪ (Sub ≤ T ≤ Super) = {∅, 1, 2, 01, 12, 012}

but the simplification you suggest would be

SubSub ≤ T ≤ Super = {∅, 0, 1, 2, 01, 02, 12, 012}

0 and 02 are included in the simplification but not in the actual union.

Translating that into Python, an example problem type would be Super \ Sub*, where Sub* indicates instances of just Sub, but not any of its subclasses. (So in English, the problem type is "instances of Super, or any subclass of Super other than Sub". That type is not in SubSub ≤ T ≤ Base, since it includes Super, which is outside the range. It's also not in Sub ≤ T ≤ Super, because it does not include Sub. But it is in SubSub ≤ T ≤ Super.

Copy link
Contributor

Choose a reason for hiding this comment

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

Makes sense, thank you! Might be worth recording a short version of this as a comment?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

* main: (26 commits)
  Ignore deprecated rules unless selected by exact code (#20167)
  Stabilize adding future import via config option (#20277)
  [`flake8-errmsg`] Stabilize extending `raw-string-in-exception` (`EM101`) to support byte strings (#20273)
  Stabilize the remaining Airflow rules (#20250)
  [`flake8-bugbear`] Stabilize support for non-context-manager calls in `assert-raises-exception` (`B017`) (#20274)
  [`flake8-commas`] Stabilize support for trailing comma checks in type parameter lists (`COM812`, `COM819`) (#20275)
  [`pygrep_hooks`] Stabilize using`AsyncMock` methods in `invalid-mock-access` (`PGH005`) (#20272)
  Stabilize new strategy for classifying imports as first party (#20268)
  [`pylint`] Stabilize ignoring `__init__.py` for `useless-import-alias` (`PLC0414`) (#20271)
  [`pylint`] Stabilize adding U+061C to `bidirectional-unicode` (`PLE2502`) (#20276)
  [`flake8-simplify`] Stabilize fix safety of `multiple-with-statements` (`SIM117`) (#20270)
  Stabilize `pytest-raises-ambiguous-pattern` (`RUF043`) (#20253)
  Stabilize `f-string-number-format` (`FURB116`) (#20247)
  [`pyupgrade`] Remove `non-pep604-isinstance` (`UP038`) (#19156)
  [`pandas-vet`] Remove `pandas-df-variable-name` (`PD901`) (#19223)
  Remove deprecated macOS config file discovery (#19210)
  Stabilize `redundant-none-literal` (`PYI061`) (#20236)
  Stabilize `generic-not-last-base-class` (`PYI059`) (#20246)
  Stabilize `useless-class-metaclass-type` (`UP050`) (#20230)
  Stabilize `os-symlink` (`PTH211`) (#20229)
  ...
@dcreager dcreager merged commit 2ac4147 into main Sep 10, 2025
38 checks passed
@dcreager dcreager deleted the dcreager/constraint-mdtest branch September 10, 2025 17:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants