-
Notifications
You must be signed in to change notification settings - Fork 2.2k
[ty] Avoid expanding same-enum comparisons #26270
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
8d25d32
[ty] Avoid expanding same-enum comparisons
charliermarsh 2b2a49f
[ty] Document compact enum comparison invariants
charliermarsh 631a560
[ty] Preserve enum literal promotability in membership narrowing
charliermarsh 7536ea8
[ty] Normalize enum comparison keys
charliermarsh 61ff8b3
[ty] Account for scalar enum value coercion
charliermarsh a5dce49
[ty] Trim enum comparison benchmarks
charliermarsh aa872fd
[ty] Recognize enum aliases across literal metadata
charliermarsh 9ec5ad6
[ty] Simplify enum comparison regression tests
charliermarsh 4cac827
[ty] Simplify narrowed enum benchmark name
charliermarsh e88a854
[ty] Clarify same-enum comparison terminology
charliermarsh File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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 hidden or 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 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -122,6 +122,119 @@ def enum_complement_rhs(x: Color, y: Intersection[Color, Not[Literal[Color.RED]] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reveal_type(x) # revealed: Literal[Color.GREEN, Color.BLUE] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| When both operands are restricted to members of the same enum, equality narrows each operand to the | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| members allowed by both. If the restrictions do not overlap, the comparison is always false: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```py | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from enum import Enum, IntEnum, StrEnum | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from typing import Literal | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class Choice(StrEnum): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FIRST = "first" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SECOND = "second" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| THIRD = "third" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FOURTH = "fourth" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def compare_after_truthiness_check(left: Choice, right: Choice): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if right and left != right: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reveal_type(right) # revealed: Choice & ~AlwaysFalsy | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reveal_type(right) # revealed: Choice | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def compare_with_narrowed_right(left: Choice, right: Choice): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if right == Choice.FIRST: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if left == right: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reveal_type(left) # revealed: Literal[Choice.SECOND, Choice.THIRD, Choice.FOURTH] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def compare_non_overlapping_narrowed_values(left: Choice, right: Choice): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if left == Choice.FIRST or left == Choice.SECOND: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if right == Choice.THIRD or right == Choice.FOURTH: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reveal_type(left == right) # revealed: Literal[False] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def compare_literal_unions( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| left: Literal[Choice.FIRST, Choice.SECOND], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| right: Literal[Choice.SECOND, Choice.THIRD], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if left == right: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reveal_type(left) # revealed: Literal[Choice.SECOND] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cool that ty can do this |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reveal_type(right) # revealed: Literal[Choice.SECOND] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def compare_non_overlapping_literal_unions( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| left: Literal[Choice.FIRST, Choice.SECOND], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| right: Literal[Choice.THIRD, Choice.FOURTH], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reveal_type(left == right) # revealed: Literal[False] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Members with the same known value are aliases, even when one value comes from a function call. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comparisons between their canonical members are always true: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```py | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def make_value() -> Literal["value"]: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "value" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class RuntimeAlias(StrEnum): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FIRST = make_value() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SECOND = "value" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reveal_type(RuntimeAlias.FIRST == RuntimeAlias.SECOND) # revealed: Literal[True] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def make_int_value() -> Literal[1]: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class RuntimeIntAlias(IntEnum): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FIRST = make_int_value() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SECOND = 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reveal_type(RuntimeIntAlias.FIRST == RuntimeIntAlias.SECOND) # revealed: Literal[True] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| A scalar mixin can normalize member values before `Enum` checks for aliases. Here, `str` converts | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `1` to `"1"`, so the two members are aliases at runtime. Since ty does not model this constructor | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| call, the comparison remains `bool`: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```py | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class CoercingAlias(str, Enum): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FIRST = 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SECOND = "1" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reveal_type(CoercingAlias.FIRST == CoercingAlias.SECOND) # revealed: bool | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Equality can transfer restrictions on enum members, but other intersection elements must stay on the | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| operand where they originated: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```py | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from enum import StrEnum | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from typing import Any, Literal, NewType | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from ty_extensions import Intersection | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class Response(StrEnum): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ACCEPT = "accept" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| REJECT = "reject" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Tag = NewType("Tag", str) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def compare_any( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| left: Response, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| right: Intersection[Literal[Response.REJECT], Any], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if left != right: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reveal_type(left) # revealed: Literal[Response.REJECT] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reveal_type(right) # revealed: Literal[Response.REJECT] & Any | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def compare_newtype(left: Response, right: Intersection[Response, Tag]): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if left != right: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reveal_type(left) # revealed: Response | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `Flag` and `IntFlag` values can include zero and unnamed combinations, so their named members do not | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cover every possible value: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -167,23 +280,18 @@ even when only one member is declared: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```py | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from enum import Enum | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class OpenEnum(Enum): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class MissingValueEnum(Enum): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ONLY = 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @classmethod | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def _missing_(cls, value: object) -> "OpenEnum": | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def _missing_(cls, value: object) -> "MissingValueEnum": | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return object.__new__(cls) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def compare_open_enums(left: OpenEnum, right: OpenEnum): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def compare_open_enums(left: MissingValueEnum, right: MissingValueEnum): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reveal_type(left == right) # revealed: bool | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if left != right: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reveal_type(left) # revealed: OpenEnum | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def exclude_declared_member(value: OpenEnum): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if value is OpenEnum.ONLY: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reveal_type(value) # revealed: OpenEnum & ~Literal[OpenEnum.ONLY] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reveal_type(left) # revealed: MissingValueEnum | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| A custom enum metaclass can add members that do not appear in the class body. Two values of a | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -204,6 +312,48 @@ def compare_transformed_enums(left: TransformedEnum, right: TransformedEnum): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reveal_type(left == right) # revealed: bool | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| A custom comparison method determines the result even when both operands have the same enum type: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```py | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from enum import Enum | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from typing import Literal | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class NeverEqual(Enum): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FIRST = 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SECOND = 2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| THIRD = 3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def __eq__(self, other: object) -> Literal[False]: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def compare_custom(left: NeverEqual, right: NeverEqual): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reveal_type(left == right) # revealed: Literal[False] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if left is NeverEqual.FIRST: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reveal_type(left == right) # revealed: Literal[False] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+332
to
+334
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could expand this test case:
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| When member values are not known statically, two different members may still compare equal: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```py | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from enum import StrEnum | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from typing import Literal | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def runtime_value(value: str) -> str: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return value | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class UnknownValues(StrEnum): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FIRST = runtime_value("first") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SECOND = runtime_value("second") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def compare_unknown_values( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| left: Literal[UnknownValues.FIRST], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| right: Literal[UnknownValues.SECOND], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reveal_type(left == right) # revealed: bool | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Unlike plain `Enum` members, `IntEnum` members inherit integer equality. Members of different | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `IntEnum` classes therefore compare equal when they have the same integer value, so both equality | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| and inequality narrowing must account for matching members from every class in the union: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
This file contains hidden or 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
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe unrelated, but ideally we should simplify out the AlwaysFalsy here. Choice has no instances that are falsy and ty should be able to figure that out.