Repository: python/mypy

Issue:
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`).


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.)

Resolving patch:
diff --git a/mypy/checker.py b/mypy/checker.py
--- 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
--- 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 declared to return {}'.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)


Test patch:
diff --git a/test-data/unit/check-warnings.test b/test-data/unit/check-warnings.test
--- a/test-data/unit/check-warnings.test
+++ b/test-data/unit/check-warnings.test
@@ -141,7 +141,22 @@ 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 declared to return "int"
+
+[case testReturnAnyFromTypedFunctionWithSpecificFormatting]
+# flags: --warn-return-any
+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 g() -> Any: pass
+def f() -> typ: return g()
+[out]
+main:11: warning: Returning Any from function declared to return <tuple: 91 items>
 
 [case testReturnAnySilencedFromTypedFunction]
 # flags: --warn-return-any