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

closured value not narrowed for immediately invoked lambda, but incorrectly narrowed for non-immediately invoked lambda #10993

Closed
DetachHead opened this issue Aug 19, 2021 · 5 comments
Labels
bug mypy got something wrong topic-type-narrowing Conditional type narrowing / binder

Comments

@DetachHead
Copy link
Contributor

f: int | str

if isinstance(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 changes
    asdf = lambda: f + 1

https://mypy-play.net/?mypy=latest&python=3.10&gist=9853f815e80f43e878bc9e1ae2d29108

@erictraut
Copy link

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).

def func1(x: int | None):
    if x is not None:
        lambda: x + 1  # This no longer generates an error

def func2(x: int | None):
    if x is not None:
        lambda: x + 1  # This still generates an error
    x = 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.

@bluebird75
Copy link

I ran into this bug too.

@hauntsaninja
Copy link
Collaborator

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

@JelleZijlstra JelleZijlstra added the topic-type-narrowing Conditional type narrowing / binder label Mar 19, 2022
@hauntsaninja
Copy link
Collaborator

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
Copy link
Collaborator

Closing as per my previous comment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-type-narrowing Conditional type narrowing / binder
Projects
None yet
Development

No branches or pull requests

5 participants