@@ -79,8 +79,7 @@ module ts {
7979 let emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
8080 let anyFunctionType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
8181 let noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
82- let inferenceFailureType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
83-
82+
8483 let anySignature = createSignature(undefined, undefined, emptyArray, anyType, 0, false, false);
8584 let unknownSignature = createSignature(undefined, undefined, emptyArray, unknownType, 0, false, false);
8685
@@ -3519,6 +3518,7 @@ module ts {
35193518 return t => {
35203519 for (let i = 0; i < context.typeParameters.length; i++) {
35213520 if (t === context.typeParameters[i]) {
3521+ context.inferences[i].isFixed = true;
35223522 return getInferredType(context, i);
35233523 }
35243524 }
@@ -4377,8 +4377,11 @@ module ts {
43774377 }
43784378
43794379 function reportNoCommonSupertypeError(types: Type[], errorLocation: Node, errorMessageChainHead: DiagnosticMessageChain): void {
4380+ // The downfallType/bestSupertypeDownfallType is the first type that caused a particular candidate
4381+ // to not be the common supertype. So if it weren't for this one downfallType (and possibly others),
4382+ // the type in question could have been the common supertype.
43804383 let bestSupertype: Type;
4381- let bestSupertypeDownfallType: Type; // The type that caused bestSupertype not to be the common supertype
4384+ let bestSupertypeDownfallType: Type;
43824385 let bestSupertypeScore = 0;
43834386
43844387 for (let i = 0; i < types.length; i++) {
@@ -4393,6 +4396,8 @@ module ts {
43934396 }
43944397 }
43954398
4399+ Debug.assert(!!downfallType, "If there is no common supertype, each type should have a downfallType");
4400+
43964401 if (score > bestSupertypeScore) {
43974402 bestSupertype = types[i];
43984403 bestSupertypeDownfallType = downfallType;
@@ -4575,13 +4580,12 @@ module ts {
45754580 function createInferenceContext(typeParameters: TypeParameter[], inferUnionTypes: boolean): InferenceContext {
45764581 let inferences: TypeInferences[] = [];
45774582 for (let unused of typeParameters) {
4578- inferences.push({ primary: undefined, secondary: undefined });
4583+ inferences.push({ primary: undefined, secondary: undefined, isFixed: false });
45794584 }
45804585 return {
4581- typeParameters: typeParameters,
4582- inferUnionTypes: inferUnionTypes,
4583- inferenceCount: 0,
4584- inferences: inferences,
4586+ typeParameters,
4587+ inferUnionTypes,
4588+ inferences,
45854589 inferredTypes: new Array(typeParameters.length),
45864590 };
45874591 }
@@ -4627,11 +4631,21 @@ module ts {
46274631 for (let i = 0; i < typeParameters.length; i++) {
46284632 if (target === typeParameters[i]) {
46294633 let inferences = context.inferences[i];
4630- let candidates = inferiority ?
4631- inferences.secondary || (inferences.secondary = []) :
4632- inferences.primary || (inferences.primary = []);
4633- if (!contains(candidates, source)) candidates.push(source);
4634- break;
4634+ if (!inferences.isFixed) {
4635+ // Any inferences that are made to a type parameter in a union type are inferior
4636+ // to inferences made to a flat (non-union) type. This is because if we infer to
4637+ // T | string[], we really don't know if we should be inferring to T or not (because
4638+ // the correct constituent on the target side could be string[]). Therefore, we put
4639+ // such inferior inferences into a secondary bucket, and only use them if the primary
4640+ // bucket is empty.
4641+ let candidates = inferiority ?
4642+ inferences.secondary || (inferences.secondary = []) :
4643+ inferences.primary || (inferences.primary = []);
4644+ if (!contains(candidates, source)) {
4645+ candidates.push(source);
4646+ }
4647+ }
4648+ return;
46354649 }
46364650 }
46374651 }
@@ -4737,21 +4751,35 @@ module ts {
47374751
47384752 function getInferredType(context: InferenceContext, index: number): Type {
47394753 let inferredType = context.inferredTypes[index];
4754+ let inferenceSucceeded: boolean;
47404755 if (!inferredType) {
47414756 let inferences = getInferenceCandidates(context, index);
47424757 if (inferences.length) {
4743- // Infer widened union or supertype, or the undefined type for no common supertype
4758+ // Infer widened union or supertype, or the unknown type for no common supertype
47444759 let unionOrSuperType = context.inferUnionTypes ? getUnionType(inferences) : getCommonSupertype(inferences);
4745- inferredType = unionOrSuperType ? getWidenedType(unionOrSuperType) : inferenceFailureType;
4760+ inferredType = unionOrSuperType ? getWidenedType(unionOrSuperType) : unknownType;
4761+ inferenceSucceeded = !!unionOrSuperType;
47464762 }
47474763 else {
4748- // Infer the empty object type when no inferences were made
4764+ // Infer the empty object type when no inferences were made. It is important to remember that
4765+ // in this case, inference still succeeds, meaning there is no error for not having inference
4766+ // candidates. An inference error only occurs when there are *conflicting* candidates, i.e.
4767+ // candidates with no common supertype.
47494768 inferredType = emptyObjectType;
4769+ inferenceSucceeded = true;
47504770 }
4751- if (inferredType !== inferenceFailureType) {
4771+
4772+ // Only do the constraint check if inference succeeded (to prevent cascading errors)
4773+ if (inferenceSucceeded) {
47524774 let constraint = getConstraintOfTypeParameter(context.typeParameters[index]);
47534775 inferredType = constraint && !isTypeAssignableTo(inferredType, constraint) ? constraint : inferredType;
47544776 }
4777+ else if (context.failedTypeParameterIndex === undefined || context.failedTypeParameterIndex > index) {
4778+ // If inference failed, it is necessary to record the index of the failed type parameter (the one we are on).
4779+ // It might be that inference has already failed on a later type parameter on a previous call to inferTypeArguments.
4780+ // So if this failure is on preceding type parameter, this type parameter is the new failure index.
4781+ context.failedTypeParameterIndex = index;
4782+ }
47554783 context.inferredTypes[index] = inferredType;
47564784 }
47574785 return inferredType;
@@ -6348,11 +6376,32 @@ module ts {
63486376 return getSignatureInstantiation(signature, getInferredTypes(context));
63496377 }
63506378
6351- function inferTypeArguments(signature: Signature, args: Expression[], excludeArgument: boolean[]) : InferenceContext {
6379+ function inferTypeArguments(signature: Signature, args: Expression[], excludeArgument: boolean[], context : InferenceContext): void {
63526380 let typeParameters = signature.typeParameters;
6353- let context = createInferenceContext(typeParameters, /*inferUnionTypes*/ false);
63546381 let inferenceMapper = createInferenceMapper(context);
63556382
6383+ // Clear out all the inference results from the last time inferTypeArguments was called on this context
6384+ for (let i = 0; i < typeParameters.length; i++) {
6385+ // As an optimization, we don't have to clear (and later recompute) inferred types
6386+ // for type parameters that have already been fixed on the previous call to inferTypeArguments.
6387+ // It would be just as correct to reset all of them. But then we'd be repeating the same work
6388+ // for the type parameters that were fixed, namely the work done by getInferredType.
6389+ if (!context.inferences[i].isFixed) {
6390+ context.inferredTypes[i] = undefined;
6391+ }
6392+ }
6393+
6394+ // On this call to inferTypeArguments, we may get more inferences for certain type parameters that were not
6395+ // fixed last time. This means that a type parameter that failed inference last time may succeed this time,
6396+ // or vice versa. Therefore, the failedTypeParameterIndex is useless if it points to an unfixed type parameter,
6397+ // because it may change. So here we reset it. However, getInferredType will not revisit any type parameters
6398+ // that were previously fixed. So if a fixed type parameter failed previously, it will fail again because
6399+ // it will contain the exact same set of inferences. So if we reset the index from a fixed type parameter,
6400+ // we will lose information that we won't recover this time around.
6401+ if (context.failedTypeParameterIndex !== undefined && !context.inferences[context.failedTypeParameterIndex].isFixed) {
6402+ context.failedTypeParameterIndex = undefined;
6403+ }
6404+
63566405 // We perform two passes over the arguments. In the first pass we infer from all arguments, but use
63576406 // wildcards for all context sensitive function expressions.
63586407 for (let i = 0; i < args.length; i++) {
@@ -6387,18 +6436,7 @@ module ts {
63876436 }
63886437 }
63896438
6390- let inferredTypes = getInferredTypes(context);
6391- // Inference has failed if the inferenceFailureType type is in list of inferences
6392- context.failedTypeParameterIndex = indexOf(inferredTypes, inferenceFailureType);
6393-
6394- // Wipe out the inferenceFailureType from the array so that error recovery can work properly
6395- for (let i = 0; i < inferredTypes.length; i++) {
6396- if (inferredTypes[i] === inferenceFailureType) {
6397- inferredTypes[i] = unknownType;
6398- }
6399- }
6400-
6401- return context;
6439+ getInferredTypes(context);
64026440 }
64036441
64046442 function checkTypeArguments(signature: Signature, typeArguments: TypeNode[], typeArgumentResultTypes: Type[], reportErrors: boolean): boolean {
@@ -6632,15 +6670,17 @@ module ts {
66326670 return resolveErrorCall(node);
66336671
66346672 function chooseOverload(candidates: Signature[], relation: Map<RelationComparisonResult>) {
6635- for (let current of candidates) {
6636- if (!hasCorrectArity(node, args, current )) {
6673+ for (let originalCandidate of candidates) {
6674+ if (!hasCorrectArity(node, args, originalCandidate )) {
66376675 continue;
66386676 }
6639-
6640- let originalCandidate = current;
6641- let inferenceResult: InferenceContext;
6677+
66426678 let candidate: Signature;
66436679 let typeArgumentsAreValid: boolean;
6680+ let inferenceContext = originalCandidate.typeParameters
6681+ ? createInferenceContext(originalCandidate.typeParameters, /*inferUnionTypes*/ false)
6682+ : undefined;
6683+
66446684 while (true) {
66456685 candidate = originalCandidate;
66466686 if (candidate.typeParameters) {
@@ -6650,9 +6690,9 @@ module ts {
66506690 typeArgumentsAreValid = checkTypeArguments(candidate, typeArguments, typeArgumentTypes, /*reportErrors*/ false)
66516691 }
66526692 else {
6653- inferenceResult = inferTypeArguments(candidate, args, excludeArgument);
6654- typeArgumentsAreValid = inferenceResult .failedTypeParameterIndex < 0 ;
6655- typeArgumentTypes = inferenceResult .inferredTypes;
6693+ inferTypeArguments(candidate, args, excludeArgument, inferenceContext );
6694+ typeArgumentsAreValid = inferenceContext .failedTypeParameterIndex === undefined ;
6695+ typeArgumentTypes = inferenceContext .inferredTypes;
66566696 }
66576697 if (!typeArgumentsAreValid) {
66586698 break;
@@ -6682,7 +6722,7 @@ module ts {
66826722 else {
66836723 candidateForTypeArgumentError = originalCandidate;
66846724 if (!typeArguments) {
6685- resultOfFailedInference = inferenceResult ;
6725+ resultOfFailedInference = inferenceContext ;
66866726 }
66876727 }
66886728 }
0 commit comments