From 8f8e9b690e44771fa654a0ee123a6c4203c0de3c Mon Sep 17 00:00:00 2001 From: sobolevn Date: Tue, 19 Oct 2021 20:00:20 +0300 Subject: [PATCH 1/6] Very naive attempt to fix #11331 --- mypy/checker.py | 3 +-- test-data/unit/check-statements.test | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index 9c389a3d08d8..574d59257e1e 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -306,8 +306,7 @@ def check_first_pass(self) -> None: self.errors.set_file(self.path, self.tree.fullname, scope=self.tscope) with self.tscope.module_scope(self.tree.fullname): with self.enter_partial_types(), self.binder.top_frame_context(): - for d in self.tree.defs: - self.accept(d) + self.accept(Block(self.tree.defs)) assert not self.current_node_deferred diff --git a/test-data/unit/check-statements.test b/test-data/unit/check-statements.test index 62d82f94a6c1..4d42d6a12d57 100644 --- a/test-data/unit/check-statements.test +++ b/test-data/unit/check-statements.test @@ -1821,3 +1821,22 @@ def foo2(): bar2 = [] # type: List[str] bar2 [builtins fixtures/list.pyi] + +[case testUnreachableModuleBody1] +# flags: --warn-unreachable +from typing import NoReturn + +def foo() -> NoReturn: + raise Exception("foo") + +foo() +x = 1 # E: Statement is unreachable +[builtins fixtures/exception.pyi] + +[case testUnreachableModuleBody2] +# flags: --warn-unreachable +from typing import NoReturn + +raise Exception +x = 1 # E: Statement is unreachable +[builtins fixtures/exception.pyi] From 582e6f92ea6357d4dc9cc3cbbe85cf24a2c42726 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Tue, 19 Oct 2021 20:05:11 +0300 Subject: [PATCH 2/6] Very naive attempt to fix #11331 --- test-data/unit/check-statements.test | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test-data/unit/check-statements.test b/test-data/unit/check-statements.test index 4d42d6a12d57..9207b2559bac 100644 --- a/test-data/unit/check-statements.test +++ b/test-data/unit/check-statements.test @@ -1825,18 +1825,14 @@ def foo2(): [case testUnreachableModuleBody1] # flags: --warn-unreachable from typing import NoReturn - def foo() -> NoReturn: raise Exception("foo") - foo() x = 1 # E: Statement is unreachable [builtins fixtures/exception.pyi] [case testUnreachableModuleBody2] # flags: --warn-unreachable -from typing import NoReturn - raise Exception x = 1 # E: Statement is unreachable [builtins fixtures/exception.pyi] From c165a583c5a316296f6d1b11d71308908d912a1c Mon Sep 17 00:00:00 2001 From: sobolevn Date: Tue, 19 Oct 2021 20:29:57 +0300 Subject: [PATCH 3/6] Very naive attempt to fix #11331 --- mypy/checker.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mypy/checker.py b/mypy/checker.py index 574d59257e1e..010f3b79fbda 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -306,7 +306,12 @@ def check_first_pass(self) -> None: self.errors.set_file(self.path, self.tree.fullname, scope=self.tscope) with self.tscope.module_scope(self.tree.fullname): with self.enter_partial_types(), self.binder.top_frame_context(): - self.accept(Block(self.tree.defs)) + for d in self.tree.defs: + if (self.binder.is_unreachable() + and self.should_report_unreachable_issues() + and not self.is_raising_or_empty(d)): + self.msg.unreachable_statement(d) + self.accept(d) assert not self.current_node_deferred From 8333ae657f4ab211c1a39adc94a96317e633a0c4 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Tue, 19 Oct 2021 20:47:08 +0300 Subject: [PATCH 4/6] Fixes existing test --- test-data/unit/check-unreachable-code.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/unit/check-unreachable-code.test b/test-data/unit/check-unreachable-code.test index 3525cbf8c612..f41ffb4da8dd 100644 --- a/test-data/unit/check-unreachable-code.test +++ b/test-data/unit/check-unreachable-code.test @@ -768,7 +768,7 @@ while isinstance(b, int): else: reveal_type(b) # E: Statement is unreachable -def foo(c: int) -> None: +def foo(c: int) -> None: # E: Statement is unreachable reveal_type(c) # N: Revealed type is "builtins.int" assert not isinstance(c, int) reveal_type(c) # E: Statement is unreachable From ba9c53a9ae89b1e1f29f7f48b1d3ae44629caa2f Mon Sep 17 00:00:00 2001 From: sobolevn Date: Tue, 19 Oct 2021 22:12:42 +0300 Subject: [PATCH 5/6] Fixes existing test --- test-data/unit/check-unreachable-code.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test-data/unit/check-unreachable-code.test b/test-data/unit/check-unreachable-code.test index f41ffb4da8dd..9b6f2592221d 100644 --- a/test-data/unit/check-unreachable-code.test +++ b/test-data/unit/check-unreachable-code.test @@ -773,8 +773,8 @@ def foo(c: int) -> None: # E: Statement is unreachable assert not isinstance(c, int) reveal_type(c) # E: Statement is unreachable -d: int -if False: +d: int # E: Statement is unreachable +if False: # E: Statement is unreachable reveal_type(d) # E: Statement is unreachable e: int From 2d51fb85261a23242f79e9ffaa4dc95cb7c0c5d0 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Fri, 22 Oct 2021 18:28:03 +0300 Subject: [PATCH 6/6] Addresses review --- mypy/checker.py | 1 + test-data/unit/check-statements.test | 15 --------- test-data/unit/check-unreachable-code.test | 36 +++++++++++++++++++--- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index 010f3b79fbda..51ba2e9610fe 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -311,6 +311,7 @@ def check_first_pass(self) -> None: and self.should_report_unreachable_issues() and not self.is_raising_or_empty(d)): self.msg.unreachable_statement(d) + break self.accept(d) assert not self.current_node_deferred diff --git a/test-data/unit/check-statements.test b/test-data/unit/check-statements.test index 9207b2559bac..62d82f94a6c1 100644 --- a/test-data/unit/check-statements.test +++ b/test-data/unit/check-statements.test @@ -1821,18 +1821,3 @@ def foo2(): bar2 = [] # type: List[str] bar2 [builtins fixtures/list.pyi] - -[case testUnreachableModuleBody1] -# flags: --warn-unreachable -from typing import NoReturn -def foo() -> NoReturn: - raise Exception("foo") -foo() -x = 1 # E: Statement is unreachable -[builtins fixtures/exception.pyi] - -[case testUnreachableModuleBody2] -# flags: --warn-unreachable -raise Exception -x = 1 # E: Statement is unreachable -[builtins fixtures/exception.pyi] diff --git a/test-data/unit/check-unreachable-code.test b/test-data/unit/check-unreachable-code.test index 9b6f2592221d..2a55db1a33c6 100644 --- a/test-data/unit/check-unreachable-code.test +++ b/test-data/unit/check-unreachable-code.test @@ -754,35 +754,46 @@ if sys.version_info[0] >= 2: reveal_type('') # N: Revealed type is "Literal['']?" [builtins fixtures/ops.pyi] -[case testUnreachableFlagWithBadControlFlow] +[case testUnreachableFlagWithBadControlFlow1] # flags: --warn-unreachable a: int if isinstance(a, int): reveal_type(a) # N: Revealed type is "builtins.int" else: reveal_type(a) # E: Statement is unreachable +[builtins fixtures/isinstancelist.pyi] +[case testUnreachableFlagWithBadControlFlow2] +# flags: --warn-unreachable b: int while isinstance(b, int): reveal_type(b) # N: Revealed type is "builtins.int" else: reveal_type(b) # E: Statement is unreachable +[builtins fixtures/isinstancelist.pyi] -def foo(c: int) -> None: # E: Statement is unreachable +[case testUnreachableFlagWithBadControlFlow3] +# flags: --warn-unreachable +def foo(c: int) -> None: reveal_type(c) # N: Revealed type is "builtins.int" assert not isinstance(c, int) reveal_type(c) # E: Statement is unreachable +[builtins fixtures/isinstancelist.pyi] -d: int # E: Statement is unreachable -if False: # E: Statement is unreachable +[case testUnreachableFlagWithBadControlFlow4] +# flags: --warn-unreachable +d: int +if False: reveal_type(d) # E: Statement is unreachable +[builtins fixtures/isinstancelist.pyi] +[case testUnreachableFlagWithBadControlFlow5] +# flags: --warn-unreachable e: int if True: reveal_type(e) # N: Revealed type is "builtins.int" else: reveal_type(e) # E: Statement is unreachable - [builtins fixtures/isinstancelist.pyi] [case testUnreachableFlagStatementAfterReturn] @@ -1390,3 +1401,18 @@ def f() -> None: if nope(): x = 1 # E: Statement is unreachable [builtins fixtures/dict.pyi] + +[case testUnreachableModuleBody1] +# flags: --warn-unreachable +from typing import NoReturn +def foo() -> NoReturn: + raise Exception("foo") +foo() +x = 1 # E: Statement is unreachable +[builtins fixtures/exception.pyi] + +[case testUnreachableModuleBody2] +# flags: --warn-unreachable +raise Exception +x = 1 # E: Statement is unreachable +[builtins fixtures/exception.pyi]