Skip to content

[ty] Fix negation upper bounds in constraint sets#21897

Merged
dcreager merged 3 commits intomainfrom
dcreager/fix-intersection-bug
Dec 10, 2025
Merged

[ty] Fix negation upper bounds in constraint sets#21897
dcreager merged 3 commits intomainfrom
dcreager/fix-intersection-bug

Conversation

@dcreager
Copy link
Member

This fixes the logic error that @sharkdp found in the constraint set upper bound normalization logic I introduced in #21871.

I had originally claimed that (T ≤ α & ~β) should simplify into (T ≤ α) ∧ ¬(T ≤ β). But that also suggests that T ≤ ~β should simplify to ¬(T ≤ β) on its own, and that's not correct.

The correct simplification is that is an "atomic" type, not an "intersection" for the purposes of our upper bound simplifcation. So (T ≤ α & ~β) should simplify to (T ≤ α) ∧ (T ≤ ~β). That is, break apart the elements of a (proper) intersection, regardless of whether each element is negated or not.

This PR fixes the logic, adds a test case, and updates the comments to be hopefully more clear and accurate.

@dcreager dcreager added the internal An internal refactor or improvement label Dec 10, 2025
@dcreager dcreager added the ty Multi-file analysis & type inference label Dec 10, 2025
@astral-sh-bot
Copy link

astral-sh-bot bot commented Dec 10, 2025

Diagnostic diff on typing conformance tests

No changes detected when running ty on typing conformance tests ✅

@astral-sh-bot
Copy link

astral-sh-bot bot commented Dec 10, 2025

mypy_primer results

Changes were detected when running on open source projects
pandas-stubs (https://github.com/pandas-dev/pandas-stubs)
+ pandas-stubs/_typing.pyi:1217:16: warning[unused-ignore-comment] Unused blanket `type: ignore` directive
- Found 5258 diagnostics
+ Found 5259 diagnostics

No memory usage changes detected ✅

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!

Comment on lines +214 to +216
negated_type = ConstraintSet.range(Never, T, Not[int])
negated_constraint = ~ConstraintSet.range(Never, T, int)
static_assert(negated_type != negated_constraint)
Copy link
Contributor

Choose a reason for hiding this comment

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

This DSL is so cool

result = result.and(
db,
ConstrainedTypeVar::new_node(db, typevar, lower, upper_element).negate(db),
ConstrainedTypeVar::new_node(db, typevar, lower, upper_element.negate(db)),
Copy link
Contributor

Choose a reason for hiding this comment

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

So subtle 😃

@dcreager dcreager merged commit 3e00221 into main Dec 10, 2025
43 checks passed
@dcreager dcreager deleted the dcreager/fix-intersection-bug branch December 10, 2025 20:07
dcreager added a commit that referenced this pull request Dec 10, 2025
…-cycle

* origin/main:
  [ty] Support implicit type of `cls` in signatures (#21771)
  [ty] add `SyntheticTypedDictType` and implement `normalized` and `is_equivalent_to` (#21784)
  [ty] Fix disjointness checks with type-of `@final` classes (#21770)
  [ty] Fix negation upper bounds in constraint sets (#21897)
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.

2 participants