@@ -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
@@ -3514,6 +3513,7 @@ module ts {
35143513 return t => {
35153514 for (let i = 0; i < context.typeParameters.length; i++) {
35163515 if (t === context.typeParameters[i]) {
3516+ context.inferences[i].isFixed = true;
35173517 return getInferredType(context, i);
35183518 }
35193519 }
@@ -4372,8 +4372,11 @@ module ts {
43724372 }
43734373
43744374 function reportNoCommonSupertypeError(types: Type[], errorLocation: Node, errorMessageChainHead: DiagnosticMessageChain): void {
4375+ // The downfallType/bestSupertypeDownfallType is the first type that caused a particular candidate
4376+ // to not be the common supertype. So if it weren't for this one downfallType (and possibly others),
4377+ // the type in question could have been the common supertype.
43754378 let bestSupertype: Type;
4376- let bestSupertypeDownfallType: Type; // The type that caused bestSupertype not to be the common supertype
4379+ let bestSupertypeDownfallType: Type;
43774380 let bestSupertypeScore = 0;
43784381
43794382 for (let i = 0; i < types.length; i++) {
@@ -4388,6 +4391,8 @@ module ts {
43884391 }
43894392 }
43904393
4394+ Debug.assert(!!downfallType, "If there is no common supertype, each type should have a downfallType");
4395+
43914396 if (score > bestSupertypeScore) {
43924397 bestSupertype = types[i];
43934398 bestSupertypeDownfallType = downfallType;
@@ -4570,13 +4575,12 @@ module ts {
45704575 function createInferenceContext(typeParameters: TypeParameter[], inferUnionTypes: boolean): InferenceContext {
45714576 let inferences: TypeInferences[] = [];
45724577 for (let unused of typeParameters) {
4573- inferences.push({ primary: undefined, secondary: undefined });
4578+ inferences.push({ primary: undefined, secondary: undefined, isFixed: false });
45744579 }
45754580 return {
4576- typeParameters: typeParameters,
4577- inferUnionTypes: inferUnionTypes,
4578- inferenceCount: 0,
4579- inferences: inferences,
4581+ typeParameters,
4582+ inferUnionTypes,
4583+ inferences,
45804584 inferredTypes: new Array(typeParameters.length),
45814585 };
45824586 }
@@ -4622,11 +4626,21 @@ module ts {
46224626 for (let i = 0; i < typeParameters.length; i++) {
46234627 if (target === typeParameters[i]) {
46244628 let inferences = context.inferences[i];
4625- let candidates = inferiority ?
4626- inferences.secondary || (inferences.secondary = []) :
4627- inferences.primary || (inferences.primary = []);
4628- if (!contains(candidates, source)) candidates.push(source);
4629- break;
4629+ if (!inferences.isFixed) {
4630+ // Any inferences that are made to a type parameter in a union type are inferior
4631+ // to inferences made to a flat (non-union) type. This is because if we infer to
4632+ // T | string[], we really don't know if we should be inferring to T or not (because
4633+ // the correct constituent on the target side could be string[]). Therefore, we put
4634+ // such inferior inferences into a secondary bucket, and only use them if the primary
4635+ // bucket is empty.
4636+ let candidates = inferiority ?
4637+ inferences.secondary || (inferences.secondary = []) :
4638+ inferences.primary || (inferences.primary = []);
4639+ if (!contains(candidates, source)) {
4640+ candidates.push(source);
4641+ }
4642+ }
4643+ return;
46304644 }
46314645 }
46324646 }
@@ -4732,21 +4746,35 @@ module ts {
47324746
47334747 function getInferredType(context: InferenceContext, index: number): Type {
47344748 let inferredType = context.inferredTypes[index];
4749+ let inferenceSucceeded: boolean;
47354750 if (!inferredType) {
47364751 let inferences = getInferenceCandidates(context, index);
47374752 if (inferences.length) {
4738- // Infer widened union or supertype, or the undefined type for no common supertype
4753+ // Infer widened union or supertype, or the unknown type for no common supertype
47394754 let unionOrSuperType = context.inferUnionTypes ? getUnionType(inferences) : getCommonSupertype(inferences);
4740- inferredType = unionOrSuperType ? getWidenedType(unionOrSuperType) : inferenceFailureType;
4755+ inferredType = unionOrSuperType ? getWidenedType(unionOrSuperType) : unknownType;
4756+ inferenceSucceeded = !!unionOrSuperType;
47414757 }
47424758 else {
4743- // Infer the empty object type when no inferences were made
4759+ // Infer the empty object type when no inferences were made. It is important to remember that
4760+ // in this case, inference still succeeds, meaning there is no error for not having inference
4761+ // candidates. An inference error only occurs when there are *conflicting* candidates, i.e.
4762+ // candidates with no common supertype.
47444763 inferredType = emptyObjectType;
4764+ inferenceSucceeded = true;
47454765 }
4746- if (inferredType !== inferenceFailureType) {
4766+
4767+ // Only do the constraint check if inference succeeded (to prevent cascading errors)
4768+ if (inferenceSucceeded) {
47474769 let constraint = getConstraintOfTypeParameter(context.typeParameters[index]);
47484770 inferredType = constraint && !isTypeAssignableTo(inferredType, constraint) ? constraint : inferredType;
47494771 }
4772+ else if (context.failedTypeParameterIndex === undefined || context.failedTypeParameterIndex > index) {
4773+ // If inference failed, it is necessary to record the index of the failed type parameter (the one we are on).
4774+ // It might be that inference has already failed on a later type parameter on a previous call to inferTypeArguments.
4775+ // So if this failure is on preceding type parameter, this type parameter is the new failure index.
4776+ context.failedTypeParameterIndex = index;
4777+ }
47504778 context.inferredTypes[index] = inferredType;
47514779 }
47524780 return inferredType;
@@ -6343,11 +6371,32 @@ module ts {
63436371 return getSignatureInstantiation(signature, getInferredTypes(context));
63446372 }
63456373
6346- function inferTypeArguments(signature: Signature, args: Expression[], excludeArgument: boolean[]) : InferenceContext {
6374+ function inferTypeArguments(signature: Signature, args: Expression[], excludeArgument: boolean[], context : InferenceContext): void {
63476375 let typeParameters = signature.typeParameters;
6348- let context = createInferenceContext(typeParameters, /*inferUnionTypes*/ false);
63496376 let inferenceMapper = createInferenceMapper(context);
63506377
6378+ // Clear out all the inference results from the last time inferTypeArguments was called on this context
6379+ for (let i = 0; i < typeParameters.length; i++) {
6380+ // As an optimization, we don't have to clear (and later recompute) inferred types
6381+ // for type parameters that have already been fixed on the previous call to inferTypeArguments.
6382+ // It would be just as correct to reset all of them. But then we'd be repeating the same work
6383+ // for the type parameters that were fixed, namely the work done by getInferredType.
6384+ if (!context.inferences[i].isFixed) {
6385+ context.inferredTypes[i] = undefined;
6386+ }
6387+ }
6388+
6389+ // On this call to inferTypeArguments, we may get more inferences for certain type parameters that were not
6390+ // fixed last time. This means that a type parameter that failed inference last time may succeed this time,
6391+ // or vice versa. Therefore, the failedTypeParameterIndex is useless if it points to an unfixed type parameter,
6392+ // because it may change. So here we reset it. However, getInferredType will not revisit any type parameters
6393+ // that were previously fixed. So if a fixed type parameter failed previously, it will fail again because
6394+ // it will contain the exact same set of inferences. So if we reset the index from a fixed type parameter,
6395+ // we will lose information that we won't recover this time around.
6396+ if (context.failedTypeParameterIndex !== undefined && !context.inferences[context.failedTypeParameterIndex].isFixed) {
6397+ context.failedTypeParameterIndex = undefined;
6398+ }
6399+
63516400 // We perform two passes over the arguments. In the first pass we infer from all arguments, but use
63526401 // wildcards for all context sensitive function expressions.
63536402 for (let i = 0; i < args.length; i++) {
@@ -6382,18 +6431,7 @@ module ts {
63826431 }
63836432 }
63846433
6385- let inferredTypes = getInferredTypes(context);
6386- // Inference has failed if the inferenceFailureType type is in list of inferences
6387- context.failedTypeParameterIndex = indexOf(inferredTypes, inferenceFailureType);
6388-
6389- // Wipe out the inferenceFailureType from the array so that error recovery can work properly
6390- for (let i = 0; i < inferredTypes.length; i++) {
6391- if (inferredTypes[i] === inferenceFailureType) {
6392- inferredTypes[i] = unknownType;
6393- }
6394- }
6395-
6396- return context;
6434+ getInferredTypes(context);
63976435 }
63986436
63996437 function checkTypeArguments(signature: Signature, typeArguments: TypeNode[], typeArgumentResultTypes: Type[], reportErrors: boolean): boolean {
@@ -6627,15 +6665,17 @@ module ts {
66276665 return resolveErrorCall(node);
66286666
66296667 function chooseOverload(candidates: Signature[], relation: Map<RelationComparisonResult>) {
6630- for (let current of candidates) {
6631- if (!hasCorrectArity(node, args, current )) {
6668+ for (let originalCandidate of candidates) {
6669+ if (!hasCorrectArity(node, args, originalCandidate )) {
66326670 continue;
66336671 }
6634-
6635- let originalCandidate = current;
6636- let inferenceResult: InferenceContext;
6672+
66376673 let candidate: Signature;
66386674 let typeArgumentsAreValid: boolean;
6675+ let inferenceContext = originalCandidate.typeParameters
6676+ ? createInferenceContext(originalCandidate.typeParameters, /*inferUnionTypes*/ false)
6677+ : undefined;
6678+
66396679 while (true) {
66406680 candidate = originalCandidate;
66416681 if (candidate.typeParameters) {
@@ -6645,9 +6685,9 @@ module ts {
66456685 typeArgumentsAreValid = checkTypeArguments(candidate, typeArguments, typeArgumentTypes, /*reportErrors*/ false)
66466686 }
66476687 else {
6648- inferenceResult = inferTypeArguments(candidate, args, excludeArgument);
6649- typeArgumentsAreValid = inferenceResult .failedTypeParameterIndex < 0 ;
6650- typeArgumentTypes = inferenceResult .inferredTypes;
6688+ inferTypeArguments(candidate, args, excludeArgument, inferenceContext );
6689+ typeArgumentsAreValid = inferenceContext .failedTypeParameterIndex === undefined ;
6690+ typeArgumentTypes = inferenceContext .inferredTypes;
66516691 }
66526692 if (!typeArgumentsAreValid) {
66536693 break;
@@ -6677,7 +6717,7 @@ module ts {
66776717 else {
66786718 candidateForTypeArgumentError = originalCandidate;
66796719 if (!typeArguments) {
6680- resultOfFailedInference = inferenceResult ;
6720+ resultOfFailedInference = inferenceContext ;
66816721 }
66826722 }
66836723 }
0 commit comments