Overloads of async generators: inconsistent Coroutine wrapping

I think pyre has the most human behavior here, but that this is a specification issue here.

consider these three functions:

async def a() -> AsyncIterator[int]:
    for i in range(10):
        yield i

async def b() -> AsyncIterator[int]:
    async for i in a():
        yield i

async def c() -> AsyncIterator[int]:
    return a()

The automatic wrapping kicks in on c, and results in a very surprising type to most people. The obvious thing would be for c’s body to be an error.

I think the best fix for obvious results would be to change the automatic wrapping to only wrap types which cannot naturally be the correct type without wrapping.

This would prevent starting with an exported AsynchronousIterator, and an erroneous change changing the type without changing the annotations.

This would mean correctly typing c’s body would be:

async def c() -> Coroutine[Any, Any, AsyncIterator[int]]:
    return a()

which is probably a significantly better outcome to begin with as this is very non-standard code, and to have your functions change types without changing annotations is not something users would generally want (for reference, if anyone I knew wrote this, I’d tell them to change it, code like in the body of c needing to await to then asynchronously iterate should set up inside the first iteration, or within an async context manager instead)