Skip to content

Commit 1655b0c

Browse files
atugushevikonsthauntsaninja
authored
Reword the error message related to void functions (#15876)
Fixes #3226. Aims to provide better assistance to users who may be confused when their void functions technically return None. Co-authored-by: Ilya Priven <ilya.konstantinov@gmail.com> Co-authored-by: hauntsaninja <hauntsaninja@gmail.com>
1 parent 6884aa2 commit 1655b0c

File tree

10 files changed

+54
-61
lines changed

10 files changed

+54
-61
lines changed

docs/source/error_code_list.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -741,7 +741,7 @@ returns ``None``:
741741
# OK: we don't do anything with the return value
742742
f()
743743
744-
# Error: "f" does not return a value [func-returns-value]
744+
# Error: "f" does not return a value (it only ever returns None) [func-returns-value]
745745
if f():
746746
print("not false")
747747

mypy/messages.py

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,18 +1021,11 @@ def duplicate_argument_value(self, callee: CallableType, index: int, context: Co
10211021

10221022
def does_not_return_value(self, callee_type: Type | None, context: Context) -> None:
10231023
"""Report an error about use of an unusable type."""
1024-
name: str | None = None
10251024
callee_type = get_proper_type(callee_type)
1026-
if isinstance(callee_type, FunctionLike):
1027-
name = callable_name(callee_type)
1028-
if name is not None:
1029-
self.fail(
1030-
f"{capitalize(name)} does not return a value",
1031-
context,
1032-
code=codes.FUNC_RETURNS_VALUE,
1033-
)
1034-
else:
1035-
self.fail("Function does not return a value", context, code=codes.FUNC_RETURNS_VALUE)
1025+
callee_name = callable_name(callee_type) if isinstance(callee_type, FunctionLike) else None
1026+
name = callee_name or "Function"
1027+
message = f"{name} does not return a value (it only ever returns None)"
1028+
self.fail(message, context, code=codes.FUNC_RETURNS_VALUE)
10361029

10371030
def deleted_as_rvalue(self, typ: DeletedType, context: Context) -> None:
10381031
"""Report an error about using an deleted type as an rvalue."""

test-data/unit/check-errorcodes.test

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -553,15 +553,15 @@ from typing import Callable
553553

554554
def f() -> None: pass
555555

556-
x = f() # E: "f" does not return a value [func-returns-value]
556+
x = f() # E: "f" does not return a value (it only ever returns None) [func-returns-value]
557557

558558
class A:
559559
def g(self) -> None: pass
560560

561-
y = A().g() # E: "g" of "A" does not return a value [func-returns-value]
561+
y = A().g() # E: "g" of "A" does not return a value (it only ever returns None) [func-returns-value]
562562

563563
c: Callable[[], None]
564-
z = c() # E: Function does not return a value [func-returns-value]
564+
z = c() # E: Function does not return a value (it only ever returns None) [func-returns-value]
565565

566566
[case testErrorCodeInstantiateAbstract]
567567
from abc import abstractmethod

test-data/unit/check-expressions.test

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,15 +1079,15 @@ class A:
10791079
a: A
10801080
o: object
10811081
if int():
1082-
a = f() # E: "f" does not return a value
1082+
a = f() # E: "f" does not return a value (it only ever returns None)
10831083
if int():
1084-
o = a() # E: Function does not return a value
1084+
o = a() # E: Function does not return a value (it only ever returns None)
10851085
if int():
1086-
o = A().g(a) # E: "g" of "A" does not return a value
1086+
o = A().g(a) # E: "g" of "A" does not return a value (it only ever returns None)
10871087
if int():
1088-
o = A.g(a, a) # E: "g" of "A" does not return a value
1089-
A().g(f()) # E: "f" does not return a value
1090-
x: A = f() # E: "f" does not return a value
1088+
o = A.g(a, a) # E: "g" of "A" does not return a value (it only ever returns None)
1089+
A().g(f()) # E: "f" does not return a value (it only ever returns None)
1090+
x: A = f() # E: "f" does not return a value (it only ever returns None)
10911091
f()
10921092
A().g(a)
10931093
[builtins fixtures/tuple.pyi]
@@ -1096,15 +1096,15 @@ A().g(a)
10961096
import typing
10971097
def f() -> None: pass
10981098

1099-
if f(): # E: "f" does not return a value
1099+
if f(): # E: "f" does not return a value (it only ever returns None)
11001100
pass
1101-
elif f(): # E: "f" does not return a value
1101+
elif f(): # E: "f" does not return a value (it only ever returns None)
11021102
pass
1103-
while f(): # E: "f" does not return a value
1103+
while f(): # E: "f" does not return a value (it only ever returns None)
11041104
pass
11051105
def g() -> object:
1106-
return f() # E: "f" does not return a value
1107-
raise f() # E: "f" does not return a value
1106+
return f() # E: "f" does not return a value (it only ever returns None)
1107+
raise f() # E: "f" does not return a value (it only ever returns None)
11081108
[builtins fixtures/exception.pyi]
11091109

11101110
[case testNoneReturnTypeWithExpressions]
@@ -1115,13 +1115,13 @@ class A:
11151115
def __add__(self, x: 'A') -> 'A': pass
11161116

11171117
a: A
1118-
[f()] # E: "f" does not return a value
1119-
f() + a # E: "f" does not return a value
1120-
a + f() # E: "f" does not return a value
1121-
f() == a # E: "f" does not return a value
1122-
a != f() # E: "f" does not return a value
1118+
[f()] # E: "f" does not return a value (it only ever returns None)
1119+
f() + a # E: "f" does not return a value (it only ever returns None)
1120+
a + f() # E: "f" does not return a value (it only ever returns None)
1121+
f() == a # E: "f" does not return a value (it only ever returns None)
1122+
a != f() # E: "f" does not return a value (it only ever returns None)
11231123
cast(A, f())
1124-
f().foo # E: "f" does not return a value
1124+
f().foo # E: "f" does not return a value (it only ever returns None)
11251125
[builtins fixtures/list.pyi]
11261126

11271127
[case testNoneReturnTypeWithExpressions2]
@@ -1134,14 +1134,14 @@ class A:
11341134

11351135
a: A
11361136
b: bool
1137-
f() in a # E: "f" does not return a value # E: Unsupported right operand type for in ("A")
1138-
a < f() # E: "f" does not return a value
1139-
f() <= a # E: "f" does not return a value
1140-
a in f() # E: "f" does not return a value
1141-
-f() # E: "f" does not return a value
1142-
not f() # E: "f" does not return a value
1143-
f() and b # E: "f" does not return a value
1144-
b or f() # E: "f" does not return a value
1137+
f() in a # E: "f" does not return a value (it only ever returns None) # E: Unsupported right operand type for in ("A")
1138+
a < f() # E: "f" does not return a value (it only ever returns None)
1139+
f() <= a # E: "f" does not return a value (it only ever returns None)
1140+
a in f() # E: "f" does not return a value (it only ever returns None)
1141+
-f() # E: "f" does not return a value (it only ever returns None)
1142+
not f() # E: "f" does not return a value (it only ever returns None)
1143+
f() and b # E: "f" does not return a value (it only ever returns None)
1144+
b or f() # E: "f" does not return a value (it only ever returns None)
11451145
[builtins fixtures/bool.pyi]
11461146

11471147

@@ -1441,7 +1441,7 @@ if int():
14411441
[case testConditionalExpressionWithEmptyCondition]
14421442
import typing
14431443
def f() -> None: pass
1444-
x = 1 if f() else 2 # E: "f" does not return a value
1444+
x = 1 if f() else 2 # E: "f" does not return a value (it only ever returns None)
14451445

14461446
[case testConditionalExpressionWithSubtyping]
14471447
import typing
@@ -1504,7 +1504,7 @@ from typing import List, Union
15041504
x = []
15051505
y = ""
15061506
x.append(y) if bool() else x.append(y)
1507-
z = x.append(y) if bool() else x.append(y) # E: "append" of "list" does not return a value
1507+
z = x.append(y) if bool() else x.append(y) # E: "append" of "list" does not return a value (it only ever returns None)
15081508
[builtins fixtures/list.pyi]
15091509

15101510
-- Special cases
@@ -1604,7 +1604,7 @@ def f(x: int) -> None:
16041604
[builtins fixtures/for.pyi]
16051605
[out]
16061606
main:1: error: The return type of a generator function should be "Generator" or one of its supertypes
1607-
main:2: error: "f" does not return a value
1607+
main:2: error: "f" does not return a value (it only ever returns None)
16081608
main:2: error: Argument 1 to "f" has incompatible type "str"; expected "int"
16091609

16101610
[case testYieldExpressionWithNone]
@@ -1624,7 +1624,7 @@ from typing import Iterator
16241624
def f() -> Iterator[int]:
16251625
yield 5
16261626
def g() -> Iterator[int]:
1627-
a = yield from f() # E: Function does not return a value
1627+
a = yield from f() # E: Function does not return a value (it only ever returns None)
16281628

16291629
[case testYieldFromGeneratorHasValue]
16301630
from typing import Iterator, Generator
@@ -1639,12 +1639,12 @@ def g() -> Iterator[int]:
16391639
[case testYieldFromTupleExpression]
16401640
from typing import Generator
16411641
def g() -> Generator[int, None, None]:
1642-
x = yield from () # E: Function does not return a value
1643-
x = yield from (0, 1, 2) # E: Function does not return a value
1642+
x = yield from () # E: Function does not return a value (it only ever returns None)
1643+
x = yield from (0, 1, 2) # E: Function does not return a value (it only ever returns None)
16441644
x = yield from (0, "ERROR") # E: Incompatible types in "yield from" (actual type "object", expected type "int") \
1645-
# E: Function does not return a value
1645+
# E: Function does not return a value (it only ever returns None)
16461646
x = yield from ("ERROR",) # E: Incompatible types in "yield from" (actual type "str", expected type "int") \
1647-
# E: Function does not return a value
1647+
# E: Function does not return a value (it only ever returns None)
16481648
[builtins fixtures/tuple.pyi]
16491649

16501650
-- dict(...)

test-data/unit/check-functions.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ if int():
250250
if int():
251251
f = o # E: Incompatible types in assignment (expression has type "object", variable has type "Callable[[], None]")
252252
if int():
253-
f = f() # E: Function does not return a value
253+
f = f() # E: Function does not return a value (it only ever returns None)
254254

255255
if int():
256256
f = f

test-data/unit/check-inference.test

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ class B: pass
3333
[case testLvarInitializedToVoid]
3434
import typing
3535
def f() -> None:
36-
a = g() # E: "g" does not return a value
37-
#b, c = g() # "g" does not return a value TODO
36+
a = g() # E: "g" does not return a value (it only ever returns None)
37+
#b, c = g() # "g" does not return a value (it only ever returns None) TODO
3838

3939
def g() -> None: pass
4040
[out]
@@ -1180,7 +1180,7 @@ for e, f in [[]]: # E: Need type annotation for "e" \
11801180
[case testForStatementInferenceWithVoid]
11811181
def f() -> None: pass
11821182

1183-
for x in f(): # E: "f" does not return a value
1183+
for x in f(): # E: "f" does not return a value (it only ever returns None)
11841184
pass
11851185
[builtins fixtures/for.pyi]
11861186

@@ -2118,7 +2118,7 @@ arr = []
21182118
arr.append(arr.append(1))
21192119
[builtins fixtures/list.pyi]
21202120
[out]
2121-
main:3: error: "append" of "list" does not return a value
2121+
main:3: error: "append" of "list" does not return a value (it only ever returns None)
21222122

21232123
-- Multipass
21242124
-- ---------

test-data/unit/check-optional.test

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -361,9 +361,9 @@ def f() -> None:
361361
def g(x: Optional[int]) -> int:
362362
pass
363363

364-
x = f() # E: "f" does not return a value
365-
f() + 1 # E: "f" does not return a value
366-
g(f()) # E: "f" does not return a value
364+
x = f() # E: "f" does not return a value (it only ever returns None)
365+
f() + 1 # E: "f" does not return a value (it only ever returns None)
366+
g(f()) # E: "f" does not return a value (it only ever returns None)
367367

368368
[case testEmptyReturn]
369369
def f() -> None:

test-data/unit/check-tuples.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,8 @@ class C(B): pass
169169
import typing
170170
def f() -> None: pass
171171

172-
(None, f()) # E: "f" does not return a value
173-
(f(), None) # E: "f" does not return a value
172+
(None, f()) # E: "f" does not return a value (it only ever returns None)
173+
(f(), None) # E: "f" does not return a value (it only ever returns None)
174174
[builtins fixtures/tuple.pyi]
175175

176176

test-data/unit/check-varargs.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ c: C
5252

5353
f(c) # E: Argument 1 to "f" has incompatible type "C"; expected "A"
5454
f(a, b, c) # E: Argument 3 to "f" has incompatible type "C"; expected "A"
55-
f(g()) # E: "g" does not return a value
56-
f(a, g()) # E: "g" does not return a value
55+
f(g()) # E: "g" does not return a value (it only ever returns None)
56+
f(a, g()) # E: "g" does not return a value (it only ever returns None)
5757
f()
5858
f(a)
5959
f(b)

test-data/unit/pythoneval-asyncio.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ try:
261261
finally:
262262
loop.close()
263263
[out]
264-
_program.py:11: error: Function does not return a value
264+
_program.py:11: error: Function does not return a value (it only ever returns None)
265265

266266
[case testErrorReturnIsNotTheSameType]
267267
from typing import Any

0 commit comments

Comments
 (0)