(self, e: YieldFromExpr, allow_none_return: bool = False)
| 6329 | return ret_type |
| 6330 | |
| 6331 | def visit_yield_from_expr(self, e: YieldFromExpr, allow_none_return: bool = False) -> Type: |
| 6332 | # NOTE: Whether `yield from` accepts an `async def` decorated |
| 6333 | # with `@types.coroutine` (or `@asyncio.coroutine`) depends on |
| 6334 | # whether the generator containing the `yield from` is itself |
| 6335 | # thus decorated. But it accepts a generator regardless of |
| 6336 | # how it's decorated. |
| 6337 | return_type = self.chk.return_types[-1] |
| 6338 | # TODO: What should the context for the sub-expression be? |
| 6339 | # If the containing function has type Generator[X, Y, ...], |
| 6340 | # the context should be Generator[X, Y, T], where T is the |
| 6341 | # context of the 'yield from' itself (but it isn't known). |
| 6342 | subexpr_type = get_proper_type(self.accept(e.expr)) |
| 6343 | |
| 6344 | # Check that the expr is an instance of Iterable and get the type of the iterator produced |
| 6345 | # by __iter__. |
| 6346 | if isinstance(subexpr_type, AnyType): |
| 6347 | iter_type: Type = AnyType(TypeOfAny.from_another_any, source_any=subexpr_type) |
| 6348 | elif self.chk.type_is_iterable(subexpr_type): |
| 6349 | if is_async_def(subexpr_type) and not has_coroutine_decorator(return_type): |
| 6350 | self.chk.msg.yield_from_invalid_operand_type(subexpr_type, e) |
| 6351 | |
| 6352 | any_type = AnyType(TypeOfAny.special_form) |
| 6353 | generic_generator_type = self.chk.named_generic_type( |
| 6354 | "typing.Generator", [any_type, any_type, any_type] |
| 6355 | ) |
| 6356 | generic_generator_type.set_line(e) |
| 6357 | iter_type, _ = self.check_method_call_by_name( |
| 6358 | "__iter__", subexpr_type, [], [], context=generic_generator_type |
| 6359 | ) |
| 6360 | else: |
| 6361 | if not (is_async_def(subexpr_type) and has_coroutine_decorator(return_type)): |
| 6362 | self.chk.msg.yield_from_invalid_operand_type(subexpr_type, e) |
| 6363 | iter_type = AnyType(TypeOfAny.from_error) |
| 6364 | else: |
| 6365 | iter_type = self.check_awaitable_expr( |
| 6366 | subexpr_type, e, message_registry.INCOMPATIBLE_TYPES_IN_YIELD_FROM |
| 6367 | ) |
| 6368 | |
| 6369 | # Check that the iterator's item type matches the type yielded by the Generator function |
| 6370 | # containing this `yield from` expression. |
| 6371 | expected_item_type = self.chk.get_generator_yield_type(return_type, False) |
| 6372 | actual_item_type = self.chk.get_generator_yield_type(iter_type, False) |
| 6373 | |
| 6374 | self.chk.check_subtype( |
| 6375 | actual_item_type, |
| 6376 | expected_item_type, |
| 6377 | e, |
| 6378 | message_registry.INCOMPATIBLE_TYPES_IN_YIELD_FROM, |
| 6379 | "actual type", |
| 6380 | "expected type", |
| 6381 | ) |
| 6382 | |
| 6383 | # Determine the type of the entire yield from expression. |
| 6384 | iter_type = get_proper_type(iter_type) |
| 6385 | expr_type = self.chk.get_generator_return_type(iter_type, is_coroutine=False) |
| 6386 | |
| 6387 | if not allow_none_return and isinstance(get_proper_type(expr_type), NoneType): |
| 6388 | self.chk.msg.does_not_return_value(None, e) |
no test coverage detected