Skip to content

Commit ae47a3e

Browse files
ddfishergvanrossum
authored andcommitted
Turn --warn-no-return on by default (#2462)
1 parent 76da328 commit ae47a3e

16 files changed

+52
-22
lines changed

mypy/checker.py

+15-11
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
Type, AnyType, CallableType, Void, FunctionLike, Overloaded, TupleType, TypedDictType,
2828
Instance, NoneTyp, ErrorType, strip_type, TypeType,
2929
UnionType, TypeVarId, TypeVarType, PartialType, DeletedType, UninhabitedType, TypeVarDef,
30-
true_only, false_only, function_type
30+
true_only, false_only, function_type, is_named_instance
3131
)
3232
from mypy.sametypes import is_same_type, is_same_types
3333
from mypy.messages import MessageBuilder
@@ -606,20 +606,24 @@ def is_implicit_any(t: Type) -> bool:
606606
self.accept(item.body)
607607
unreachable = self.binder.is_unreachable()
608608

609-
if (self.options.warn_no_return and not unreachable
610-
and not isinstance(self.return_types[-1], (Void, NoneTyp, AnyType))
611-
and (defn.is_coroutine or not defn.is_generator)):
612-
# Control flow fell off the end of a function that was
613-
# declared to return a non-None type.
614-
# Allow functions that are entirely pass/Ellipsis.
615-
if self.is_trivial_body(defn.body):
616-
pass
609+
if (self.options.warn_no_return and not unreachable):
610+
if (defn.is_generator or
611+
is_named_instance(self.return_types[-1], 'typing.AwaitableGenerator')):
612+
return_type = self.get_generator_return_type(self.return_types[-1],
613+
defn.is_coroutine)
617614
else:
618-
if isinstance(self.return_types[-1], UninhabitedType):
615+
return_type = self.return_types[-1]
616+
617+
if (not isinstance(return_type, (Void, NoneTyp, AnyType))
618+
and not self.is_trivial_body(defn.body)):
619+
# Control flow fell off the end of a function that was
620+
# declared to return a non-None type and is not
621+
# entirely pass/Ellipsis.
622+
if isinstance(return_type, UninhabitedType):
619623
# This is a NoReturn function
620624
self.msg.note(messages.INVALID_IMPLICIT_RETURN, defn)
621625
else:
622-
self.msg.note(messages.MISSING_RETURN_STATEMENT, defn)
626+
self.msg.fail(messages.MISSING_RETURN_STATEMENT, defn)
623627

624628
self.return_types.pop()
625629

mypy/main.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,8 @@ def add_invertible_flag(flag: str,
219219
" --check-untyped-defs enabled")
220220
add_invertible_flag('--warn-redundant-casts', default=False, strict_flag=True,
221221
help="warn about casting an expression to its inferred type")
222-
add_invertible_flag('--warn-no-return', default=False,
223-
help="warn about functions that end without returning")
222+
add_invertible_flag('--no-warn-no-return', dest='warn_no_return', default=True,
223+
help="do not warn about functions that end without returning")
224224
add_invertible_flag('--warn-unused-ignores', default=False, strict_flag=True,
225225
help="warn about unneeded '# type: ignore' comments")
226226
add_invertible_flag('--show-error-context', default=True,

mypy/options.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def __init__(self) -> None:
6363
self.warn_redundant_casts = False
6464

6565
# Warn about falling off the end of a function returning non-None
66-
self.warn_no_return = False
66+
self.warn_no_return = True
6767

6868
# Warn about unused '# type: ignore' comments
6969
self.warn_unused_ignores = False

test-data/samples/crawl.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ def close(self, recycle: bool = False) -> None:
319319
self.conn = None
320320

321321
@asyncio.coroutine
322-
def putline(self, line: str) -> Generator[Any, None, None]:
322+
def putline(self, line: str) -> None:
323323
"""Write a line to the connection.
324324
325325
Used for the request line and headers.

test-data/stdlib-samples/3.2/subprocess.py

+1
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,7 @@ def __exit__(self, type: type, value: BaseException,
784784
self.stdin.close()
785785
# Wait for the process to terminate, to avoid zombies.
786786
self.wait()
787+
return False
787788

788789
def __del__(self, _maxsize: int = sys.maxsize,
789790
_active: List['Popen'] = _active) -> None:

test-data/stdlib-samples/3.2/tempfile.py

+4
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ def __stat(fn: str) -> object:
101101
except IOError:
102102
raise _os.error()
103103
f.close()
104+
return None
104105
_stat = __stat
105106

106107
def _exists(fn: str) -> bool:
@@ -421,6 +422,7 @@ def __exit__(self, exc: _Type[BaseException], value: BaseException,
421422
def __exit__(self, exc: _Type[BaseException], value: BaseException,
422423
tb: _Optional[_TracebackType]) -> bool:
423424
self.file.__exit__(exc, value, tb)
425+
return False
424426

425427

426428
def NamedTemporaryFile(mode: str = 'w+b', buffering: int = -1,
@@ -554,6 +556,7 @@ def __enter__(self) -> 'SpooledTemporaryFile':
554556
def __exit__(self, exc: type, value: BaseException,
555557
tb: _TracebackType) -> bool:
556558
self._file.close()
559+
return False
557560

558561
# file protocol
559562
def __iter__(self) -> _Iterable[_Any]:
@@ -690,6 +693,7 @@ def cleanup(self, _warn: bool = False) -> None:
690693
def __exit__(self, exc: type, value: BaseException,
691694
tb: _TracebackType) -> bool:
692695
self.cleanup()
696+
return False
693697

694698
def __del__(self) -> None:
695699
# Issue a ResourceWarning if implicit cleanup needed

test-data/unit/check-async-await.test

+3-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ async def f() -> int:
2020
make_this_not_trivial = 1
2121
[builtins fixtures/async_await.pyi]
2222
[out]
23-
main:2: note: Missing return statement
23+
main:2: error: Missing return statement
2424

2525
[case testAsyncDefReturnWithoutValue]
2626
# flags: --fast-parser
@@ -69,6 +69,7 @@ T = TypeVar('T')
6969
async def f(x: T) -> T:
7070
y = await f(x) # type: int
7171
reveal_type(y)
72+
return x
7273
[out]
7374
main:5: error: Argument 1 to "f" has incompatible type "T"; expected "int"
7475
main:6: error: Revealed type is 'builtins.int'
@@ -113,6 +114,7 @@ async def g() -> int:
113114
return 0
114115
async def f() -> str:
115116
x = await g() # type: str
117+
return x
116118
[builtins fixtures/async_await.pyi]
117119
[out]
118120
main:5: error: Incompatible types in assignment (expression has type "int", variable has type "str")

test-data/unit/check-classes.test

+1
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,7 @@ class A:
838838
def f(self) -> str:
839839
self.x = 1
840840
self.x = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
841+
return ''
841842
[builtins fixtures/property.pyi]
842843
[out]
843844

test-data/unit/check-generics.test

+1
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ class A(Generic[T]):
250250
a = object() # Fail
251251
b = self.f() # type: object
252252
b = self.f()
253+
return None
253254
[out]
254255
main:5: error: Incompatible types in assignment (expression has type "object", variable has type "T")
255256
main:6: error: Incompatible types in assignment (expression has type "object", variable has type "T")

test-data/unit/check-incremental.test

+1
Original file line numberDiff line numberDiff line change
@@ -1553,6 +1553,7 @@ from funcs import callee
15531553
from classes import Outer
15541554
def caller(a: Outer.Inner) -> int:
15551555
callee(a)
1556+
return 0
15561557

15571558
[case testIncrementalLoadsParentAfterChild]
15581559
# cmd: mypy -m r.s

test-data/unit/check-optional.test

+1-1
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ def f() -> None:
493493
def g() -> int:
494494
1 + 1 #
495495
[out]
496-
main:5: note: Missing return statement
496+
main:5: error: Missing return statement
497497

498498
[case testGenericTypeAliasesOptional]
499499
from typing import TypeVar, Generic, Optional

test-data/unit/check-statements.test

+12
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ def f() -> Generator[int, None, str]:
6161
return # E: Return value expected
6262
[out]
6363

64+
[case testNoReturnInGenerator]
65+
from typing import Generator
66+
def f() -> Generator[int, None, str]: # E: Missing return statement
67+
yield 1
68+
[out]
69+
6470
[case testEmptyReturnInNoneTypedGenerator]
6571
from typing import Generator
6672
def f() -> Generator[int, None, None]:
@@ -722,6 +728,7 @@ def f(*a: BaseException) -> int:
722728
except BaseException as err: pass
723729
try: pass
724730
except BaseException as err: f(err)
731+
return 0
725732
x = f()
726733
[builtins fixtures/exception.pyi]
727734

@@ -732,6 +739,7 @@ def f(*a: BaseException) -> int:
732739
x
733740
try: pass
734741
except BaseException as err: f(err)
742+
return 0
735743
x = f()
736744
[builtins fixtures/exception.pyi]
737745

@@ -742,6 +750,7 @@ def f(*a: BaseException) -> int:
742750
try: pass
743751
except BaseException as err: f(err)
744752
x
753+
return 0
745754
x = f()
746755
[builtins fixtures/exception.pyi]
747756

@@ -762,6 +771,7 @@ def f(*arg: BaseException) -> int:
762771
f(err)
763772
b = err.b
764773
reveal_type(b)
774+
return 0
765775
x = f()
766776
[builtins fixtures/exception.pyi]
767777
[out]
@@ -785,6 +795,7 @@ def f(*arg: BaseException) -> int:
785795
f(err)
786796
b = err.b
787797
reveal_type(b)
798+
return 0
788799
x = f()
789800
[builtins fixtures/exception.pyi]
790801
[out]
@@ -808,6 +819,7 @@ def f(*arg: BaseException) -> int:
808819
b = err.b
809820
reveal_type(b)
810821
x
822+
return 0
811823
x = f()
812824
[builtins fixtures/exception.pyi]
813825
[out]

test-data/unit/check-super.test

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class A(B):
1515
a = super().f() # E: Incompatible types in assignment (expression has type "B", variable has type "A")
1616
a = super().g() # E: "g" undefined in superclass
1717
b = super().f()
18+
return a
1819
[out]
1920

2021
[case testAccessingSuperTypeMethodWithArgs]
@@ -85,7 +86,7 @@ class A:
8586
class B(A):
8687
def __new__(cls, x: int, y: str = '') -> 'A':
8788
super().__new__(cls, 1)
88-
super().__new__(cls, 1, '') # E: Too many arguments for "__new__" of "A"
89+
return super().__new__(cls, 1, '') # E: Too many arguments for "__new__" of "A"
8990
B('') # E: Argument 1 to "B" has incompatible type "str"; expected "int"
9091
B(1)
9192
B(1, 'x')

test-data/unit/check-typevar-values.test

+3
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ def f(x: T) -> T:
9999
b = x
100100
a = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
101101
b = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "str")
102+
return x
102103
[out]
103104

104105
[case testIsinstanceAndTypeVarValues]
@@ -107,9 +108,11 @@ T = TypeVar('T', int, str)
107108
def f(x: T) -> T:
108109
if isinstance(x, int):
109110
return 2
111+
return x
110112
def g(x: T) -> T:
111113
if isinstance(x, str):
112114
return ''
115+
return x
113116
def h(x: T) -> T:
114117
if isinstance(x, int):
115118
return '' # E: Incompatible return value type (got "str", expected "int")

test-data/unit/check-warnings.test

+3-3
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def g() -> int:
7171
return 1
7272
[builtins fixtures/list.pyi]
7373
[out]
74-
main:5: note: Missing return statement
74+
main:5: error: Missing return statement
7575

7676
[case testNoReturnWhile]
7777
# flags: --warn-no-return
@@ -95,7 +95,7 @@ def j() -> int:
9595
continue
9696
[builtins fixtures/list.pyi]
9797
[out]
98-
main:7: note: Missing return statement
98+
main:7: error: Missing return statement
9999

100100
[case testNoReturnExcept]
101101
# flags: --warn-no-return
@@ -122,7 +122,7 @@ def h() -> int:
122122
return 1
123123
[builtins fixtures/exception.pyi]
124124
[out]
125-
main:2: note: Missing return statement
125+
main:2: error: Missing return statement
126126

127127
[case testNoReturnEmptyBodyWithDocstring]
128128
def f() -> int:

test-data/unit/typexport-basic.test

+1-1
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ from typing import TypeVar, Generic
314314
T = TypeVar('T')
315315
class A(Generic[T]):
316316
def f(self) -> T:
317-
self.f()
317+
return self.f()
318318
[out]
319319
CallExpr(5) : T`1
320320
MemberExpr(5) : def () -> T`1

0 commit comments

Comments
 (0)