-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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
Typing narrowing fails depending on the order of if clauses #15706
Comments
Essentially the same answer as in #15332 (comment). if (string_a is None) and (string_b is None):
... # we know string_a == string_b == None
if string_a is None:
... # we know string_a == None but we don't apply the condition from the previous 'if' I've created #15653 to better document expectations. |
Does that also explain why |
Kind of :) The order in which mypy narrows types matches the Python evaluation order. For example:
📝 BTW, we should document this, but I cannot find an appropriate section... So yes, in Why lack of conditional narrowing explain why it doesn't work? Let's rewrite def takes_two_optional_str0a(string: str | None, whatever: bool) -> str:
- if not (whatever and (string is None)) and whatever:
- return takes_one_str(string)
+ if not (whatever and (string is None)):
+ if whatever:
+ return takes_one_str(string)
+ else:
+ pass
+ else:
+ pass
return "" Let's annotate the new code: if not (whatever and (string is None)):
# In the 'if', we can't narrow 'whatever' or 'string' on their own,
# and mypy isn't smart enough to track conditions.
if whatever:
# In the 'if', 'whatever: Literal[True]'.
# We don't track conditions, so we can't narrow 'string'
return takes_one_str(string)
else:
# In the 'else', narrow 'whatever: Literal[False]'.
pass
else:
# In the 'else', narrow 'whatever: Literal[True]' and 'string: None'
pass |
Thanks for the detailed explanation! Now I fully understand why current mypy works the way it does. I guess future mypy users will appreciate having this documented (both the lack of aliased type narrowing as well as the effect of the execution order), and if aliased type narrowing were supported, that would be great as well ;) |
Bug Report
Type narrowing fails in the code below.
To Reproduce
https://mypy-play.net/?mypy=latest&python=3.11&gist=3f3ce6b3021c1a71a4ecf31d35f62a98
Expected Behavior
No errors
Actual Behavior
bug.py:8: error: Argument 1 to "takes_one_str" has incompatible type "str | None"; expected "str" [arg-type]
bug.py:26: error: Argument 1 to "takes_one_str" has incompatible type "str | None"; expected "str" [arg-type]
Found 2 errors in 1 file (checked 1 source file)
Your Environment
mypy.ini
(and other config files): NoneThe text was updated successfully, but these errors were encountered: