As Eric suggests, there should be nothing special about `LiteralString`. The PEP doesn't say it so clearly, but I think it's just the case that every `Literal[expr]` type where expr has type `str` is a subtype of `LiteralString`, and `LiteralString` is a subtype of `str`. Everything else is a consequence. The issue with the list literals is a general issue with collection literals, not about LiteralString specifically. A list literal where the elements all have type T can actually have type `list[S]` for all types `S` s.t. T is a consistent subtype of S. So `['foo', 'bar']` can have type `list[Literal['foo'] | Literal['bar']]` and also `list[LiteralString]` and `list[str]` and `list[str | bytes]` and `list[Iterable[Any]]` and `list[object]`, etc. That is, ['foo', 'bar'] might be a list of objects that just happens to currently contain only strings. But once you determine a type for that value, it cannot change. If you determine it's a list[object] then someone might put an int or something in it and you can't later say that it's actually a list of literal strings. And if you determine that it's a list[LiteralString] then that necessarily prevents it being used as a list[object]. Eric mentions bidirectional type inference, and that's something that you could try. If you do it for literals as you suggest, it will be "easy". If you do it for variables like `xs = ['foo']; ... xs ...` then you will have to find some way to consider all the contexts that `xs` occurs in. Another idea that seems similar to bidirectional inference (I think) is to treat the type of ['foo', 'bar'] as involving an unknown type that is bounded by a subtype: list[Unknown > Literal['foo'] | Literal['bar']]. Then when you generate consistent subtype constraints for your example of couple(['foo'], [s]) you would have constraints: list[Unknown > Literal['foo']] < T list[str] < T And because `list` is invariant then you have a consistency ("equality) constraint that (Unknown > Literal['foo']) = str which you can solve by str. On Sat, Jun 17, 2023 at 5:47 PM Eric Traut <eric@traut.com> wrote:
Hi Mikhail. I presume that PyCharm already has support for Literal, which was introduced in PEP 586. You can think of LiteralString as "the union of all possible literal strings". Unlike bool and enum literals, you can't feasibly enumerate all possible string literals, so this is conceptual rather than real. It's still a useful concept from the perspective of type checking because you can treat LiteralString just like any other union of string literals. To answer all of your questions above, you can just ask yourself "how do we handle Literal['a', 'b'] in this situation?". The answer should be the same for LiteralString.
In pyright, the default inference rules for list expressions always widen literals to their non-literal counterparts. To use your example `xs = ['foo', 'bar']`, pyright infers the type of `xs` as `list[str]`. For more details, refer to https://microsoft.github.io/pyright/#/type-inference?id=literals. Mypy likewise infers `list[str]` in this case.
These default inference rules can be overridden through the use of bidirectional type inference (also referred to as an "expected type" or a "type context"). For example, `xs: list[LiteralString] = ['foo', 'bar']` overrides the default type inference rules for list expressions. For more details, refer to https://microsoft.github.io/pyright/#/type-inference?id=bidirectional-type-i... .
You also asked about constraint solving for type variables. Pyright's constraint solver does not produce literals unless they are required to meet the constraints. Normally, the solved type is widened to its non-literal counterpart. For example, if you have a function `def func(a: T) -> T: ...`, the expression `func('hi')` evaluates to type `str`, not `Literal['hi']` or `LiteralString`. However, if an additional constraint is present that requires a literal type solution, it will oblige. For example, `x: LiteralString = func("hi")` is fine, and so is `x: Literal['hi', 'bye'] = func("hi")`. Obviously, `x: Literal['bye'] = func("hi")` will produce an error.
I'll note that mypy and pyright differ somewhat when it comes to the handling of literals in their constraint solvers. You can read about those differences here: https://microsoft.github.io/pyright/#/mypy-comparison?id=constraint-solver-l... .
Apologies if that was more detail than you were looking for.
My basic advice for LiteralString is to simply treat it the same as you would any union of Literal strings.
--
Eric Traut Author of pyright _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ Member address: kmillikin@google.com