Skip to content

Unable to narrow the type of a tagged union when using a match statement #15190

Open
@jonathan-laurent

Description

@jonathan-laurent

Bug Report

Mypy is unable to narrow the type of a tagged union when deconstructing it using a match statement.

To Reproduce

from typing import Literal, TypeAlias


Expr: TypeAlias = (
    tuple[Literal["const"], int] | tuple[Literal["add"], tuple["Expr", "Expr"]]
)


# OK
def eval(e: Expr) -> int:
    if e[0] == "const":
        return e[1]
    else:
        e1, e2 = e[1]
        return eval(e1) + eval(e2)


# Rejected by mypy (see errors below)
def eval2(e: Expr) -> int:
    match e:
        case ("const", x):
            return x
        case ("add", (e1, e2)):
            return eval2(e1) + eval2(e2)

Expected Behavior

Both eval and eval2 should typecheck.

Actual Behavior

Function eval typechecks but eval2 does not.

Mypy playground link

main.py:19: error: Missing return statement  [return]
main.py:22: error: Incompatible return value type (got "object", expected "int")  [return-value]
main.py:24: error: Argument 1 to "eval2" has incompatible type "object"; expected "Expr"  [arg-type]
Found 3 errors in 1 file (checked 1 source file)

Your Environment

  • Mypy version used: 1.2.0
  • Mypy command-line flags: none
  • Mypy configuration options from mypy.ini (and other config files): none
  • Python version used: 3.11

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions