mirror of
https://github.com/microsoft/pyright.git
synced 2024-09-11 07:55:56 +03:00
Fixed a bug that results in incorrect (local) type evaluation of an instance variable with a declared type when assigned within a loop that uses an augmented assignment. This addresses #8090. (#8093)
This commit is contained in:
parent
aad860332e
commit
ec229aa925
@ -117,6 +117,7 @@ export function validateBinaryOperation(
|
||||
): Type {
|
||||
const leftType = leftTypeResult.type;
|
||||
const rightType = rightTypeResult.type;
|
||||
const isIncomplete = !!leftTypeResult.isIncomplete || !!rightTypeResult.isIncomplete;
|
||||
let type: Type | undefined;
|
||||
let concreteLeftType = evaluator.makeTopLevelTypeVarsConcrete(leftType);
|
||||
|
||||
@ -485,7 +486,8 @@ export function validateBinaryOperation(
|
||||
);
|
||||
}
|
||||
}
|
||||
return resultType;
|
||||
|
||||
return resultType ?? UnknownType.create(isIncomplete);
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -493,7 +495,7 @@ export function validateBinaryOperation(
|
||||
}
|
||||
}
|
||||
|
||||
return type ?? UnknownType.create();
|
||||
return type ?? UnknownType.create(isIncomplete);
|
||||
}
|
||||
|
||||
export function getTypeOfBinaryOperation(
|
||||
@ -738,7 +740,7 @@ export function getTypeOfBinaryOperation(
|
||||
// within a loop construct using __add__.
|
||||
const isTupleAddAllowed = !isUnion(leftType);
|
||||
|
||||
let type = validateBinaryOperation(
|
||||
const type = validateBinaryOperation(
|
||||
evaluator,
|
||||
node.operator,
|
||||
{ type: leftType, isIncomplete: leftTypeResult.isIncomplete },
|
||||
@ -788,8 +790,6 @@ export function getTypeOfBinaryOperation(
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
type = UnknownType.create();
|
||||
}
|
||||
|
||||
return { type, isIncomplete, typeErrors };
|
||||
@ -934,8 +934,6 @@ export function getTypeOfAugmentedAssignment(
|
||||
node
|
||||
);
|
||||
}
|
||||
|
||||
type = UnknownType.create();
|
||||
}
|
||||
|
||||
typeResult = { type, isIncomplete };
|
||||
@ -1073,7 +1071,7 @@ export function getTypeOfUnaryOperation(
|
||||
}
|
||||
}
|
||||
|
||||
type = UnknownType.create();
|
||||
type = UnknownType.create(isIncomplete);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26040,6 +26040,11 @@ export function createTypeEvaluator(
|
||||
// should be completely reworked once there has been a public discussion
|
||||
// about the correct behavior.
|
||||
|
||||
// If the result is incomplete, do not attempt to narrow the type.
|
||||
if (assignedTypeResult.isIncomplete) {
|
||||
return assignedTypeResult;
|
||||
}
|
||||
|
||||
const narrowedType = mapSubtypes(assignedTypeResult.type, (assignedSubtype) => {
|
||||
// Handle the special case where the assigned type is a literal type.
|
||||
// Some types include very large unions of literal types, and we don't
|
||||
|
24
packages/pyright-internal/src/tests/samples/loop48.py
Normal file
24
packages/pyright-internal/src/tests/samples/loop48.py
Normal file
@ -0,0 +1,24 @@
|
||||
# This sample tests a case where an instance variable is assigned within
|
||||
# a loop using its own value.
|
||||
|
||||
# pyright: strict
|
||||
|
||||
|
||||
class ClassA:
|
||||
x: int | None
|
||||
|
||||
def method1(self) -> None:
|
||||
self.x = 0
|
||||
|
||||
for _ in range(1, 10):
|
||||
self.x = reveal_type(self.x, expected_text="int") + 1
|
||||
|
||||
reveal_type(self.x, expected_text="int")
|
||||
|
||||
def method2(self) -> None:
|
||||
self.x = 0
|
||||
|
||||
for _ in range(1, 10):
|
||||
self.x += 1
|
||||
|
||||
reveal_type(self.x, expected_text="int")
|
@ -455,6 +455,12 @@ test('Loop47', () => {
|
||||
TestUtils.validateResults(analysisResults, 0);
|
||||
});
|
||||
|
||||
test('Loop48', () => {
|
||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['loop48.py']);
|
||||
|
||||
TestUtils.validateResults(analysisResults, 0);
|
||||
});
|
||||
|
||||
test('ForLoop1', () => {
|
||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['forLoop1.py']);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user