mirror of
https://github.com/microsoft/pyright.git
synced 2024-11-10 10:44:34 +03:00
Implemented lazy evaluation of inferred function return types.
This commit is contained in:
parent
728fff47dd
commit
c4e155cb5f
@ -1014,7 +1014,7 @@ export class Checker extends ParseTreeWalker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const inferredReturnType = functionType.inferredReturnType || UnknownType.create();
|
const inferredReturnType = this._evaluator.getFunctionInferredReturnType(functionType);
|
||||||
if (inferredReturnType.category === TypeCategory.Unknown) {
|
if (inferredReturnType.category === TypeCategory.Unknown) {
|
||||||
this._evaluator.addDiagnostic(
|
this._evaluator.addDiagnostic(
|
||||||
this._fileInfo.diagnosticSettings.reportUnknownParameterType,
|
this._fileInfo.diagnosticSettings.reportUnknownParameterType,
|
||||||
|
@ -56,10 +56,10 @@ import { addDefaultFunctionParameters, addTypeVarsToListIfUnique, applyExpectedT
|
|||||||
canBeTruthy, ClassMember, ClassMemberLookupFlags, cloneTypeVarMap, containsUnknown, convertClassToObject,
|
canBeTruthy, ClassMember, ClassMemberLookupFlags, cloneTypeVarMap, containsUnknown, convertClassToObject,
|
||||||
derivesFromClassRecursive, doForSubtypes, getConcreteTypeFromTypeVar, getDeclaredGeneratorReturnType,
|
derivesFromClassRecursive, doForSubtypes, getConcreteTypeFromTypeVar, getDeclaredGeneratorReturnType,
|
||||||
getDeclaredGeneratorSendType, getMetaclass, getSpecializedTupleType, getTypeVarArgumentsRecursive,
|
getDeclaredGeneratorSendType, getMetaclass, getSpecializedTupleType, getTypeVarArgumentsRecursive,
|
||||||
isEllipsisType, isOptionalType, lookUpClassMember, lookUpObjectMember, partiallySpecializeType,
|
isEllipsisType, isNoReturnType, isOptionalType, lookUpClassMember, lookUpObjectMember,
|
||||||
printLiteralValue, removeFalsinessFromType, removeTruthinessFromType,
|
partiallySpecializeType, printLiteralValue, removeFalsinessFromType,
|
||||||
requiresSpecialization, selfSpecializeClassType, specializeType, specializeTypeVarType,
|
removeTruthinessFromType, requiresSpecialization, selfSpecializeClassType, specializeType,
|
||||||
stripFirstParameter, stripLiteralValue, transformTypeObjectToClass, TypedDictEntry } from './typeUtils';
|
specializeTypeVarType, stripFirstParameter, stripLiteralValue, transformTypeObjectToClass, TypedDictEntry } from './typeUtils';
|
||||||
|
|
||||||
interface TypeResult {
|
interface TypeResult {
|
||||||
type: Type;
|
type: Type;
|
||||||
@ -233,6 +233,7 @@ export interface TypeEvaluator {
|
|||||||
|
|
||||||
getEffectiveTypeOfSymbol: (symbol: Symbol) => Type;
|
getEffectiveTypeOfSymbol: (symbol: Symbol) => Type;
|
||||||
getFunctionDeclaredReturnType: (node: FunctionNode) => Type | undefined;
|
getFunctionDeclaredReturnType: (node: FunctionNode) => Type | undefined;
|
||||||
|
getFunctionInferredReturnType: (type: FunctionType) => Type;
|
||||||
getBuiltInType: (node: ParseNode, name: string) => Type;
|
getBuiltInType: (node: ParseNode, name: string) => Type;
|
||||||
getTypeOfMember: (member: ClassMember) => Type;
|
getTypeOfMember: (member: ClassMember) => Type;
|
||||||
bindFunctionToClassOrObject: (baseType: ClassType | ObjectType | undefined,
|
bindFunctionToClassOrObject: (baseType: ClassType | ObjectType | undefined,
|
||||||
@ -958,14 +959,14 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
type: classType
|
type: classType
|
||||||
});
|
});
|
||||||
addDefaultFunctionParameters(newType);
|
addDefaultFunctionParameters(newType);
|
||||||
FunctionType.setDeclaredReturnType(newType, ObjectType.create(classType));
|
newType.details.declaredReturnType = ObjectType.create(classType);
|
||||||
|
|
||||||
FunctionType.addParameter(initType, {
|
FunctionType.addParameter(initType, {
|
||||||
category: ParameterCategory.Simple,
|
category: ParameterCategory.Simple,
|
||||||
name: 'self',
|
name: 'self',
|
||||||
type: ObjectType.create(classType)
|
type: ObjectType.create(classType)
|
||||||
});
|
});
|
||||||
FunctionType.setDeclaredReturnType(initType, NoneType.create());
|
initType.details.declaredReturnType = NoneType.create();
|
||||||
|
|
||||||
// Maintain a list of all dataclass parameters (including
|
// Maintain a list of all dataclass parameters (including
|
||||||
// those from inherited classes) plus a list of only those
|
// those from inherited classes) plus a list of only those
|
||||||
@ -1071,7 +1072,7 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
type: classType
|
type: classType
|
||||||
});
|
});
|
||||||
addDefaultFunctionParameters(newType);
|
addDefaultFunctionParameters(newType);
|
||||||
FunctionType.setDeclaredReturnType(newType, ObjectType.create(classType));
|
newType.details.declaredReturnType = ObjectType.create(classType);
|
||||||
|
|
||||||
// Synthesize an __init__ method.
|
// Synthesize an __init__ method.
|
||||||
const initType = FunctionType.create(
|
const initType = FunctionType.create(
|
||||||
@ -1081,7 +1082,7 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
name: 'self',
|
name: 'self',
|
||||||
type: ObjectType.create(classType)
|
type: ObjectType.create(classType)
|
||||||
});
|
});
|
||||||
FunctionType.setDeclaredReturnType(initType, NoneType.create());
|
initType.details.declaredReturnType = NoneType.create();
|
||||||
|
|
||||||
// All parameters must be named, so insert an empty "*".
|
// All parameters must be named, so insert an empty "*".
|
||||||
FunctionType.addParameter(initType, {
|
FunctionType.addParameter(initType, {
|
||||||
@ -1743,7 +1744,7 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
|
|
||||||
if (memberType.category === TypeCategory.Function) {
|
if (memberType.category === TypeCategory.Function) {
|
||||||
const methodType = bindFunctionToClassOrObject(objType, memberType) as FunctionType;
|
const methodType = bindFunctionToClassOrObject(objType, memberType) as FunctionType;
|
||||||
return getEffectiveReturnType(methodType);
|
return getFunctionEffectiveReturnType(methodType);
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
@ -1770,7 +1771,7 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
if (memberType.category === TypeCategory.Function) {
|
if (memberType.category === TypeCategory.Function) {
|
||||||
const methodType = bindFunctionToClassOrObject(
|
const methodType = bindFunctionToClassOrObject(
|
||||||
classType, memberType, true) as FunctionType;
|
classType, memberType, true) as FunctionType;
|
||||||
return getEffectiveReturnType(methodType);
|
return getFunctionEffectiveReturnType(methodType);
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
@ -1979,7 +1980,7 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
name: 'fn',
|
name: 'fn',
|
||||||
type: UnknownType.create()
|
type: UnknownType.create()
|
||||||
});
|
});
|
||||||
FunctionType.setDeclaredReturnType(decoratorType, baseType);
|
decoratorType.details.declaredReturnType = baseType;
|
||||||
type = decoratorType;
|
type = decoratorType;
|
||||||
} else {
|
} else {
|
||||||
diag.addMessage(`Unknown property member`);
|
diag.addMessage(`Unknown property member`);
|
||||||
@ -2179,7 +2180,7 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
const getMemberType = getTypeOfMember(getMember);
|
const getMemberType = getTypeOfMember(getMember);
|
||||||
if (getMemberType.category === TypeCategory.Function) {
|
if (getMemberType.category === TypeCategory.Function) {
|
||||||
if (usage.method === 'get') {
|
if (usage.method === 'get') {
|
||||||
type = getEffectiveReturnType(getMemberType);
|
type = getFunctionEffectiveReturnType(getMemberType);
|
||||||
} else {
|
} else {
|
||||||
// The type isn't important for set or delete usage.
|
// The type isn't important for set or delete usage.
|
||||||
// We just need to return some defined type.
|
// We just need to return some defined type.
|
||||||
@ -2250,7 +2251,7 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
|
|
||||||
if (getAttribType && getAttribType.category === TypeCategory.Function) {
|
if (getAttribType && getAttribType.category === TypeCategory.Function) {
|
||||||
return {
|
return {
|
||||||
type: getEffectiveReturnType(getAttribType),
|
type: getFunctionEffectiveReturnType(getAttribType),
|
||||||
isClassMember: false
|
isClassMember: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -2259,7 +2260,7 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
'__getattr__', { method: 'get' }, MemberAccessFlags.SkipForMethodLookup);
|
'__getattr__', { method: 'get' }, MemberAccessFlags.SkipForMethodLookup);
|
||||||
if (getAttrType && getAttrType.category === TypeCategory.Function) {
|
if (getAttrType && getAttrType.category === TypeCategory.Function) {
|
||||||
return {
|
return {
|
||||||
type: getEffectiveReturnType(getAttrType),
|
type: getFunctionEffectiveReturnType(getAttrType),
|
||||||
isClassMember: false
|
isClassMember: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -3449,7 +3450,7 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return specializeType(getEffectiveReturnType(type), typeVarMap);
|
return specializeType(getFunctionEffectiveReturnType(type), typeVarMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateArgType(argParam: ValidateArgTypeParams, typeVarMap: TypeVarMap,
|
function validateArgType(argParam: ValidateArgTypeParams, typeVarMap: TypeVarMap,
|
||||||
@ -3820,7 +3821,7 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
const constructorType = FunctionType.create(
|
const constructorType = FunctionType.create(
|
||||||
FunctionTypeFlags.StaticMethod | FunctionTypeFlags.ConstructorMethod |
|
FunctionTypeFlags.StaticMethod | FunctionTypeFlags.ConstructorMethod |
|
||||||
FunctionTypeFlags.SynthesizedMethod);
|
FunctionTypeFlags.SynthesizedMethod);
|
||||||
FunctionType.setDeclaredReturnType(constructorType, ObjectType.create(classType));
|
constructorType.details.declaredReturnType = ObjectType.create(classType);
|
||||||
FunctionType.addParameter(constructorType, {
|
FunctionType.addParameter(constructorType, {
|
||||||
category: ParameterCategory.Simple,
|
category: ParameterCategory.Simple,
|
||||||
name: 'cls',
|
name: 'cls',
|
||||||
@ -3975,27 +3976,27 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
FunctionTypeFlags.InstanceMethod | FunctionTypeFlags.SynthesizedMethod);
|
FunctionTypeFlags.InstanceMethod | FunctionTypeFlags.SynthesizedMethod);
|
||||||
FunctionType.addParameter(initType, selfParameter);
|
FunctionType.addParameter(initType, selfParameter);
|
||||||
addDefaultFunctionParameters(initType);
|
addDefaultFunctionParameters(initType);
|
||||||
FunctionType.setDeclaredReturnType(initType, NoneType.create());
|
initType.details.declaredReturnType = NoneType.create();
|
||||||
|
|
||||||
classFields.set('__new__', Symbol.createWithType(SymbolFlags.ClassMember, constructorType));
|
classFields.set('__new__', Symbol.createWithType(SymbolFlags.ClassMember, constructorType));
|
||||||
classFields.set('__init__', Symbol.createWithType(SymbolFlags.ClassMember, initType));
|
classFields.set('__init__', Symbol.createWithType(SymbolFlags.ClassMember, initType));
|
||||||
|
|
||||||
const keysItemType = FunctionType.create(FunctionTypeFlags.SynthesizedMethod);
|
const keysItemType = FunctionType.create(FunctionTypeFlags.SynthesizedMethod);
|
||||||
FunctionType.setDeclaredReturnType(keysItemType, getBuiltInObject(errorNode, 'list',
|
keysItemType.details.declaredReturnType = getBuiltInObject(errorNode, 'list',
|
||||||
[getBuiltInObject(errorNode, 'str')]));
|
[getBuiltInObject(errorNode, 'str')]);
|
||||||
classFields.set('keys', Symbol.createWithType(SymbolFlags.InstanceMember, keysItemType));
|
classFields.set('keys', Symbol.createWithType(SymbolFlags.InstanceMember, keysItemType));
|
||||||
classFields.set('items', Symbol.createWithType(SymbolFlags.InstanceMember, keysItemType));
|
classFields.set('items', Symbol.createWithType(SymbolFlags.InstanceMember, keysItemType));
|
||||||
|
|
||||||
const lenType = FunctionType.create(
|
const lenType = FunctionType.create(
|
||||||
FunctionTypeFlags.InstanceMethod | FunctionTypeFlags.SynthesizedMethod);
|
FunctionTypeFlags.InstanceMethod | FunctionTypeFlags.SynthesizedMethod);
|
||||||
FunctionType.setDeclaredReturnType(lenType, getBuiltInObject(errorNode, 'int'));
|
lenType.details.declaredReturnType = getBuiltInObject(errorNode, 'int');
|
||||||
FunctionType.addParameter(lenType, selfParameter);
|
FunctionType.addParameter(lenType, selfParameter);
|
||||||
classFields.set('__len__', Symbol.createWithType(SymbolFlags.ClassMember, lenType));
|
classFields.set('__len__', Symbol.createWithType(SymbolFlags.ClassMember, lenType));
|
||||||
|
|
||||||
if (addGenericGetAttribute) {
|
if (addGenericGetAttribute) {
|
||||||
const getAttribType = FunctionType.create(
|
const getAttribType = FunctionType.create(
|
||||||
FunctionTypeFlags.InstanceMethod | FunctionTypeFlags.SynthesizedMethod);
|
FunctionTypeFlags.InstanceMethod | FunctionTypeFlags.SynthesizedMethod);
|
||||||
FunctionType.setDeclaredReturnType(getAttribType, AnyType.create());
|
getAttribType.details.declaredReturnType = AnyType.create();
|
||||||
FunctionType.addParameter(getAttribType, selfParameter);
|
FunctionType.addParameter(getAttribType, selfParameter);
|
||||||
FunctionType.addParameter(getAttribType, {
|
FunctionType.addParameter(getAttribType, {
|
||||||
category: ParameterCategory.Simple,
|
category: ParameterCategory.Simple,
|
||||||
@ -4794,7 +4795,7 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
// present, should specify the return type.
|
// present, should specify the return type.
|
||||||
function createCallableType(typeArgs?: TypeResult[]): FunctionType {
|
function createCallableType(typeArgs?: TypeResult[]): FunctionType {
|
||||||
const functionType = FunctionType.create(FunctionTypeFlags.None);
|
const functionType = FunctionType.create(FunctionTypeFlags.None);
|
||||||
FunctionType.setDeclaredReturnType(functionType, AnyType.create());
|
functionType.details.declaredReturnType = AnyType.create();
|
||||||
|
|
||||||
if (typeArgs && typeArgs.length > 0) {
|
if (typeArgs && typeArgs.length > 0) {
|
||||||
if (typeArgs[0].typeList) {
|
if (typeArgs[0].typeList) {
|
||||||
@ -4826,9 +4827,9 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
} else if (typeArgs[1].type.category === TypeCategory.Module) {
|
} else if (typeArgs[1].type.category === TypeCategory.Module) {
|
||||||
addError(`Module not allowed in this context`, typeArgs[1].node);
|
addError(`Module not allowed in this context`, typeArgs[1].node);
|
||||||
}
|
}
|
||||||
FunctionType.setDeclaredReturnType(functionType, convertClassToObject(typeArgs[1].type));
|
functionType.details.declaredReturnType = convertClassToObject(typeArgs[1].type);
|
||||||
} else {
|
} else {
|
||||||
FunctionType.setDeclaredReturnType(functionType, AnyType.create());
|
functionType.details.declaredReturnType = AnyType.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeArgs && typeArgs.length > 2) {
|
if (typeArgs && typeArgs.length > 2) {
|
||||||
@ -5573,7 +5574,7 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
// validated against this type.
|
// validated against this type.
|
||||||
if (node.returnTypeAnnotation) {
|
if (node.returnTypeAnnotation) {
|
||||||
const returnType = getTypeOfAnnotation(node.returnTypeAnnotation);
|
const returnType = getTypeOfAnnotation(node.returnTypeAnnotation);
|
||||||
FunctionType.setDeclaredReturnType(functionType, returnType);
|
functionType.details.declaredReturnType = returnType;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the class as abstract if it contains at least one abstract method.
|
// Mark the class as abstract if it contains at least one abstract method.
|
||||||
@ -5688,14 +5689,9 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Infer the return type based on the body of the function.
|
|
||||||
if (!node.returnTypeAnnotation) {
|
|
||||||
functionType.inferredReturnType = inferFunctionReturnType(
|
|
||||||
node, FunctionType.isAbstractMethod(functionType));
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it's an async function, wrap the return type in an Awaitable or Generator.
|
// If it's an async function, wrap the return type in an Awaitable or Generator.
|
||||||
const preDecoratedType = node.isAsync ? createAwaitableFunction(node, functionType) : functionType;
|
const preDecoratedType = node.isAsync ?
|
||||||
|
createAwaitableFunction(node, functionType) : functionType;
|
||||||
|
|
||||||
// Apply all of the decorators in reverse order.
|
// Apply all of the decorators in reverse order.
|
||||||
decoratedType = preDecoratedType;
|
decoratedType = preDecoratedType;
|
||||||
@ -5924,12 +5920,24 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createAwaitableFunction(node: ParseNode, functionType: FunctionType): FunctionType {
|
function createAwaitableFunction(node: FunctionNode, functionType: FunctionType): FunctionType {
|
||||||
const returnType = functionType.details.declaredReturnType || functionType.inferredReturnType;
|
// Clone the original function and replace its return type with an
|
||||||
if (!returnType) {
|
// Awaitable[<returnType>].
|
||||||
return functionType;
|
const awaitableFunctionType = FunctionType.clone(functionType);
|
||||||
|
|
||||||
|
if (functionType.details.declaredReturnType) {
|
||||||
|
awaitableFunctionType.details.declaredReturnType = createAwaitableReturnType(
|
||||||
|
node, functionType.details.declaredReturnType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note that the inferred type, once lazily computed, needs to wrap the
|
||||||
|
// resulting type in an awaitable.
|
||||||
|
awaitableFunctionType.details.flags |= FunctionTypeFlags.WrapReturnTypeInAwait;
|
||||||
|
|
||||||
|
return awaitableFunctionType;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createAwaitableReturnType(node: ParseNode, returnType: Type): Type {
|
||||||
let awaitableReturnType: Type | undefined;
|
let awaitableReturnType: Type | undefined;
|
||||||
|
|
||||||
if (returnType.category === TypeCategory.Object) {
|
if (returnType.category === TypeCategory.Object) {
|
||||||
@ -5968,12 +5976,7 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone the original function and replace its return type with an
|
return awaitableReturnType;
|
||||||
// Awaitable[<returnType>].
|
|
||||||
const awaitableFunctionType = FunctionType.clone(functionType);
|
|
||||||
FunctionType.setDeclaredReturnType(awaitableFunctionType, awaitableReturnType);
|
|
||||||
|
|
||||||
return awaitableFunctionType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function inferFunctionReturnType(node: FunctionNode, isAbstract: boolean): Type | undefined {
|
function inferFunctionReturnType(node: FunctionNode, isAbstract: boolean): Type | undefined {
|
||||||
@ -6211,7 +6214,7 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
if (memberType) {
|
if (memberType) {
|
||||||
let memberReturnType: Type;
|
let memberReturnType: Type;
|
||||||
if (memberType.category === TypeCategory.Function) {
|
if (memberType.category === TypeCategory.Function) {
|
||||||
memberReturnType = getEffectiveReturnType(memberType);
|
memberReturnType = getFunctionEffectiveReturnType(memberType);
|
||||||
} else {
|
} else {
|
||||||
memberReturnType = UnknownType.create();
|
memberReturnType = UnknownType.create();
|
||||||
}
|
}
|
||||||
@ -7235,6 +7238,13 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
function useSpeculativeMode(callback: () => void) {
|
function useSpeculativeMode(callback: () => void) {
|
||||||
const prevSpeculativeMode = isSpeculativeMode;
|
const prevSpeculativeMode = isSpeculativeMode;
|
||||||
isSpeculativeMode = true;
|
isSpeculativeMode = true;
|
||||||
|
callback();
|
||||||
|
isSpeculativeMode = prevSpeculativeMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
function disableSpeculativeMode(callback: () => void) {
|
||||||
|
const prevSpeculativeMode = isSpeculativeMode;
|
||||||
|
isSpeculativeMode = false;
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
|
|
||||||
@ -7639,13 +7649,49 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getEffectiveReturnType(type: FunctionType) {
|
function getFunctionEffectiveReturnType(type: FunctionType) {
|
||||||
const specializedReturnType = FunctionType.getSpecializedReturnType(type);
|
const specializedReturnType = FunctionType.getSpecializedReturnType(type);
|
||||||
if (specializedReturnType) {
|
if (specializedReturnType) {
|
||||||
return specializedReturnType;
|
return specializedReturnType;
|
||||||
}
|
}
|
||||||
|
|
||||||
return type.inferredReturnType || UnknownType.create();
|
return getFunctionInferredReturnType(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFunctionInferredReturnType(type: FunctionType) {
|
||||||
|
// If the return type has already been lazily evaluated,
|
||||||
|
// don't bother computing it again.
|
||||||
|
if (type.inferredReturnType) {
|
||||||
|
return type.inferredReturnType;
|
||||||
|
}
|
||||||
|
|
||||||
|
let returnType: Type | undefined;
|
||||||
|
if (type.details.declaration) {
|
||||||
|
const functionNode = type.details.declaration.node;
|
||||||
|
|
||||||
|
// We should never get here if there is a type annotation.
|
||||||
|
assert(!functionNode.returnTypeAnnotation);
|
||||||
|
|
||||||
|
// Temporarily disable speculative mode while we
|
||||||
|
// lazily evaluate the return type.
|
||||||
|
disableSpeculativeMode(() => {
|
||||||
|
returnType = inferFunctionReturnType(functionNode, FunctionType.isAbstractMethod(type));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Do we need to wrap this in an awaitable?
|
||||||
|
if (returnType && FunctionType.isWrapReturnTypeInAwait(type) && !isNoReturnType(returnType)) {
|
||||||
|
returnType = createAwaitableReturnType(functionNode, returnType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!returnType) {
|
||||||
|
returnType = UnknownType.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache the type for next time.
|
||||||
|
type.inferredReturnType = returnType;
|
||||||
|
|
||||||
|
return returnType;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFunctionDeclaredReturnType(node: FunctionNode): Type | undefined {
|
function getFunctionDeclaredReturnType(node: FunctionNode): Type | undefined {
|
||||||
@ -8239,7 +8285,7 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
const constructorFunction = FunctionType.create(
|
const constructorFunction = FunctionType.create(
|
||||||
FunctionTypeFlags.StaticMethod | FunctionTypeFlags.ConstructorMethod |
|
FunctionTypeFlags.StaticMethod | FunctionTypeFlags.ConstructorMethod |
|
||||||
FunctionTypeFlags.SynthesizedMethod);
|
FunctionTypeFlags.SynthesizedMethod);
|
||||||
FunctionType.setDeclaredReturnType(constructorFunction, ObjectType.create(srcType));
|
constructorFunction.details.declaredReturnType = ObjectType.create(srcType);
|
||||||
|
|
||||||
const newMemberInfo = lookUpClassMember(srcType, '__new__', importLookup,
|
const newMemberInfo = lookUpClassMember(srcType, '__new__', importLookup,
|
||||||
ClassMemberLookupFlags.SkipInstanceVariables | ClassMemberLookupFlags.SkipObjectBaseClass);
|
ClassMemberLookupFlags.SkipInstanceVariables | ClassMemberLookupFlags.SkipObjectBaseClass);
|
||||||
@ -8439,8 +8485,8 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Match the return parameter.
|
// Match the return parameter.
|
||||||
const srcReturnType = getEffectiveReturnType(srcType);
|
const srcReturnType = getFunctionEffectiveReturnType(srcType);
|
||||||
const destReturnType = getEffectiveReturnType(destType);
|
const destReturnType = getFunctionEffectiveReturnType(destType);
|
||||||
|
|
||||||
if (!canAssignType(destReturnType, srcReturnType, diag.createAddendum(),
|
if (!canAssignType(destReturnType, srcReturnType, diag.createAddendum(),
|
||||||
typeVarMap, CanAssignFlags.Default, recursionCount + 1)) {
|
typeVarMap, CanAssignFlags.Default, recursionCount + 1)) {
|
||||||
@ -8519,8 +8565,8 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const baseReturnType = getEffectiveReturnType(baseMethod);
|
const baseReturnType = getFunctionEffectiveReturnType(baseMethod);
|
||||||
const overrideReturnType = getEffectiveReturnType(overrideMethod);
|
const overrideReturnType = getFunctionEffectiveReturnType(overrideMethod);
|
||||||
if (!canAssignType(baseReturnType, overrideReturnType, diag.createAddendum())) {
|
if (!canAssignType(baseReturnType, overrideReturnType, diag.createAddendum())) {
|
||||||
diag.addMessage(`Return type mismatch: ` +
|
diag.addMessage(`Return type mismatch: ` +
|
||||||
`base method returns type '${printType(baseReturnType)}, ` +
|
`base method returns type '${printType(baseReturnType)}, ` +
|
||||||
@ -8839,7 +8885,7 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
return paramString;
|
return paramString;
|
||||||
});
|
});
|
||||||
|
|
||||||
const returnType = getEffectiveReturnType(type);
|
const returnType = getFunctionEffectiveReturnType(type);
|
||||||
const returnTypeString = recursionCount < maxTypeRecursionCount ?
|
const returnTypeString = recursionCount < maxTypeRecursionCount ?
|
||||||
printType(returnType, recursionCount + 1) : '';
|
printType(returnType, recursionCount + 1) : '';
|
||||||
return [paramTypeStrings, returnTypeString];
|
return [paramTypeStrings, returnTypeString];
|
||||||
@ -8888,7 +8934,7 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
|
|
||||||
case TypeCategory.Property: {
|
case TypeCategory.Property: {
|
||||||
const propertyType = type;
|
const propertyType = type;
|
||||||
const returnType = getEffectiveReturnType(propertyType.getter);
|
const returnType = getFunctionEffectiveReturnType(propertyType.getter);
|
||||||
const returnTypeString = recursionCount < maxTypeRecursionCount ?
|
const returnTypeString = recursionCount < maxTypeRecursionCount ?
|
||||||
printType(returnType, recursionCount + 1) : '';
|
printType(returnType, recursionCount + 1) : '';
|
||||||
return returnTypeString;
|
return returnTypeString;
|
||||||
@ -8963,6 +9009,7 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
|||||||
resolveAliasDeclaration,
|
resolveAliasDeclaration,
|
||||||
getEffectiveTypeOfSymbol,
|
getEffectiveTypeOfSymbol,
|
||||||
getFunctionDeclaredReturnType,
|
getFunctionDeclaredReturnType,
|
||||||
|
getFunctionInferredReturnType,
|
||||||
getBuiltInType,
|
getBuiltInType,
|
||||||
getTypeOfMember,
|
getTypeOfMember,
|
||||||
bindFunctionToClassOrObject,
|
bindFunctionToClassOrObject,
|
||||||
|
@ -515,7 +515,8 @@ export const enum FunctionTypeFlags {
|
|||||||
DisableDefaultChecks = 1 << 6,
|
DisableDefaultChecks = 1 << 6,
|
||||||
SynthesizedMethod = 1 << 7,
|
SynthesizedMethod = 1 << 7,
|
||||||
Overloaded = 1 << 8,
|
Overloaded = 1 << 8,
|
||||||
Async = 1 << 9
|
Async = 1 << 9,
|
||||||
|
WrapReturnTypeInAwait = 1 << 10
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FunctionDetails {
|
interface FunctionDetails {
|
||||||
@ -646,6 +647,10 @@ export namespace FunctionType {
|
|||||||
return (type.details.flags & FunctionTypeFlags.Async) !== 0;
|
return (type.details.flags & FunctionTypeFlags.Async) !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isWrapReturnTypeInAwait(type: FunctionType) {
|
||||||
|
return (type.details.flags & FunctionTypeFlags.WrapReturnTypeInAwait) !== 0;
|
||||||
|
}
|
||||||
|
|
||||||
export function getEffectiveParameterType(type: FunctionType, index: number): Type {
|
export function getEffectiveParameterType(type: FunctionType, index: number): Type {
|
||||||
assert(index < type.details.parameters.length);
|
assert(index < type.details.parameters.length);
|
||||||
if (type.specializedTypes) {
|
if (type.specializedTypes) {
|
||||||
@ -663,10 +668,6 @@ export namespace FunctionType {
|
|||||||
return type.specializedTypes && type.specializedTypes.returnType ?
|
return type.specializedTypes && type.specializedTypes.returnType ?
|
||||||
type.specializedTypes.returnType : type.details.declaredReturnType;
|
type.specializedTypes.returnType : type.details.declaredReturnType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setDeclaredReturnType(type: FunctionType, returnType?: Type) {
|
|
||||||
type.details.declaredReturnType = returnType;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OverloadedFunctionType extends TypeBase {
|
export interface OverloadedFunctionType extends TypeBase {
|
||||||
|
Loading…
Reference in New Issue
Block a user