Skip to content

Commit 83ade13

Browse files
Fix a false positive unreachable for NoReturn coroutine functions (#9844)
1 parent c25bef3 commit 83ade13

File tree

4 files changed

+46
-11
lines changed

4 files changed

+46
-11
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fixed a false positive `unreachable` for `NoReturn` coroutine functions.
2+
3+
Closes #9840.

pylint/checkers/utils.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -2197,8 +2197,12 @@ def is_terminating_func(node: nodes.Call) -> bool:
21972197
inferred._proxied, astroid.UnboundMethod
21982198
):
21992199
inferred = inferred._proxied._proxied
2200-
if (
2200+
if ( # pylint: disable=too-many-boolean-expressions
22012201
isinstance(inferred, nodes.FunctionDef)
2202+
and (
2203+
not isinstance(inferred, nodes.AsyncFunctionDef)
2204+
or isinstance(node.parent, nodes.Await)
2205+
)
22022206
and isinstance(inferred.returns, nodes.Name)
22032207
and (inferred_func := safe_infer(inferred.returns))
22042208
and hasattr(inferred_func, "qname")

tests/functional/u/unreachable.py

+26
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import os
55
import signal
66
import sys
7+
from typing import NoReturn
78

89
def func1():
910
return 1
@@ -79,3 +80,28 @@ def func12():
7980
incognito_function()
8081
var = 2 + 2 # [unreachable]
8182
print(var)
83+
84+
def func13():
85+
def inner() -> NoReturn:
86+
while True:
87+
pass
88+
89+
inner()
90+
print("unreachable") # [unreachable]
91+
92+
async def func14():
93+
async def inner() -> NoReturn:
94+
while True:
95+
pass
96+
97+
await inner()
98+
print("unreachable") # [unreachable]
99+
100+
async def func15():
101+
async def inner() -> NoReturn:
102+
while True:
103+
pass
104+
105+
coro = inner()
106+
print("reachable")
107+
await coro

tests/functional/u/unreachable.txt

+12-10
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
unreachable:10:4:10:24:func1:Unreachable code:HIGH
2-
unreachable:15:8:15:28:func2:Unreachable code:HIGH
3-
unreachable:21:8:21:28:func3:Unreachable code:HIGH
4-
unreachable:25:4:25:16:func4:Unreachable code:HIGH
5-
unreachable:38:4:38:24:func6:Unreachable code:HIGH
6-
unreachable:42:4:42:15:func7:Unreachable code:INFERENCE
7-
unreachable:64:4:64:15:func9:Unreachable code:INFERENCE
8-
unreachable:69:4:69:15:func10:Unreachable code:INFERENCE
9-
unreachable:74:4:74:15:func11:Unreachable code:INFERENCE
10-
unreachable:80:4:80:15:func12:Unreachable code:INFERENCE
1+
unreachable:11:4:11:24:func1:Unreachable code:HIGH
2+
unreachable:16:8:16:28:func2:Unreachable code:HIGH
3+
unreachable:22:8:22:28:func3:Unreachable code:HIGH
4+
unreachable:26:4:26:16:func4:Unreachable code:HIGH
5+
unreachable:39:4:39:24:func6:Unreachable code:HIGH
6+
unreachable:43:4:43:15:func7:Unreachable code:INFERENCE
7+
unreachable:65:4:65:15:func9:Unreachable code:INFERENCE
8+
unreachable:70:4:70:15:func10:Unreachable code:INFERENCE
9+
unreachable:75:4:75:15:func11:Unreachable code:INFERENCE
10+
unreachable:81:4:81:15:func12:Unreachable code:INFERENCE
11+
unreachable:90:4:90:24:func13:Unreachable code:INFERENCE
12+
unreachable:98:4:98:24:func14:Unreachable code:INFERENCE

0 commit comments

Comments
 (0)