Skip to content

Conversation

@dcreager
Copy link
Member

@dcreager dcreager commented Nov 5, 2025

When checking whether a constraint set is satisfied, if a typevar has a non-fully-static upper bound or constraint, we are free to choose any materialization that makes the check succeed.

In non-inferable positions, we have to show that the constraint set is satisfied for all valid specializations, so it's best to choose the most restrictive materialization, since that minimizes the set of valid specializations that have to pass.

In inferable positions, we only have to show that the constraint set is satisfied for some valid specializations, so it's best to choose the most permissive materialization, since that maximizes our chances of finding a specialization that passes.

@dcreager dcreager added internal An internal refactor or improvement ty Multi-file analysis & type inference labels Nov 5, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Nov 5, 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 Nov 5, 2025

mypy_primer results

No ecosystem changes detected ✅
No memory usage changes detected ✅

Comment on lines 147 to 148
must satisfy the constraint set. (That means we will almost always choose `Never` — or more
precisely, the bottom specialization — as the upper bound.) In inferable positions, the opposite is
Copy link
Member

Choose a reason for hiding this comment

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

I think that only holds true if the upper bound of a typevar is a gradual specialization of an invariant type? The bottom materialization of list[Any] is Never, but the bottom materialization of Sequence[Any] is Sequence[Never], since Sequence[Never] is a subtype of Sequence[int] and Sequence[str], and is still an inhabited type ([], () can both inhabit Sequence[Never], for example). Similarly for contravariance, the bottom materialization of Callable[[Any], int] is Callable[[object], int].

Copy link
Member Author

Choose a reason for hiding this comment

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

Which part doesn't hold true? This might be poor wording on my part — I am not trying to claim that the bottom materialization is always Never. I am (attempting to) say that for T: Any, we pick T: Never, but it's more precise to say that we pick the bottom specialization, because for T: list[Any], we pick T: Bottom[list[Any]].

Copy link
Contributor

Choose a reason for hiding this comment

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

might be poor wording on my part

I think I understood it the way you explained in your comment now, but I also stumbled over it.

Copy link
Member

Choose a reason for hiding this comment

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

This might be poor wording on my part — I am not trying to claim that the bottom materialization is always Never.

Ah, okay -- yes, I think the wording can be improved there a little!

Copy link
Member Author

Choose a reason for hiding this comment

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

Reworded this, lmkwyt

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.

4 participants