Repository: python/mypy

Issue:
Error when assigning a ternary with an empty collection to a union type variable
Hello,

the following code:
```python
from typing import List, Union
import sys
p : Union[int, List[int]] = 1 if len(sys.argv) else []
```

incorrectly generates the following error:

    t.py:3: error: Incompatible types in assignment (expression has type "Union[int, List[<nothing>]]", variable has type "Union[int, List[int]]")

Adding an integer in the list makes the error disappear. I first observed this issue with a dictionary:
```python
from typing import Dict, Union
import sys
p : Union[int, Dict[int, int]] = 1 if len(sys.argv) else {}
```
Error:

    t.py:3: error: Incompatible types in assignment (expression has type "Union[int, Dict[<nothing>, <nothing>]]", variable has type "Union[int, Dict[int, int]]")

It seems `<nothing>` should be matched with any type in type parameters in unions.


Discussion:
Please, take a look at [this](https://github.com/python/typing/issues/157) topic. Perhaps mypy should consider an empty list like an object that fits `List[int]`, but unfortunately it doesn't. 
I think the best solution for you would be use `Any` type: 

`p : Union[int, List[Any]] = 1 if len(sys.argv) else []`
I worked around this issue by getting rid of the ternary condition and using a regular if statement instead.
Another possible workaround could be using a covariant collection like `Sequence`. I however think mypy can do better here. We can probably pass through the type context in case of the ternary expressions.
This actually may be not hard to fix, one just needs to update the logic in `mypy/checkexpr.py` in `visit_conditional_expr()` to try the original context `ctx` for the else expression.

Resolving patch:
diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py
--- a/mypy/checkexpr.py
+++ b/mypy/checkexpr.py
@@ -3534,9 +3534,11 @@ def visit_conditional_expr(self, e: ConditionalExpr) -> Type:
 
         if_type = self.analyze_cond_branch(if_map, e.if_expr, context=ctx)
 
+        # Analyze the right branch using full type context and store the type
+        full_context_else_type = self.analyze_cond_branch(else_map, e.else_expr, context=ctx)
         if not mypy.checker.is_valid_inferred_type(if_type):
             # Analyze the right branch disregarding the left branch.
-            else_type = self.analyze_cond_branch(else_map, e.else_expr, context=ctx)
+            else_type = full_context_else_type
 
             # If it would make a difference, re-analyze the left
             # branch using the right branch's type as context.
@@ -3556,7 +3558,7 @@ def visit_conditional_expr(self, e: ConditionalExpr) -> Type:
         #
         # TODO: Always create a union or at least in more cases?
         if isinstance(get_proper_type(self.type_context[-1]), UnionType):
-            res = make_simplified_union([if_type, else_type])
+            res = make_simplified_union([if_type, full_context_else_type])
         else:
             res = join.join_types(if_type, else_type)
 


Test patch:
diff --git a/test-data/unit/check-unions.test b/test-data/unit/check-unions.test
--- a/test-data/unit/check-unions.test
+++ b/test-data/unit/check-unions.test
@@ -1004,3 +1004,12 @@ do_thing_with_enums(boop)  # E: Argument 1 to "do_thing_with_enums" has incompat
                            # N: "List" is invariant -- see http://mypy.readthedocs.io/en/latest/common_issues.html#variance \
                            # N: Consider using "Sequence" instead, which is covariant
 [builtins fixtures/isinstancelist.pyi]
+
+[case testAssignUnionWithTenaryExprWithEmptyCollection]
+from typing import Dict, List, Union
+x: Union[int, List[int]] = 1 if bool() else []
+y: Union[int, Dict[int, int]] = 1 if bool() else {}
+
+u: Union[int, List[int]] = [] if bool() else 1
+v: Union[int, Dict[int, int]] = {} if bool() else 1
+[builtins fixtures/isinstancelist.pyi]