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

Match exhaustiveness with class inheriting from tuple #17139

Open
tobiasBora opened this issue Apr 18, 2024 · 1 comment
Open

Match exhaustiveness with class inheriting from tuple #17139

tobiasBora opened this issue Apr 18, 2024 · 1 comment
Labels
bug mypy got something wrong topic-match-statement Python 3.10's match statement

Comments

@tobiasBora
Copy link

tobiasBora commented Apr 18, 2024

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
@tobiasBora tobiasBora added the bug mypy got something wrong label Apr 18, 2024
@AlexWaygood AlexWaygood added the topic-match-statement Python 3.10's match statement label Apr 18, 2024
@JelleZijlstra JelleZijlstra changed the title Match fails when defining class with Foo(int) Match exhaustiveness with class inheriting from tuple Apr 18, 2024
@JelleZijlstra
Copy link
Member

The problem isn't the Foo(int), but the Add(tuple[int, int]). This works fine (https://mypy-play.net/?mypy=latest&python=3.12&gist=5e61f50c5c61bf4c90b5e1403f2b6be1):

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

class Add(int):
    pass

class Const(int):
    pass

Expr = Add | Const

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

print(my_eval(Const(42)))
print(my_eval(Add(4)))

As for the solution, tuple types are often special; something will have to change in mypy's handling of them but I'm not sure where.

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

No branches or pull requests

3 participants