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

Improve unification of conditional expressions #1094

Closed
ZeeD opened this issue Dec 22, 2015 · 5 comments
Closed

Improve unification of conditional expressions #1094

ZeeD opened this issue Dec 22, 2015 · 5 comments
Assignees
Labels
bug mypy got something wrong

Comments

@ZeeD
Copy link

ZeeD commented Dec 22, 2015

I have this snippet of code

from typing import Any,List

class Node:
    def __init__(self, value:Any, *, children:List['Node']=None) -> None:
        self.value = value
        self.children = [] if children is None else children # type: List[Node]

if I use mypy I get

Tree.py: note: In member "__init__" of class "Node":
Tree.py:10: error: Incompatible types in assignment (expression has type "object", variable has type List[Node])

I think it's something related to the children parameter setted to None, but the problem is... how do I specify that yes, maybe the children parameter can be None, but self.children, by construction is always a List of Nodes?

@gvanrossum
Copy link
Member

gvanrossum commented Dec 22, 2015 via email

@JukkaL JukkaL added the bug mypy got something wrong label Dec 28, 2015
@JukkaL
Copy link
Collaborator

JukkaL commented Dec 28, 2015

The if..else expression doesn't propagate the type context (in your example List[Node]) to the child expressions. Propagating the context would let mypy infer type List[Node] for the left operand.

A related way to fix this would be to use the type of the right operand as the type context for the first expression, in case the latter has an incomplete inferred type. This would have the benefit of not requiring a type annotation.

I think that you could also work around the problem by rearranging the expression:

self.children = children if children is not None else []

@gvanrossum
Copy link
Member

gvanrossum commented Dec 30, 2015 via email

@gvanrossum
Copy link
Member

I keep running into this. The type of (a if x else b) where a and b don't have the same type often degenerates to object or some other useless type rather than the intersection of the two types. Latest example:

class A: pass
class B:
    def foo(self): pass
class C(A, B): pass  # No error if we switch this to C(B, A)
a = B() if True else C()
a.foo()  # E: "object" has no attribute "foo"

Also, e.g.in Python 2 mode:

float(Decimal(0) if True else 0)  # E: No overload variant of "float" matches argument types [builtins.object]

In Python 3 mode this gives

error: Argument 1 to "float" has incompatible type "object"; expected "Union[SupportsFloat, str, bytes]"

@gvanrossum gvanrossum changed the title Incompatible types in assignment (handling optional parameters) Improve unification of conditional expressions Apr 14, 2016
@gvanrossum gvanrossum self-assigned this Apr 15, 2016
@gvanrossum
Copy link
Member

I'm going to have a crack at this.

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

No branches or pull requests

4 participants