Improved consistency of type narrowing on assignment when the target is a variable with a declared type and the assigned value is an unknown or partially-unknown type. Previously, if the assigned value was Unknown, the declared type was assumed, but if the assigned value was a union that included Unknown, the narrowed type (including the Unknown) was assumed. We now always include an Unknown in the assigned type so the reportUnknownVariableType diagnostic is reported.

This commit is contained in:
Eric Traut 2023-03-19 08:11:55 -06:00
parent d36c524916
commit b9e72bf147
3 changed files with 40 additions and 4 deletions

View File

@ -25184,11 +25184,17 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
});
// If the result of narrowing is Any, stick with the declared (unnarrowed) type.
// If the result of narrowing is an Unknown that is complete, stick with Unknown.
// If it's incomplete, propagate the incomplete type for the benefit of
// code flow analysis.
if (isAnyOrUnknown(assignedType) && !isIncompleteUnknown(assignedType)) {
// If the result of narrowing is an Unknown that is incomplete, propagate the
// incomplete type for the benefit of code flow analysis.
// If the result of narrowing is a complete Unknown, combine the Unknown type
// with the declared type. In strict mode, this will retain the "unknown type"
// diagnostics while still providing reasonable completion suggestions.
if (isAny(narrowedType)) {
return declaredType;
} else if (isIncompleteUnknown(narrowedType)) {
return narrowedType;
} else if (isUnknown(narrowedType)) {
return combineTypes([narrowedType, declaredType]);
}
return narrowedType;

View File

@ -0,0 +1,19 @@
# This sample tests the case where a variable with a declared type
# is assigned an unknown value or partially-unknown value.
def a_test(x: int):
u = x.upper() # type: ignore
reveal_type(u, expected_text="Unknown")
# This should generate an error if reportUnknownVariableType is enabled.
y: str = u
reveal_type(y, expected_text="Unknown | str")
def b_test(x: int | str):
u = x.upper() # type: ignore
reveal_type(u, expected_text="Unknown | str")
# This should generate an error if reportUnknownVariableType is enabled.
y: str = u
reveal_type(y, expected_text="Unknown | str")

View File

@ -132,6 +132,17 @@ test('Assignment11', () => {
TestUtils.validateResults(analysisResults, 2);
});
test('Assignment12', () => {
const configOptions = new ConfigOptions('.');
const analysisResults1 = TestUtils.typeAnalyzeSampleFiles(['assignment12.py'], configOptions);
TestUtils.validateResults(analysisResults1, 0);
configOptions.diagnosticRuleSet.reportUnknownVariableType = 'error';
const analysisResults2 = TestUtils.typeAnalyzeSampleFiles(['assignment12.py'], configOptions);
TestUtils.validateResults(analysisResults2, 2);
});
test('AugmentedAssignment1', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['augmentedAssignment1.py']);