-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
Narrowing and exhaustiveness errors when matching on a tuple of optionals #14731
Comments
For some reason the link to mypy playground is currently giving me an error Is this issue e.g. about the following? def foo(a: str | None, b: str | None) -> None:
match a, b:
case None, None:
return
case a_matched, None:
reveal_type(a_matched)
return
case None, b_matched:
reveal_type(b_matched)
return
case a_matched, b_matched:
reveal_type(a_matched)
reveal_type(b_matched)
return The revealed types are:
and I was wondering if this is supposed to infer non-optional value even without explicit guards. Using explicit guards seems to work in this case, but it is syntactically more clumsy than an def foo(a: str | None, b: str | None) -> None:
match a, b:
case None, None:
return
case (a_matched, None) if a_matched is not None:
reveal_type(a_matched)
return
case (None, b_matched) if b_matched is not None:
reveal_type(b_matched)
return
case (a_matched, b_matched) if a_matched is not None and b_matched is not None:
reveal_type(a_matched)
reveal_type(b_matched)
return |
Allows sequence pattern matching of tuple types with union members to use an unmatched pattern to narrow the possible type of union member to the type that was not matched in the sequence pattern. For example given a type of `tuple[int, int | None]` a pattern match like: ``` match tuple_type: case a, None: return case t: reveal_type(t) # narrows tuple type to tuple[int, int] return ``` The case ..., None sequence pattern match can now narrow the type in further match statements to rule out the None side of the union. This is implemented by moving the original implementation of tuple narrowing in sequence pattern matching since its functionality should be to the special case where a tuple only has length of one. This implementation does not hold for tuples of length greater than one since it does not account all combinations of alternative types. This replace that implementation with a new one that builds the rest type by iterating over the potential rest type members preserving narrowed types if they are available and replacing any uninhabited types with the original type of tuple member since these matches are only exhaustive if all members of the tuple are matched. Fixes python#14731
Bug Report
When using
match
on a tuple of optionals, Mypy doesn't seem to:Optional[T]
toT
in non-optional cases, even if all theNone
cases have been handled.This feels similar to #12267 (comment), or maybe #12364 or #13989, but the example is a little different; apologies if it's a dupe / already known—and thanks for taking a look!
To Reproduce
https://mypy-play.net/?mypy=latest&python=3.11&gist=b6c10a27006d7b5ad55729467c2c5de8
Expected Behavior
No errors. 😊
I've used this match-on-a-tuple pattern in Rust and Swift a few times, which is why I was a little surprised that Mypy didn't like it.
Actual Behavior
Your Environment
The text was updated successfully, but these errors were encountered: