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

Support exhausted matching on enums #767

Closed
thomascobb opened this issue Jun 26, 2020 · 6 comments
Closed

Support exhausted matching on enums #767

thomascobb opened this issue Jun 26, 2020 · 6 comments
Labels
addressed in next version Issue is fixed and will appear in next published version enhancement request New feature or request

Comments

@thomascobb
Copy link

Describe the bug
Mypy supports exhaustive matching on Enums, so if an entry is added later and not checked, it will show an error. An example is python/mypy#6366 (comment)

To Reproduce

  1. Create a new file with the text:
from enum import Enum
from typing import NoReturn


class SomeEnum(Enum):
    VALUE1 = 1
    VALUE2 = 2
    VALUE3 = 3


def assert_never(x: NoReturn) -> NoReturn:
    """Used to cause Mypy to catch impossible cases."""
    # https://github.com/python/mypy/issues/6366#issuecomment-560369716
    assert False, "Unhandled type: {}".format(type(x).__name__)


def func1(a: SomeEnum):
    if a == SomeEnum.VALUE1:
        pass
    elif a == SomeEnum.VALUE2:
        pass
    else:
        assert_never(a)

pyright correctly gives an error for a: Argument of type "Literal[SomeEnum.VALUE3]" cannot be assigned to parameter "x" of type "NoReturn" in function "assert_never". "Literal[SomeEnum.VALUE3]" is incompatible with "NoReturn"Pyright (reportGeneralTypeIssues)

  1. Change a == to a is. pyright gives an error for a: Argument of type "SomeEnum" cannot be assigned to parameter "x" of type "NoReturn" in function "assert_never". "SomeEnum" is incompatible with "NoReturn"Pyright (reportGeneralTypeIssues)

  2. Comment out VALUE3 = 3. pyright gives an error for a: Argument of type "Never" cannot be assigned to parameter "x" of type "NoReturn" in function "assert_never". Type "Never" cannot be assigned to type "NoReturn"Pyright (reportGeneralTypeIssues)

Expected behavior

  1. This is correct
  2. pyright should give the same error as in 1)
  3. pyright should not give an error

VS Code extension or command-line
VS Code extension v1.1.46

Additional context
Thanks for #653 , Enum support is really good now!

@erictraut erictraut added the enhancement request New feature or request label Jun 27, 2020
@erictraut
Copy link
Collaborator

Thanks for the suggestion. I didn't know that mypy supported this special use of NoReturn. I've added the same for Pyright. It can be used for all forms of type narrowing, not just for enums. For example:

def func2(val: Literal["a", "b"]):
    if val == "a":
        pass
    elif val == "b":
        pass
    else:
        assert_never(val)


def func3(val: Union[str, int]):
    if isinstance(val, str):
        pass
    elif isinstance(val, int):
        pass
    else:
        assert_never(val)

@erictraut erictraut added the addressed in next version Issue is fixed and will appear in next published version label Jun 27, 2020
@erictraut
Copy link
Collaborator

This is now implemented in version 1.1.47, which I just published.

@thomascobb
Copy link
Author

Thanks for the quick response! I can confirm that pyright now understands the NoReturn trick. However, if I change a == SomeEnum.VALUE1 to a is SomeEnum.VALUE1 then the type narrowing doesn't occur. Shall I open a new issue for that?

@erictraut
Copy link
Collaborator

Yeah, that's a separate issue. Currently, type narrowing supports "is" and "is not" operators only for None values, since that's the most common pattern. I didn't realize you could use "is" in place of "==" for other types. Is there a difference between the two?

@erictraut
Copy link
Collaborator

My general philosophy for type narrowing support is to support the most common expression types and calls and not the more esoteric ones. Each one requires hand-coded logic and adds complexity. Since no one else has requested this broader support for "is" previously, I will likely not add it unless/until it is upvoted — especially given that there's such an easy workaround.

@thomascobb
Copy link
Author

Thanks for that, I've added a new issue #779 with details on the differences so others can add upvote it if they want

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
addressed in next version Issue is fixed and will appear in next published version enhancement request New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants