Fixed bug that caused Callable type not to be assignable to generic Type[_T] parameter.

This commit is contained in:
Eric Traut 2019-09-30 11:01:10 -07:00
parent 532b3783e7
commit 8b6c825fec
3 changed files with 75 additions and 24 deletions

View File

@ -322,33 +322,24 @@ export function canAssignType(destType: Type, srcType: Type, diag: DiagnosticAdd
return true;
}
if (srcType.category === TypeCategory.Class) {
if (destType.category === TypeCategory.Object) {
const destClassType = destType.classType;
if (ClassType.isBuiltIn(destClassType)) {
// Is the dest a generic "type" object?
const destClassName = ClassType.getClassName(destClassType);
if (destClassName === 'type') {
return true;
}
// Is the src a specialized "Type" object?
if (srcType.category === TypeCategory.Object &&
ClassType.isBuiltIn(srcType.classType, 'Type')) {
if (destClassName === 'Type') {
const destTypeArgs = ClassType.getTypeArguments(destClassType);
if (destTypeArgs && destTypeArgs.length >= 1) {
return canAssignType(destTypeArgs[0],
ObjectType.create(srcType), diag.createAddendum(), typeVarMap,
flags, recursionCount + 1);
}
}
// All classes derive from object.
if (destClassName === 'object') {
return true;
}
const srcTypeArgs = ClassType.getTypeArguments(srcType.classType);
if (srcTypeArgs && srcTypeArgs.length >= 1) {
if (isAnyOrUnknown(srcTypeArgs[0])) {
return true;
} else if (srcTypeArgs[0].category === TypeCategory.Object) {
return canAssignType(destType,
srcTypeArgs[0].classType, diag.createAddendum(), typeVarMap,
flags, recursionCount + 1);
}
}
}
if (destType.category === TypeCategory.Class) {
if (destType.category === TypeCategory.Class) {
if (srcType.category === TypeCategory.Class) {
return _canAssignClass(destType, srcType, diag,
typeVarMap, flags, recursionCount + 1, false);
}
@ -357,13 +348,49 @@ export function canAssignType(destType: Type, srcType: Type, diag: DiagnosticAdd
if (destType.category === TypeCategory.Object) {
const destClassType = destType.classType;
// Is the dest a generic "type" object?
if (ClassType.isBuiltIn(destClassType, 'type')) {
if (srcType.category === TypeCategory.Class ||
srcType.category === TypeCategory.Function ||
srcType.category === TypeCategory.OverloadedFunction) {
return true;
}
}
// Is the dest a specialized "Type" object?
if (ClassType.isBuiltIn(destClassType, 'Type')) {
const destTypeArgs = ClassType.getTypeArguments(destClassType);
if (destTypeArgs && destTypeArgs.length >= 1) {
if (isAnyOrUnknown(destTypeArgs[0])) {
return true;
} else if (destTypeArgs[0].category === TypeCategory.Object) {
return canAssignType(destTypeArgs[0].classType,
srcType, diag.createAddendum(), typeVarMap,
flags, recursionCount + 1);
} else if (destTypeArgs[0].category === TypeCategory.TypeVar) {
if (srcType.category === TypeCategory.Class) {
return canAssignType(destTypeArgs[0],
ObjectType.create(srcType), diag.createAddendum(), typeVarMap,
flags, recursionCount + 1);
} else if (srcType.category === TypeCategory.Function ||
srcType.category === TypeCategory.OverloadedFunction) {
return canAssignType(destTypeArgs[0],
srcType, diag.createAddendum(), typeVarMap,
flags, recursionCount + 1);
}
}
}
}
if (srcType.category === TypeCategory.Object) {
const destLiteral = destType.literalValue;
if (destLiteral !== undefined) {
const srcLiteral = srcType.literalValue;
if (srcLiteral !== destLiteral) {
diag.addMessage(`'${ srcLiteral ? printLiteralValue(srcType) : printType(srcType) }' ` +
`cannot be assigned to '${ printLiteralValue(destType) }'`);
`cannot be assigned to '${ printLiteralValue(destType) }'`);
return false;
}
@ -398,6 +425,11 @@ export function canAssignType(destType: Type, srcType: Type, diag: DiagnosticAdd
if (ClassType.isBuiltIn(destClassType, 'ModuleType')) {
return true;
}
} else if (srcType.category === TypeCategory.Class) {
// All classes are assignable to "object".
if (ClassType.isBuiltIn(destType.classType, 'object')) {
return true;
}
}
}
@ -484,6 +516,8 @@ export function canAssignType(destType: Type, srcType: Type, diag: DiagnosticAdd
return false;
}
diag.addMessage(`'${ printType(srcType) }' ` +
`cannot be assigned to '${ printType(destType) }'`);
return false;
}

View File

@ -0,0 +1,11 @@
# This sample tests the ability for a Callable generic
# to be assigned to a Type[_T] parameter.
from typing import Callable, cast
FUNC = Callable[[int], int]
def foo(i: int) -> int:
return 42
bar = cast(FUNC, foo)

View File

@ -622,6 +622,12 @@ test('GenericTypes2', () => {
validateResults(analysisResults, 1);
});
test('GenericTypes3', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['genericTypes3.py']);
validateResults(analysisResults, 0);
});
test('TypedDict1', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['typedDict1.py']);