Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

erroneous type mismatch with Union and Literal (false positive) #17151

Open
finite-state-machine opened this issue Apr 22, 2024 · 0 comments
Open
Labels
bug mypy got something wrong

Comments

@finite-state-machine
Copy link

finite-state-machine commented Apr 22, 2024

Bug Report

Mypy does not sufficiently simplify Unions and Literals before some type checks (the reproduction case uses assert_type(), but assignments and calls will also trigger the issue). The result is false positive errors.

To Reproduce

[mypy-play.net]

from __future__ import annotations
from enum import (
        Enum,
        auto,
        )
from typing import (
        Literal,
        Union,
        )
from typing_extensions import (
        assert_type,
        reveal_type,
        )

class Color(Enum):
    RED = auto()
    GREEN = auto()
    BLUE = auto()

RedKwds = Literal['RED', 'R']
GreenKwds = Literal['GREEN', 'G']
BlueKwds = Literal['BLUE', 'B']
ColorKwds = Union[RedKwds, GreenKwds, BlueKwds]

RedSpec = Union[Literal[Color.RED], RedKwds]
GreenSpec = Union[Literal[Color.GREEN], GreenKwds]
BlueSpec = Union[Literal[Color.BLUE], BlueKwds]

ColorSpec = Union[Color, ColorKwds]             # ⎱ these are entirely
RGBSpec = Union[RedSpec, GreenSpec, BlueSpec]   # ⎰ equivalent types


rgb_spec: RGBSpec
assert_type(rgb_spec, ColorSpec)  # fails; should be silent             # L34
        # Expression is of type...
        #   Union[
        #       Union[Literal[Color.RED], Literal['RED', 'R']],
        #       Union[Literal[Color.GREEN], Literal['GREEN', 'G']],
        #       Union[Literal[Color.BLUE], Literal['BLUE', 'B']]
        #       ]
        # ... not ...
        #   Union[
        #       Color,
        #       Union[
        #           Literal['RED', 'R'],
        #           Literal['GREEN', 'G'],
        #           Literal['BLUE', 'B']
        #           ]
        #       ]
reveal_type(rgb_spec)                                                   # L50
        # Union[
        #       Literal[Color.RED], Literal['RED'], Literal['R'],
        #       Literal[Color.GREEN], Literal['GREEN'], Literal['G'],
        #       Literal[Color.BLUE], Literal['BLUE'], Literal['B']
        #       ]


# "shaking" the variable (where "shaking" is clearly a no-op) causes
# things to work as expected:
rgb_spec_shaken = (
        rgb_spec
        if isinstance(rgb_spec, Color) else
        rgb_spec
        )
assert_type(rgb_spec_shaken, ColorSpec)  # passes!
reveal_type(rgb_spec_shaken)                                            # L66
        # Union[
        #       Color,
        #       Literal['RED'], Literal['R'],
        #       Literal['GREEN'], Literal['G'],
        #       Literal['BLUE'], Literal['B']
        #       ]

Expected Behavior

The types are provably equivalent; no error should be raised.

Actual Behavior

Mypy does not sufficiently simplify the types, resulting in an erroneous "mismatch".

Your Environment

  • Mypy version used: 1.9.0, master 2024-04-22
  • Mypy command-line flags: none
  • Mypy configuration options from mypy.ini (and other config files): none
  • Python version used: 3.8, 3.12
@finite-state-machine finite-state-machine added the bug mypy got something wrong label Apr 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong
Projects
None yet
Development

No branches or pull requests

1 participant