microsoft / pyright

Static Type Checker for Python
Other
13.04k stars 1.39k forks source link

`case {**kw}:` does not match all `dict()` cases? #8356

Closed arjenzorgdoc closed 1 month ago

arjenzorgdoc commented 1 month ago

If I want to match all dicts in a match statement I cannot use case {**kw}:. I need to use case dict():

Is your feature request related to a problem? Please describe.

Code sample in pyright playground

from typing import Literal, assert_never

def is_dict_ok(d: dict[str, str]) -> bool:
    match d:
        case dict():
            print(len(d))
            return True
    assert_never(d)

def is_dict_not_ok(d: dict[str, str]) -> bool:
    match d:
        case {**kw}:
            print(len(kw))
            return True
    assert_never(d)
Cases within match statement do not exhaustively handle all values
  Unhandled type: "dict[str, str]"
  If exhaustive handling is not intended, add "case _: pass"  (reportMatchNotExhaustive)
Argument of type "dict[str, str]" cannot be assigned to parameter "arg" of type "Never" in function "assert_never"
  Type "dict[str, str]" is incompatible with type "Never"  (reportArgumentType)

Describe the solution you’d like

I would like that case {**kw}: would handle the dict-case.

erictraut commented 1 month ago

I think this is a reasonable enhancement request. Narrowing in the fall-through case is safe if the pattern contains a single dictionary expand pattern and the type is provably a Mapping.

Incidentally, mypy doesn't support type narrowing in this case.

This will be included in the next release of pyright.

erictraut commented 1 month ago

This is addressed in pyright 1.1.372.