Fixed false positive error when using a union type expression in an isinstance or issubclass call on Python 3.10.

This commit is contained in:
Eric Traut 2021-11-19 20:29:07 -08:00
parent ec5c68f18f
commit f70318dd29
3 changed files with 25 additions and 8 deletions

View File

@ -479,6 +479,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
let cancellationToken: CancellationToken | undefined;
let isBasicTypesInitialized = false;
let noneType: Type | undefined;
let unionType: Type | undefined;
let objectType: Type | undefined;
let typeClassType: Type | undefined;
let functionObj: Type | undefined;
@ -12771,6 +12772,12 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
// Validate __init_subclass__ call.
validateInitSubclassArgs(node, classType, initSubclassArgs);
// Stash away a reference to the UnionType class if we encounter it.
// There's no easy way to otherwise reference it.
if (ClassType.isBuiltIn(classType, 'UnionType')) {
unionType = ClassType.cloneAsInstance(classType);
}
return { classType, decoratedType };
}
@ -18656,9 +18663,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
// Handle the special case where the expression is an actual
// UnionType special form.
if (isUnion(srcType) && TypeBase.isSpecialForm(srcType)) {
if (objectType) {
srcType = objectType;
}
srcType = unionType || objectType || AnyType.create();
}
if (isUnion(destType)) {

View File

@ -24,9 +24,15 @@ if isinstance(a, A):
if isinstance(a, A[str]):
pass
# This should generate an error because unions are not
# allowed.
if issubclass(a, Union[A, int]):
# This should generate an error in Python 3.9 and older
# because unions are not allowed.
if issubclass(A, Union[A, int]):
pass
# This should generate an error in Python 3.9 and older
# because unions are not allowed. A second error will be
# generated because the | operator isn't allowed.
if issubclass(A, A | int):
pass

View File

@ -202,9 +202,15 @@ test('isInstance2', () => {
});
test('isInstance3', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['isinstance3.py']);
const configOptions = new ConfigOptions('.');
TestUtils.validateResults(analysisResults, 3);
configOptions.defaultPythonVersion = PythonVersion.V3_9;
const analysisResults1 = TestUtils.typeAnalyzeSampleFiles(['isinstance3.py'], configOptions);
TestUtils.validateResults(analysisResults1, 4);
configOptions.defaultPythonVersion = PythonVersion.V3_10;
const analysisResults2 = TestUtils.typeAnalyzeSampleFiles(['isinstance3.py'], configOptions);
TestUtils.validateResults(analysisResults2, 1);
});
test('isInstance4', () => {