From 409a891443690d67da9b3b4a9a64fd33b63299a5 Mon Sep 17 00:00:00 2001 From: detachhead Date: Sat, 24 May 2025 13:04:47 +1000 Subject: [PATCH 1/9] prevent narrowed types from being added to unions after the narrowing if statement as they can lead to unnecessary `reportUnknown...` errors --- .../src/analyzer/codeFlowEngine.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/pyright-internal/src/analyzer/codeFlowEngine.ts b/packages/pyright-internal/src/analyzer/codeFlowEngine.ts index f22265a594..8a7693d74a 100644 --- a/packages/pyright-internal/src/analyzer/codeFlowEngine.ts +++ b/packages/pyright-internal/src/analyzer/codeFlowEngine.ts @@ -666,7 +666,7 @@ export function getCodeFlowEngine( } } - return getTypeFromBranchFlowNode(curFlowNode as FlowLabel); + return getTypeFromBranchFlowNode(branchFlowNode); } if (curFlowNode.flags & FlowFlags.LoopLabel) { @@ -934,31 +934,34 @@ export function getCodeFlowEngine( } } - function getTypeFromBranchFlowNode(branchNode: FlowLabel): FlowNodeTypeResult { + function getTypeFromBranchFlowNode(branchNode: FlowBranchLabel): FlowNodeTypeResult { const typesToCombine: Type[] = []; - let sawIncomplete = false; + const preBranchAntecedentType = branchNode.preBranchAntecedent + ? getTypeFromFlowNode(branchNode.preBranchAntecedent).type + : undefined; + let sawIncomplete = false; for (const antecedent of branchNode.antecedents) { const flowTypeResult = getTypeFromFlowNode(antecedent); - if (reference === undefined && flowTypeResult.type && !isNever(flowTypeResult.type)) { // If we're solving for "reachability", and we have now proven // reachability, there's no reason to do more work. The type we // return here doesn't matter as long as it's not undefined. return setCacheEntry(branchNode, UnknownType.create(), /* isIncomplete */ false); } - if (flowTypeResult.isIncomplete) { sawIncomplete = true; } - - if (flowTypeResult.type) { + if (!preBranchAntecedentType && flowTypeResult.type) { typesToCombine.push(flowTypeResult.type); } } - const effectiveType = typesToCombine.length > 0 ? combineTypes(typesToCombine) : undefined; + const effectiveType = + // if there's a preBranchAntecedent, we discard the types from the antecendents after the if statement + // and use its type instead to prevent it from creating a union of redundant types + preBranchAntecedentType ?? (typesToCombine.length > 0 ? combineTypes(typesToCombine) : undefined); return setCacheEntry(branchNode, effectiveType, sawIncomplete); } From 64671c139e1354b6b5f1eb43dfd8569563b8eb6c Mon Sep 17 00:00:00 2001 From: detachhead Date: Wed, 28 May 2025 18:24:06 +1000 Subject: [PATCH 2/9] fix narrowed type from assignment inside if statement being forgotten after the if statement --- .../src/analyzer/codeFlowEngine.ts | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/packages/pyright-internal/src/analyzer/codeFlowEngine.ts b/packages/pyright-internal/src/analyzer/codeFlowEngine.ts index 8a7693d74a..4144807370 100644 --- a/packages/pyright-internal/src/analyzer/codeFlowEngine.ts +++ b/packages/pyright-internal/src/analyzer/codeFlowEngine.ts @@ -666,7 +666,7 @@ export function getCodeFlowEngine( } } - return getTypeFromBranchFlowNode(branchFlowNode); + return getTypeFromBranchFlowNode(curFlowNode as FlowLabel); } if (curFlowNode.flags & FlowFlags.LoopLabel) { @@ -934,34 +934,37 @@ export function getCodeFlowEngine( } } - function getTypeFromBranchFlowNode(branchNode: FlowBranchLabel): FlowNodeTypeResult { + function getTypeFromBranchFlowNode(branchNode: FlowLabel): FlowNodeTypeResult { const typesToCombine: Type[] = []; - const preBranchAntecedentType = branchNode.preBranchAntecedent - ? getTypeFromFlowNode(branchNode.preBranchAntecedent).type - : undefined; - let sawIncomplete = false; + for (const antecedent of branchNode.antecedents) { const flowTypeResult = getTypeFromFlowNode(antecedent); + if (reference === undefined && flowTypeResult.type && !isNever(flowTypeResult.type)) { // If we're solving for "reachability", and we have now proven // reachability, there's no reason to do more work. The type we // return here doesn't matter as long as it's not undefined. return setCacheEntry(branchNode, UnknownType.create(), /* isIncomplete */ false); } + if (flowTypeResult.isIncomplete) { sawIncomplete = true; } - if (!preBranchAntecedentType && flowTypeResult.type) { + + // if the antecendent isn't an assignment to the target symbol, we discard the types from the antecendents + // after the if statement and use its type instead to prevent it from creating a union of redundant types + if ( + flowTypeResult.type && + (!(antecedent.flags & FlowFlags.Assignment) || + (antecedent as FlowAssignment).targetSymbolId === options?.targetSymbolId) + ) { typesToCombine.push(flowTypeResult.type); } } - const effectiveType = - // if there's a preBranchAntecedent, we discard the types from the antecendents after the if statement - // and use its type instead to prevent it from creating a union of redundant types - preBranchAntecedentType ?? (typesToCombine.length > 0 ? combineTypes(typesToCombine) : undefined); + const effectiveType = typesToCombine.length > 0 ? combineTypes(typesToCombine) : undefined; return setCacheEntry(branchNode, effectiveType, sawIncomplete); } From 00f01edf14f12ab59d2d3344eb6e5f1e8d2ea89d Mon Sep 17 00:00:00 2001 From: detachhead Date: Wed, 28 May 2025 21:53:10 +1000 Subject: [PATCH 3/9] fix resetting type of narrowed class attribute when the variable is reassigned --- packages/pyright-internal/src/analyzer/codeFlowEngine.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/pyright-internal/src/analyzer/codeFlowEngine.ts b/packages/pyright-internal/src/analyzer/codeFlowEngine.ts index 4144807370..9df4d72b80 100644 --- a/packages/pyright-internal/src/analyzer/codeFlowEngine.ts +++ b/packages/pyright-internal/src/analyzer/codeFlowEngine.ts @@ -39,6 +39,7 @@ import { formatControlFlowGraph } from './codeFlowUtils'; import { getBoundCallMethod, getBoundNewMethod } from './constructors'; import { isMatchingExpression, isPartialMatchingExpression, printExpression } from './parseTreeUtils'; import { getPatternSubtypeNarrowingCallback } from './patternMatching'; +import { indeterminateSymbolId } from './symbol'; import { SpeculativeTypeTracker } from './typeCacheUtils'; import { narrowForKeyAssignment } from './typedDicts'; import { EvalFlags, Reachability, TypeEvaluator, TypeResult } from './typeEvaluatorTypes'; @@ -958,6 +959,7 @@ export function getCodeFlowEngine( if ( flowTypeResult.type && (!(antecedent.flags & FlowFlags.Assignment) || + options?.targetSymbolId === indeterminateSymbolId || (antecedent as FlowAssignment).targetSymbolId === options?.targetSymbolId) ) { typesToCombine.push(flowTypeResult.type); From b1840b29d006396ed144d32a97509d85799e759d Mon Sep 17 00:00:00 2001 From: detachhead Date: Wed, 28 May 2025 23:47:27 +1000 Subject: [PATCH 4/9] does this fix it --- .../src/analyzer/codeFlowEngine.ts | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/pyright-internal/src/analyzer/codeFlowEngine.ts b/packages/pyright-internal/src/analyzer/codeFlowEngine.ts index 9df4d72b80..8abc231b9f 100644 --- a/packages/pyright-internal/src/analyzer/codeFlowEngine.ts +++ b/packages/pyright-internal/src/analyzer/codeFlowEngine.ts @@ -940,6 +940,11 @@ export function getCodeFlowEngine( let sawIncomplete = false; + const preBranchAntecedentType = + 'preBranchAntecedent' in branchNode && (branchNode as FlowBranchLabel).preBranchAntecedent + ? getTypeFromFlowNode((branchNode as FlowBranchLabel).preBranchAntecedent!).type + : undefined; + for (const antecedent of branchNode.antecedents) { const flowTypeResult = getTypeFromFlowNode(antecedent); @@ -956,13 +961,16 @@ export function getCodeFlowEngine( // if the antecendent isn't an assignment to the target symbol, we discard the types from the antecendents // after the if statement and use its type instead to prevent it from creating a union of redundant types - if ( - flowTypeResult.type && - (!(antecedent.flags & FlowFlags.Assignment) || + if (flowTypeResult.type) { + if ( + !(antecedent.flags & FlowFlags.Assignment) || options?.targetSymbolId === indeterminateSymbolId || - (antecedent as FlowAssignment).targetSymbolId === options?.targetSymbolId) - ) { - typesToCombine.push(flowTypeResult.type); + (antecedent as FlowAssignment).targetSymbolId === options?.targetSymbolId + ) { + typesToCombine.push(flowTypeResult.type); + } else if (preBranchAntecedentType) { + typesToCombine.push(preBranchAntecedentType); + } } } From c899ae93b397d2e4a1378cb3b2de4c4e07d4d586 Mon Sep 17 00:00:00 2001 From: detachhead Date: Thu, 29 May 2025 19:16:48 +1000 Subject: [PATCH 5/9] what about this --- .../pyright-internal/src/analyzer/binder.ts | 5 ----- .../src/analyzer/codeFlowEngine.ts | 18 +----------------- 2 files changed, 1 insertion(+), 22 deletions(-) diff --git a/packages/pyright-internal/src/analyzer/binder.ts b/packages/pyright-internal/src/analyzer/binder.ts index 5a35d15880..e251b44256 100644 --- a/packages/pyright-internal/src/analyzer/binder.ts +++ b/packages/pyright-internal/src/analyzer/binder.ts @@ -3078,11 +3078,6 @@ export class Binder extends ParseTreeWalker { return antecedent; } - expressionList.forEach((expr) => { - const referenceKey = createKeyForReference(expr); - this._currentScopeCodeFlowExpressions!.add(referenceKey); - }); - // Select the first name expression. const filteredExprList = expressionList.filter((expr) => expr.nodeType === ParseNodeType.Name); diff --git a/packages/pyright-internal/src/analyzer/codeFlowEngine.ts b/packages/pyright-internal/src/analyzer/codeFlowEngine.ts index 8abc231b9f..f22265a594 100644 --- a/packages/pyright-internal/src/analyzer/codeFlowEngine.ts +++ b/packages/pyright-internal/src/analyzer/codeFlowEngine.ts @@ -39,7 +39,6 @@ import { formatControlFlowGraph } from './codeFlowUtils'; import { getBoundCallMethod, getBoundNewMethod } from './constructors'; import { isMatchingExpression, isPartialMatchingExpression, printExpression } from './parseTreeUtils'; import { getPatternSubtypeNarrowingCallback } from './patternMatching'; -import { indeterminateSymbolId } from './symbol'; import { SpeculativeTypeTracker } from './typeCacheUtils'; import { narrowForKeyAssignment } from './typedDicts'; import { EvalFlags, Reachability, TypeEvaluator, TypeResult } from './typeEvaluatorTypes'; @@ -940,11 +939,6 @@ export function getCodeFlowEngine( let sawIncomplete = false; - const preBranchAntecedentType = - 'preBranchAntecedent' in branchNode && (branchNode as FlowBranchLabel).preBranchAntecedent - ? getTypeFromFlowNode((branchNode as FlowBranchLabel).preBranchAntecedent!).type - : undefined; - for (const antecedent of branchNode.antecedents) { const flowTypeResult = getTypeFromFlowNode(antecedent); @@ -959,18 +953,8 @@ export function getCodeFlowEngine( sawIncomplete = true; } - // if the antecendent isn't an assignment to the target symbol, we discard the types from the antecendents - // after the if statement and use its type instead to prevent it from creating a union of redundant types if (flowTypeResult.type) { - if ( - !(antecedent.flags & FlowFlags.Assignment) || - options?.targetSymbolId === indeterminateSymbolId || - (antecedent as FlowAssignment).targetSymbolId === options?.targetSymbolId - ) { - typesToCombine.push(flowTypeResult.type); - } else if (preBranchAntecedentType) { - typesToCombine.push(preBranchAntecedentType); - } + typesToCombine.push(flowTypeResult.type); } } From 75db45e5a7f0c1c6747748cde8bcd85e7bfa6a87 Mon Sep 17 00:00:00 2001 From: detachhead Date: Thu, 29 May 2025 22:35:03 +1000 Subject: [PATCH 6/9] asdf --- .../pyright-internal/src/analyzer/binder.ts | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/packages/pyright-internal/src/analyzer/binder.ts b/packages/pyright-internal/src/analyzer/binder.ts index e251b44256..6b53f95be9 100644 --- a/packages/pyright-internal/src/analyzer/binder.ts +++ b/packages/pyright-internal/src/analyzer/binder.ts @@ -1383,19 +1383,19 @@ export class Binder extends ParseTreeWalker { const isTypeCheckingNode = (node: ExpressionNode): node is NameNode => node.nodeType === ParseNodeType.Name && node.d.value === 'TYPE_CHECKING'; - postIfLabel.affectedExpressions = this._trackCodeFlowExpressions(() => { - // Determine if the test condition is always true or always false. If so, - // we can treat either the then or the else clause as unconditional. - const constExprValue = StaticExpressions.evaluateStaticBoolLikeExpression( - node.d.testExpr, - this._fileInfo.executionEnvironment, - this._fileInfo.definedConstants, - this._typingImportAliases, - this._sysImportAliases - ); + // Determine if the test condition is always true or always false. If so, + // we can treat either the then or the else clause as unconditional. + const constExprValue = StaticExpressions.evaluateStaticBoolLikeExpression( + node.d.testExpr, + this._fileInfo.executionEnvironment, + this._fileInfo.definedConstants, + this._typingImportAliases, + this._sysImportAliases + ); - this._bindConditional(node.d.testExpr, thenLabel, elseLabel); + this._bindConditional(node.d.testExpr, thenLabel, elseLabel); + postIfLabel.affectedExpressions = this._trackCodeFlowExpressions(() => { // Handle the if clause. if (constExprValue === false) { this._currentFlowNode = @@ -1424,7 +1424,9 @@ 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 = savedExpressions; } this._addAntecedent(postIfLabel, this._currentFlowNode); this._currentFlowNode = this._finishFlowLabel(postIfLabel); @@ -3078,6 +3080,11 @@ export class Binder extends ParseTreeWalker { return antecedent; } + expressionList.forEach((expr) => { + const referenceKey = createKeyForReference(expr); + this._currentScopeCodeFlowExpressions!.add(referenceKey); + }); + // Select the first name expression. const filteredExprList = expressionList.filter((expr) => expr.nodeType === ParseNodeType.Name); From 35bf9fc419ac5f0ecd08e1a1fd38ebc742cf9ac3 Mon Sep 17 00:00:00 2001 From: detachhead Date: Sat, 31 May 2025 11:38:43 +1000 Subject: [PATCH 7/9] asdf --- packages/pyright-internal/src/analyzer/binder.ts | 3 ++- .../src/tests/samples/typeNarrowingIsinstance15.py | 2 +- .../src/tests/samples/typeNarrowingIsinstance16.py | 4 ++-- .../src/tests/samples/typeNarrowingIsinstance5.py | 2 +- .../src/tests/samples/typeNarrowingTypeEquals1.py | 2 +- .../src/tests/samples/typeNarrowingTypeIs1.py | 2 +- 6 files changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/pyright-internal/src/analyzer/binder.ts b/packages/pyright-internal/src/analyzer/binder.ts index 6b53f95be9..bb8eebcf2c 100644 --- a/packages/pyright-internal/src/analyzer/binder.ts +++ b/packages/pyright-internal/src/analyzer/binder.ts @@ -1426,7 +1426,8 @@ export class Binder extends ParseTreeWalker { } else { const savedExpressions = new Set(this._currentScopeCodeFlowExpressions); this._bindNeverCondition(node.d.testExpr, postIfLabel, /* isPositiveTest */ false); - this._currentScopeCodeFlowExpressions = savedExpressions; + this._currentScopeCodeFlowExpressions!.clear(); + savedExpressions.forEach((it) => this._currentScopeCodeFlowExpressions!.add(it)); } this._addAntecedent(postIfLabel, this._currentFlowNode); this._currentFlowNode = this._finishFlowLabel(postIfLabel); 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: ... From 5065aedaa0127d5e4ad1438162fbf24da63bdfcb Mon Sep 17 00:00:00 2001 From: detachhead Date: Sat, 31 May 2025 13:57:04 +1000 Subject: [PATCH 8/9] asdf --- .../pyright-internal/src/analyzer/binder.ts | 48 ++++++++++++------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/packages/pyright-internal/src/analyzer/binder.ts b/packages/pyright-internal/src/analyzer/binder.ts index bb8eebcf2c..423232c4f8 100644 --- a/packages/pyright-internal/src/analyzer/binder.ts +++ b/packages/pyright-internal/src/analyzer/binder.ts @@ -1383,19 +1383,21 @@ export class Binder extends ParseTreeWalker { const isTypeCheckingNode = (node: ExpressionNode): node is NameNode => node.nodeType === ParseNodeType.Name && node.d.value === 'TYPE_CHECKING'; - // Determine if the test condition is always true or always false. If so, - // we can treat either the then or the else clause as unconditional. - const constExprValue = StaticExpressions.evaluateStaticBoolLikeExpression( - node.d.testExpr, - this._fileInfo.executionEnvironment, - this._fileInfo.definedConstants, - this._typingImportAliases, - this._sysImportAliases - ); - - this._bindConditional(node.d.testExpr, thenLabel, elseLabel); - postIfLabel.affectedExpressions = this._trackCodeFlowExpressions(() => { + // Determine if the test condition is always true or always false. If so, + // we can treat either the then or the else clause as unconditional. + const constExprValue = StaticExpressions.evaluateStaticBoolLikeExpression( + node.d.testExpr, + this._fileInfo.executionEnvironment, + this._fileInfo.definedConstants, + this._typingImportAliases, + this._sysImportAliases + ); + + this._bindConditional(node.d.testExpr, thenLabel, elseLabel, [ + ParseNodeType.AssignmentExpression, + ParseNodeType.Index, + ]); // Handle the if clause. if (constExprValue === false) { this._currentFlowNode = @@ -3017,7 +3019,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); }); @@ -3025,11 +3032,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) ); } } @@ -3054,7 +3061,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; } @@ -3083,7 +3095,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. From ef8e47b13853300144135d7d8ab85033a81e2df3 Mon Sep 17 00:00:00 2001 From: detachhead Date: Sat, 31 May 2025 14:10:48 +1000 Subject: [PATCH 9/9] asdf --- packages/pyright-internal/src/analyzer/binder.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/pyright-internal/src/analyzer/binder.ts b/packages/pyright-internal/src/analyzer/binder.ts index 423232c4f8..2fe3ccc1d5 100644 --- a/packages/pyright-internal/src/analyzer/binder.ts +++ b/packages/pyright-internal/src/analyzer/binder.ts @@ -1397,6 +1397,7 @@ export class Binder extends ParseTreeWalker { this._bindConditional(node.d.testExpr, thenLabel, elseLabel, [ ParseNodeType.AssignmentExpression, ParseNodeType.Index, + ParseNodeType.MemberAccess, ]); // Handle the if clause. if (constExprValue === false) {