Repository: python/mypy

Issue:
Tuple assignment and list * unpacking crashes mypy
Ran mypy over the following code:

```
a = [1, 2, 3]
first, *other = [*a, None]
```
Interestingly enough, `first, *other = [None, *a]` works correctly. Happy to give it a shot at fixing this myself is someone can give me some pointers on where to start.

Exception:
```
(.venv3) luka-mbp:typeshed luka$ mypy test.py --show-traceback
test.py:2: error: INTERNAL ERROR -- please report a bug at https://github.com/python/mypy/issues version: 0.530-dev-82cb95cb2cf4680bde12a341ce0f4354c79b3dcd
Traceback (most recent call last):
  File "/Users/luka/Desktop/typeshed/.venv3/bin/mypy", line 11, in <module>
    load_entry_point('mypy===0.530-dev-82cb95cb2cf4680bde12a341ce0f4354c79b3dcd', 'console_scripts', 'mypy')()
  File "/Users/luka/Desktop/typeshed/.venv3/lib/python3.6/site-packages/mypy/__main__.py", line 7, in console_entry
    main(None)
  File "/Users/luka/Desktop/typeshed/.venv3/lib/python3.6/site-packages/mypy/main.py", line 50, in main
    res = type_check_only(sources, bin_dir, options)
  File "/Users/luka/Desktop/typeshed/.venv3/lib/python3.6/site-packages/mypy/main.py", line 97, in type_check_only
    options=options)
  File "/Users/luka/Desktop/typeshed/.venv3/lib/python3.6/site-packages/mypy/build.py", line 196, in build
    graph = dispatch(sources, manager)
  File "/Users/luka/Desktop/typeshed/.venv3/lib/python3.6/site-packages/mypy/build.py", line 1801, in dispatch
    process_graph(graph, manager)
  File "/Users/luka/Desktop/typeshed/.venv3/lib/python3.6/site-packages/mypy/build.py", line 2044, in process_graph
    process_stale_scc(graph, scc, manager)
  File "/Users/luka/Desktop/typeshed/.venv3/lib/python3.6/site-packages/mypy/build.py", line 2147, in process_stale_scc
    graph[id].type_check_first_pass()
  File "/Users/luka/Desktop/typeshed/.venv3/lib/python3.6/site-packages/mypy/build.py", line 1716, in type_check_first_pass
    self.type_checker.check_first_pass()
  File "/Users/luka/Desktop/typeshed/.venv3/lib/python3.6/site-packages/mypy/checker.py", line 189, in check_first_pass
    self.accept(d)
  File "/Users/luka/Desktop/typeshed/.venv3/lib/python3.6/site-packages/mypy/checker.py", line 277, in accept
    stmt.accept(self)
  File "/Users/luka/Desktop/typeshed/.venv3/lib/python3.6/site-packages/mypy/nodes.py", line 859, in accept
    return visitor.visit_assignment_stmt(self)
  File "/Users/luka/Desktop/typeshed/.venv3/lib/python3.6/site-packages/mypy/checker.py", line 1236, in visit_assignment_stmt
    self.check_assignment(s.lvalues[-1], s.rvalue, s.type is None, s.new_syntax)
  File "/Users/luka/Desktop/typeshed/.venv3/lib/python3.6/site-packages/mypy/checker.py", line 1263, in check_assignment
    infer_lvalue_type)
  File "/Users/luka/Desktop/typeshed/.venv3/lib/python3.6/site-packages/mypy/checker.py", line 1505, in check_assignment_to_multiple_lvalues
    self.check_assignment(lv, rv, infer_lvalue_type)
  File "/Users/luka/Desktop/typeshed/.venv3/lib/python3.6/site-packages/mypy/checker.py", line 1328, in check_assignment
    rvalue)
  File "/Users/luka/Desktop/typeshed/.venv3/lib/python3.6/site-packages/mypy/checker.py", line 1716, in infer_variable_type
    elif not is_valid_inferred_type(init_type):
  File "/Users/luka/Desktop/typeshed/.venv3/lib/python3.6/site-packages/mypy/checker.py", line 3146, in is_valid_inferred_type
    if is_same_type(typ, NoneTyp()):
  File "/Users/luka/Desktop/typeshed/.venv3/lib/python3.6/site-packages/mypy/sametypes.py", line 28, in is_same_type
    return left.accept(SameTypeVisitor(right))
  File "/Users/luka/Desktop/typeshed/.venv3/lib/python3.6/site-packages/mypy/types.py", line 1033, in accept
    assert isinstance(visitor, SyntheticTypeVisitor)
AssertionError:
test.py:2: note: use --pdb to drop into pdb
```


Discussion:
Based on `first, *other = [None, *a]` working correctly I'm guessing with `first, *other = [*a, None]` we are trying to unpack `*a` into `first`, and `None` into `*other`, which is wrong.
(Bumping priority to high since this appeared again in the context of mypyc)
I think the cop-out way to fix this would be to have `check_assignment_to_multiple_lvalues` not recurse into a ListExpr/TupleExpr if the rhs has a star expression, or maybe as more of a compromise, check the lvalues *up to* the right-hand-side's star individually, then check the rest via `check_multi_assignment`.
I came across this error when working on #7779. I think both issues will be fixed by the same solution.

@refi64 I don't think getting the index of the starred expression will work the same as it does for lvalues, because the star does really different things on an lvalue vs an rvalue, and there can be more than one:

```python
a = (1, 2, 3)
first, *other = *a, 4        # mypy: crash
print(other)                 # python: [2, 3, 4]
first, *other = *(*a, 4), 5  # mypy: crash
print(other)                 # python: [2, 3, 4, 5]
first, *other = *a, *a       # mypy: crash
print(other)                 # python: [2, 3, 1, 2, 3]
```

Another similar looking example reported in #8635:

```py
a, b = *(1, 2)
```
This ends up in an internal error too:

```python3
a, b = *(1,), *(2,)
```

Maybe it would be useful to add this one too to future tests to be completely sure.

(Just ran into this issue for the first time and ended up with this version. Good luck brave fixers!)
Just ran into this issue on 0.8.12 trying to do essentially this:
```python3
tup = (1, (2, 3))
a, b = *tup
```
Looks like flake8 does not pick up on this being a syntax error.

Resolving patch:
diff --git a/mypy/semanal.py b/mypy/semanal.py
--- a/mypy/semanal.py
+++ b/mypy/semanal.py
@@ -1683,6 +1683,8 @@ class Foo(Bar, Generic[T]): ...
         declared_tvars: TypeVarLikeList = []
         is_protocol = False
         for i, base_expr in enumerate(base_type_exprs):
+            if isinstance(base_expr, StarExpr):
+                base_expr.valid = True
             self.analyze_type_expr(base_expr)
 
             try:
@@ -4539,8 +4541,7 @@ def visit_dict_expr(self, expr: DictExpr) -> None:
 
     def visit_star_expr(self, expr: StarExpr) -> None:
         if not expr.valid:
-            # XXX TODO Change this error message
-            self.fail("Can use starred expression only as assignment target", expr)
+            self.fail("Can use starred expression only as assignment target", expr, blocker=True)
         else:
             expr.expr.accept(self)
 


Test patch:
diff --git a/test-data/unit/check-tuples.test b/test-data/unit/check-tuples.test
--- a/test-data/unit/check-tuples.test
+++ b/test-data/unit/check-tuples.test
@@ -972,6 +972,17 @@ b = (1, 'x')
 a = (0, *b, '')
 [builtins fixtures/tuple.pyi]
 
+[case testUnpackSyntaxError]
+*foo  # E: Can use starred expression only as assignment target
+[builtins fixtures/tuple.pyi]
+
+[case testUnpackBases]
+class A: ...
+class B: ...
+bases = (A, B)
+class C(*bases): ...  # E: Invalid base class
+[builtins fixtures/tuple.pyi]
+
 [case testTupleMeetTupleAny]
 from typing import Union, Tuple
 class A: pass