Repository: python/mypy
Pull request: Format types nicely in incorrectly-returning-Any warning
This fixes #3899.

Problem statement:
Error message for incorrectly returning Any does not format types correctly
Consider this contrived example:

```py
from typing import Any, Tuple

typ = Tuple[int, int, int, int, int, int, int, int, int, int, int, int, int,
            int, int, int, int, int, int, int, int, int, int, int, int, int,
            int, int, int, int, int, int, int, int, int, int, int, int, int,
            int, int, int, int, int, int, int, int, int, int, int, int, int,
            int, int, int, int, int, int, int, int, int, int, int, int, int,
            int, int, int, int, int, int, int, int, int, int, int, int, int,
            int, int, int, int, int, int, int, int, int, int, int, int, int]


def foo() -> typ:
    x = None  # type: Any
    return x

foo() + 3
```

`mypy --strict` currently outputs:

```
2.py:15: warning: Returning Any from function with declared return type "Tuple[builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int, builtins.int]"
2.py:17: error: Unsupported operand types for + (tuple(length 91) and "int")
```

The first line should be shortened the same way that the second line is (and were it not to be shortened, each element should be displayed as `int`, not `builtins.int`).

Hints from issue discussion:
This should be easy enough to fix, I think; mypy/checker.py:2018 currently does a direct string format when it should instead use the MessageBuilder format logic.

(There are probably a few other cases where this is happening with other constants, I'll see if I can catch any of those as well.)

Commit message: Format types nicely in incorrectly-returning-Any warning

Patch to review:
diff --git a/mypy/checker.py b/mypy/checker.py
index 2e7943fe48e6..3f1ae83366a6 100644
--- a/mypy/checker.py
+++ b/mypy/checker.py
@@ -2015,7 +2015,7 @@ def check_return_stmt(self, s: ReturnStmt) -> None:
                     # function is not declared to return Any)
                     if (self.options.warn_return_any and
                             not is_proper_subtype(AnyType(TypeOfAny.special_form), return_type)):
-                        self.warn(messages.RETURN_ANY.format(return_type), s)
+                        self.msg.incorrectly_returning_any(return_type, s)
                     return
 
                 # Disallow return expressions in functions declared to return
diff --git a/mypy/messages.py b/mypy/messages.py
index d02b12a4cbde..b8348d7ebf77 100644
--- a/mypy/messages.py
+++ b/mypy/messages.py
@@ -29,7 +29,6 @@
 MISSING_RETURN_STATEMENT = 'Missing return statement'
 INVALID_IMPLICIT_RETURN = 'Implicit return in function which does not return'
 INCOMPATIBLE_RETURN_VALUE_TYPE = 'Incompatible return value type'
-RETURN_ANY = 'Returning Any from function with declared return type "{}"'
 RETURN_VALUE_EXPECTED = 'Return value expected'
 NO_RETURN_EXPECTED = 'Return statement in function which does not return'
 INVALID_EXCEPTION = 'Exception must be derived from BaseException'
@@ -1005,6 +1004,11 @@ def disallowed_any_type(self, typ: Type, context: Context) -> None:
             message = 'Expression type contains "Any" (has type {})'.format(self.format(typ))
         self.fail(message, context)
 
+    def incorrectly_returning_any(self, typ: Type, context: Context) -> None:
+        message = 'Returning Any from function with declared return type {}'.format(
+            self.format(typ))
+        self.warn(message, context)
+
     def untyped_decorated_function(self, typ: Type, context: Context) -> None:
         if isinstance(typ, AnyType):
             self.fail("Function is untyped after decorator transformation", context)
diff --git a/test-data/unit/check-warnings.test b/test-data/unit/check-warnings.test
index c95baec1cc93..d9902ccf2d9d 100644
--- a/test-data/unit/check-warnings.test
+++ b/test-data/unit/check-warnings.test
@@ -141,7 +141,7 @@ from typing import Any
 def g() -> Any: pass
 def f() -> int: return g()
 [out]
-main:4: warning: Returning Any from function with declared return type "builtins.int"
+main:4: warning: Returning Any from function with declared return type "int"
 
 [case testReturnAnySilencedFromTypedFunction]
 # flags: --warn-return-any


Code review comments:
diff_hunk: @@ -1005,6 +1004,11 @@ def disallowed_any_type(self, typ: Type, context: Context) -> None:
             message = 'Expression type contains "Any" (has type {})'.format(self.format(typ))
         self.fail(message, context)
 
+    def incorrectly_returning_any(self, typ: Type, context: Context) -> None:
+        message = 'Returning Any from function with declared return type {}'.format(
path: mypy/messages.py
text: @user1:
This error might sound awkward in situations like:
```
Returning Any from function with declared return type <nothing>
Returning Any from function with declared return type overloaded function
Returning Any from function with declared return type Module
```
I think it will sound better if you say something like
```
Returning Any from function declared to return <nothing>
Returning Any from function declared to return overloaded function
Returning Any from function declared to return Module
```