Repository: python/mypy

Issue:
"yield from f()" infers wrong type for type variable
I have the following test case on mypy 0.521: 

```py
from typing import Generator, TypeVar
T = TypeVar('T')
def f(v: T) -> Generator[None, None, T]:
    yield
    return v

def g() -> Generator[None, None, None]:
    # This works:
    gen = f(1)
    result_int = yield from gen

    # This breaks:
    result_int_2 = yield from f(1)
    # I get
    #  mypy_bug.py:13: error: Function does not return a value
    #  mypy_bug.py:13: error: Argument 1 to "f" has incompatible type "int"; expected None
```

I expected this to type-check, but instead it complains on the last line. (I'm using strict-optional, although I don't think that is essential to this example)
"yield from f()" infers wrong type for type variable
I have the following test case on mypy 0.521: 

```py
from typing import Generator, TypeVar
T = TypeVar('T')
def f(v: T) -> Generator[None, None, T]:
    yield
    return v

def g() -> Generator[None, None, None]:
    # This works:
    gen = f(1)
    result_int = yield from gen

    # This breaks:
    result_int_2 = yield from f(1)
    # I get
    #  mypy_bug.py:13: error: Function does not return a value
    #  mypy_bug.py:13: error: Argument 1 to "f" has incompatible type "int"; expected None
```

I expected this to type-check, but instead it complains on the last line. (I'm using strict-optional, although I don't think that is essential to this example)


Discussion:
Definitely a bug. I'll look into it.
Remarkably, the bug seems to have been introduced with 074dadac7ee7c32243e414391f33208e3932d6de. (This is so old I can't even find the corresponding PR.) (**EDIT:** Also, before that commit, `yield from` incorrectly returned a Generator type. So basically it's always been wrong.)
Definitely a bug. I'll look into it.
Remarkably, the bug seems to have been introduced with 074dadac7ee7c32243e414391f33208e3932d6de. (This is so old I can't even find the corresponding PR.) (**EDIT:** Also, before that commit, `yield from` incorrectly returned a Generator type. So basically it's always been wrong.)

Resolving patch:
diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py
--- a/mypy/checkexpr.py
+++ b/mypy/checkexpr.py
@@ -2340,7 +2340,11 @@ def visit_yield_from_expr(self, e: YieldFromExpr, allow_none_return: bool = Fals
         # thus decorated.  But it accepts a generator regardless of
         # how it's decorated.
         return_type = self.chk.return_types[-1]
-        subexpr_type = self.accept(e.expr, return_type)
+        # TODO: What should the context for the sub-expression be?
+        # If the containing function has type Generator[X, Y, ...],
+        # the context should be Generator[X, Y, T], where T is the
+        # context of the 'yield from' itself (but it isn't known).
+        subexpr_type = self.accept(e.expr)
         iter_type = None  # type: Type
 
         # Check that the expr is an instance of Iterable and get the type of the iterator produced


Test patch:
diff --git a/test-data/unit/check-statements.test b/test-data/unit/check-statements.test
--- a/test-data/unit/check-statements.test
+++ b/test-data/unit/check-statements.test
@@ -1136,9 +1136,8 @@ def f() -> Iterator[None]:
 
 -- Yield from statement
 -- --------------------
-
--- Iterables
--- ----------
+--
+-- (It's not really a statement, but don't want to move the tests.)
 
 [case testSimpleYieldFromWithIterator]
 from typing import Iterator
@@ -1216,6 +1215,15 @@ def f(a):
     return b
 [out]
 
+[case testYieldFromGenericCall]
+from typing import Generator, TypeVar
+T = TypeVar('T')
+def f(a: T) -> Generator[int, str, T]: pass
+def g() -> Generator[int, str, float]:
+    r = yield from f('')
+    reveal_type(r)  # E: Revealed type is 'builtins.str*'
+    return 3.14
+
 -- With statement
 -- --------------