Skip to content
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

Narrow individual items when matching a tuple to a sequence pattern #16905

Merged

Conversation

loic-simon
Copy link
Contributor

Fixes #12364

When matching a tuple to a sequence pattern, this change narrows the type of tuple items inside the matched case:

def test(a: bool, b: bool) -> None:
    match a, b:
        case True, True:
            reveal_type(a)  # before: "builtins.bool", after: "Literal[True]"

This also works with nested tuples, recursively:

def test(a: bool, b: bool, c: bool) -> None:
    match a, (b, c):
        case _, [True, False]:
            reveal_type(c)  # before: "builtins.bool", after: "Literal[False]"

This only partially fixes issue #12364; see my comment there for more context.


This is my first contribution to mypy, so I may miss some context or conventions; I'm eager for any feedback!

This comment has been minimized.

typ_ = get_proper_type(typ)
if isinstance(expr, TupleExpr) and isinstance(typ_, TupleType):
# When matching a tuple expression with a sequence pattern, narrow individual tuple items
assert len(expr.items) == len(typ_.items)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add some test cases where the length doesn't match, to make sure we don't fail this assertion? Especially in nested tuples.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! I did not check anything in non-matching cases, just that the assertion didn't fail, eg.

match m, n, o:
    case [3, "foo"]:
        pass
    case [3, "foo", True, True]:
        pass

Interestingly, these paths are not considered unreachable by mypy. They probably should, but that's unrelated to this issue!

Copy link
Contributor

github-actions bot commented Apr 2, 2024

According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅

@JelleZijlstra JelleZijlstra merged commit 8019010 into python:master Apr 4, 2024
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

mypy unable to narrow type of tuple elements in case clause in pattern matching
2 participants