fix(match): enum literal narrowing is order-sensitive in match statements#21196
Open
Bahtya wants to merge 1 commit intopython:masterfrom
Open
fix(match): enum literal narrowing is order-sensitive in match statements#21196Bahtya wants to merge 1 commit intopython:masterfrom
Bahtya wants to merge 1 commit intopython:masterfrom
Conversation
When matching a union containing Literal[SomeEnum.VALUE] and other types, the order of match cases affected type narrowing results. Matching the enum literal first (before other types) failed to narrow the subject type, causing false positives with assert_never. Root cause: visit_value_pattern used narrow_type_by_identity_equality with '==' semantics, which has an overly-conservative enum ambiguity check for StrEnum/IntEnum (since they can compare equal to str/int). In match statements, this check is unnecessary when the other union members are unrelated types. Fix: For enum literal values without custom __eq__, bypass the identity equality narrowing and use conditional_types_with_intersection directly, which correctly narrows based on the literal value regardless of enum base type ambiguity. Fixes python#21187 Signed-off-by: bahtya <bahtyar153@qq.com>
Contributor
|
According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅ |
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Fix for #21187
Problem
When matching a union containing
Literal[SomeEnum.VALUE]and other types (e.g.,DummyClass), the order ofmatchcases affected type narrowing results:case DummyClass(): ... case MyEnum.RELEVANT:→ ✅ works correctlycase MyEnum.RELEVANT: ... case DummyClass():→ ❌ false positive onassert_neverThis is a regression from mypy 1.19 to 1.20.
Root Cause
visit_value_patternincheckpattern.pyusesnarrow_type_by_identity_equalitywith"=="semantics. This function has a conservative enum ambiguity check that skips narrowing forStrEnum/IntEnumtypes because they can compare equal tostr/intvalues. While this is correct for general equality comparisons (if x == MyEnum.RELEVANT:), it is overly conservative in match statements where the other union members (likeDummyClass) are unrelated types.Solution
For enum literal values without custom
__eq__, bypassnarrow_type_by_identity_equalityand useconditional_types_with_intersectiondirectly (same approach used byvisit_singleton_pattern). This correctly narrows based on the literal value regardless of the enum's base type ambiguity withstr/int.Enums with custom
__eq__are excluded to preserve the existing narrowing behavior (where the type stays as the full enum type, not narrowed to a specific literal).Testing
StrEnumandIntEnumtestMatchLiteralPatternEnumCustomEquals(custom__eq__still respected)Fixes #21187