mypy icon indicating copy to clipboard operation
mypy copied to clipboard

[1.16 regression] failure to exhaustively narrow type var bounded by union with value pattern match

Open hauntsaninja opened this issue 7 months ago • 9 comments

Courtesy of @delfick

So if we have two files

# a.py
from typing import assert_never

import b


def switch[T_Choice: b.One | b.Two](choice: type[T_Choice]) -> None:
    match choice:
        case b.One:
            print(1)
        case b.Two:
            print(2)
        case _:
            assert_never(choice)


switch(b.One)

and

# b.py
class One: ...
class Two: ...

Then I get no errors with mypy 1.15 and this error with 1.16

a.py:13: error: Argument 1 to "assert_never" has incompatible type "type[Two] | Never"; expected "Never"  [arg-type]

hauntsaninja avatar May 28 '25 04:05 hauntsaninja

Bisects to https://github.com/python/mypy/pull/18972

hauntsaninja avatar May 28 '25 04:05 hauntsaninja

I would say though that I think the above example should probably only work if the two classes are decorated with @typing.final and it does seem the same errors happen with that decorator being used (i.e. no error in 1.15, that new error in 1.16)

delfick avatar May 28 '25 04:05 delfick

I'm a little surprised that we apparently don't have a test for this. This looks like a significant regression, though it wasn't obvious likely because many projects we test against still support 3.9, which doesn't support the match statement.

cc @ilevkivskyi as the author of https://github.com/python/mypy/pull/18972

JukkaL avatar May 28 '25 10:05 JukkaL

I'm a little surprised that we apparently don't have a test for this.

I didn't realized that this only happens in a fairly specific scenario. Having everything in a single file doesn't reproduce the issue.

JukkaL avatar May 28 '25 12:05 JukkaL

I may not have time to properly look into this until weekend, but FWIW this looks really niche to me. I would even say we may go ahead with the release and fix this later, unless this causes big troubles for some repos.

ilevkivskyi avatar May 28 '25 14:05 ilevkivskyi

Ok, I treat this as a non-blocker for the release.

JukkaL avatar May 28 '25 14:05 JukkaL

Ok, that's fine on my end, there's only a few assert_never that I would have to change to an Exception in my repo :)

delfick avatar May 28 '25 22:05 delfick

Btw I improved some behaviour here in https://github.com/python/mypy/pull/19320 , but we do not still exhaustively narrow so leaving this open

hauntsaninja avatar Jun 29 '25 23:06 hauntsaninja

In the original example, I think it is correct for mypy to complain about the assert_never because this case will be selected at runtime if we make a class A(b.One) and call switch(A). Value patterns are evaluated by equality (==).

randolf-scholz avatar Dec 09 '25 16:12 randolf-scholz

Closing this as per above and discussion in https://github.com/python/mypy/pull/20146

hauntsaninja avatar Dec 14 '25 08:12 hauntsaninja