Match statement with None pattern does not induce type narrowing #3372
Replies: 5 comments
-
This is "as designed" behavior. Type narrowing cannot be applied here because the subject expression (the expression you are matching against) is a tuple expression, and type narrowing does not apply to tuples. It applies only to simple names, member access expressions, and simple index expressions. If you want type narrowing to work (in pylance or other type checkers like mypy), you will need to refactor your code so you match against an expression type where type narrowing is supported. Here's one approach. def foo(bar: str | None, spam: Spam) -> str:
match bar:
case None:
result = "absent"
case b:
match spam:
case Spam.state1:
result = f"state 1: {b.upper()}"
case Spam.state2:
result = f"state 2: {b.upper()}"
return result |
Beta Was this translation helpful? Give feedback.
-
Actually, my previous explanation was a bit misleading. The problem is not that the subject expression form is not supported. The issue is that the type checker doesn't perform narrowing on individual elements of a tuple. The initial type of the subject expression is |
Beta Was this translation helpful? Give feedback.
-
@judej, convert to enhancement discussion? |
Beta Was this translation helpful? Give feedback.
-
Moving this issue to discussion as an enhancement request for comments and upvotes. |
Beta Was this translation helpful? Give feedback.
-
Right, I had indeed not interpreted this as matching a tuple against each branch. I can see that extending type narrowing to individual tuple elements might be a slippery slope (e.g. how should |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Environment data
Code Snippet
Consider the following structural matching example:
Pylance reports that
b
is of typestr | None
and so"upper" is not a known member of "None"
is reported. However, thecase None, _:
pattern should be seen as an assertion thatb is not None
for the other branches.The issue can be mitigated by adding
if b
guards:I'm not sure if this is directly related, but Pylance also reports that
result is possibly Unbound
; the branches of the match statement are exhaustive as all combinations ofbar
andspam
are covered (eitherbar
isNone
and it doesn't matter what valuespam
has, orbar
is a string and all possible values forspam
are covered).This issue can be mitigated by adding a wildcard case with
raise
orassert False
:Beta Was this translation helpful? Give feedback.
All reactions