|
169 | 169 | unify_generic_callable, |
170 | 170 | ) |
171 | 171 | from mypy.traverser import TraverserVisitor, all_return_statements, has_return_statement |
| 172 | +from mypy.suggestions import get_return_types |
172 | 173 | from mypy.treetransform import TransformVisitor |
173 | 174 | from mypy.typeanal import check_for_explicit_any, has_any_from_unimported_type, make_optional_type |
174 | 175 | from mypy.typeops import ( |
@@ -1600,6 +1601,38 @@ def check_func_def( |
1600 | 1601 | ): |
1601 | 1602 | self.note(message_registry.EMPTY_BODY_ABSTRACT, defn) |
1602 | 1603 |
|
| 1604 | + # Infer return type from return statements if function has no explicit return type annotation |
| 1605 | + if isinstance(item, FuncDef) and isinstance(typ, CallableType): |
| 1606 | + def is_unannotated_any(t: Type) -> bool: |
| 1607 | + if not isinstance(t, ProperType): |
| 1608 | + return False |
| 1609 | + return isinstance(t, AnyType) and t.type_of_any == TypeOfAny.unannotated |
| 1610 | + |
| 1611 | + ret_type_proper = get_proper_type(typ.ret_type) |
| 1612 | + # Only infer for functions without explicit return type annotations |
| 1613 | + # Skip generators and coroutines as they have special return type handling |
| 1614 | + if ( |
| 1615 | + is_unannotated_any(ret_type_proper) |
| 1616 | + and not defn.is_generator |
| 1617 | + and not defn.is_coroutine |
| 1618 | + and not self.dynamic_funcs[-1] |
| 1619 | + ): |
| 1620 | + # Collect return types from return statements |
| 1621 | + # Merge types from all type maps to get complete picture |
| 1622 | + all_return_types: list[Type] = [] |
| 1623 | + for type_map in self._type_maps: |
| 1624 | + return_types_list = get_return_types(type_map, item) |
| 1625 | + all_return_types.extend(return_types_list) |
| 1626 | + |
| 1627 | + if all_return_types: |
| 1628 | + # Create union of all return types |
| 1629 | + inferred_ret_type = make_simplified_union(all_return_types) |
| 1630 | + # Update the function's return type |
| 1631 | + typ = typ.copy_modified(ret_type=inferred_ret_type) |
| 1632 | + item.type = typ |
| 1633 | + # Update the return_types stack as well |
| 1634 | + self.return_types[-1] = inferred_ret_type |
| 1635 | + |
1603 | 1636 | self.return_types.pop() |
1604 | 1637 |
|
1605 | 1638 | self.binder = old_binder |
|
0 commit comments