Skip to content

Type is not being narrowed properly in match statement #17549

Open
@bergkvist

Description

@bergkvist

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:

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions