Repository: python/mypy

Issue:
overwriting None from Tuple[AnyStr]'s only item causes PartialType-related crash
``` python
import os.path

x = None
if 0:
    _, x = os.path.split("blah")
```

results in:

```
Traceback (most recent call last):
  File "/usr/local/bin/mypy", line 6, in <module>
    main(__file__)
  File "/usr/local/lib/python3.5/site-packages/mypy/main.py", line 54, in main
    res = type_check_only(sources, bin_dir, options)
  File "/usr/local/lib/python3.5/site-packages/mypy/main.py", line 102, in type_check_only
    python_path=options.python_path)
  File "/usr/local/lib/python3.5/site-packages/mypy/build.py", line 209, in build
    dispatch(sources, manager)
  File "/usr/local/lib/python3.5/site-packages/mypy/build.py", line 1325, in dispatch
    process_graph(graph, manager)
  File "/usr/local/lib/python3.5/site-packages/mypy/build.py", line 1456, in process_graph
    process_stale_scc(graph, scc)
  File "/usr/local/lib/python3.5/site-packages/mypy/build.py", line 1486, in process_stale_scc
    graph[id].type_check()
  File "/usr/local/lib/python3.5/site-packages/mypy/build.py", line 1305, in type_check
    manager.type_checker.visit_file(self.tree, self.xpath)
  File "/usr/local/lib/python3.5/site-packages/mypy/checker.py", line 424, in visit_file
    self.accept(d)
  File "/usr/local/lib/python3.5/site-packages/mypy/checker.py", line 465, in accept
    typ = node.accept(self)
  File "/usr/local/lib/python3.5/site-packages/mypy/nodes.py", line 862, in accept
    return visitor.visit_if_stmt(self)
  File "/usr/local/lib/python3.5/site-packages/mypy/checker.py", line 1661, in visit_if_stmt
    self.accept(b)
  File "/usr/local/lib/python3.5/site-packages/mypy/checker.py", line 465, in accept
    typ = node.accept(self)
  File "/usr/local/lib/python3.5/site-packages/mypy/nodes.py", line 715, in accept
    return visitor.visit_block(self)
  File "/usr/local/lib/python3.5/site-packages/mypy/checker.py", line 1149, in visit_block
    self.accept(s)
  File "/usr/local/lib/python3.5/site-packages/mypy/checker.py", line 465, in accept
    typ = node.accept(self)
  File "/usr/local/lib/python3.5/site-packages/mypy/nodes.py", line 753, in accept
    return visitor.visit_assignment_stmt(self)
  File "/usr/local/lib/python3.5/site-packages/mypy/checker.py", line 1158, in visit_assignment_stmt
    self.check_assignment(s.lvalues[-1], s.rvalue, s.type is None)
  File "/usr/local/lib/python3.5/site-packages/mypy/checker.py", line 1175, in check_assignment
    infer_lvalue_type)
  File "/usr/local/lib/python3.5/site-packages/mypy/checker.py", line 1244, in check_assignment_to_multiple_lvalues
    self.check_multi_assignment(lvalues, rvalue, context, infer_lvalue_type)
  File "/usr/local/lib/python3.5/site-packages/mypy/checker.py", line 1277, in check_multi_assignment
    context, undefined_rvalue, infer_lvalue_type)
  File "/usr/local/lib/python3.5/site-packages/mypy/checker.py", line 1297, in check_multi_assignment_from_tuple
    rvalue_type = cast(TupleType, self.accept(rvalue, lvalue_type))
  File "/usr/local/lib/python3.5/site-packages/mypy/checker.py", line 465, in accept
    typ = node.accept(self)
  File "/usr/local/lib/python3.5/site-packages/mypy/nodes.py", line 1185, in accept
    return visitor.visit_call_expr(self)
  File "/usr/local/lib/python3.5/site-packages/mypy/checker.py", line 1997, in visit_call_expr
    return self.expr_checker.visit_call_expr(e)
  File "/usr/local/lib/python3.5/site-packages/mypy/checkexpr.py", line 141, in visit_call_expr
    return self.check_call_expr_with_callee_type(callee_type, e)
  File "/usr/local/lib/python3.5/site-packages/mypy/checkexpr.py", line 192, in check_call_expr_with_callee_type
    e.arg_names, callable_node=e.callee)[0]
  File "/usr/local/lib/python3.5/site-packages/mypy/checkexpr.py", line 230, in check_call
    callee, context)
  File "/usr/local/lib/python3.5/site-packages/mypy/checkexpr.py", line 370, in infer_function_type_arguments_using_context
    args = infer_type_arguments(callable.type_var_ids(), ret_type, erased_ctx)
  File "/usr/local/lib/python3.5/site-packages/mypy/infer.py", line 43, in infer_type_arguments
    return solve_constraints(type_var_ids, constraints)
  File "/usr/local/lib/python3.5/site-packages/mypy/solve.py", line 50, in solve_constraints
    top = meet_types(top, c.target)
  File "/usr/local/lib/python3.5/site-packages/mypy/meet.py", line 22, in meet_types
    return t.accept(TypeMeetVisitor(s))
  File "/usr/local/lib/python3.5/site-packages/mypy/types.py", line 763, in accept
    return visitor.visit_partial_type(self)
  File "/usr/local/lib/python3.5/site-packages/mypy/meet.py", line 208, in visit_partial_type
    assert False, 'Internal error'
AssertionError: Internal error

*** INTERNAL ERROR ***

test.py:5: error: Internal error -- please report a bug at https://github.com/python/mypy/issues

NOTE: you can use "mypy --pdb ..." to drop into the debugger when this happens.
```

We might want to fix this before releasing.



Discussion:
Here's a simpler repro which produces a similar error:

``` python
from typing import AnyStr, Tuple

def split() -> Tuple[int, AnyStr]: ...
x = None
_, x = split()
```

What is it supposed to mean? That x becomes an optional AnyStr? Maybe it's
crashing trying to report the problem?

--Guido (mobile)

I can hit this using mkstemp with an overload that returns AnyStr.  It only happens if the variable is defined as None beforehand and not annotated.

```
import tempfile
from typing import Any

def fine_test():
    # type: () -> Any
    # Annotated
    hash_set_path = None  # type: Any
    try:
        fd, hash_set_path = tempfile.mkstemp(dir=u"blah")
    except Exception:
        print("Ack moving on")
    return hash_set_path

def fine_test2():
    # type: () -> Any
    # Not annotated but not overloaded
    hash_set_path = None
    try:
        fd, hash_set_path = tempfile.mkstemp()
    except Exception:
        print("Ack moving on")
    return hash_set_path

def fine_test3():
    # type: () -> Any
    # Variable not defined beforehand
    try:
        fd, hash_set_path = tempfile.mkstemp()
    except Exception:
        print("Ack moving on")
        return None
    return hash_set_path

def crashes_test():
    # type: () -> Any
    hash_set_path = None
    try:
        fd, hash_set_path = tempfile.mkstemp(dir=u"blah")
    except Exception:
        print("Ack moving on")
    return hash_set_path
```

Simpler repro (similar to https://github.com/python/mypy/issues/1587#issuecomment-222258781 but without the confusing "output-only type var"):

```
from typing import AnyStr, Tuple
def f(a: AnyStr) -> Tuple[AnyStr]: pass
x = None
(x,) = f('')

```


Resolving patch:
diff --git a/mypy/applytype.py b/mypy/applytype.py
--- a/mypy/applytype.py
+++ b/mypy/applytype.py
@@ -3,7 +3,7 @@
 import mypy.subtypes
 from mypy.sametypes import is_same_type
 from mypy.expandtype import expand_type
-from mypy.types import Type, TypeVarId, TypeVarType, CallableType, AnyType
+from mypy.types import Type, TypeVarId, TypeVarType, CallableType, AnyType, PartialType
 from mypy.messages import MessageBuilder
 from mypy.nodes import Context
 
@@ -34,14 +34,15 @@ def apply_generic_arguments(callable: CallableType, types: List[Type],
                        for v1 in type.values):
                     continue
             for value in values:
-                if mypy.subtypes.is_subtype(type, value):
+                if isinstance(type, PartialType) or mypy.subtypes.is_subtype(type, value):
                     types[i] = value
                     break
             else:
                 msg.incompatible_typevar_value(callable, i + 1, type, context)
 
         upper_bound = callable.variables[i].upper_bound
-        if type and not mypy.subtypes.satisfies_upper_bound(type, upper_bound):
+        if (type and not isinstance(type, PartialType) and
+                not mypy.subtypes.satisfies_upper_bound(type, upper_bound)):
             msg.incompatible_typevar_value(callable, i + 1, type, context)
 
     # Create a map from type variable id to target type.


Test patch:
diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test
--- a/test-data/unit/check-inference.test
+++ b/test-data/unit/check-inference.test
@@ -935,6 +935,15 @@ if A:
 class A: pass
 class B: pass
 
+[case testAssigningAnyStrToNone]
+from typing import Tuple, TypeVar
+AnyStr = TypeVar('AnyStr', str, bytes)
+
+def f(x: AnyStr) -> Tuple[AnyStr]: pass
+x = None
+(x,) = f('')
+reveal_type(x)  # E: Revealed type is 'builtins.str'
+
 
 -- Inferring attribute types
 -- -------------------------