You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
closured value not narrowed for immediately invoked lambda, but incorrectly narrowed for non-immediately invoked lambda #10993
f: int|strifisinstance(f, int):
# error: Unsupported operand types for + ("str" and "int")# even though there's no chance the value could be a string here since the lambda is immediately invoked
(lambda: f+1)()
# no error, even though the lambda could get called later when the type changesasdf=lambda: f+1
I just introduced a new feature in pyright that addresses this case. It applies type narrowing to local variables and parameters that are captured in an inner-scoped function or lambda. It's able to do so in a type-safe manner by verifying that the symbol is not assigned a new value on any code path after the lambda or def statement. If it detects such a reassignment, it does not apply type narrowing (i.e., it falls back to the current behavior).
deffunc1(x: int|None):
ifxisnotNone:
lambda: x+1# This no longer generates an errordeffunc2(x: int|None):
ifxisnotNone:
lambda: x+1# This still generates an errorx=get_new_value()
This feature was tricky to implement. I needed to apply some limitations and handle a bunch of edge cases that were not obvious at first. If someone is interested in implementing similar functionality in mypy, I'd be happy to assist you by providing some pointers. You might also find these test cases to be useful.
Note that these days mypy handles this much better in practice, at least inside of functions. I don't think it's ever going to learn exactly the trick about immediate evaluation, but hopefully the current heuristics work significantly better in most cases.
Activity
erictraut commentedon Sep 27, 2021
I just introduced a new feature in pyright that addresses this case. It applies type narrowing to local variables and parameters that are captured in an inner-scoped function or lambda. It's able to do so in a type-safe manner by verifying that the symbol is not assigned a new value on any code path after the lambda or def statement. If it detects such a reassignment, it does not apply type narrowing (i.e., it falls back to the current behavior).
This feature was tricky to implement. I needed to apply some limitations and handle a bunch of edge cases that were not obvious at first. If someone is interested in implementing similar functionality in mypy, I'd be happy to assist you by providing some pointers. You might also find these test cases to be useful.
bluebird75 commentedon Dec 9, 2021
I ran into this bug too.
hauntsaninja commentedon Dec 9, 2021
For people who stumble onto this issue, see https://mypy.readthedocs.io/en/stable/common_issues.html#narrowing-and-inner-functions and discussion in this issue #2608
Awesome that Pyright tracks assignments to make things better here. For my future self, microsoft/pyright@e121a78 seems to be the relevant commit
hauntsaninja commentedon Nov 5, 2023
Note that these days mypy handles this much better in practice, at least inside of functions. I don't think it's ever going to learn exactly the trick about immediate evaluation, but hopefully the current heuristics work significantly better in most cases.
hauntsaninja commentedon Jan 4, 2024
Closing as per my previous comment