Skip to content

Improve match statement union narrowing/inference #17600

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

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

bergkvist
Copy link

@bergkvist bergkvist commented Jul 27, 2024

Improve inference/narrowing support for union types in match statements.

Fixes #17549

Before:

var: tuple[int, int] | tuple[str, str]

# TODO: we can infer better here.
match var:
    case (42, a):
        reveal_type(a)  # N: Revealed type is "Union[builtins.int, builtins.str]"
    case ("yes", b):
        reveal_type(b)  # N: Revealed type is "Union[builtins.int, builtins.str]"

After:

var: tuple[int, int] | tuple[str, str]

match var:
    case (42, a):
        reveal_type(a)  # N: Revealed type is "builtins.int"
    case ("yes", b):
        reveal_type(b)  # N: Revealed type is "builtins.str"

Related:

This comment has been minimized.

Copy link
Contributor

@Hnasar Hnasar left a comment

Choose a reason for hiding this comment

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

Nice!
Does your fix address any of the other match statement issues?
https://github.com/python/mypy/issues?q=sort%3Aupdated-desc+is%3Aopen+label%3Atopic-match-statement

This comment has been minimized.

@bergkvist
Copy link
Author

Nice! Does your fix address any of the other match statement issues? https://github.com/python/mypy/issues?q=sort%3Aupdated-desc+is%3Aopen+label%3Atopic-match-statement

From reading through the issues, I believe it should at least solve these:

I notice there are a bunch of match exhaustiveness issues with narrowing of the type passed on to the next match branches, which this PR does not fix.

This comment has been minimized.

@hjwp
Copy link

hjwp commented Aug 21, 2024

maybe it would address this too? #16835

@bergkvist
Copy link
Author

maybe it would address this too? #16835

I don't think so, as I return the "current type" as the "rest type", which means the remainder/rest type (which is what gets passed on to the next match case) doesn't get narrowed properly yet. I have yet to figure out how to do this.

This comment has been minimized.

Copy link
Contributor

github-actions bot commented Sep 2, 2024

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

@smurzin
Copy link

smurzin commented Jan 22, 2025

Hi @bergkvist @Hnasar are there any blockers for landing this PR?
even though it might not address all match narrowing issues it moves it towards a better place.

@lordmauve
Copy link

lordmauve commented Apr 8, 2025

I don't think this is solving the issue in my use case involving TypedDicts:

$ uvx --from 'mypy @ git+https://github.com/bergkvist/mypy@tobias/match-union-narrowing' mypy
    Updated https://github.com/bergkvist/mypy (92d3c91aaf2757706f9ef923650eb342d19af2fb)
      Built mypy @ git+https://github.com/bergkvist/mypy@92d3c91aaf2757706f9ef923650eb342d19af2fb
Installed 3 packages in 17ms
src/pack.py:150: error: "object" has no attribute "encode"  [attr-defined]
src/pack.py:151: error: "object" has no attribute "encode"  [attr-defined]

I have:

match node:
    case {"type": ("assign" | "cond_assign") as op, "key": key, "value": value}:
        kbs = key.encode()
        vbs = value.encode()
        ...

where reveal_type(node) shows

src/pack.py:148: note: Revealed type is "Union[TypedDict('propsast.AssignmentOperation', {'type': Union[Literal['assign'], Literal['cond_assign']], 'key': builtins.str, 'value': builtins.str, 'lineno': builtins.int}), TypedDict('propsast.IncludeOperation', {'type': Union[Literal['include'], Literal['tryinclude']], 'filename': builtins.str, 'lineno': builtins.int})]"

I tried removing the disjunction in the case statement and having a case branch for each literal value but that didn't help.

@Hnasar
Copy link
Contributor

Hnasar commented Apr 9, 2025

@bergkvist Sorry for the late reply, but can you rebase this on the latest mypy, then we can ping one of the real maintainers to get someone with commit privileges to take a look.

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.

Type is not being narrowed properly in match statement
5 participants