Repository: python/mypy

Issue:
Incorrect complain about async function return value type
The following example
```python
def t() -> None:
    async def f() -> int:
        return 1

    def g() -> int:
        return len(x)

    x = [1]
```
produces an incorrect MyPy error:
```
coro.py:3: error: Incompatible return value type (got "int", expected "Coroutine[Any, Any, int]")
```
At module level all works. If remove `g` all works. If make `g` returning a constant all works. If move the definitions of `g` after `x` all works.


Discussion:
Thanks for filing an issue.
I've started to encounter this problem since mypy 0.720 but was unable to reproduce in a simple test.
I did not figure out that nested function-level scope is needed.
Thanks for reporting! This looks like a bug in the new semantic analyzer. The function gets deferred (because there is a forward reference) so its return type is wrapped into `Coroutine[...]` twice.

There is some logic that tries to guard against this (wrapping happens conditionally under `if ... and not self.deferred: ...`), but the flag gets reset between the two iterations.

Resolving patch:
diff --git a/mypy/semanal.py b/mypy/semanal.py
--- a/mypy/semanal.py
+++ b/mypy/semanal.py
@@ -200,6 +200,12 @@ class SemanticAnalyzer(NodeVisitor[None],
     plugin = None  # type: Plugin     # Mypy plugin for special casing of library features
     statement = None  # type: Optional[Statement]  # Statement/definition being analyzed
 
+    # Mapping from 'async def' function definitions to their return type wrapped as a
+    # 'Coroutine[Any, Any, T]'. Used to keep track of whether a function definition's
+    # return type has already been wrapped, by checking if the function definition's
+    # type is stored in this mapping and that it still matches.
+    wrapped_coro_return_types = {}  # type: Dict[FuncDef, Type]
+
     def __init__(self,
                  modules: Dict[str, MypyFile],
                  missing_modules: Set[str],
@@ -571,7 +577,9 @@ def analyze_func_def(self, defn: FuncDef) -> None:
 
         self.analyze_arg_initializers(defn)
         self.analyze_function_body(defn)
-        if defn.is_coroutine and isinstance(defn.type, CallableType) and not self.deferred:
+        if (defn.is_coroutine and
+                isinstance(defn.type, CallableType) and
+                self.wrapped_coro_return_types.get(defn) != defn.type):
             if defn.is_async_generator:
                 # Async generator types are handled elsewhere
                 pass
@@ -583,6 +591,7 @@ def analyze_func_def(self, defn: FuncDef) -> None:
                                                    [any_type, any_type, defn.type.ret_type])
                 assert ret_type is not None, "Internal error: typing.Coroutine not found"
                 defn.type = defn.type.copy_modified(ret_type=ret_type)
+                self.wrapped_coro_return_types[defn] = defn.type
 
     def prepare_method_signature(self, func: FuncDef, info: TypeInfo) -> None:
         """Check basic signature validity and tweak annotation of self/cls argument."""


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
@@ -731,3 +731,17 @@ reveal_type(f) # N: Revealed type is 'def () -> typing.Coroutine[Any, Any, None]
 reveal_type(g) # N: Revealed type is 'Any'
 [builtins fixtures/async_await.pyi]
 [typing fixtures/typing-async.pyi]
+
+[case testAsyncDeferredAnalysis]
+
+def t() -> None:
+    async def f() -> int:
+        return 1
+
+    def g() -> int:
+        return next(iter(x))
+
+    x = [1]
+
+[builtins fixtures/async_await.pyi]
+[typing fixtures/typing-async.pyi]