-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
fix: Narrowing with "tags" on unions (of TypedDicts or normal classes) doesn't work with the match statement #18791
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
Conversation
…) doesn't work with the match statement Signed-off-by: Gene Parmesan Thomas <[email protected]>
This comment has been minimized.
This comment has been minimized.
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.
This looks good, just had two minor comments
CHANGELOG.md
Outdated
@@ -45,6 +45,14 @@ class A: | |||
|
|||
Contributed by Marc Mueller (PR [18641](https://github.com/python/mypy/pull/18641)) | |||
|
|||
### Other Notable Fixes and Improvements |
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.
we typically will do changelog entries later, can you remove this?
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.
Removed the changelog entry for now; will add it later alongside other notes.
mypy/checker.py
Outdated
@@ -5527,6 +5527,14 @@ def visit_match_stmt(self, s: MatchStmt) -> None: | |||
pattern_map, else_map = conditional_types_to_typemaps( | |||
named_subject, pattern_type.type, pattern_type.rest_type | |||
) | |||
# Also refine the parent expression of the subject. |
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.
thanks for docs, but i think this is fairly clear from the propagate_up_typemap_info docstring, so could you remove the comment?
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.
Dropped the extra comment here since the helper’s docstring is enough
Signed-off-by: gopoto <[email protected]>
According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅ |
Summary
Addressed issue #16286, which reported that
match
statements failed to narrow unions when matching on discriminant values (e.g.tag
fields inTypedDict
s or classes). This led to mypy complaining about missing keys/attributes insidecase
blocks even though plainif ... ==
branches worked.What changed?
mypy/checker.py
:visit_match_stmt
, after callingconditional_types_to_typemaps
for the subject, the resulting type map is passed throughpropagate_up_typemap_info
(just like in theif
/isinstance
code paths). This means if the subject is an attribute or index expression (d.tag
/d["tag"]
), we try to refine the parentd
based on the pattern.pattern_map
when it's defined, to avoidUnboundLocalError
in unreachable branches.test-data/unit/check-python310.test
:testMatchNarrowingUnionTypedDictViaIndex
checks thatmatch d["tag"]
refines aTypedDict
union and allows access to the appropriate key in each branch.testMatchNarrowingUnionClassViaAttribute
checks the same for a class union usingmatch d.tag
.Why?
Previously, the binder only narrowed the type of the expression being matched (e.g.
d["tag"]
), not the parent expression. Without propagating that information upwards, mypy didn't realize it could rule out unrelatedTypedDict
/class variants in eachcase
, leading to erroneoustypeddict-item
andunion-attr
errors. The fix mirrors the existing behaviour forif
and similar checks.How was it tested?
pytest -k testMatchNarrowingUnionTypedDictViaIndex
andpytest -k testMatchNarrowingUnionClassViaAttribute
to confirm the new tests passed.pytest -k check-python310
to ensure the entire pattern-matching suite still passes after the change.python runtests.py self
).pre-commit run --all-files
to satisfy formatting and lint hooks.Checklist
CHANGELOG.md
.Fixes #16286.
This PR was generated by an AI system in collaboration with maintainers: @hauntsaninja