Fixed false positive error related to heuristics employed in bidirectional type inference for calls when the expected type comprises a union and the return type of the call is a union that includes Any and a type variable.

This commit is contained in:
Eric Traut 2021-11-07 19:39:45 -08:00
parent 2349041a68
commit 44451a99c8
3 changed files with 35 additions and 0 deletions

View File

@ -19130,6 +19130,20 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
}
}
// Handle the special case where the dest is a union of Any and
// a type variable and CanAssignFlags.AllowTypeVarNarrowing is
// in effect. This occurs, for example, with the return type of
// the getattr function.
if ((flags & CanAssignFlags.AllowTypeVarNarrowing) !== 0 && isUnion(destType)) {
const nonAnySubtypes = destType.subtypes.filter((t) => !isAnyOrUnknown(t));
if (nonAnySubtypes.length === 1 && isTypeVar(nonAnySubtypes[0])) {
canAssignType(nonAnySubtypes[0], srcType, /* diag */ undefined, typeVarMap, flags, recursionCount + 1);
// This always succeeds because the destination contains Any.
return true;
}
}
// For union sources, all of the types need to be assignable to the dest.
let isIncompatible = false;
doForEachSubtype(srcType, (subtype) => {

View File

@ -0,0 +1,15 @@
# This sample tests a special case of bidirectional type inference when
# the expected type is a union and the destination type is a union that
# contains Any and a TypeVar.
from typing import Any, Literal, TypeVar
_T = TypeVar("_T")
def getattr(__o: object, name: str, __default: _T) -> Any | _T:
...
x: Literal[1, 2, 3] = getattr(object(), "", 1)

View File

@ -757,6 +757,12 @@ test('GenericTypes71', () => {
TestUtils.validateResults(analysisResults, 4);
});
test('GenericTypes72', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['genericTypes72.py']);
TestUtils.validateResults(analysisResults, 0);
});
test('Protocol1', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['protocol1.py']);