-
Notifications
You must be signed in to change notification settings - Fork 1.6k
[ty] Promote literals in invariant return position #21320
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Diagnostic diff on typing conformance testsChanges were detected when running ty on typing conformance tests--- old-output.txt 2025-11-10 23:05:16.349873661 +0000
+++ new-output.txt 2025-11-10 23:05:19.738890404 +0000
@@ -688,6 +688,8 @@
literals_interactions.py:60:49: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Matrix[A@Matrix, B@Matrix]`
literals_interactions.py:63:52: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Matrix[A@Matrix, C@__matmul__]`
literals_interactions.py:66:28: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Matrix[B@Matrix, A@Matrix]`
+literals_interactions.py:71:9: error[unsupported-operator] Operator `@` is unsupported between objects of type `Matrix[Literal[2], Literal[3]]` and `Matrix[Literal[3], Literal[7]]`
+literals_interactions.py:72:5: error[type-assertion-failure] Argument does not have asserted type `Matrix[Literal[2], Literal[7]]`
literals_interactions.py:106:35: error[invalid-argument-type] Argument to function `expects_bad_status` is incorrect: Expected `Literal["MALFORMED", "ABORTED"]`, found `str`
literals_interactions.py:109:32: error[invalid-argument-type] Argument to function `expects_pending_status` is incorrect: Expected `Literal["PENDING"]`, found `str`
literals_literalstring.py:23:51: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `LiteralString`
@@ -1007,5 +1009,5 @@
typeddicts_usage.py:28:17: error[missing-typed-dict-key] Missing required key 'name' in TypedDict `Movie` constructor
typeddicts_usage.py:28:18: error[invalid-key] Invalid key for TypedDict `Movie`: Unknown key "title"
typeddicts_usage.py:40:24: error[invalid-type-form] The special form `typing.TypedDict` is not allowed in type expressions. Did you mean to use a concrete TypedDict or `collections.abc.Mapping[str, object]` instead?
-Found 1009 diagnostics
+Found 1011 diagnostics
WARN A fatal error occurred while checking some files. Not all project files were analyzed. See the diagnostics list above for details.
|
0888d4b to
0f07e50
Compare
|
|
The primer report looks excellent but it looks like there's a new type-assertion failure in the conformance test suite -- have you checked out if that's expected? |
Note that both the primer and the conformance checks here include changes from the previous PRs on which this is stacked. We compare against main. |
crates/ty_python_semantic/resources/mdtest/generics/pep695/classes.md
Outdated
Show resolved
Hide resolved
crates/ty_python_semantic/resources/mdtest/generics/pep695/classes.md
Outdated
Show resolved
Hide resolved
| reveal_type(frozenset((1, 2, 3))) # revealed: frozenset[Literal[1, 2, 3]] | ||
| reveal_type(frozenset(((1, 2, 3),))) # revealed: frozenset[tuple[Literal[1], Literal[2], Literal[3]]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wonderful!
| let promote_literals = |typevar: GenericContextTypeVar<'db>, ty: Type<'db>| -> Type<'db> { | ||
| let bound_typevar = typevar.bound_typevar(); | ||
|
|
||
| if typevar.is_inherited() && bound_typevar.variance(self.db).is_invariant() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does is_inherited mean here? Why does it matter whether a typevar is inherited or not?
(It would be great if is_inherited could have a doc-comment explaining what it does 😃)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I think I see -- you're using the term to mean that the typevar is associated with a class's generic context rather than the generic context of a function or method? So it doesn't have any thing to do with the generic context of a class's base classes etc.?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's right, though I didn't invent that terminology.
Ideally we wouldn't need to special case inherited type variables, but we don't currently have a robust way to get access to the bound type of a constructor method (the synthesized_constructor_return_ty).
37ac0b5 to
25ed082
Compare
0f07e50 to
47cdf49
Compare
4d88df9 to
4da67a1
Compare
|
Hmm this is more tricky than I realized. We can only perform the literal promotion of a given type variable if it does not lead to argument assignability errors. We may need to resort to a simple heuristic of "promote every type variable in invariant position", and fallback to not performing any promotion if type-checking fails, as I suspect attempting partial promotion would be too expensive. |
|
Superseded by #21439. |
Summary
We currently unconditionally promote literals in generic class constructors. We should do this for any literal in an invariant position in the return type. Resolves astral-sh/ty#1357.
This PR is stacked on #20933.