[ty] Promote literals in invariant return position#21320
[ty] Promote literals in invariant return position#21320ibraheemdev wants to merge 3 commits intomainfrom
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]]] |
| 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.
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.
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.
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.