Skip to content

[1.20 regression] Type narrowing is order sensitive in match-case statement with narrowed enum type #21187

@SebastiaanZ

Description

@SebastiaanZ

Bug Report

Under specific circumstances, changing the order of case-statements in a match-statement influences mypy's type narrowing, leading to flaky assert_never errors.

Specifically, this happens you narrow enum values to specific enum values using Literal and combine that narrowed type with other types in a union.

(I've not done an exhaustive search, but I've only seen this with Literal[SomeEnum.SPECIFIC_VALUE].)

This bug does not occur with mypy==1.19

I've tried to reproduce this bug with Mypy 1.19, but it only occurs with Mypy 1.20. (We ran into this after upgrading Mypy.)

To Reproduce

In the script below, the only different between the dummy_class_then_enum and enum_then_dummy_class is the order of the case-statements within the match statement.

In both instances, all possible value types are handled, but mypy will throw an error on the assert_never in the enum_then_dummy_class function.

import enum
from typing import Literal, assert_never


class DummyClass:
    """A dummy class."""


class MyEnum(enum.StrEnum):
    """A dummy enum class."""

    RELEVANT = enum.auto()
    IGNORED = enum.auto()


type MyUnionType = DummyClass | Literal[MyEnum.RELEVANT]


def dummy_class_then_enum(arg: MyUnionType) -> str:
    match arg:
        case DummyClass():
            return "dummy class"
        case MyEnum.RELEVANT:
            return "relevant"
        case _ as unreachable:
            assert_never(unreachable)


def enum_then_dummy_class(arg: MyUnionType) -> str:
    match arg:
        case MyEnum.RELEVANT:
            return "relevant"
        case DummyClass():
            return "dummy class"
        case _ as unreachable:
            assert_never(unreachable)

Expected Behavior

Mypy reports no errors (or errors for both functions).

Actual Behavior

We only get an error for the second function, not the first.

(mypy-demo) sebastiaan@python MypyDemo % mypy bug_demo.py
bug_demo.py:36: error: Argument 1 to "assert_never" has incompatible type "Literal[MyEnum.RELEVANT]"; expected "Never"  [arg-type]
Found 1 error in 1 file (checked 1 source file)

Your Environment

  • Mypy version used: 1.20
  • Mypy command-line flags: None
  • Mypy configuration options from mypy.ini (and other config files): None
  • Python version used: 3.14.3

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