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

Union should be automatically inferred when assignment occurs in multiple branches #2611

Closed
JelleZijlstra opened this issue Dec 27, 2016 · 3 comments

Comments

@JelleZijlstra
Copy link
Member

Not sure if this has already been discussed; I couldn't find an exact duplicate although #1094 and #1174 are similar. I have code like this:

try:
    x = 3
    reveal_type(x)  # expect int
except SomeError:
     x = None
     reveal_type(x) # expect None
else:
     reveal_type(x)  # expect int
     # (do things that assume that x is an int)
reveal_type(x)  # expect Union[int, None]

but mypy gives an error the assignment in the except block and doesn't infer the union. I tried adding an explicit # type: Optional[int] to the first assignment, but then mypy no longer recognizes that x is a non-Optional int in the else block. I ran into this with a try block but I assume an if block would get the same result.

Not sure how easy this is to change or if it affects some other behavior in mypy. I have implemented similar logic in the past by inferring types separately from assignments in the two branches and then unifying the two.

@rwbarton
Copy link
Contributor

rwbarton commented Jan 2, 2017

Mypy doesn't infer a union here by design. I think the main reasons are

  • If mypy did infer a union in this kind of situation, there'd be no such thing as a type-incorrect assignment. Especially during development, writing an erroneous assignment is probably more common than intending for a union to be inferred. By inferring a union mypy will effectively defer the reported error to a later use of the variable, and then it will be harder to track down the actual error.

  • Making mypy's inference smarter means that it can accept more programs without type signatures, but it also means that a reader of the code has to be correspondingly smarter to work out the types mypy has inferred. Currently if the initialization of a variable is an unannotated x = 3, the reader knows that the type of x is definitely int. Under your proposal, x could later be reassigned to any other type at any time without even any kind of explicit marking of the type change.

    There are cases where mypy does do nontrivial type inference of variable type (initializers like x = []), and I think we discussed also inferring optional-ness at some point, but I doubt it's a good idea to infer arbitrary unions.

I tried adding an explicit # type: Optional[int] to the first assignment, but [...]

This is closer to a bug in mypy. It sounds like the same issue as #2008.

@JelleZijlstra
Copy link
Member Author

If mypy did infer a union in this kind of situation, there'd be no such thing as a type-incorrect assignment.

That's not necessarily true. I'm suggesting that mypy automatically infer a union only when two branches of a conditional use different types (treating the except and else blocks of a try statement as conditional blocks). So, this would be legal:

if some_condition():
    x = 3
else:
    x = None

but this would not be:

x = None
x = 3

or even this:

x = None
if some_condition():
    x = 3

@JukkaL
Copy link
Collaborator

JukkaL commented Jan 28, 2020

Closing in favor of #6233, which has more discussion.

@JukkaL JukkaL closed this as completed Jan 28, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants