diff --git a/mypy/messages.py b/mypy/messages.py index c9bf26f8952e..8e3a0ad0a6b1 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -1310,6 +1310,22 @@ def return_type_incompatible_with_supertype( code=codes.OVERRIDE, ) + original = get_proper_type(original) + override = get_proper_type(override) + if ( + isinstance(original, Instance) + and isinstance(override, Instance) + and override.type.fullname == "typing.AsyncIterator" + and original.type.fullname == "typing.Coroutine" + and len(original.args) == 3 + and original.args[2] == override + ): + self.note(f'Consider declaring "{name}" in {target} without "async"', context) + self.note( + "See https://mypy.readthedocs.io/en/stable/more_types.html#asynchronous-iterators", + context, + ) + def override_target(self, name: str, name_in_super: str, supertype: str) -> str: target = f'supertype "{supertype}"' if name_in_super != name: diff --git a/test-data/unit/check-async-await.test b/test-data/unit/check-async-await.test index 653025a0bb24..7afdbd687135 100644 --- a/test-data/unit/check-async-await.test +++ b/test-data/unit/check-async-await.test @@ -1021,3 +1021,19 @@ def coro() -> Generator[int, None, None]: reveal_type(coro) # N: Revealed type is "def () -> typing.AwaitableGenerator[builtins.int, None, None, typing.Generator[builtins.int, None, None]]" [builtins fixtures/async_await.pyi] [typing fixtures/typing-async.pyi] + +[case asyncIteratorInProtocol] +from typing import AsyncIterator, Protocol + +class P(Protocol): + async def launch(self) -> AsyncIterator[int]: + raise BaseException + +class Launcher(P): + def launch(self) -> AsyncIterator[int]: # E: Return type "AsyncIterator[int]" of "launch" incompatible with return type "Coroutine[Any, Any, AsyncIterator[int]]" in supertype "P" \ + # N: Consider declaring "launch" in supertype "P" without "async" \ + # N: See https://mypy.readthedocs.io/en/stable/more_types.html#asynchronous-iterators + raise BaseException + +[builtins fixtures/async_await.pyi] +[typing fixtures/typing-async.pyi]