diff --git a/mypy/errorcodes.py b/mypy/errorcodes.py index a96f5f723a7d..87c605744960 100644 --- a/mypy/errorcodes.py +++ b/mypy/errorcodes.py @@ -319,5 +319,10 @@ def __hash__(self) -> int: default_enabled=False, ) +MISSING_RETURN_ANNOTATION = ErrorCode( + "missing-return-annotation", "Function has no return type annotation", "Optional" +) + + # This copy will not include any error codes defined later in the plugins. mypy_error_codes = error_codes.copy() diff --git a/mypy/semanal.py b/mypy/semanal.py index 17dc9bfadc1f..792ab35c79bd 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -57,7 +57,7 @@ from mypy import errorcodes as codes, message_registry from mypy.constant_fold import constant_fold_expr -from mypy.errorcodes import PROPERTY_DECORATOR, ErrorCode +from mypy.errorcodes import MISSING_RETURN_ANNOTATION, PROPERTY_DECORATOR, ErrorCode from mypy.errors import Errors, report_internal_error from mypy.exprtotype import TypeTranslationError, expr_to_unanalyzed_type from mypy.message_registry import ErrorMessage @@ -926,6 +926,24 @@ def visit_func_def(self, defn: FuncDef) -> None: with self.inside_except_star_block_set(value=False): self.analyze_func_def(defn) + # Missing return annotation check (optional error code) + from mypy.types import CallableType + + if ( + # Makes sure return type is not specified, ignores lambdas and special cases + isinstance(defn.type, CallableType) + and defn.type.ret_type is None + and any(arg.type_annotation is not None for arg in defn.arguments) + and defn.name != "__init__" + and not defn.is_lambda + and not defn.is_overload + ): + self.msg.fail( + f'Function "{defn.name}" has no return type annotation', + defn, + code=MISSING_RETURN_ANNOTATION, + ) + def function_fullname(self, fullname: str) -> str: if self.current_overload_item is None: return fullname diff --git a/test-data/unit/check-missing-return-annotation.test b/test-data/unit/check-missing-return-annotation.test new file mode 100644 index 000000000000..1c4d74fe6013 --- /dev/null +++ b/test-data/unit/check-missing-return-annotation.test @@ -0,0 +1,8 @@ +[case test_missing_return_annotation_ok] +# flags: --enable-error-code missing-return-annotation +def g(x: int) -> int: + return x + +[case test_missing_return_annotation_off_by_default] +def h(x: int): + return x # no error expected, since code is opt-in