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

Type is not being narrowed properly in match statement #17549

Open
bergkvist opened this issue Jul 20, 2024 · 2 comments · May be fixed by #17600
Open

Type is not being narrowed properly in match statement #17549

bergkvist opened this issue Jul 20, 2024 · 2 comments · May be fixed by #17600
Labels
bug mypy got something wrong good-second-issue topic-match-statement Python 3.10's match statement

Comments

@bergkvist
Copy link

Bug Report

When using if-statements, the type is being properly narrowed depending on the conditions checked. mypy seems unable to do the same type of narrowing in a match statement

To Reproduce
https://mypy-play.net/?mypy=latest&python=3.12&gist=eb4da8b4996d740af15df17b231e0527

from typing import Literal, TypeAlias

Expr: TypeAlias = (
    tuple[Literal['lit'], int] |
    tuple[Literal['var'], str]
)

def square_lits(expr: Expr) -> Expr:
    match expr:
        case ('lit', x):
            return ('lit', square(x))
        case _:
            return expr

def square(x: int) -> int:
    return x * x

Here I get an error:

test.py:11: error: Argument 1 to "square" has incompatible type "int | str"; expected "int"  [arg-type]
Found 1 error in 1 file (checked 1 source file)

While the following works fine:
https://mypy-play.net/?mypy=latest&python=3.12&gist=ab7f28a259a5bff450413ce2f2924e74

from typing import Literal, TypeAlias

Expr: TypeAlias = (
    tuple[Literal['lit'], int] |
    tuple[Literal['var'], str]
)

def square_lits(expr: Expr) -> Expr:
    if expr[0] == 'lit':
        return ('lit', square(expr[1]))
    return expr

def square(x: int) -> int:
    return x * x

Expected Behavior

Both examples should work fine without any typechecking errors

Actual Behavior

Mypy is not able to narrow the type in the match statement case like it is able to when using if-conditions

Your Environment

The mypy playground links (mypy version 1.11.0, Python version 3.12).

Related:

@bergkvist bergkvist added the bug mypy got something wrong label Jul 20, 2024
@hauntsaninja hauntsaninja added topic-match-statement Python 3.10's match statement good-second-issue labels Jul 20, 2024
@bergkvist
Copy link
Author

This seems to be where the if statement types are narrowed into tuple[Literal['lit'], int] and tuple[Literal['var'], str]:

if_map, else_map = self.find_isinstance_check(e)

@bergkvist bergkvist linked a pull request Jul 27, 2024 that will close this issue
@Prabhat-Thapa45
Copy link

Nice finding. match being a relatively new feature, i.e., in 3.10 Python, might be one reason for mypy to fail or not being mature enough to handle this. Also, it can be relatively complex to handle this, although you have come up with a very straightforward example above but I can imagine it should be quite a task to achieve

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong good-second-issue topic-match-statement Python 3.10's match statement
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants