Skip to content

Exhaustiveness checking false positive regression in 1.10 #17252

Closed
@antonagestam

Description

@antonagestam

Bug Report

While upgrading from 1.9 to 1.10 we found this regression in exhaustiveness checking. It looks like mypy stops inspecting a match expression once it's found an non-possible member.

To Reproduce

Playground link for below, note it's passing on 1.9.

import enum
from typing import assert_never


class Member(enum.Enum):
    a = enum.auto()
    b = enum.auto()
    c = enum.auto()


def fn(value: Member) -> None:
    if value is Member.b:
        return

    match value:
        case (
            Member.a
            | Member.b
            | Member.c
        ):
            # This only reveals Member.a!
            reveal_type(value)  
            ...
        case no_match:
            assert_never(no_match)
Related, removing Member.a causes the reveal_type() to be muted!
import enum
from typing import assert_never


class Member(enum.Enum):
    b = enum.auto()
    c = enum.auto()


def fn(value: Member) -> None:
    if value is Member.b:
        return

    match value:
        case (
            Member.b
            | Member.c
        ):
            # No reveal is printed!
            reveal_type(value)  
            ...
        case no_match:
            assert_never(no_match)

It's probably also worth pointing out that order matters. Inverting order in the match expression to case Member.c | Member.b: makes the issue go away. I suspect an early return optimization to be at fault! 🕵️

Expected Behavior

This was caused by an already excluded member of the enum. The error message that mypy presents does not make this obvious and the fact that it presents it as an exhaustiveness failure I consider a bug that should be fixed.

The reveal_type() should contain both members .a and .c, there should be no type error.

It should be noted that we were able to work around this by removing the erroneously included member (Member.b in the minimal reproduction) from the match expression.

Actual Behavior

reveal_type() contains only .a, and there is a type error:

repro.py:21: note: Revealed type is "Literal[repro.Member.a]"
repro.py:24: error: Argument 1 to "assert_never" has incompatible type "Literal[Member.c]"; expected "NoReturn"  [arg-type]
Found 1 error in 1 file (checked 1 source file)

Your Environment

See playground link.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrong

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions