isValidMethodAccess: Instantiate signature this type if necessary (#21722)

This commit is contained in:
Andy 2018-03-06 10:18:06 -08:00 committed by GitHub
parent e5f91f5948
commit a138985448
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 21 additions and 8 deletions

View file

@ -6959,7 +6959,10 @@ namespace ts {
}
function createSignatureInstantiation(signature: Signature, typeArguments: Type[]): Signature {
return instantiateSignature(signature, createTypeMapper(signature.typeParameters, typeArguments), /*eraseTypeParameters*/ true);
return instantiateSignature(signature, createSignatureTypeMapper(signature, typeArguments), /*eraseTypeParameters*/ true);
}
function createSignatureTypeMapper(signature: Signature, typeArguments: Type[]): TypeMapper {
return createTypeMapper(signature.typeParameters, typeArguments);
}
function getErasedSignature(signature: Signature): Signature {
@ -11419,8 +11422,8 @@ namespace ts {
}
}
function createInferenceContext(typeParameters: TypeParameter[], signature: Signature, flags: InferenceFlags, compareTypes?: TypeComparer, baseInferences?: InferenceInfo[]): InferenceContext {
const inferences = baseInferences ? map(baseInferences, cloneInferenceInfo) : map(typeParameters, createInferenceInfo);
function createInferenceContext(typeParameters: TypeParameter[], signature: Signature | undefined, flags: InferenceFlags, compareTypes?: TypeComparer, baseInferences?: InferenceInfo[]): InferenceContext {
const inferences = baseInferences ? baseInferences.map(cloneInferenceInfo) : typeParameters.map(createInferenceInfo);
const context = mapper as InferenceContext;
context.typeParameters = typeParameters;
context.signature = signature;
@ -16409,15 +16412,23 @@ namespace ts {
return isValidPropertyAccessWithType(node, node.expression, property.escapedName, type)
&& (!(property.flags & SymbolFlags.Method) || isValidMethodAccess(property, type));
}
function isValidMethodAccess(method: Symbol, type: Type) {
function isValidMethodAccess(method: Symbol, actualThisType: Type): boolean {
const propType = getTypeOfFuncClassEnumModule(method);
const signatures = getSignaturesOfType(getNonNullableType(propType), SignatureKind.Call);
Debug.assert(signatures.length !== 0);
return signatures.some(sig => {
const thisType = getThisTypeOfSignature(sig);
return !thisType || isTypeAssignableTo(type, thisType);
const signatureThisType = getThisTypeOfSignature(sig);
return !signatureThisType || isTypeAssignableTo(actualThisType, getInstantiatedSignatureThisType(sig, signatureThisType, actualThisType));
});
}
function getInstantiatedSignatureThisType(sig: Signature, signatureThisType: Type, actualThisType: Type): Type {
if (!sig.typeParameters) {
return signatureThisType;
}
const context = createInferenceContext(sig.typeParameters, sig, InferenceFlags.None);
inferTypes(context.inferences, actualThisType, signatureThisType);
return instantiateType(signatureThisType, createSignatureTypeMapper(sig, getInferredTypes(context)));
}
function isValidPropertyAccessWithType(
node: PropertyAccessExpression | QualifiedName,

View file

@ -4,6 +4,8 @@
//// value: T; // Make the type parameter actually matter
//// ms(this: A<string>) {}
//// mo(this: A<{}>) {}
//// mp<P>(this: A<P>) {}
//// mps<P extends string>(this: A<P>) {}
////}
////
////const s = new A<string>();
@ -11,5 +13,5 @@
////s./*s*/;
////n./*n*/;
verify.completionsAt("s", ["value", "ms", "mo"]);
verify.completionsAt("n", ["value", "mo"]);
verify.completionsAt("s", ["value", "ms", "mo", "mp", "mps"]);
verify.completionsAt("n", ["value", "mo", "mp"]);