Skip to content

Match-case on type() is not well interpreted #11576

Description

Environment

  • Python version: 3.12.3
  • PyRight version: 1.1.411
  • PyRight configuration: pyrightconfig.json

Describe the bug

Discriminating based on the type of an object, using a match-case statement, seems erroneously interpreted by PyRight. It complains about lack of cases coverage, erroneously, and additionally suggest terms to add case statements which are syntactically invalid for Python.

PyRight is very clean and useful, but I feel disappointed with this issue, because case coverage checking is as much important as type checking (like in SML). Can still type-check adding an assert isintance(...) at the start of each case branch, but ensuring coverage is sadly missing and it's really important.

Code or Screenshots

There are explanations in the comments.

Note to other people: the example below only matches exact classes (the real case is with some NamedTuple classes). If inst was an instance of a derived class of B, it would not work (would print nothing). I don’t know if there exist a way to express the same with the idea of matching derived class and with the benefit of cases coverage check. There is isinstance but it cannot be used in this match expression.

import builtins

class Base:
    pass

class A(Base):
    pass

class B(Base):
    pass

class C(Base):
    pass

# Add classes in a kind of name-space, so that the cases in the match, are not
# taken to be variable names. Without this, the case statements don’t mean what
# is intended. The bug is not here, this to explain to people who try to
# discover and learn things.
class NS:
    A = A
    B = B
    C = C

inst: Base = B()

match type(inst):
    case NS.A:
        print("A")
    case NS.B:
        print("B")
    case NS.C:
        print("C")

# It prints "B", as expected, so it works, but PyRight complains about this:
# > error: Cases within match statement do not exhaustively handle all values
# > Unhandled type: "type[B]"

# Additionally, the suggestion is misleading, because using `type[...]` yields
# a syntax error. Please, un-comment the below if you want to test it.
#
#  match type(inst):
#      case builtins.type[NS.A]:
#          print("A")
#      case builtins.type[NS.B]:
#          print("B")
#      case builtins.type[NS.C]:
#          print("C")

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions