You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add support for narrowing Literals using equality (#8151)
This pull request (finally) adds support for narrowing expressions
using Literal types by equality, instead of just identity. For example,
the following "tagged union" pattern is now supported:
```python
class Foo(TypedDict):
key: Literal["A"]
blah: int
class Bar(TypedDict):
key: Literal["B"]
something: str
x: Union[Foo, Bar]
if x.key == "A":
reveal_type(x) # Revealed type is 'Foo'
else:
reveal_type(x) # Revealed type is 'Bar'
```
Previously, this was possible to do only with Enum Literals and the
`is` operator, which is perhaps not very intuitive.
The main limitation with this pull request is that it'll perform narrowing
only if either the LHS or RHS contains an explicit Literal type
somewhere. If this limitation is not present, we end up breaking a decent
amount of real-world code -- mostly tests -- that do something like this:
```python
def some_test_case() -> None:
worker = Worker()
# Without the limitation, we narrow 'worker.state' to
# Literal['ready'] in this assert...
assert worker.state == 'ready'
worker.start()
# ...which subsequently causes this second assert to narrow
# worker.state to <uninhabited>, causing the last line to be
# unreachable.
assert worker.state == 'running'
worker.query()
```
I tried for several weeks to find a more intelligent way around this
problem, but everything I tried ended up being either insufficient or
super-hacky, so I gave up and went for this brute-force solution.
The other main limitation is that we perform narrowing only if both the
LHS and RHS do not define custom `__eq__` or `__ne__` methods, but this
seems like a more reasonable one to me.
Resolves#7944.
0 commit comments