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

Incorrect error on specific order of multi-pattern case clause #6008

Closed
DanielRosenwasser opened this issue Sep 23, 2023 · 4 comments
Closed
Labels
addressed in next version Issue is fixed and will appear in next published version bug Something isn't working

Comments

@DanielRosenwasser
Copy link
Member

I noticed a difference in the ordering between a match of str(v) | bool(v) | float(v) and str(v) | float(v) | bool(v). The code is below.

Pyright incorrectly issues errors on code in the last match.

SimpleValue = str | float | bool | None

def f(x: SimpleValue):
    print(f"Running with value {x}")

    match x:
        # No errors. ✅
        case str(v) | bool(v) | float(v):
            print("Match 1 happened!")
            print(v)
        case _:
            print("Match 1 didn't happen.")

    
    match x:
        # No errors. ✅
        case str() | float() | bool():
            print("Match 2 happened!")
        case _:
            print("Match 2 didn't happen.")

    match x:
        # Errors! ❌
        case str(v) | float(v) | bool(v):
            #                    ~~~~~~
            # Pattern will never be matched for subject type "None"
            # (reportUnnecessaryComparison)
            print("Match 3 happened!")

            print(v)
            #     ~
            # Argument type is partially unknown
            #     Argument corresponds to parameter "values" in function "print"
            #     Argument type is "str | bool | float | Unknown"
            # (reportUnknownArgumentType)
        case _:
            print("Match 3 didn't happen.")

f(True)
f(None)

# Output:
#   Running with value True
#   Match 1 happened!
#   True
#   Match 2 happened!
#   Match 3 happened!
#   True
#   Running with value None
#   Match 1 didn't happen.
#   Match 2 didn't happen.
#   Match 3 didn't happen.

Admittedly1, this only happens when you write useless code like str(v) | float(v) | bool(v), or more-realistically, the still-useless str(_) | float(_) | bool(_). If you remove the binding variable from these, the error goes away entirely.

VS Code extension or command-line

I'm running in VS Code via Pylance 2023.9.20


1Be patient with me, this is my second time using pattern matching. 😅

@DanielRosenwasser DanielRosenwasser added the bug Something isn't working label Sep 23, 2023
@DanielRosenwasser
Copy link
Member Author

Actually, you can see this without placeholders if you have a clause like case str() | bool() | float() | int().

@erictraut
Copy link
Collaborator

Thanks for the bug report.

This is due to a small inconsistency between the Python type system and the Python runtime. The bool type is a subtype of int (both at runtime and in the type system).

print(isinstance(True, int)) # True

In the type system, according to PEP 484, int should be treated as a subtype of float even though this isn't true at runtime.

print(isinstance(1, float)) # False

In general, when there's a difference between the type system and the runtime, pyright honors the type system. That's why you're seeing the behavior here.

I'll need to think more about whether this is something we might want to address. I'm reluctant to fix just this case but leave all other cases where pyright honors the type system over the runtime. If this change is made, it would need to be made everywhere, which would be a pretty significant change with lots of churn.

@erictraut erictraut added needs decision needs investigation Requires additional investigation to determine course of action and removed needs decision labels Sep 23, 2023
erictraut pushed a commit that referenced this issue Sep 24, 2023
…ased in PEP 484 as "promotion types". The new logic now properly models the runtime behavior for `isinstance` and class pattern matching when used with these promotion types. This addresses #6008.
erictraut pushed a commit that referenced this issue Sep 24, 2023
…ased in PEP 484 as "promotion types". The new logic now properly models the runtime behavior for `isinstance` and class pattern matching when used with these promotion types. This addresses #6008.
@erictraut erictraut removed the needs investigation Requires additional investigation to determine course of action label Sep 24, 2023
@erictraut
Copy link
Collaborator

This will be addressed in the next release.

@erictraut erictraut added the addressed in next version Issue is fixed and will appear in next published version label Sep 24, 2023
erictraut added a commit that referenced this issue Sep 24, 2023
…ased in PEP 484 as "promotion types". The new logic now properly models the runtime behavior for `isinstance` and class pattern matching when used with these promotion types. This addresses #6008. (#6013)

Co-authored-by: Eric Traut <erictr@microsoft.com>
@erictraut
Copy link
Collaborator

This is addressed in pyright 1.1.329, which I just published. It will also be included in a future release of pylance.

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 bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants