mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-26 18:06:43 +00:00
[ty] Expansion of enums into unions of literals (#19382)
## Summary
Implement expansion of enums into unions of enum literals (and the
reverse operation). For the enum below, this allows us to understand
that `Color = Literal[Color.RED, Color.GREEN, Color.BLUE]`, or that
`Color & ~Literal[Color.RED] = Literal[Color.GREEN, Color.BLUE]`. This
helps in exhaustiveness checking, which is why we see some removed
`assert_never` false positives. And since exhaustiveness checking also
helps with understanding terminal control flow, we also see a few
removed `invalid-return-type` and `possibly-unresolved-reference` false
positives. This PR also adds expansion of enums in overload resolution
and type narrowing constructs.
```py
from enum import Enum
from typing_extensions import Literal, assert_never
from ty_extensions import Intersection, Not, static_assert, is_equivalent_to
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
type Red = Literal[Color.RED]
type Green = Literal[Color.GREEN]
type Blue = Literal[Color.BLUE]
static_assert(is_equivalent_to(Red | Green | Blue, Color))
static_assert(is_equivalent_to(Intersection[Color, Not[Red]], Green | Blue))
def color_name(color: Color) -> str: # no error here (we detect that this can not implicitly return None)
if color is Color.RED:
return "Red"
elif color is Color.GREEN:
return "Green"
elif color is Color.BLUE:
return "Blue"
else:
assert_never(color) # no error here
```
## Performance
I avoided an initial regression here for large enums, but the
`UnionBuilder` and `IntersectionBuilder` parts can certainly still be
optimized. We might want to use the same technique that we also use for
unions of other literals. I didn't see any problems in our benchmarks so
far, so this is not included yet.
## Test Plan
Many new Markdown tests
This commit is contained in:
parent
926e83323a
commit
dc66019fbc
19 changed files with 750 additions and 102 deletions
|
|
@ -2355,12 +2355,13 @@ import enum
|
|||
|
||||
reveal_type(enum.Enum.__members__) # revealed: MappingProxyType[str, Unknown]
|
||||
|
||||
class Foo(enum.Enum):
|
||||
BAR = 1
|
||||
class Answer(enum.Enum):
|
||||
NO = 0
|
||||
YES = 1
|
||||
|
||||
reveal_type(Foo.BAR) # revealed: Literal[Foo.BAR]
|
||||
reveal_type(Foo.BAR.value) # revealed: Any
|
||||
reveal_type(Foo.__members__) # revealed: MappingProxyType[str, Unknown]
|
||||
reveal_type(Answer.NO) # revealed: Literal[Answer.NO]
|
||||
reveal_type(Answer.NO.value) # revealed: Any
|
||||
reveal_type(Answer.__members__) # revealed: MappingProxyType[str, Unknown]
|
||||
```
|
||||
|
||||
## References
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue