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

Persist type checks across later conditional blocks with the same condition #2199

Closed
Terrance opened this issue Aug 17, 2021 · 6 comments
Closed
Labels
enhancement request New feature or request

Comments

@Terrance
Copy link

Describe the feature

It would be nice for later use of the same conditional check to share its type "context", so that the likes of bound variables and type narrowing can be referenced later, without needing to set otherwise-unused defaults or recheck types.

Current behaviour

def func(flag: bool, value: Optional[str]):
    if flag:
        num = 1
        assert value
        reveal_type(value)  # Type of "value" is "str"
    ...
    if flag:
        print(num)  # "num" is possibly unbound
        reveal_type(value)  # Type of "value" is "str | None"

Expected behavior

Because the same* condition is used, any type logic that applied within the previous uses of the condition should apply here too. In this case, num is always defined and value is always narrowed when flag is set.

*In my case I am looking at a single bool flag here for the condition, so I'd be happy with an exact syntax match rather than an equivalence if the latter is trickier to achieve.

VS Code extension or command-line

Pyright 1.1.162 in VSCode.

@Terrance Terrance added the enhancement request New feature or request label Aug 17, 2021
@erictraut
Copy link
Collaborator

erictraut commented Aug 17, 2021

This would involve tracking types of variables that depend on types of other variables. For example, it would need to remember that num is either type int or Unbound depending on the result of a previous conditional. It would also know that these conditional types would need to "collapse" (e.g. become a Union[int, Unbound] in your example above) if any part of the condition is modified (e.g. a variable within the expression was reassigned).

These would both add significant complexity and performance/memory overhead to the type evaluator. I don't know of any type checker in any language that does this.

I'll think about this a bit more, but it's likely that this problem is unsolvable except in the simplest of cases, and even then it might add so much overhead and complexity as to be undesirable.

@erictraut
Copy link
Collaborator

I can't think of a way to do this without adding significant complexity and a massive performance penalty.

Like I said above, I'm not aware of any static type checker or compiler in any language that does this, and there's good reason for it.

@bryanforbes
Copy link

Part of the desired behavior seems to be supported by mypy (whether it's a side effect or not, I'm not sure):

from __future__ import annotations


def func(flag: bool, value: str | None) -> None:
    if flag:
        num = 1
        assert value
        reveal_type(num)
        reveal_type(value)

    if flag:
        reveal_type(num)
        reveal_type(value)

Here are the types given by mypy vs. pyright:

Line no. mypy pyright
8 builtins.int Literal[1]
9 builtins.str str
12 builtins.int Unbound | Literal[1]
13 Union[builtins.str, None] str | None

@JelleZijlstra
Copy link
Contributor

That just looks like a consequence of the fact that mypy doesn't track whether local variables have been bound. It sees a single assignment to num, so it sets the type of num to int. There is no narrowing involved.

@erictraut
Copy link
Collaborator

Mypy doesn't do any tracking of unbound values. It has been an open feature request for a long time.

@bryanforbes
Copy link

Thanks. Sorry for the noise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement request New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants