Skip to content

Commit

Permalink
Fixed bug in code flow analysis that resulted in an incorrect type ev…
Browse files Browse the repository at this point in the history
…aluation when a "NoReturn" call is made within a code block protected by an exception-suppressing context manager. This addresses #6850. (#6859)
  • Loading branch information
erictraut authored Dec 30, 2023
1 parent 76b2e69 commit 8c178ce
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 4 deletions.
6 changes: 2 additions & 4 deletions packages/pyright-internal/src/analyzer/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3240,6 +3240,8 @@ export class Binder extends ParseTreeWalker {

private _createCallFlowNode(node: CallNode) {
if (!this._isCodeUnreachable()) {
this._addExceptTargets(this._currentFlowNode!);

const flowNode: FlowCall = {
flags: FlowFlags.Call,
id: this._getUniqueFlowNodeId(),
Expand All @@ -3249,10 +3251,6 @@ export class Binder extends ParseTreeWalker {

this._currentFlowNode = flowNode;
}

if (!this._isCodeUnreachable()) {
this._addExceptTargets(this._currentFlowNode!);
}
}

private _createVariableAnnotationFlowNode() {
Expand Down
4 changes: 4 additions & 0 deletions packages/pyright-internal/src/analyzer/codeFlowEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,10 @@ export function getCodeFlowEngine(
}
}

if (flowTypeResult && !isFlowNodeReachable(flowNode)) {
flowTypeResult = undefined;
}

return setCacheEntry(curFlowNode, flowTypeResult?.type, !!flowTypeResult?.isIncomplete);
}

Expand Down
16 changes: 16 additions & 0 deletions packages/pyright-internal/src/tests/samples/with3.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# for the __exit__ or __aexit__ method.

from contextlib import suppress, AsyncExitStack
from typing import Never


def test1() -> None:
Expand Down Expand Up @@ -71,3 +72,18 @@ def test4() -> None:
async def test5() -> str:
async with AsyncExitStack():
return "from exit stack"


def no_return() -> Never:
raise Exception()


def test6():
val = None
with suppress():
val = 1
no_return()
val = 2

assert val is not None
reveal_type(val, expected_text="Literal[1]")

0 comments on commit 8c178ce

Please sign in to comment.