Repository: python/mypy

Issue:
New semanal: Spurious "Missing return statement" in async function
```
$ cat santa/scheduler/loop.py 
from typing import Any


async def loop() -> None:
    def signal_handler(signum: Any, frame: Any) -> None:
        nonlocal running
        running = False

    running = True
$ mypy --new-semantic-analyzer santa/scheduler/loop.py 
santa/scheduler/loop.py:4: error: Missing return statement
santa/scheduler/loop.py:6: error: No binding for nonlocal 'running' found
```
The second error is #7057, but the first error goes away if I fix that error (by removing the nonlocal or moving the `running = True` above the nested function).

I ran into this issue in two places in my code. I minimized the other one to this:
```
$ cat santa/lib/git_repo.py 
from typing import Any


async def ensure_exists(self) -> None:
    async def create_worktree_at(x: Any) -> None:
        await x.check_call(worktree_dir)
$ mypy --new-semantic-analyzer santa/lib/git_repo.py 
santa/lib/git_repo.py:4: error: Missing return statement
santa/lib/git_repo.py:5: error: Missing return statement
santa/lib/git_repo.py:6: error: Name 'worktree_dir' is not defined
```
Here too there is an unrelated error that has to trigger for the "Missing return statement" to appear. The original code actually had no errors, though.


Discussion:

Resolving patch:
diff --git a/mypy/newsemanal/semanal.py b/mypy/newsemanal/semanal.py
--- a/mypy/newsemanal/semanal.py
+++ b/mypy/newsemanal/semanal.py
@@ -566,7 +566,7 @@ def analyze_func_def(self, defn: FuncDef) -> None:
                     arg.initializer.accept(self)
 
         self.analyze_function_body(defn)
-        if defn.is_coroutine and isinstance(defn.type, CallableType):
+        if defn.is_coroutine and isinstance(defn.type, CallableType) and not self.deferred:
             if defn.is_async_generator:
                 # Async generator types are handled elsewhere
                 pass


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
@@ -695,8 +695,40 @@ async def h() -> Any:
     yield 0
 
 async def g():  # E: Function is missing a return type annotation \
-                # N: Use "-> None" if function does not return a value   
+                # N: Use "-> None" if function does not return a value
     yield 0
 [builtins fixtures/async_await.pyi]
 [typing fixtures/typing-full.pyi]
 [out]
+
+[case testAsyncOverloadedFunction]
+from typing import overload
+
+@overload
+async def f(x: int) -> int: ...
+@overload
+async def f(x: str) -> str: ...
+async def f(x):
+    pass
+
+reveal_type(f) # N: Revealed type is 'Overload(def (x: builtins.int) -> typing.Coroutine[Any, Any, builtins.int], def (x: builtins.str) -> typing.Coroutine[Any, Any, builtins.str])'
+[builtins fixtures/async_await.pyi]
+[typing fixtures/typing-full.pyi]
+
+[case testAsyncForwardRefInBody]
+# flags: --new-semantic-analyzer
+async def f() -> None:
+    forwardref: C
+    class C: pass
+
+def dec(x): pass
+
+@dec
+async def g() -> None:
+    forwardref: C
+    class C: pass
+
+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-full.pyi]