Skip to content

Narrow match value type based on earlier cases #20189

@connorbrinton

Description

@connorbrinton

Bug Report

Mypy does not exclude types from earlier match cases in subsequent cases. This makes it difficult to work with values that could match multiple cases.

I'm specifically running into this when trying to handle types from the OpenAI and Anthropic Python SDKs. The type annotations in those libraries frequently have patterns like content: Union[str, Iterable[ContentArrayOfContentPart], None]. Applying a match/case statement to the content causes issues in the case Iterable(): case, because Mypy thinks that the value could still be a string (even though that was handled in a previous case).

To Reproduce

Playground URL

import random
from collections.abc import Iterable
from typing import assert_never

x: str | list[int]
if random.random() < 0.5:
    x = "a"
else:
    x = [1, 2, 3]

match x:
    case str():
        reveal_type(x)
    case Iterable():
        reveal_type(x)
    case _:
        assert_never(x)

Expected Behavior

I would expect Mypy to show a revealed type of only builtins.list[builtins.int] for x on line 17, like:

main.py:15: note: Revealed type is "builtins.str"
main.py:17: note: Revealed type is "builtins.list[builtins.int]"
Success: no issues found in 1 source file

Actual Behavior

Even though a string would never make it to the second case, x on line 17 is still considered to possibly be a string:

main.py:15: note: Revealed type is "builtins.str"
main.py:17: note: Revealed type is "builtins.str | builtins.list[builtins.int]"
Success: no issues found in 1 source file

Your Environment

  • Mypy version used: 1.18.2
  • Mypy command-line flags: N/A
  • Mypy configuration options from mypy.ini (and other config files): N/A
  • Python version used: 3.12

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