Skip to content

Match exhaustiveness with class inheriting from tuple #17139

Open
@tobiasBora

Description

Bug Report

If I run:

# Run the type checking with "mypy --strict foo.py"

class Add(tuple[int,int]):
    pass

class Const(int):
    pass

Expr = Add | Const

def my_eval(e : Expr) -> int:
    match e:
        case Add((a,b)):
            return a + b
        case Const(x):
            return x

print(my_eval(Const(42)))
print(my_eval(Add((42,45))))

with python 11, it runs just fine. But if I run mypy on this file (with or without strict), I get an error:

$ mypy --strict foo.py
foo.py:11: error: Missing return statement  [return]
Found 1 error in 1 file (checked 1 source file)

Usually I get this error when a branch in a match is forgotten… but here I have covered all cases.

Note that the following code does work, but I would prefer the above code that is less verbose and error prone:

# Run the type checking with "mypy --strict foo.py"

class Add:
    left: int
    right: int
    def __init__(self, left:int, right:int):
        self.left = left
        self.right = right

class Const:
    val: int
    def __init__(self, val:int):
        self.val = val

Expr = Add | Const

def my_eval(e : Expr) -> int:
    match e:
        case Add():
            return e.left + e.right
        case Const():
            return e.val

print(my_eval(Const(42)))
print(my_eval(Add(42,45)))

To Reproduce

Gist URL: https://gist.github.com/mypy-play/5e61f50c5c61bf4c90b5e1403f2b6be1
Playground URL: https://mypy-play.net/?mypy=latest&python=3.12&gist=5e61f50c5c61bf4c90b5e1403f2b6be1

Expected Behavior

I would expect this to type fine. I need this for instance in this context https://stackoverflow.com/questions/78345055/python-static-type-checking-for-union-type-and-pattern-maching/78345797#78345797

I would also expect this to work when using forward reference:

# Run the type checking with "mypy --strict foo.py"

class Add(tuple['Expr','Expr']):
    pass

class Const(int):
    pass

Expr = Add | Const

def my_eval(e : Expr) -> int:
    match e:
        case Add((a,b)):
            return my_eval(a) + my_eval(b)
        case Const(x):
            return x

print(my_eval(Const(42)))
print(my_eval(Add((Const(42),Const(45)))))

Actual Behavior

I get an error.

Your Environment

  • Mypy version used: 1.5.1
  • Mypy command-line flags: None or strict
  • Mypy configuration options from mypy.ini (and other config files): none
  • Python version used: 3.11.8

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrongtopic-match-statementPython 3.10's match statement

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions