-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[red-knot] Deeper understanding of
LiteralString
(#14649)
## Summary Resolves #14648. ## Test Plan Markdown tests. --------- Co-authored-by: Carl Meyer <[email protected]>
- Loading branch information
1 parent
3e702e1
commit 246a6df
Showing
5 changed files
with
159 additions
and
1 deletion.
There are no files selected for viewing
128 changes: 128 additions & 0 deletions
128
crates/red_knot_python_semantic/resources/mdtest/annotations/literal_string.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
# `LiteralString` | ||
|
||
`LiteralString` represents a string that is either defined directly within the source code or is | ||
made up of such components. | ||
|
||
Parts of the testcases defined here were adapted from [the specification's examples][1]. | ||
|
||
## Usages | ||
|
||
### Valid places | ||
|
||
It can be used anywhere a type is accepted: | ||
|
||
```py | ||
from typing import LiteralString | ||
|
||
x: LiteralString | ||
|
||
def f(): | ||
reveal_type(x) # revealed: LiteralString | ||
``` | ||
|
||
### Within `Literal` | ||
|
||
`LiteralString` cannot be used within `Literal`: | ||
|
||
```py | ||
from typing import Literal, LiteralString | ||
|
||
bad_union: Literal["hello", LiteralString] # error: [invalid-literal-parameter] | ||
bad_nesting: Literal[LiteralString] # error: [invalid-literal-parameter] | ||
``` | ||
|
||
### Parametrized | ||
|
||
`LiteralString` cannot be parametrized. | ||
|
||
```py | ||
from typing import LiteralString | ||
|
||
a: LiteralString[str] # error: [invalid-type-parameter] | ||
b: LiteralString["foo"] # error: [invalid-type-parameter] | ||
``` | ||
|
||
### As a base class | ||
|
||
Subclassing `LiteralString` leads to a runtime error. | ||
|
||
```py | ||
from typing import LiteralString | ||
|
||
class C(LiteralString): ... # error: [invalid-base] | ||
``` | ||
|
||
## Inference | ||
|
||
### Common operations | ||
|
||
```py | ||
foo: LiteralString = "foo" | ||
reveal_type(foo) # revealed: Literal["foo"] | ||
|
||
bar: LiteralString = "bar" | ||
reveal_type(foo + bar) # revealed: Literal["foobar"] | ||
|
||
baz: LiteralString = "baz" | ||
baz += foo | ||
reveal_type(baz) # revealed: Literal["bazfoo"] | ||
|
||
qux = (foo, bar) | ||
reveal_type(qux) # revealed: tuple[Literal["foo"], Literal["bar"]] | ||
|
||
# TODO: Infer "LiteralString" | ||
reveal_type(foo.join(qux)) # revealed: @Todo(call todo) | ||
|
||
template: LiteralString = "{}, {}" | ||
reveal_type(template) # revealed: Literal["{}, {}"] | ||
# TODO: Infer `LiteralString` | ||
reveal_type(template.format(foo, bar)) # revealed: @Todo(call todo) | ||
``` | ||
|
||
### Assignability | ||
|
||
`Literal[""]` is assignable to `LiteralString`, and `LiteralString` is assignable to `str`, but not | ||
vice versa. | ||
|
||
```py | ||
def coinflip() -> bool: | ||
return True | ||
|
||
foo_1: Literal["foo"] = "foo" | ||
bar_1: LiteralString = foo_1 # fine | ||
|
||
foo_2 = "foo" if coinflip() else "bar" | ||
reveal_type(foo_2) # revealed: Literal["foo", "bar"] | ||
bar_2: LiteralString = foo_2 # fine | ||
|
||
foo_3: LiteralString = "foo" * 1_000_000_000 | ||
bar_3: str = foo_2 # fine | ||
|
||
baz_1: str = str() | ||
qux_1: LiteralString = baz_1 # error: [invalid-assignment] | ||
|
||
baz_2: LiteralString = "baz" * 1_000_000_000 | ||
qux_2: Literal["qux"] = baz_2 # error: [invalid-assignment] | ||
|
||
baz_3 = "foo" if coinflip() else 1 | ||
reveal_type(baz_3) # revealed: Literal["foo"] | Literal[1] | ||
qux_3: LiteralString = baz_3 # error: [invalid-assignment] | ||
``` | ||
|
||
### Narrowing | ||
|
||
```py | ||
lorem: LiteralString = "lorem" * 1_000_000_000 | ||
|
||
reveal_type(lorem) # revealed: LiteralString | ||
|
||
if lorem == "ipsum": | ||
reveal_type(lorem) # revealed: Literal["ipsum"] | ||
|
||
reveal_type(lorem) # revealed: LiteralString | ||
|
||
if "" < lorem == "ipsum": | ||
reveal_type(lorem) # revealed: Literal["ipsum"] | ||
``` | ||
|
||
[1]: https://typing.readthedocs.io/en/latest/spec/literal.html#literalstring |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters