Skip to content

Commit 517ff28

Browse files
committed
Decouple warning and skipping unreachable code
1 parent 2ab8849 commit 517ff28

10 files changed

+114
-63
lines changed

mypy/checker.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -462,14 +462,14 @@ def check_first_pass(self) -> None:
462462
with self.tscope.module_scope(self.tree.fullname):
463463
with self.enter_partial_types(), self.binder.top_frame_context():
464464
for d in self.tree.defs:
465-
if (
466-
self.binder.is_unreachable()
467-
and self.should_report_unreachable_issues()
468-
and not self.is_raising_or_empty(d)
469-
):
470-
self.msg.unreachable_statement(d)
471-
break
472-
self.accept(d)
465+
if self.binder.is_unreachable():
466+
if not self.should_report_unreachable_issues():
467+
break
468+
if not self.is_noop_for_reachability(d):
469+
self.msg.unreachable_statement(d)
470+
break
471+
else:
472+
self.accept(d)
473473

474474
assert not self.current_node_deferred
475475

@@ -2678,10 +2678,13 @@ def visit_block(self, b: Block) -> None:
26782678
return
26792679
for s in b.body:
26802680
if self.binder.is_unreachable():
2681-
if self.should_report_unreachable_issues() and not self.is_raising_or_empty(s):
2681+
if not self.should_report_unreachable_issues():
2682+
break
2683+
if not self.is_noop_for_reachability(s):
26822684
self.msg.unreachable_statement(s)
2683-
break
2684-
self.accept(s)
2685+
break
2686+
else:
2687+
self.accept(s)
26852688

26862689
def should_report_unreachable_issues(self) -> bool:
26872690
return (
@@ -2691,11 +2694,11 @@ def should_report_unreachable_issues(self) -> bool:
26912694
and not self.binder.is_unreachable_warning_suppressed()
26922695
)
26932696

2694-
def is_raising_or_empty(self, s: Statement) -> bool:
2697+
def is_noop_for_reachability(self, s: Statement) -> bool:
26952698
"""Returns 'true' if the given statement either throws an error of some kind
26962699
or is a no-op.
26972700
2698-
We use this function mostly while handling the '--warn-unreachable' flag. When
2701+
We use this function while handling the '--warn-unreachable' flag. When
26992702
that flag is present, we normally report an error on any unreachable statement.
27002703
But if that statement is just something like a 'pass' or a just-in-case 'assert False',
27012704
reporting an error would be annoying.

test-data/unit/check-classes.test

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7684,10 +7684,14 @@ class D:
76847684
def __new__(cls) -> NoReturn: ...
76857685
def __init__(self) -> NoReturn: ...
76867686

7687-
reveal_type(A()) # N: Revealed type is "<nothing>"
7688-
reveal_type(B()) # N: Revealed type is "<nothing>"
7689-
reveal_type(C()) # N: Revealed type is "<nothing>"
7690-
reveal_type(D()) # N: Revealed type is "<nothing>"
7687+
if object():
7688+
reveal_type(A()) # N: Revealed type is "<nothing>"
7689+
if object():
7690+
reveal_type(B()) # N: Revealed type is "<nothing>"
7691+
if object():
7692+
reveal_type(C()) # N: Revealed type is "<nothing>"
7693+
if object():
7694+
reveal_type(D()) # N: Revealed type is "<nothing>"
76917695

76927696
[case testOverloadedNewAndInitNoReturn]
76937697
from typing import NoReturn, overload
@@ -7726,13 +7730,20 @@ class D:
77267730
def __init__(self, a: int) -> None: ...
77277731
def __init__(self, a: int = ...) -> None: ...
77287732

7729-
reveal_type(A()) # N: Revealed type is "<nothing>"
7733+
if object():
7734+
reveal_type(A()) # N: Revealed type is "<nothing>"
77307735
reveal_type(A(1)) # N: Revealed type is "__main__.A"
7731-
reveal_type(B()) # N: Revealed type is "<nothing>"
7736+
7737+
if object():
7738+
reveal_type(B()) # N: Revealed type is "<nothing>"
77327739
reveal_type(B(1)) # N: Revealed type is "__main__.B"
7733-
reveal_type(C()) # N: Revealed type is "<nothing>"
7740+
7741+
if object():
7742+
reveal_type(C()) # N: Revealed type is "<nothing>"
77347743
reveal_type(C(1)) # N: Revealed type is "__main__.C"
7735-
reveal_type(D()) # N: Revealed type is "<nothing>"
7744+
7745+
if object():
7746+
reveal_type(D()) # N: Revealed type is "<nothing>"
77367747
reveal_type(D(1)) # N: Revealed type is "__main__.D"
77377748

77387749
[case testClassScopeImportWithWrapperAndError]

test-data/unit/check-fastparse.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,8 +228,8 @@ def g(): # E: Type signature has too many arguments
228228
assert 1, 2
229229
assert (1, 2) # E: Assertion is always true, perhaps remove parentheses?
230230
assert (1, 2), 3 # E: Assertion is always true, perhaps remove parentheses?
231-
assert ()
232231
assert (1,) # E: Assertion is always true, perhaps remove parentheses?
232+
assert ()
233233
[builtins fixtures/tuple.pyi]
234234

235235
[case testFastParseAssertMessage]

test-data/unit/check-incremental.test

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5413,7 +5413,8 @@ reveal_type(z)
54135413
[out]
54145414
tmp/c.py:2: note: Revealed type is "a.<subclass of "A" and "B">"
54155415
[out2]
5416-
tmp/c.py:2: note: Revealed type is "a.A"
5416+
tmp/b.py:2: error: Cannot determine type of "y"
5417+
tmp/c.py:2: note: Revealed type is "Any"
54175418

54185419
[case testIsInstanceAdHocIntersectionIncrementalUnreachaableToIntersection]
54195420
import c
@@ -5444,7 +5445,8 @@ from b import z
54445445
reveal_type(z)
54455446
[builtins fixtures/isinstance.pyi]
54465447
[out]
5447-
tmp/c.py:2: note: Revealed type is "a.A"
5448+
tmp/b.py:2: error: Cannot determine type of "y"
5449+
tmp/c.py:2: note: Revealed type is "Any"
54485450
[out2]
54495451
tmp/c.py:2: note: Revealed type is "a.<subclass of "A" and "B">"
54505452

test-data/unit/check-inference-context.test

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -622,8 +622,10 @@ reveal_type((lambda x, y: x + y)(1, 2)) # N: Revealed type is "builtins.int"
622622
reveal_type((lambda s, i: s)(i=0, s='x')) # N: Revealed type is "Literal['x']?"
623623
reveal_type((lambda s, i: i)(i=0, s='x')) # N: Revealed type is "Literal[0]?"
624624
reveal_type((lambda x, s, i: x)(1.0, i=0, s='x')) # N: Revealed type is "builtins.float"
625-
(lambda x, s, i: x)() # E: Too few arguments
626-
(lambda: 0)(1) # E: Too many arguments
625+
if object():
626+
(lambda x, s, i: x)() # E: Too few arguments
627+
if object():
628+
(lambda: 0)(1) # E: Too many arguments
627629
-- varargs are not handled, but it should not crash
628630
reveal_type((lambda *k, s, i: i)(type, i=0, s='x')) # N: Revealed type is "Any"
629631
reveal_type((lambda s, *k, i: i)(i=0, s='x')) # N: Revealed type is "Any"

test-data/unit/check-native-int.test

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,10 @@ reveal_type(meet(f32, f)) # N: Revealed type is "mypy_extensions.i32"
8787
reveal_type(meet(f, f32)) # N: Revealed type is "mypy_extensions.i32"
8888
reveal_type(meet(f64, f)) # N: Revealed type is "mypy_extensions.i64"
8989
reveal_type(meet(f, f64)) # N: Revealed type is "mypy_extensions.i64"
90-
reveal_type(meet(f32, f64)) # N: Revealed type is "<nothing>"
91-
reveal_type(meet(f64, f32)) # N: Revealed type is "<nothing>"
90+
if object():
91+
reveal_type(meet(f32, f64)) # N: Revealed type is "<nothing>"
92+
if object():
93+
reveal_type(meet(f64, f32)) # N: Revealed type is "<nothing>"
9294

9395
reveal_type(meet(f, fa)) # N: Revealed type is "builtins.int"
9496
reveal_type(meet(f32, fa)) # N: Revealed type is "mypy_extensions.i32"
@@ -148,8 +150,10 @@ def meet(c1: Callable[[T], None], c2: Callable[[T], None]) -> T:
148150
def ff(x: float) -> None: pass
149151
def fi32(x: i32) -> None: pass
150152

151-
reveal_type(meet(ff, fi32)) # N: Revealed type is "<nothing>"
152-
reveal_type(meet(fi32, ff)) # N: Revealed type is "<nothing>"
153+
if object():
154+
reveal_type(meet(ff, fi32)) # N: Revealed type is "<nothing>"
155+
if object():
156+
reveal_type(meet(fi32, ff)) # N: Revealed type is "<nothing>"
153157
[builtins fixtures/dict.pyi]
154158

155159
[case testNativeIntForLoopRange]

test-data/unit/check-statements.test

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -405,11 +405,16 @@ main:5: error: Exception must be derived from BaseException
405405
class A: pass
406406
class MyError(BaseException): pass
407407
def f(): pass
408-
raise BaseException
409-
raise MyError
410-
raise A # E: Exception must be derived from BaseException
411-
raise object # E: Exception must be derived from BaseException
412-
raise f # E: Exception must be derived from BaseException
408+
if object():
409+
raise BaseException
410+
if object():
411+
raise MyError
412+
if object():
413+
raise A # E: Exception must be derived from BaseException
414+
if object():
415+
raise object # E: Exception must be derived from BaseException
416+
if object():
417+
raise f # E: Exception must be derived from BaseException
413418
[builtins fixtures/exception.pyi]
414419

415420
[case testRaiseClassObjectCustomInit]
@@ -425,18 +430,30 @@ class MyKwError(Exception):
425430
class MyErrorWithDefault(Exception):
426431
def __init__(self, optional=1) -> None:
427432
...
428-
raise BaseException
429-
raise Exception
430-
raise BaseException(1)
431-
raise Exception(2)
432-
raise MyBaseError(4)
433-
raise MyError(5, 6)
434-
raise MyKwError(kwonly=7)
435-
raise MyErrorWithDefault(8)
436-
raise MyErrorWithDefault
437-
raise MyBaseError # E: Too few arguments for "MyBaseError"
438-
raise MyError # E: Too few arguments for "MyError"
439-
raise MyKwError # E: Missing named argument "kwonly" for "MyKwError"
433+
if object():
434+
raise BaseException
435+
if object():
436+
raise Exception
437+
if object():
438+
raise BaseException(1)
439+
if object():
440+
raise Exception(2)
441+
if object():
442+
raise MyBaseError(4)
443+
if object():
444+
raise MyError(5, 6)
445+
if object():
446+
raise MyKwError(kwonly=7)
447+
if object():
448+
raise MyErrorWithDefault(8)
449+
if object():
450+
raise MyErrorWithDefault
451+
if object():
452+
raise MyBaseError # E: Too few arguments for "MyBaseError"
453+
if object():
454+
raise MyError # E: Too few arguments for "MyError"
455+
if object():
456+
raise MyKwError # E: Missing named argument "kwonly" for "MyKwError"
440457
[builtins fixtures/exception.pyi]
441458

442459
[case testRaiseExceptionType]
@@ -469,10 +486,14 @@ f = None # type: MyError
469486
a = None # type: A
470487
x = None # type: BaseException
471488
del x
472-
raise e from a # E: Exception must be derived from BaseException
473-
raise e from e
474-
raise e from f
475-
raise e from x # E: Trying to read deleted variable "x"
489+
if object():
490+
raise e from a # E: Exception must be derived from BaseException
491+
if object():
492+
raise e from e
493+
if object():
494+
raise e from f
495+
if object():
496+
raise e from x # E: Trying to read deleted variable "x"
476497
class A: pass
477498
class MyError(BaseException): pass
478499
[builtins fixtures/exception.pyi]
@@ -482,11 +503,16 @@ import typing
482503
class A: pass
483504
class MyError(BaseException): pass
484505
def f(): pass
485-
raise BaseException from BaseException
486-
raise BaseException from MyError
487-
raise BaseException from A # E: Exception must be derived from BaseException
488-
raise BaseException from object # E: Exception must be derived from BaseException
489-
raise BaseException from f # E: Exception must be derived from BaseException
506+
if object():
507+
raise BaseException from BaseException
508+
if object():
509+
raise BaseException from MyError
510+
if object():
511+
raise BaseException from A # E: Exception must be derived from BaseException
512+
if object():
513+
raise BaseException from object # E: Exception must be derived from BaseException
514+
if object():
515+
raise BaseException from f # E: Exception must be derived from BaseException
490516
[builtins fixtures/exception.pyi]
491517

492518
[case testTryFinallyStatement]

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ reveal_type(f(args)) # N: Revealed type is "Tuple[builtins.int, builtins.str]"
1717

1818
reveal_type(f(varargs)) # N: Revealed type is "builtins.tuple[builtins.int, ...]"
1919

20-
f(0) # E: Argument 1 to "f" has incompatible type "int"; expected <nothing>
20+
if object():
21+
f(0) # E: Argument 1 to "f" has incompatible type "int"; expected <nothing>
2122

2223
def g(a: Tuple[Unpack[Ts]], b: Tuple[Unpack[Ts]]) -> Tuple[Unpack[Ts]]:
2324
return a

test-data/unit/check-unreachable-code.test

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -873,15 +873,15 @@ def expect_str(x: str) -> str: pass
873873
x: int
874874
if False:
875875
assert False
876-
reveal_type(x)
876+
reveal_type(x) # E: Statement is unreachable
877877

878878
if False:
879879
raise Exception()
880-
reveal_type(x)
880+
reveal_type(x) # E: Statement is unreachable
881881

882882
if False:
883883
assert_never(x)
884-
reveal_type(x)
884+
reveal_type(x) # E: Statement is unreachable
885885

886886
if False:
887887
nonthrowing_assert_never(x) # E: Statement is unreachable
@@ -890,7 +890,7 @@ if False:
890890
if False:
891891
# Ignore obvious type errors
892892
assert_never(expect_str(x))
893-
reveal_type(x)
893+
reveal_type(x) # E: Statement is unreachable
894894
[builtins fixtures/exception.pyi]
895895

896896
[case testNeverVariants]

test-data/unit/fine-grained.test

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9666,7 +9666,8 @@ reveal_type(z)
96669666
[out]
96679667
c.py:2: note: Revealed type is "a.<subclass of "A" and "B">"
96689668
==
9669-
c.py:2: note: Revealed type is "a.A"
9669+
c.py:2: note: Revealed type is "Any"
9670+
b.py:2: error: Cannot determine type of "y"
96709671

96719672
[case testIsInstanceAdHocIntersectionFineGrainedIncrementalUnreachaableToIntersection]
96729673
import c
@@ -9697,7 +9698,8 @@ from b import z
96979698
reveal_type(z)
96989699
[builtins fixtures/isinstance.pyi]
96999700
[out]
9700-
c.py:2: note: Revealed type is "a.A"
9701+
b.py:2: error: Cannot determine type of "y"
9702+
c.py:2: note: Revealed type is "Any"
97019703
==
97029704
c.py:2: note: Revealed type is "a.<subclass of "A" and "B">"
97039705

0 commit comments

Comments
 (0)