Repository: python/mypy

Issue:
Crash with async generator and disallow_untyped_defs
On this file:

```python
from typing import AsyncGenerator, Awaitable, Callable, Any
import asyncio

async def f() -> AsyncGenerator[int, None]:
    yield 3
    await asyncio.sleep(1)
```

I get:
```
$ mypy --show-traceback --disallow-untyped-defs bin/asyncg.py 
bin/asyncg.py:4: error: INTERNAL ERROR -- please report a bug at https://github.com/python/mypy/issues version: 0.610+dev-c29210ea2f79f4017ec68435b5674d56e87c5105
Traceback (most recent call last):
  File "/Users/jzijlstra-mpbt/py/venvs/venv36/bin/mypy", line 11, in <module>
    load_entry_point('mypy', 'console_scripts', 'mypy')()
  File "/Users/jzijlstra-mpbt/py/mypy/mypy/__main__.py", line 7, in console_entry
    main(None)
  File "/Users/jzijlstra-mpbt/py/mypy/mypy/main.py", line 91, in main
    res = type_check_only(sources, bin_dir, options, flush_errors, fscache)  # noqa
  File "/Users/jzijlstra-mpbt/py/mypy/mypy/main.py", line 148, in type_check_only
    fscache=fscache)
  File "/Users/jzijlstra-mpbt/py/mypy/mypy/build.py", line 185, in build
    flush_errors, fscache)
  File "/Users/jzijlstra-mpbt/py/mypy/mypy/build.py", line 285, in _build
    graph = dispatch(sources, manager)
  File "/Users/jzijlstra-mpbt/py/mypy/mypy/build.py", line 2398, in dispatch
    process_graph(graph, manager)
  File "/Users/jzijlstra-mpbt/py/mypy/mypy/build.py", line 2691, in process_graph
    process_stale_scc(graph, scc, manager)
  File "/Users/jzijlstra-mpbt/py/mypy/mypy/build.py", line 2807, in process_stale_scc
    graph[id].type_check_first_pass()
  File "/Users/jzijlstra-mpbt/py/mypy/mypy/build.py", line 2029, in type_check_first_pass
    self.type_checker().check_first_pass()
  File "/Users/jzijlstra-mpbt/py/mypy/mypy/checker.py", line 252, in check_first_pass
    self.accept(d)
  File "/Users/jzijlstra-mpbt/py/mypy/mypy/checker.py", line 351, in accept
    stmt.accept(self)
  File "/Users/jzijlstra-mpbt/py/mypy/mypy/nodes.py", line 586, in accept
    return visitor.visit_func_def(self)
  File "/Users/jzijlstra-mpbt/py/mypy/mypy/checker.py", line 654, in visit_func_def
    self._visit_func_def(defn)
  File "/Users/jzijlstra-mpbt/py/mypy/mypy/checker.py", line 658, in _visit_func_def
    self.check_func_item(defn, name=defn.name())
  File "/Users/jzijlstra-mpbt/py/mypy/mypy/checker.py", line 720, in check_func_item
    self.check_func_def(defn, typ, name)
  File "/Users/jzijlstra-mpbt/py/mypy/mypy/checker.py", line 755, in check_func_def
    self.check_for_missing_annotations(fdef)
  File "/Users/jzijlstra-mpbt/py/mypy/mypy/checker.py", line 933, in check_for_missing_annotations
    is_unannotated_any(self.get_coroutine_return_type(ret_type))):
  File "/Users/jzijlstra-mpbt/py/mypy/mypy/checker.py", line 626, in get_coroutine_return_type
    return return_type.args[2]
IndexError: list index out of range
bin/asyncg.py:4: : note: use --pdb to drop into pdb
```

If nobody else gets to it first, I can look into fixing this within the next few days.


Discussion:

Resolving patch:
diff --git a/mypy/checker.py b/mypy/checker.py
--- a/mypy/checker.py
+++ b/mypy/checker.py
@@ -929,9 +929,13 @@ def is_unannotated_any(t: Type) -> bool:
                 ret_type = fdef.type.ret_type
                 if is_unannotated_any(ret_type):
                     self.fail(messages.RETURN_TYPE_EXPECTED, fdef)
-                elif (fdef.is_coroutine and isinstance(ret_type, Instance) and
-                      is_unannotated_any(self.get_coroutine_return_type(ret_type))):
-                    self.fail(messages.RETURN_TYPE_EXPECTED, fdef)
+                elif fdef.is_generator:
+                    if is_unannotated_any(self.get_generator_return_type(ret_type,
+                                                                        fdef.is_coroutine)):
+                        self.fail(messages.RETURN_TYPE_EXPECTED, fdef)
+                elif fdef.is_coroutine and isinstance(ret_type, Instance):
+                    if is_unannotated_any(self.get_coroutine_return_type(ret_type)):
+                        self.fail(messages.RETURN_TYPE_EXPECTED, fdef)
                 if any(is_unannotated_any(t) for t in fdef.type.arg_types):
                     self.fail(messages.ARGUMENT_TYPE_EXPECTED, fdef)
 


Test patch:
diff --git a/test-data/unit/check-async-await.test b/test-data/unit/check-async-await.test
--- a/test-data/unit/check-async-await.test
+++ b/test-data/unit/check-async-await.test
@@ -669,3 +669,33 @@ async def decorated_host_coroutine() -> None:
 [builtins fixtures/async_await.pyi]
 [typing fixtures/typing-full.pyi]
 [out]
+
+[case testAsyncGenDisallowUntyped]
+# flags: --disallow-untyped-defs
+# These should not crash
+from typing import AsyncGenerator, Any
+
+async def f() -> AsyncGenerator[int, None]:
+    yield 0
+
+async def g() -> AsyncGenerator[Any, None]:
+    yield 0
+[builtins fixtures/async_await.pyi]
+[typing fixtures/typing-full.pyi]
+[out]
+
+[case testAsyncGenDisallowUntypedTriggers]
+# flags: --disallow-untyped-defs
+from typing import AsyncGenerator, Any
+
+async def f() -> AsyncGenerator[Any, Any]:
+    yield None
+
+async def h() -> Any:
+    yield 0
+
+async def g():  # E: Function is missing a type annotation
+    yield 0
+[builtins fixtures/async_await.pyi]
+[typing fixtures/typing-full.pyi]
+[out]