diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 957a3e3630aef..44178aed74b23 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3505,6 +3505,7 @@ module ts { return t => { for (let i = 0; i < context.typeParameters.length; i++) { if (t === context.typeParameters[i]) { + context.inferences[i].isFixed = true; return getInferredType(context, i); } } @@ -4563,12 +4564,11 @@ module ts { function createInferenceContext(typeParameters: TypeParameter[], inferUnionTypes: boolean): InferenceContext { let inferences: TypeInferences[] = []; for (let unused of typeParameters) { - inferences.push({ primary: undefined, secondary: undefined }); + inferences.push({ primary: undefined, secondary: undefined, isFixed: false }); } return { typeParameters: typeParameters, inferUnionTypes: inferUnionTypes, - inferenceCount: 0, inferences: inferences, inferredTypes: new Array(typeParameters.length), }; @@ -4615,11 +4615,13 @@ module ts { for (let i = 0; i < typeParameters.length; i++) { if (target === typeParameters[i]) { let inferences = context.inferences[i]; - let candidates = inferiority ? - inferences.secondary || (inferences.secondary = []) : - inferences.primary || (inferences.primary = []); - if (!contains(candidates, source)) candidates.push(source); - break; + if (!inferences.isFixed) { + let candidates = inferiority ? + inferences.secondary || (inferences.secondary = []) : + inferences.primary || (inferences.primary = []); + if (!contains(candidates, source)) candidates.push(source); + } + return; } } } @@ -6336,11 +6338,15 @@ module ts { return getSignatureInstantiation(signature, getInferredTypes(context)); } - function inferTypeArguments(signature: Signature, args: Expression[], excludeArgument: boolean[]): InferenceContext { + function inferTypeArguments(signature: Signature, args: Expression[], excludeArgument: boolean[], context: InferenceContext): void { let typeParameters = signature.typeParameters; - let context = createInferenceContext(typeParameters, /*inferUnionTypes*/ false); let inferenceMapper = createInferenceMapper(context); + // Clear out all the inference results from the last time inferTypeArguments was called on this context + for (let i = 0; i < typeParameters.length; i++) { + context.inferredTypes[i] = undefined; + } + // We perform two passes over the arguments. In the first pass we infer from all arguments, but use // wildcards for all context sensitive function expressions. for (let i = 0; i < args.length; i++) { @@ -6385,8 +6391,6 @@ module ts { inferredTypes[i] = unknownType; } } - - return context; } function checkTypeArguments(signature: Signature, typeArguments: TypeNode[], typeArgumentResultTypes: Type[], reportErrors: boolean): boolean { @@ -6620,15 +6624,17 @@ module ts { return resolveErrorCall(node); function chooseOverload(candidates: Signature[], relation: Map) { - for (let current of candidates) { - if (!hasCorrectArity(node, args, current)) { + for (let originalCandidate of candidates) { + if (!hasCorrectArity(node, args, originalCandidate)) { continue; } - - let originalCandidate = current; - let inferenceResult: InferenceContext; + let candidate: Signature; let typeArgumentsAreValid: boolean; + let inferenceContext = originalCandidate.typeParameters + ? createInferenceContext(originalCandidate.typeParameters, /*inferUnionTypes*/ false) + : undefined; + while (true) { candidate = originalCandidate; if (candidate.typeParameters) { @@ -6638,9 +6644,9 @@ module ts { typeArgumentsAreValid = checkTypeArguments(candidate, typeArguments, typeArgumentTypes, /*reportErrors*/ false) } else { - inferenceResult = inferTypeArguments(candidate, args, excludeArgument); - typeArgumentsAreValid = inferenceResult.failedTypeParameterIndex < 0; - typeArgumentTypes = inferenceResult.inferredTypes; + inferTypeArguments(candidate, args, excludeArgument, inferenceContext); + typeArgumentsAreValid = inferenceContext.failedTypeParameterIndex < 0; + typeArgumentTypes = inferenceContext.inferredTypes; } if (!typeArgumentsAreValid) { break; @@ -6670,7 +6676,7 @@ module ts { else { candidateForTypeArgumentError = originalCandidate; if (!typeArguments) { - resultOfFailedInference = inferenceResult; + resultOfFailedInference = inferenceContext; } } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c43591911abd4..5880dfdce92ce 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1485,6 +1485,8 @@ module ts { export interface TypeInferences { primary: Type[]; // Inferences made directly to a type parameter secondary: Type[]; // Inferences made to a type parameter in a union type + isFixed: boolean; // Whether the type parameter is fixed, as defined in section 4.12.2 of the TypeScript spec + // If a type parameter is fixed, no more inferences can be made for the type parameter } export interface InferenceContext { diff --git a/tests/baselines/reference/APISample_compile.js b/tests/baselines/reference/APISample_compile.js index 985718231810c..d08d0b3fcc276 100644 --- a/tests/baselines/reference/APISample_compile.js +++ b/tests/baselines/reference/APISample_compile.js @@ -1175,6 +1175,7 @@ declare module "typescript" { interface TypeInferences { primary: Type[]; secondary: Type[]; + isFixed: boolean; } interface InferenceContext { typeParameters: TypeParameter[]; diff --git a/tests/baselines/reference/APISample_compile.types b/tests/baselines/reference/APISample_compile.types index 087c0389d0fce..df0c57444b0a8 100644 --- a/tests/baselines/reference/APISample_compile.types +++ b/tests/baselines/reference/APISample_compile.types @@ -3767,6 +3767,9 @@ declare module "typescript" { secondary: Type[]; >secondary : Type[] >Type : Type + + isFixed: boolean; +>isFixed : boolean } interface InferenceContext { >InferenceContext : InferenceContext diff --git a/tests/baselines/reference/APISample_linter.js b/tests/baselines/reference/APISample_linter.js index d43d622007210..fb390d78f8f2e 100644 --- a/tests/baselines/reference/APISample_linter.js +++ b/tests/baselines/reference/APISample_linter.js @@ -1206,6 +1206,7 @@ declare module "typescript" { interface TypeInferences { primary: Type[]; secondary: Type[]; + isFixed: boolean; } interface InferenceContext { typeParameters: TypeParameter[]; diff --git a/tests/baselines/reference/APISample_linter.types b/tests/baselines/reference/APISample_linter.types index 14eb2936242bd..90360b5fe6122 100644 --- a/tests/baselines/reference/APISample_linter.types +++ b/tests/baselines/reference/APISample_linter.types @@ -3913,6 +3913,9 @@ declare module "typescript" { secondary: Type[]; >secondary : Type[] >Type : Type + + isFixed: boolean; +>isFixed : boolean } interface InferenceContext { >InferenceContext : InferenceContext diff --git a/tests/baselines/reference/APISample_transform.js b/tests/baselines/reference/APISample_transform.js index bfe62135a0db3..96b54ccd91730 100644 --- a/tests/baselines/reference/APISample_transform.js +++ b/tests/baselines/reference/APISample_transform.js @@ -1207,6 +1207,7 @@ declare module "typescript" { interface TypeInferences { primary: Type[]; secondary: Type[]; + isFixed: boolean; } interface InferenceContext { typeParameters: TypeParameter[]; diff --git a/tests/baselines/reference/APISample_transform.types b/tests/baselines/reference/APISample_transform.types index baa497c95fa50..999c81af401e2 100644 --- a/tests/baselines/reference/APISample_transform.types +++ b/tests/baselines/reference/APISample_transform.types @@ -3863,6 +3863,9 @@ declare module "typescript" { secondary: Type[]; >secondary : Type[] >Type : Type + + isFixed: boolean; +>isFixed : boolean } interface InferenceContext { >InferenceContext : InferenceContext diff --git a/tests/baselines/reference/APISample_watcher.js b/tests/baselines/reference/APISample_watcher.js index ee1fd06251576..8a3d2065a23b4 100644 --- a/tests/baselines/reference/APISample_watcher.js +++ b/tests/baselines/reference/APISample_watcher.js @@ -1244,6 +1244,7 @@ declare module "typescript" { interface TypeInferences { primary: Type[]; secondary: Type[]; + isFixed: boolean; } interface InferenceContext { typeParameters: TypeParameter[]; diff --git a/tests/baselines/reference/APISample_watcher.types b/tests/baselines/reference/APISample_watcher.types index a8b534439d546..f66c818c53dc4 100644 --- a/tests/baselines/reference/APISample_watcher.types +++ b/tests/baselines/reference/APISample_watcher.types @@ -4036,6 +4036,9 @@ declare module "typescript" { secondary: Type[]; >secondary : Type[] >Type : Type + + isFixed: boolean; +>isFixed : boolean } interface InferenceContext { >InferenceContext : InferenceContext