Repository: python/mypy

Issue:
Generator expression returned from a function is interpreted as an Iterator
I have a function like this:

```python
def foo(some_list: List[Any]) -> Generator[Any, None, None]:
    return (element for element in some_list)
```

This should be correct according to the documentation of [`typing.Generator`](https://docs.python.org/3/library/typing.html#typing.Generator), yet mypy complains that it got an Iterator as the return value:

    error: Incompatible return value type (got "Iterator[Any]", expected "Generator[Any, None, None]")

Question was originally posted on Stackoverflow [here](https://stackoverflow.com/questions/50273130/mypy-error-when-returning-a-generator-expression?noredirect=1#comment87617942_50273130). Versions are Python 3.6.4, mypy 0.600.


Discussion:
Thanks for the report! This should be pretty easy to fix: the bad code is at https://github.com/python/mypy/blob/master/mypy/checkexpr.py#L2231. Would you be interested in sending a PR to fix it?
You mean by adjusting the `typ = ...` lines?

Resolving patch:
diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py
--- a/mypy/checkexpr.py
+++ b/mypy/checkexpr.py
@@ -2232,14 +2232,20 @@ def visit_generator_expr(self, e: GeneratorExpr) -> Type:
         # If any of the comprehensions use async for, the expression will return an async generator
         # object
         if any(e.is_async):
-            typ = 'typing.AsyncIterator'
+            typ = 'typing.AsyncGenerator'
+            # received type is always None in async generator expressions
+            additional_args = [NoneTyp()]  # type: List[Type]
         else:
-            typ = 'typing.Iterator'
-        return self.check_generator_or_comprehension(e, typ, '<generator>')
+            typ = 'typing.Generator'
+            # received type and returned type are None
+            additional_args = [NoneTyp(), NoneTyp()]
+        return self.check_generator_or_comprehension(e, typ, '<generator>',
+                                                     additional_args=additional_args)
 
     def check_generator_or_comprehension(self, gen: GeneratorExpr,
                                          type_name: str,
-                                         id_for_messages: str) -> Type:
+                                         id_for_messages: str,
+                                         additional_args: List[Type] = []) -> Type:
         """Type check a generator expression or a list comprehension."""
         with self.chk.binder.frame_context(can_skip=True, fall_through=0):
             self.check_for_comp(gen)
@@ -2247,12 +2253,12 @@ def check_generator_or_comprehension(self, gen: GeneratorExpr,
             # Infer the type of the list comprehension by using a synthetic generic
             # callable type.
             tvdef = TypeVarDef('T', 'T', -1, [], self.object_type())
-            tv = TypeVarType(tvdef)
+            tv_list = [TypeVarType(tvdef)]  # type: List[Type]
             constructor = CallableType(
-                [tv],
+                tv_list,
                 [nodes.ARG_POS],
                 [None],
-                self.chk.named_generic_type(type_name, [tv]),
+                self.chk.named_generic_type(type_name, tv_list + additional_args),
                 self.chk.named_type('builtins.function'),
                 name=id_for_messages,
                 variables=[tvdef])


Test patch:
diff --git a/test-data/unit/check-async-await.test b/test-data/unit/check-async-await.test
--- a/test-data/unit/check-async-await.test
+++ b/test-data/unit/check-async-await.test
@@ -215,9 +215,9 @@ async def dictcomp(obj: Iterable[Tuple[int, str]]):
 
 async def generatorexp(obj: Iterable[int]):
     lst = (i async for i in asyncify(obj))
-    reveal_type(lst)  # E: Revealed type is 'typing.AsyncIterator[builtins.int*]'
+    reveal_type(lst)  # E: Revealed type is 'typing.AsyncGenerator[builtins.int*, None]'
     lst2 = (i async for i in asyncify(obj) for i in obj)
-    reveal_type(lst2)  # E: Revealed type is 'typing.AsyncIterator[builtins.int*]'
+    reveal_type(lst2)  # E: Revealed type is 'typing.AsyncGenerator[builtins.int*, None]'
 
 [builtins fixtures/async_await.pyi]
 [typing fixtures/typing-full.pyi]
diff --git a/test-data/unit/check-isinstance.test b/test-data/unit/check-isinstance.test
--- a/test-data/unit/check-isinstance.test
+++ b/test-data/unit/check-isinstance.test
@@ -1348,7 +1348,7 @@ l = [x for x in a if isinstance(x, int)]
 g = (x for x in a if isinstance(x, int))
 d = {0: x for x in a if isinstance(x, int)}
 reveal_type(l) # E: Revealed type is 'builtins.list[builtins.int*]'
-reveal_type(g) # E: Revealed type is 'typing.Iterator[builtins.int*]'
+reveal_type(g) # E: Revealed type is 'typing.Generator[builtins.int*, None, None]'
 reveal_type(d) # E: Revealed type is 'builtins.dict[builtins.int*, builtins.int*]'
 [builtins fixtures/isinstancelist.pyi]