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

Mypy doesn't recognize that different string literals in if/else statement match a union of string literals #18442

Open
notatallshaw opened this issue Jan 10, 2025 · 1 comment
Labels
bug mypy got something wrong topic-join-v-union Using join vs. using unions

Comments

@notatallshaw
Copy link

notatallshaw commented Jan 10, 2025

Bug Report

When a function has a type signature like def foo(bar: Literal["a", "b"]) -> None: ... mypy throws an error if the argument passed in can be either a or b as it implies a general string.

To Reproduce

from typing import Literal

CHOICE = bool(...)

def foo(bar: Literal["a", "b"]) -> None: ...

def main() -> None:
    bar = "a"
    if CHOICE:
        bar = "b"

    foo(bar)

Expected Behavior

It would be nice if mypy recognized that bar here could only be Literal["a"] or Literal["b"], i.e Literal["a", "b"].

Actual Behavior

mre.py:12: error: Argument 1 to "foo" has incompatible type "str"; expected "Literal['a', 'b']" [arg-type]

Your Environment

  • Mypy version used: 1.14.1
  • Mypy command-line flags: Default
  • Mypy configuration options from mypy.ini (and other config files): Default
  • Python version used: 3.13

Context

This came up because of a recent change in typeshed python/typeshed#12181 which causes this pip code to trigger a mypy error: https://github.com/pypa/pip/blob/24.3.1/src/pip/_internal/utils/unpacking.py#L179

I assume this issue of different implicit Literal / str types inside branches has been discussed before but I couldn't find it searching through the GitHub issues.

x-ref: pypa/pip#13148

@notatallshaw notatallshaw added the bug mypy got something wrong label Jan 10, 2025
@A5rocks
Copy link
Contributor

A5rocks commented Jan 10, 2025

More generally, even if mypy were to infer literals for types, when merging the two branches mypy will use join rather than a union, which would still cause this. (I forget the rules for literal inference so that may already work, I don't know).

I don't know much about the logic but maybe it's possible to do a Union and put it in last_known_value for Instance? (but I'm not sure) nevermind that gets erased unless the variable is maked Final :/

@brianschubert brianschubert added the topic-join-v-union Using join vs. using unions label Jan 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-join-v-union Using join vs. using unions
Projects
None yet
Development

No branches or pull requests

3 participants