Skip to content

Conversation

@dcreager
Copy link
Member

#21414 added the ability to create a specialization from a constraint set. It handled mutually constrained typevars just fine, e.g. given T ≤ int ∧ U = T we can infer T = int, U = int.

But it didn't handle nested constraints correctly, e.g. T ≤ int ∧ U = list[T]. Now we do! This requires doing a fixed-point "apply the specialization to itself" step to propagate the assignments of any nested typevars, and then a cycle detection check to make sure we don't have an infinite expansion in the specialization.

This gets at an interesting nuance in our constraint set structure that @sharkdp has asked about before. Constraint sets are BDDs, and each internal node represents an individual constraint, of the form lower ≤ T ≤ upper. lower and upper are allowed to be other typevars, but only if they appear "later" in the arbitary ordering that we establish over typevars. The main purpose of this is to avoid infinite expansion for mutually constrained typevars.

However, that restriction doesn't help us here, because only applies when lower and upper are typevars, not when they contain typevars. That distinction is important, since it means the restriction does not affect our expressiveness: we can always rewrite Never ≤ T ≤ U (a constraint on T) into T ≤ U ≤ object (a constraint on U). The same is not true of Never ≤ T ≤ list[U] — there is no "inverse" of list that we could apply to both sides to transform this into a constraint on a bare U.

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

astral-sh-bot bot commented Nov 19, 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 Nov 19, 2025

mypy_primer results

No ecosystem changes detected ✅

No memory usage changes detected ✅

if discovered.contains(outgoing) {
return true;
}
if !finished.contains(outgoing) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Could finished be eliminated in favor of removing keys from reachable_typevars when finished checking them?

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm, yes! Have to jump through some borrow checker hoops but nothing too bad

@dcreager dcreager merged commit 83134fb into main Nov 19, 2025
41 checks passed
@dcreager dcreager deleted the dcreager/specialize-cycles branch November 19, 2025 22:37
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