Skip to content

Commit 2ae0667

Browse files
authored
Add await to empty context hack (#19777)
Fixes #19716. It is a follow-up to #19767 and was missed there due to malformed test stubs (the same testcase fails when run by full mypy against typeshed, I did not notice missing AwaitExpr because of the passing test...). I synced typevar variance with typeshed definitions and added AwaitExpr to the list of context-dependent exprs. Cc @ilevkivskyi
1 parent 7e7d7a7 commit 2ae0667

File tree

3 files changed

+34
-20
lines changed

3 files changed

+34
-20
lines changed

mypy/checker.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
AssertStmt,
8181
AssignmentExpr,
8282
AssignmentStmt,
83+
AwaitExpr,
8384
Block,
8485
BreakStmt,
8586
BytesExpr,
@@ -4924,7 +4925,11 @@ def check_return_stmt(self, s: ReturnStmt) -> None:
49244925
allow_none_func_call = is_lambda or declared_none_return or declared_any_return
49254926

49264927
# Return with a value.
4927-
if isinstance(s.expr, (CallExpr, ListExpr, TupleExpr, DictExpr, SetExpr, OpExpr)):
4928+
if (
4929+
isinstance(s.expr, (CallExpr, ListExpr, TupleExpr, DictExpr, SetExpr, OpExpr))
4930+
or isinstance(s.expr, AwaitExpr)
4931+
and isinstance(s.expr.expr, CallExpr)
4932+
):
49284933
# For expressions that (strongly) depend on type context (i.e. those that
49294934
# are handled like a function call), we allow fallback to empty type context
49304935
# in case of errors, this improves user experience in some cases,

test-data/unit/check-inference-context.test

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,3 +1582,5 @@ async def inner(c: Cls[T]) -> Optional[T]:
15821582

15831583
async def outer(c: Cls[T]) -> Optional[T]:
15841584
return await inner(c)
1585+
[builtins fixtures/async_await.pyi]
1586+
[typing fixtures/typing-async.pyi]

test-data/unit/fixtures/typing-async.pyi

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ Self = 0
2828

2929
T = TypeVar('T')
3030
T_co = TypeVar('T_co', covariant=True)
31+
R_co = TypeVar('R_co', covariant=True)
3132
T_contra = TypeVar('T_contra', contravariant=True)
33+
S_contra = TypeVar('S_contra', contravariant=True)
3234
U = TypeVar('U')
3335
V = TypeVar('V')
3436
S = TypeVar('S')
@@ -49,9 +51,9 @@ class Iterator(Iterable[T_co], Protocol):
4951
@abstractmethod
5052
def __next__(self) -> T_co: pass
5153

52-
class Generator(Iterator[T], Generic[T, U, V]):
54+
class Generator(Iterator[T_co], Generic[T_co, S_contra, R_co]):
5355
@abstractmethod
54-
def send(self, value: U) -> T: pass
56+
def send(self, value: S_contra) -> T_co: pass
5557

5658
@abstractmethod
5759
def throw(self, typ: Any, val: Any=None, tb: Any=None) -> None: pass
@@ -60,49 +62,54 @@ class Generator(Iterator[T], Generic[T, U, V]):
6062
def close(self) -> None: pass
6163

6264
@abstractmethod
63-
def __iter__(self) -> 'Generator[T, U, V]': pass
65+
def __iter__(self) -> 'Generator[T_co, S_contra, R_co]': pass
6466

65-
class AsyncGenerator(AsyncIterator[T], Generic[T, U]):
67+
class AsyncGenerator(AsyncIterator[T_co], Generic[T_co, S_contra]):
6668
@abstractmethod
67-
def __anext__(self) -> Awaitable[T]: pass
69+
def __anext__(self) -> Awaitable[T_co]: pass
6870

6971
@abstractmethod
70-
def asend(self, value: U) -> Awaitable[T]: pass
72+
def asend(self, value: S_contra) -> Awaitable[T_co]: pass
7173

7274
@abstractmethod
73-
def athrow(self, typ: Any, val: Any=None, tb: Any=None) -> Awaitable[T]: pass
75+
def athrow(self, typ: Any, val: Any=None, tb: Any=None) -> Awaitable[T_co]: pass
7476

7577
@abstractmethod
76-
def aclose(self) -> Awaitable[T]: pass
78+
def aclose(self) -> Awaitable[T_co]: pass
7779

7880
@abstractmethod
79-
def __aiter__(self) -> 'AsyncGenerator[T, U]': pass
81+
def __aiter__(self) -> 'AsyncGenerator[T_co, S_contra]': pass
8082

81-
class Awaitable(Protocol[T]):
83+
class Awaitable(Protocol[T_co]):
8284
@abstractmethod
83-
def __await__(self) -> Generator[Any, Any, T]: pass
85+
def __await__(self) -> Generator[Any, Any, T_co]: pass
8486

85-
class AwaitableGenerator(Generator[T, U, V], Awaitable[V], Generic[T, U, V, S], metaclass=ABCMeta):
87+
class AwaitableGenerator(
88+
Awaitable[R_co],
89+
Generator[T_co, S_contra, R_co],
90+
Generic[T_co, S_contra, R_co, S],
91+
metaclass=ABCMeta
92+
):
8693
pass
8794

88-
class Coroutine(Awaitable[V], Generic[T, U, V]):
95+
class Coroutine(Awaitable[R_co], Generic[T_co, S_contra, R_co]):
8996
@abstractmethod
90-
def send(self, value: U) -> T: pass
97+
def send(self, value: S_contra) -> T_co: pass
9198

9299
@abstractmethod
93100
def throw(self, typ: Any, val: Any=None, tb: Any=None) -> None: pass
94101

95102
@abstractmethod
96103
def close(self) -> None: pass
97104

98-
class AsyncIterable(Protocol[T]):
105+
class AsyncIterable(Protocol[T_co]):
99106
@abstractmethod
100-
def __aiter__(self) -> 'AsyncIterator[T]': pass
107+
def __aiter__(self) -> 'AsyncIterator[T_co]': pass
101108

102-
class AsyncIterator(AsyncIterable[T], Protocol):
103-
def __aiter__(self) -> 'AsyncIterator[T]': return self
109+
class AsyncIterator(AsyncIterable[T_co], Protocol):
110+
def __aiter__(self) -> 'AsyncIterator[T_co]': return self
104111
@abstractmethod
105-
def __anext__(self) -> Awaitable[T]: pass
112+
def __anext__(self) -> Awaitable[T_co]: pass
106113

107114
class Sequence(Iterable[T_co], Container[T_co]):
108115
@abstractmethod

0 commit comments

Comments
 (0)