Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -5721,11 +5721,12 @@ def visit_decorator_inner(
# Fix the type if decorated with `@types.coroutine` or `@asyncio.coroutine`.
defn = e.func
if defn.is_awaitable_coroutine:
assert isinstance(defn.type, CallableType)
typ = self.function_type(defn)
assert isinstance(typ, CallableType)
# Update the return type to AwaitableGenerator (unless we already did).
# Note, this doesn't exist in typing.py, only in typing.pyi.
if not is_named_instance(defn.type.ret_type, "typing.AwaitableGenerator"):
t = defn.type.ret_type
if not is_named_instance(typ.ret_type, "typing.AwaitableGenerator"):
t = typ.ret_type
c = defn.is_coroutine
ty = self.get_generator_yield_type(t, c)
tc = self.get_generator_receive_type(t, c)
Expand All @@ -5734,8 +5735,7 @@ def visit_decorator_inner(
else:
tr = self.get_generator_return_type(t, c)
ret_type = self.named_generic_type("typing.AwaitableGenerator", [ty, tc, tr, t])
typ = defn.type.copy_modified(ret_type=ret_type)
defn.type = typ
defn.type = typ.copy_modified(ret_type=ret_type)

# Type check initialization expressions as part of top-level.
if not self.can_skip_diagnostics:
Expand Down
6 changes: 5 additions & 1 deletion mypy/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1068,7 +1068,11 @@ def max_fixed_argc(self) -> int:
return self.max_pos

def is_dynamic(self) -> bool:
return self.type is None
return (
self.type is None
or isinstance(self.type, mypy.types.CallableType)
and self.type.implicit
)


FUNCDEF_FLAGS: Final = FUNCITEM_FLAGS + [
Expand Down
32 changes: 32 additions & 0 deletions test-data/unit/check-async-await.test
Original file line number Diff line number Diff line change
Expand Up @@ -1091,3 +1091,35 @@ class Launcher(P):
# E: "list[int]" has no attribute "__aiter__" (not async iterable)
[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]

[case testTypesCoroutineDecoratorUntyped]
import types

@types.coroutine
def f(x):
yield
1 + "" # OK, in untyped function
return 1

async def test() -> None:
reveal_type(f) # N: Revealed type is "def (x: Any) -> typing.AwaitableGenerator[Any, Any, Any, Any]"
reveal_type(await f(1)) # N: Revealed type is "Any"

[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]

[case testTypesCoroutineDecoratorPartiallyTyped]
import types

@types.coroutine
def f(x: int):
yield
1 + "" # E: Unsupported left operand type for + ("int")
return 1

async def test() -> None:
reveal_type(f) # N: Revealed type is "def (x: builtins.int) -> typing.AwaitableGenerator[Any, Any, Any, Any]"
reveal_type(await f(1)) # N: Revealed type is "Any"

[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]
Loading