mypy icon indicating copy to clipboard operation
mypy copied to clipboard

Simple `Literal` type narrowing via pattern matching is broken

Open willofferfit opened this issue 1 year ago • 1 comments

Bug Report

Narrowing an int into a Literal via pattern matching is not working, please see example below.

To Reproduce

Python 3.12.2

from typing import Literal, reveal_type

import numpy as np


def sign1(x: int) -> Literal[-1, 0, 1]:
    """Extracts the sign of x."""
    match s := int(np.sign(x)):  # s has type int
        case -1 | 0 | 1:
            reveal_type(s)  # narrowed to Literal[-1, 0, 1]
            return s
        case _:
            raise AssertionError("Unreachable.")


def sign2(x: int) -> Literal[-1, 0, 1]:
    """Extracts the sign of x."""
    match s := int(np.sign(x)):
        case -1:
            reveal_type(s)  # narrowed to Literal[-1]
            return s
        case 0:
            reveal_type(s)  # narrowed to Literal[0]
            return s
        case 1:
            reveal_type(s)  # narrowed to Literal[1]
            return s
        case _:
            raise AssertionError("Unreachable.")


def sign3(x: int) -> Literal[-1, 0, 1]:
    """Extracts the sign of x."""
    match s := int(np.sign(x)):
        case -1:
            return -1
        case 0:
            return 0
        case 1:
            return 1
        case _:
            raise AssertionError("Unreachable.")

Expected Behavior

pyright 1.1.364

_.py
  _.py:10:25 - information: Type of "s" is "Literal[-1, 0, 1]"
  _.py:20:25 - information: Type of "s" is "Literal[-1]"
  _.py:23:25 - information: Type of "s" is "Literal[0]"
  _.py:26:25 - information: Type of "s" is "Literal[1]"
0 errors, 0 warnings, 4 informations 

Actual Behavior

mypy 1.10.0:

_.py:10: note: Revealed type is "Union[Literal[-1], Literal[0], Literal[1]]"
_.py:11: error: Incompatible return value type (got "Literal[-1, 0, 1]", expected "Literal[-1, 0, 1]")  [return-value]
_.py:20: note: Revealed type is "Literal[-1]"
_.py:21: error: Incompatible return value type (got "Literal[-1]", expected "Literal[-1, 0, 1]")  [return-value]
_.py:23: note: Revealed type is "Literal[0]"
_.py:26: note: Revealed type is "Literal[1]"
Found 2 errors in 1 file (checked 1 source file)

willofferfit avatar May 25 '24 04:05 willofferfit

seems to be fixed on latest master branch: https://mypy-play.net/?mypy=master&python=3.12&gist=1beb20f898106c5956f964afc7a65615

Kakadus avatar Jun 17 '24 23:06 Kakadus

Yes, this looks fixed now.

ilevkivskyi avatar Feb 16 '25 10:02 ilevkivskyi