diff --git a/packages/pyright-internal/src/analyzer/binder.ts b/packages/pyright-internal/src/analyzer/binder.ts index 5a35d15880..2fe3ccc1d5 100644 --- a/packages/pyright-internal/src/analyzer/binder.ts +++ b/packages/pyright-internal/src/analyzer/binder.ts @@ -1394,8 +1394,11 @@ export class Binder extends ParseTreeWalker { this._sysImportAliases ); - this._bindConditional(node.d.testExpr, thenLabel, elseLabel); - + this._bindConditional(node.d.testExpr, thenLabel, elseLabel, [ + ParseNodeType.AssignmentExpression, + ParseNodeType.Index, + ParseNodeType.MemberAccess, + ]); // Handle the if clause. if (constExprValue === false) { this._currentFlowNode = @@ -1424,7 +1427,10 @@ export class Binder extends ParseTreeWalker { if (node.d.elseSuite) { this.walk(node.d.elseSuite); } else { + const savedExpressions = new Set(this._currentScopeCodeFlowExpressions); this._bindNeverCondition(node.d.testExpr, postIfLabel, /* isPositiveTest */ false); + this._currentScopeCodeFlowExpressions!.clear(); + savedExpressions.forEach((it) => this._currentScopeCodeFlowExpressions!.add(it)); } this._addAntecedent(postIfLabel, this._currentFlowNode); this._currentFlowNode = this._finishFlowLabel(postIfLabel); @@ -3014,7 +3020,12 @@ export class Binder extends ParseTreeWalker { } } - private _bindConditional(node: ExpressionNode, trueTarget: FlowLabel, falseTarget: FlowLabel) { + private _bindConditional( + node: ExpressionNode, + trueTarget: FlowLabel, + falseTarget: FlowLabel, + nodeTypeFilter?: ParseNodeType[] + ) { this._setTrueFalseTargets(trueTarget, falseTarget, () => { this.walk(node); }); @@ -3022,11 +3033,11 @@ export class Binder extends ParseTreeWalker { if (!this._isLogicalExpression(node)) { this._addAntecedent( trueTarget, - this._createFlowConditional(FlowFlags.TrueCondition, this._currentFlowNode!, node) + this._createFlowConditional(FlowFlags.TrueCondition, this._currentFlowNode!, node, nodeTypeFilter) ); this._addAntecedent( falseTarget, - this._createFlowConditional(FlowFlags.FalseCondition, this._currentFlowNode!, node) + this._createFlowConditional(FlowFlags.FalseCondition, this._currentFlowNode!, node, nodeTypeFilter) ); } } @@ -3051,7 +3062,12 @@ export class Binder extends ParseTreeWalker { this._currentFalseTarget = savedFalseTarget; } - private _createFlowConditional(flags: FlowFlags, antecedent: FlowNode, expression: ExpressionNode): FlowNode { + private _createFlowConditional( + flags: FlowFlags, + antecedent: FlowNode, + expression: ExpressionNode, + nodeTypeFilter?: ParseNodeType[] + ): FlowNode { if (antecedent.flags & FlowFlags.Unreachable) { return antecedent; } @@ -3080,7 +3096,9 @@ export class Binder extends ParseTreeWalker { expressionList.forEach((expr) => { const referenceKey = createKeyForReference(expr); - this._currentScopeCodeFlowExpressions!.add(referenceKey); + if (!nodeTypeFilter || nodeTypeFilter.includes(expr.nodeType)) { + this._currentScopeCodeFlowExpressions!.add(referenceKey); + } }); // Select the first name expression. diff --git a/packages/pyright-internal/src/tests/samples/typeNarrowingIsinstance15.py b/packages/pyright-internal/src/tests/samples/typeNarrowingIsinstance15.py index 1562a3f437..fbf8a4f8b8 100644 --- a/packages/pyright-internal/src/tests/samples/typeNarrowingIsinstance15.py +++ b/packages/pyright-internal/src/tests/samples/typeNarrowingIsinstance15.py @@ -37,5 +37,5 @@ def func2(arg: T2) -> T2: if isinstance(arg, str): reveal_type(arg, expected_text="str*") - reveal_type(arg, expected_text="str* | object*") + reveal_type(arg, expected_text="T2@func2") return arg diff --git a/packages/pyright-internal/src/tests/samples/typeNarrowingIsinstance16.py b/packages/pyright-internal/src/tests/samples/typeNarrowingIsinstance16.py index a7b7281b7e..f5f0baf326 100644 --- a/packages/pyright-internal/src/tests/samples/typeNarrowingIsinstance16.py +++ b/packages/pyright-internal/src/tests/samples/typeNarrowingIsinstance16.py @@ -9,11 +9,11 @@ def bar(cls, other: type): reveal_type(other, expected_text="type[Self@ClassA]") if issubclass(other, (int, cls)): - reveal_type(other, expected_text="type[Self@ClassA] | type[int]") + reveal_type(other, expected_text="type[int] | type[Self@ClassA]") def baz(self, other: object): if isinstance(other, type(self)): reveal_type(other, expected_text="Self@ClassA") if isinstance(other, (int, type(self))): - reveal_type(other, expected_text="Self@ClassA | int") + reveal_type(other, expected_text="int | Self@ClassA") \ No newline at end of file diff --git a/packages/pyright-internal/src/tests/samples/typeNarrowingIsinstance5.py b/packages/pyright-internal/src/tests/samples/typeNarrowingIsinstance5.py index 4981b135fd..af6c6d966e 100644 --- a/packages/pyright-internal/src/tests/samples/typeNarrowingIsinstance5.py +++ b/packages/pyright-internal/src/tests/samples/typeNarrowingIsinstance5.py @@ -34,7 +34,7 @@ def func1( if isinstance(obj, Callable): reveal_type(obj, expected_text="((int, str) -> int) | B | TCall1@func1") else: - reveal_type(obj, expected_text="Sequence[Unknown] | C | list[int] | D | A") + reveal_type(obj, expected_text="list[int] | A | C | D") class CB1: diff --git a/packages/pyright-internal/src/tests/samples/typeNarrowingTypeEquals1.py b/packages/pyright-internal/src/tests/samples/typeNarrowingTypeEquals1.py index 137618b9d5..3527f334c8 100644 --- a/packages/pyright-internal/src/tests/samples/typeNarrowingTypeEquals1.py +++ b/packages/pyright-internal/src/tests/samples/typeNarrowingTypeEquals1.py @@ -90,7 +90,7 @@ def func7(val: Any): else: reveal_type(val, expected_text="Any") - reveal_type(val, expected_text="int | Any") + reveal_type(val, expected_text="Any") class CParent: ... diff --git a/packages/pyright-internal/src/tests/samples/typeNarrowingTypeIs1.py b/packages/pyright-internal/src/tests/samples/typeNarrowingTypeIs1.py index a103c98fe4..f390627865 100644 --- a/packages/pyright-internal/src/tests/samples/typeNarrowingTypeIs1.py +++ b/packages/pyright-internal/src/tests/samples/typeNarrowingTypeIs1.py @@ -90,7 +90,7 @@ def func7(val: Any): else: reveal_type(val, expected_text="Any") - reveal_type(val, expected_text="int | Any") + reveal_type(val, expected_text="Any") class CParent: ...