Skip to content

Commit a5f4b6a

Browse files
committed
Generalize yield statement function type
Functions containing yield statements can now return any supertype of generator. This fixes #1011.
1 parent 4127a66 commit a5f4b6a

File tree

5 files changed

+24
-6
lines changed

5 files changed

+24
-6
lines changed

mypy/checker.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1458,10 +1458,16 @@ def count_nested_types(self, typ: Instance, check_type: str) -> int:
14581458
def visit_yield_stmt(self, s: YieldStmt) -> Type:
14591459
return_type = self.return_types[-1]
14601460
if isinstance(return_type, Instance):
1461-
if return_type.type.fullname() != 'typing.Iterator':
1461+
if not is_subtype(self.named_generic_type('typing.Generator', [AnyType(), AnyType(), AnyType()]), return_type):
14621462
self.fail(messages.INVALID_RETURN_TYPE_FOR_YIELD, s)
14631463
return None
1464-
expected_item_type = return_type.args[0]
1464+
if return_type.args:
1465+
expected_item_type = return_type.args[0]
1466+
else:
1467+
# if the declared supertype of `Generator` has no type
1468+
# parameters (i.e. is `object`), then the yielded values can't
1469+
# be accessed so any type is acceptable.
1470+
expected_item_type = AnyType()
14651471
elif isinstance(return_type, AnyType):
14661472
expected_item_type = AnyType()
14671473
else:

mypy/messages.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
INVALID_EXCEPTION = 'Exception must be derived from BaseException'
3131
INVALID_EXCEPTION_TYPE = 'Exception type must be derived from BaseException'
3232
INVALID_RETURN_TYPE_FOR_YIELD = \
33-
'Iterator function return type expected for "yield"'
33+
'Generator or supertype function return type expected for "yield"'
3434
INVALID_RETURN_TYPE_FOR_YIELD_FROM = \
3535
'Iterable function return type expected for "yield from"'
3636
INCOMPATIBLE_TYPES = 'Incompatible types'

mypy/test/data/check-statements.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,7 @@ def f() -> Any:
656656
[case testYieldInFunctionReturningFunction]
657657
from typing import Callable
658658
def f() -> Callable[[], None]:
659-
yield object() # E: Iterator function return type expected for "yield"
659+
yield object() # E: Generator or supertype function return type expected for "yield"
660660
[out]
661661
main: note: In function "f":
662662

@@ -668,7 +668,7 @@ def f():
668668
[case testWithInvalidInstanceReturnType]
669669
import typing
670670
def f() -> int:
671-
yield 1 # E: Iterator function return type expected for "yield"
671+
yield 1 # E: Generator or supertype function return type expected for "yield"
672672
[builtins fixtures/for.py]
673673
[out]
674674
main: note: In function "f":

mypy/test/data/fixtures/for.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# builtins stub used in for statement test cases
22

3-
from typing import TypeVar, Generic, Iterable, Iterator
3+
from typing import TypeVar, Generic, Iterable, Iterator, Generator
44
from abc import abstractmethod, ABCMeta
55

66
t = TypeVar('t')

mypy/test/data/lib-stub/typing.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
Set = 0
2424

2525
T = TypeVar('T')
26+
U = TypeVar('U')
27+
V = TypeVar('V')
2628

2729
class Container(Generic[T]):
2830
@abstractmethod
@@ -41,6 +43,16 @@ class Iterator(Iterable[T], Generic[T]):
4143
@abstractmethod
4244
def __next__(self) -> T: pass
4345

46+
class Generator(Iterator[T], Generic[T, U, V]):
47+
@abstractmethod
48+
def send(self, value: U) -> T: pass
49+
50+
@abstractmethod
51+
def throw(self, typ: Any, val: Any=None, tb=None) -> None: pass
52+
53+
@abstractmethod
54+
def close(self) -> None: pass
55+
4456
class Sequence(Generic[T]):
4557
@abstractmethod
4658
def __getitem__(self, n: Any) -> T: pass

0 commit comments

Comments
 (0)