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
15 changes: 14 additions & 1 deletion mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -8128,7 +8128,20 @@ def iterable_item_type(self, it: ProperType, context: Context) -> Type:
return self.analyze_iterable_item_type_without_expression(it, context)[1]

def function_type(self, func: FuncBase) -> FunctionLike:
return function_type(func, self.named_type("builtins.function"))
typ = function_type(func, self.named_type("builtins.function"))
if (
isinstance(func, FuncItem)
and func.is_coroutine
and not func.is_async_generator
and func.type is None
and isinstance(typ, CallableType)
):
any_type = AnyType(TypeOfAny.special_form)
ret_type = self.named_generic_type(
"typing.Coroutine", [any_type, any_type, typ.ret_type]
)
return typ.copy_modified(ret_type=ret_type)
return typ

def push_type_map(self, type_map: TypeMap, *, from_assignment: bool = True) -> None:
if is_unreachable_map(type_map):
Expand Down
6 changes: 6 additions & 0 deletions mypy/checker_shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
ArgKind,
Context,
Expression,
FuncBase,
FuncItem,
LambdaExpr,
MypyFile,
Expand All @@ -28,6 +29,7 @@
from mypy.plugin import CheckerPluginInterface, Plugin
from mypy.types import (
CallableType,
FunctionLike,
Instance,
LiteralValue,
Overloaded,
Expand Down Expand Up @@ -149,6 +151,10 @@ def expr_checker(self) -> ExpressionCheckerSharedApi:
def named_type(self, name: str) -> Instance:
raise NotImplementedError

@abstractmethod
def function_type(self, func: FuncBase) -> FunctionLike:
raise NotImplementedError

@abstractmethod
def lookup_typeinfo(self, fullname: str) -> TypeInfo:
raise NotImplementedError
Expand Down
3 changes: 1 addition & 2 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@
false_only,
fixup_partial_type,
freeze_all_type_vars,
function_type,
get_all_type_vars,
get_type_vars,
is_literal_type_like,
Expand Down Expand Up @@ -415,7 +414,7 @@ def analyze_static_reference(
if isinstance(node, (Var, Decorator, OverloadedFuncDef)):
return node.type or AnyType(TypeOfAny.special_form)
elif isinstance(node, FuncDef):
return function_type(node, self.named_type("builtins.function"))
return self.chk.function_type(node)
elif isinstance(node, TypeInfo):
# Reference to a type object.
if node.typeddict_type:
Expand Down
7 changes: 3 additions & 4 deletions mypy/checkmember.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
bind_self,
erase_to_bound,
freeze_all_type_vars,
function_type,
get_all_type_vars,
make_simplified_union,
supported_self_type,
Expand Down Expand Up @@ -360,7 +359,7 @@ def analyze_instance_member_access(
if mx.is_lvalue and not mx.suppress_errors:
mx.msg.cant_assign_to_method(mx.context)
if not isinstance(method, OverloadedFuncDef):
signature = function_type(method, mx.named_type("builtins.function"))
signature = mx.chk.function_type(method)
else:
if method.type is None:
# Overloads may be not ready if they are decorated. Handle this in same
Expand Down Expand Up @@ -1325,7 +1324,7 @@ def analyze_class_attribute_access(
return AnyType(TypeOfAny.from_error)
else:
assert isinstance(node.node, SYMBOL_FUNCBASE_TYPES)
typ = function_type(node.node, mx.named_type("builtins.function"))
typ = mx.chk.function_type(node.node)
# Note: if we are accessing class method on class object, the cls argument is bound.
# Annotated and/or explicit class methods go through other code paths above, for
# unannotated implicit class methods we do this here.
Expand Down Expand Up @@ -1490,7 +1489,7 @@ def analyze_decorator_or_funcbase_access(
"""
if isinstance(defn, Decorator):
return analyze_var(name, defn.var, itype, mx)
typ = function_type(defn, mx.chk.named_type("builtins.function"))
typ = mx.chk.function_type(defn)
if isinstance(defn, (FuncDef, OverloadedFuncDef)) and defn.is_trivial_self:
return bind_self_fast(typ, mx.self_type)
typ = check_self_arg(typ, mx.self_type, defn.is_class, mx.context, name, mx.msg)
Expand Down
28 changes: 28 additions & 0 deletions test-data/unit/check-async-await.test
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,34 @@ def bar() -> None:
[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]

[case testUntypedAsyncFunctionAndMethodReturnCoroutine]
# flags: --show-error-codes
async def foo():
pass

class C:
async def method(self):
pass

def f(c: C) -> None:
a = foo()
b = c.method()
reveal_type(foo) # N: Revealed type is "def () -> typing.Coroutine[Any, Any, Any]"
reveal_type(a) # E: Value of type "Coroutine[Any, Any, Any]" must be used [unused-coroutine] \
# N: Are you missing an await? \
# N: Revealed type is "typing.Coroutine[Any, Any, Any]"
foo() # E: Value of type "Coroutine[Any, Any, Any]" must be used [unused-coroutine] \
# N: Are you missing an await?
reveal_type(c.method) # N: Revealed type is "def () -> typing.Coroutine[Any, Any, Any]"
reveal_type(b) # E: Value of type "Coroutine[Any, Any, Any]" must be used [unused-coroutine] \
# N: Are you missing an await? \
# N: Revealed type is "typing.Coroutine[Any, Any, Any]"
c.method() # E: Value of type "Coroutine[Any, Any, Any]" must be used [unused-coroutine] \
# N: Are you missing an await?

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

[case testAsyncForOutsideCoroutine]
async def g():
yield 0
Expand Down
2 changes: 1 addition & 1 deletion test-data/unit/check-flags.test
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ async def f(): # E: Function is missing a return type annotation \
# N: Use "-> None" if function does not return a value
pass
[builtins fixtures/async_await.pyi]
[typing fixtures/typing-medium.pyi]
[typing fixtures/typing-async.pyi]

[case testAsyncUnannotatedArgument]
# flags: --disallow-untyped-defs
Expand Down
Loading