Skip to content

Commit 6918ccf

Browse files
ddfishergvanrossum
authored andcommitted
Make mypy --warn-no-return clean (#2332)
1 parent 3f19c13 commit 6918ccf

File tree

6 files changed

+51
-29
lines changed

6 files changed

+51
-29
lines changed

mypy/checker.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ def accept(self, node: Union[Expression, Statement, FuncItem],
259259
return typ
260260

261261
def accept_loop(self, body: Statement, else_body: Statement = None, *,
262-
exit_condition: Expression = None) -> Type:
262+
exit_condition: Expression = None) -> None:
263263
"""Repeatedly type check a loop body until the frame doesn't change.
264264
If exit_condition is set, assume it must be False on exit from the loop.
265265
@@ -298,6 +298,7 @@ def visit_overloaded_func_def(self, defn: OverloadedFuncDef) -> Type:
298298
self.check_method_override(defn)
299299
self.check_inplace_operator_method(defn)
300300
self.check_overlapping_overloads(defn)
301+
return None
301302

302303
def check_overlapping_overloads(self, defn: OverloadedFuncDef) -> None:
303304
for i, item in enumerate(defn.items):
@@ -494,10 +495,11 @@ def visit_func_def(self, defn: FuncDef) -> Type:
494495
messages.INCOMPATIBLE_REDEFINITION,
495496
'redefinition with type',
496497
'original type')
498+
return None
497499

498500
def check_func_item(self, defn: FuncItem,
499501
type_override: CallableType = None,
500-
name: str = None) -> Type:
502+
name: str = None) -> None:
501503
"""Type check a function.
502504
503505
If type_override is provided, use it as the function type.
@@ -994,6 +996,7 @@ def visit_class_def(self, defn: ClassDef) -> Type:
994996
self.check_multiple_inheritance(typ)
995997
self.leave_partial_types()
996998
self.errors.pop_type()
999+
return None
9971000

9981001
def check_multiple_inheritance(self, typ: TypeInfo) -> None:
9991002
"""Check for multiple inheritance related errors."""
@@ -1051,11 +1054,13 @@ def check_compatibility(self, name: str, base1: TypeInfo,
10511054

10521055
def visit_import_from(self, node: ImportFrom) -> Type:
10531056
self.check_import(node)
1057+
return None
10541058

10551059
def visit_import_all(self, node: ImportAll) -> Type:
10561060
self.check_import(node)
1061+
return None
10571062

1058-
def check_import(self, node: ImportBase) -> Type:
1063+
def check_import(self, node: ImportBase) -> None:
10591064
for assign in node.assignments:
10601065
lvalue = assign.lvalues[0]
10611066
lvalue_type, _, __ = self.check_lvalue(lvalue)
@@ -1079,6 +1084,7 @@ def visit_block(self, b: Block) -> Type:
10791084
if self.binder.is_unreachable():
10801085
break
10811086
self.accept(s)
1087+
return None
10821088

10831089
def visit_assignment_stmt(self, s: AssignmentStmt) -> Type:
10841090
"""Type check an assignment statement.
@@ -1095,6 +1101,7 @@ def visit_assignment_stmt(self, s: AssignmentStmt) -> Type:
10951101
rvalue = self.temp_node(self.type_map[s.rvalue], s)
10961102
for lv in s.lvalues[:-1]:
10971103
self.check_assignment(lv, rvalue, s.type is None)
1104+
return None
10981105

10991106
def check_assignment(self, lvalue: Lvalue, rvalue: Expression, infer_lvalue_type: bool = True,
11001107
new_syntax: bool = False) -> None:
@@ -1512,11 +1519,13 @@ def try_infer_partial_type_from_indexed_assignment(
15121519

15131520
def visit_expression_stmt(self, s: ExpressionStmt) -> Type:
15141521
self.accept(s.expr)
1522+
return None
15151523

15161524
def visit_return_stmt(self, s: ReturnStmt) -> Type:
15171525
"""Type check a return statement."""
15181526
self.check_return_stmt(s)
15191527
self.binder.unreachable()
1528+
return None
15201529

15211530
def check_return_stmt(self, s: ReturnStmt) -> None:
15221531
if self.is_within_function():
@@ -1586,6 +1595,7 @@ def visit_while_stmt(self, s: WhileStmt) -> Type:
15861595
"""Type check a while statement."""
15871596
self.accept_loop(IfStmt([s.expr], [s.body], None), s.else_body,
15881597
exit_condition=s.expr)
1598+
return None
15891599

15901600
def visit_operator_assignment_stmt(self,
15911601
s: OperatorAssignmentStmt) -> Type:
@@ -1600,6 +1610,7 @@ def visit_operator_assignment_stmt(self,
16001610
else:
16011611
if not is_subtype(rvalue_type, lvalue_type):
16021612
self.msg.incompatible_operator_assignment(s.op, s)
1613+
return None
16031614

16041615
def visit_assert_stmt(self, s: AssertStmt) -> Type:
16051616
self.accept(s.expr)
@@ -1608,6 +1619,7 @@ def visit_assert_stmt(self, s: AssertStmt) -> Type:
16081619
true_map, _ = self.find_isinstance_check(s.expr)
16091620

16101621
self.push_type_map(true_map)
1622+
return None
16111623

16121624
def visit_raise_stmt(self, s: RaiseStmt) -> Type:
16131625
"""Type check a raise statement."""
@@ -1616,6 +1628,7 @@ def visit_raise_stmt(self, s: RaiseStmt) -> Type:
16161628
if s.from_expr:
16171629
self.type_check_raise(s.from_expr, s, True)
16181630
self.binder.unreachable()
1631+
return None
16191632

16201633
def type_check_raise(self, e: Expression, s: RaiseStmt,
16211634
optional: bool = False) -> None:
@@ -1765,6 +1778,7 @@ def visit_for_stmt(self, s: ForStmt) -> Type:
17651778
item_type = self.analyze_iterable_item_type(s.expr)
17661779
self.analyze_index_variables(s.index, item_type, s)
17671780
self.accept_loop(s.body, s.else_body)
1781+
return None
17681782

17691783
def analyze_async_iterable_item_type(self, expr: Expression) -> Type:
17701784
"""Analyse async iterable expression and return iterator item type."""
@@ -1878,6 +1892,7 @@ def visit_decorator(self, e: Decorator) -> Type:
18781892
e.var.is_ready = True
18791893
if e.func.is_property:
18801894
self.check_incompatible_property_override(e)
1895+
return None
18811896

18821897
def check_incompatible_property_override(self, e: Decorator) -> None:
18831898
if not e.var.is_settable_property and e.func.info is not None:
@@ -1898,6 +1913,7 @@ def visit_with_stmt(self, s: WithStmt) -> Type:
18981913
else:
18991914
self.check_with_item(expr, target)
19001915
self.accept(s.body)
1916+
return None
19011917

19021918
def check_async_with_item(self, expr: Expression, target: Expression) -> None:
19031919
echk = self.expr_checker
@@ -1933,6 +1949,7 @@ def visit_print_stmt(self, s: PrintStmt) -> Type:
19331949
if not isinstance(target_type, NoneTyp):
19341950
# TODO: Also verify the type of 'write'.
19351951
self.expr_checker.analyze_external_member_access('write', target_type, s.target)
1952+
return None
19361953

19371954
#
19381955
# Expressions

mypy/checkexpr.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1616,6 +1616,7 @@ def analyze_super(self, e: SuperExpr, is_lvalue: bool) -> Type:
16161616
not_ready_callback=self.not_ready_callback,
16171617
msg=self.msg, override_info=base, chk=self.chk,
16181618
original_type=declared_self)
1619+
assert False, 'unreachable'
16191620
else:
16201621
# Invalid super. This has been reported by the semantic analyzer.
16211622
return AnyType()

mypy/parse.py

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
from mypy import experiments
4141

4242

43+
class ParseError(Exception): pass
44+
45+
4346
precedence = {
4447
'**': 16,
4548
'-u': 15, '+u': 15, '~': 15, # unary operators (-, + and ~)
@@ -236,7 +239,7 @@ def parse_import_from(self) -> ImportBase:
236239
node = None # type: ImportBase
237240
if self.current_str() == '*':
238241
if name == '__future__':
239-
self.parse_error()
242+
raise self.parse_error()
240243
# An import all from a module node:
241244
self.skip()
242245
node = ImportAll(name, relative)
@@ -402,8 +405,7 @@ def is_no_type_check_decorator(self, expr: Expression) -> bool:
402405
elif isinstance(expr, MemberExpr):
403406
if isinstance(expr.expr, NameExpr):
404407
return expr.expr.name == 'typing' and expr.name == 'no_type_check'
405-
else:
406-
return False
408+
return False
407409

408410
def parse_function(self, no_type_checks: bool = False) -> FuncDef:
409411
def_tok = self.expect('def')
@@ -628,7 +630,7 @@ def parse_arg_list(self, allow_signature: bool = True,
628630
elif self.current_str() in ['*', '**']:
629631
if bare_asterisk_before == len(args):
630632
# named arguments must follow bare *
631-
self.parse_error()
633+
raise self.parse_error()
632634

633635
arg = self.parse_asterisk_arg(
634636
allow_signature,
@@ -790,6 +792,8 @@ def parse_parameter_annotation(self) -> Expression:
790792
if self.current_str() == ':':
791793
self.skip()
792794
return self.parse_expression(precedence[','])
795+
else:
796+
return None
793797

794798
def parse_arg_type(self, allow_signature: bool) -> Type:
795799
if self.current_str() == ':' and allow_signature:
@@ -987,7 +991,7 @@ def parse_return_stmt(self) -> ReturnStmt:
987991
expr = None
988992
current = self.current()
989993
if current.string == 'yield':
990-
self.parse_error()
994+
raise self.parse_error()
991995
if not isinstance(current, Break):
992996
expr = self.parse_expression()
993997
node = ReturnStmt(expr)
@@ -1243,10 +1247,10 @@ def parse_print_stmt(self) -> PrintStmt:
12431247
if self.current_str() == ',':
12441248
self.skip()
12451249
if isinstance(self.current(), Break):
1246-
self.parse_error()
1250+
raise self.parse_error()
12471251
else:
12481252
if not isinstance(self.current(), Break):
1249-
self.parse_error()
1253+
raise self.parse_error()
12501254
comma = False
12511255
while not isinstance(self.current(), Break):
12521256
args.append(self.parse_expression(precedence[',']))
@@ -1321,7 +1325,7 @@ def parse_expression(self, prec: int = 0, star_expr_allowed: bool = False) -> Ex
13211325
expr = self.parse_ellipsis()
13221326
else:
13231327
# Invalid expression.
1324-
self.parse_error()
1328+
raise self.parse_error()
13251329

13261330
# Set the line of the expression node, if not specified. This
13271331
# simplifies recording the line number as not every node type needs to
@@ -1496,7 +1500,7 @@ def parse_dict_or_set_expr(self) -> Union[SetComprehension, SetExpr,
14961500
elif self.current_str() == 'for' and items == []:
14971501
return self.parse_set_comprehension(key)
14981502
elif self.current_str() != ':':
1499-
self.parse_error()
1503+
raise self.parse_error()
15001504
colon = self.expect(':')
15011505
value = self.parse_expression(precedence['<for>'])
15021506
if self.current_str() == 'for' and items == []:
@@ -1666,7 +1670,7 @@ def parse_arg_expr(self) -> Tuple[List[Expression], List[int], List[str]]:
16661670
kinds.append(nodes.ARG_POS)
16671671
names.append(None)
16681672
else:
1669-
self.parse_error()
1673+
raise self.parse_error()
16701674
args.append(self.parse_expression(precedence[',']))
16711675
if self.current_str() != ',':
16721676
break
@@ -1734,7 +1738,7 @@ def parse_bin_op_expr(self, left: Expression, prec: int) -> OpExpr:
17341738
op_str = op.string
17351739
if op_str == '~':
17361740
self.ind -= 1
1737-
self.parse_error()
1741+
raise self.parse_error()
17381742
right = self.parse_expression(prec)
17391743
node = OpExpr(op_str, left, right)
17401744
return node
@@ -1751,7 +1755,7 @@ def parse_comparison_expr(self, left: Expression, prec: int) -> ComparisonExpr:
17511755
op_str = 'not in'
17521756
self.skip()
17531757
else:
1754-
self.parse_error()
1758+
raise self.parse_error()
17551759
elif op_str == 'is' and self.current_str() == 'not':
17561760
op_str = 'is not'
17571761
self.skip()
@@ -1818,7 +1822,7 @@ def expect(self, string: str) -> Token:
18181822
self.ind += 1
18191823
return self.tok[self.ind - 1]
18201824
else:
1821-
self.parse_error()
1825+
raise self.parse_error()
18221826

18231827
def expect_indent(self) -> Token:
18241828
if isinstance(self.current(), Indent):
@@ -1836,7 +1840,7 @@ def expect_type(self, typ: type) -> Token:
18361840
self.ind += 1
18371841
return current
18381842
else:
1839-
self.parse_error()
1843+
raise self.parse_error()
18401844

18411845
def expect_break(self) -> Token:
18421846
return self.expect_type(Break)
@@ -1850,9 +1854,9 @@ def current_str(self) -> str:
18501854
def peek(self) -> Token:
18511855
return self.tok[self.ind + 1]
18521856

1853-
def parse_error(self) -> None:
1857+
def parse_error(self) -> ParseError:
18541858
self.parse_error_at(self.current())
1855-
raise ParseError()
1859+
return ParseError()
18561860

18571861
def parse_error_at(self, tok: Token, skip: bool = True, reason: Optional[str] = None) -> None:
18581862
msg = ''
@@ -1936,9 +1940,6 @@ def parse_type_comment(self, token: Token, signature: bool) -> Type:
19361940
return None
19371941

19381942

1939-
class ParseError(Exception): pass
1940-
1941-
19421943
def token_repr(tok: Token) -> str:
19431944
"""Return a representation of a token for use in parse error messages."""
19441945
if isinstance(tok, Break):

mypy/parsetype.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def parse_type(self) -> Type:
7373
raise TypeParseError(e.token, self.ind)
7474
return result
7575
else:
76-
self.parse_error()
76+
raise self.parse_error()
7777

7878
def parse_parens(self) -> Type:
7979
self.expect('(')
@@ -166,23 +166,23 @@ def expect(self, string: str) -> Token:
166166
self.ind += 1
167167
return self.tok[self.ind - 1]
168168
else:
169-
self.parse_error()
169+
raise self.parse_error()
170170

171171
def expect_type(self, typ: type) -> Token:
172172
if isinstance(self.current_token(), typ):
173173
self.ind += 1
174174
return self.tok[self.ind - 1]
175175
else:
176-
self.parse_error()
176+
raise self.parse_error()
177177

178178
def current_token(self) -> Token:
179179
return self.tok[self.ind]
180180

181181
def current_token_str(self) -> str:
182182
return self.current_token().string
183183

184-
def parse_error(self) -> None:
185-
raise TypeParseError(self.tok[self.ind], self.ind)
184+
def parse_error(self) -> TypeParseError:
185+
return TypeParseError(self.tok[self.ind], self.ind)
186186

187187

188188
def parse_str_as_type(typestr: str, line: int) -> Type:

mypy/semanal.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2094,6 +2094,8 @@ def is_valid_del_target(self, s: Expression) -> bool:
20942094
return True
20952095
elif isinstance(s, TupleExpr):
20962096
return all(self.is_valid_del_target(item) for item in s.items)
2097+
else:
2098+
return False
20972099

20982100
def visit_global_decl(self, g: GlobalDecl) -> None:
20992101
for name in g.names:

runtests.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,9 @@ def add_basic(driver: Driver) -> None:
176176

177177

178178
def add_selftypecheck(driver: Driver) -> None:
179-
driver.add_mypy_package('package mypy', 'mypy')
180-
driver.add_mypy_package('package mypy', 'mypy', '--config-file', 'mypy_strict_optional.ini')
179+
driver.add_mypy_package('package mypy', 'mypy', '--fast-parser', '--warn-no-return')
180+
driver.add_mypy_package('package mypy', 'mypy', '--fast-parser',
181+
'--config-file', 'mypy_strict_optional.ini')
181182

182183

183184
def find_files(base: str, prefix: str = '', suffix: str = '') -> List[str]:

0 commit comments

Comments
 (0)