Skip to content

Commit 7dc8683

Browse files
committed
Address PR feedback
1 parent 431bf9a commit 7dc8683

1 file changed

Lines changed: 48 additions & 9 deletions

File tree

src/compiler/checker.ts

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3930,15 +3930,15 @@ module ts {
39303930
}
39313931
}
39323932

3933-
function createInferenceContext(typeParameters: TypeParameter[], inferUnionTypes: boolean, typeArgumentResultTypes?: Type[]): InferenceContext {
3933+
function createInferenceContext(typeParameters: TypeParameter[], inferUnionTypes: boolean): InferenceContext {
39343934
var inferences: Type[][] = [];
39353935
for (var i = 0; i < typeParameters.length; i++) inferences.push([]);
39363936
return {
39373937
typeParameters: typeParameters,
39383938
inferUnionTypes: inferUnionTypes,
39393939
inferenceCount: 0,
39403940
inferences: inferences,
3941-
inferredTypes: typeArgumentResultTypes || new Array(typeParameters.length),
3941+
inferredTypes: new Array(typeParameters.length),
39423942
};
39433943
}
39443944

@@ -5154,9 +5154,9 @@ module ts {
51545154
return getSignatureInstantiation(signature, getInferredTypes(context));
51555155
}
51565156

5157-
function inferTypeArguments(signature: Signature, args: Expression[], typeArgumentResultTypes: Type[], excludeArgument?: boolean[]): InferenceContext {
5157+
function inferTypeArguments(signature: Signature, args: Expression[], excludeArgument?: boolean[]): InferenceContext {
51585158
var typeParameters = signature.typeParameters;
5159-
var context = createInferenceContext(typeParameters, /*inferUnionTypes*/ false, typeArgumentResultTypes);
5159+
var context = createInferenceContext(typeParameters, /*inferUnionTypes*/ false);
51605160
var mapper = createInferenceMapper(context);
51615161
// First infer from arguments that are not context sensitive
51625162
for (var i = 0; i < args.length; i++) {
@@ -5205,8 +5205,7 @@ module ts {
52055205
if (typeArgumentsAreAssignable /* so far */) {
52065206
var constraint = getConstraintOfTypeParameter(typeParameters[i]);
52075207
if (constraint) {
5208-
typeArgumentsAreAssignable = typeArgumentsAreAssignable &&
5209-
checkTypeAssignableTo(typeArgument, constraint, reportErrors ? typeArgNode : undefined,
5208+
typeArgumentsAreAssignable = checkTypeAssignableTo(typeArgument, constraint, reportErrors ? typeArgNode : undefined,
52105209
Diagnostics.Type_0_does_not_satisfy_the_constraint_1_Colon, Diagnostics.Type_0_does_not_satisfy_the_constraint_1);
52115210
}
52125211
}
@@ -5257,10 +5256,42 @@ module ts {
52575256
}
52585257
}
52595258

5259+
// The following variables are captured and modified by calls to chooseOverload.
5260+
// If overload resolution or type argument inference fails, we want to report the
5261+
// best error possible. The best error is one which says that an argument was not
5262+
// assignable to a parameter. This implies that everything else about the overload
5263+
// was fine. So if there is any overload that is only incorrect because of an
5264+
// argument, we will report an error on that one.
5265+
//
5266+
// function foo(s: string) {}
5267+
// function foo(n: number) {} // Report argument error on this overload
5268+
// function foo() {}
5269+
// foo(true);
5270+
//
5271+
// If none of the overloads even made it that far, there are two possibilities.
5272+
// There was a problem with type arguments for some overload, in which case
5273+
// report an error on that. Or none of the overloads even had correct arity,
5274+
// in which case give an arity error.
5275+
//
5276+
// function foo<T>(x: T, y: T) {} // Report type argument inference error
5277+
// function foo() {}
5278+
// foo(0, true);
5279+
//
52605280
var candidateForArgumentError: Signature;
52615281
var candidateForTypeArgumentError: Signature;
52625282
var resultOfFailedInference: InferenceContext;
52635283
var result: Signature;
5284+
5285+
// Section 4.12.1:
5286+
// if the candidate list contains one or more signatures for which the type of each argument
5287+
// expression is a subtype of each corresponding parameter type, the return type of the first
5288+
// of those signatures becomes the return type of the function call.
5289+
// Otherwise, the return type of the first signature in the candidate list becomes the return
5290+
// type of the function call.
5291+
//
5292+
// Whether the call is an error is determined by assignability of the arguments. The subtype pass
5293+
// is just important for choosing the best signature. So in the case where there is only one
5294+
// signature, the subtype pass is useless. So skipping it is an optimization.
52645295
if (candidates.length > 1) {
52655296
result = chooseOverload(candidates, subtypeRelation, excludeArgument);
52665297
}
@@ -5280,6 +5311,11 @@ module ts {
52805311
// If candidate is undefined, it means that no candidates had a suitable arity. In that case,
52815312
// skip the checkApplicableSignature check.
52825313
if (candidateForArgumentError) {
5314+
// excludeArgument is undefined, in this case also equivalent to [undefined, undefined, ...]
5315+
// The importance of exlcludeArgument is to prevent us from typing function expression parameters
5316+
// in arguments too early. If possible, we'd like to only type them once we know the correct
5317+
// overload. However, this matters for the case where the call is correct. When the call is
5318+
// an error, we don't need to exclude any arguments, although it would cause no harm to do so.
52835319
checkApplicableSignature(node, candidateForArgumentError, assignableRelation, /*excludeArgument*/ undefined, /*reportErrors*/ true);
52845320
}
52855321
else if (candidateForTypeArgumentError) {
@@ -5329,14 +5365,16 @@ module ts {
53295365
while (true) {
53305366
var candidate = originalCandidate;
53315367
if (candidate.typeParameters) {
5332-
var typeArgumentTypes = new Array<Type>(candidate.typeParameters.length);
5368+
var typeArgumentTypes: Type[];
53335369
var typeArgumentsAreValid: boolean;
53345370
if (node.typeArguments) {
5371+
typeArgumentTypes = new Array<Type>(candidate.typeParameters.length);
53355372
typeArgumentsAreValid = checkTypeArguments(candidate, node.typeArguments, typeArgumentTypes, /*reportErrors*/ false)
53365373
}
53375374
else {
5338-
inferenceResult = inferTypeArguments(candidate, args, typeArgumentTypes, excludeArgument);
5375+
inferenceResult = inferTypeArguments(candidate, args, excludeArgument);
53395376
typeArgumentsAreValid = inferenceResult.failureIndex < 0;
5377+
typeArgumentTypes = inferenceResult.inferredTypes;
53405378
}
53415379
if (!typeArgumentsAreValid) {
53425380
break;
@@ -5371,7 +5409,8 @@ module ts {
53715409
}
53725410
}
53735411
else {
5374-
candidateForArgumentError = originalCandidate; // Could be candidate too
5412+
Debug.assert(originalCandidate === candidate);
5413+
candidateForArgumentError = originalCandidate;
53755414
}
53765415
}
53775416

0 commit comments

Comments
 (0)