@@ -79,8 +79,7 @@ module ts {
79
79
let emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
80
80
let anyFunctionType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
81
81
let noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
82
- let inferenceFailureType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
83
-
82
+
84
83
let anySignature = createSignature(undefined, undefined, emptyArray, anyType, 0, false, false);
85
84
let unknownSignature = createSignature(undefined, undefined, emptyArray, unknownType, 0, false, false);
86
85
@@ -3514,6 +3513,7 @@ module ts {
3514
3513
return t => {
3515
3514
for (let i = 0; i < context.typeParameters.length; i++) {
3516
3515
if (t === context.typeParameters[i]) {
3516
+ context.inferences[i].isFixed = true;
3517
3517
return getInferredType(context, i);
3518
3518
}
3519
3519
}
@@ -4372,8 +4372,11 @@ module ts {
4372
4372
}
4373
4373
4374
4374
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.
4375
4378
let bestSupertype: Type;
4376
- let bestSupertypeDownfallType: Type; // The type that caused bestSupertype not to be the common supertype
4379
+ let bestSupertypeDownfallType: Type;
4377
4380
let bestSupertypeScore = 0;
4378
4381
4379
4382
for (let i = 0; i < types.length; i++) {
@@ -4388,6 +4391,8 @@ module ts {
4388
4391
}
4389
4392
}
4390
4393
4394
+ Debug.assert(!!downfallType, "If there is no common supertype, each type should have a downfallType");
4395
+
4391
4396
if (score > bestSupertypeScore) {
4392
4397
bestSupertype = types[i];
4393
4398
bestSupertypeDownfallType = downfallType;
@@ -4570,13 +4575,12 @@ module ts {
4570
4575
function createInferenceContext(typeParameters: TypeParameter[], inferUnionTypes: boolean): InferenceContext {
4571
4576
let inferences: TypeInferences[] = [];
4572
4577
for (let unused of typeParameters) {
4573
- inferences.push({ primary: undefined, secondary: undefined });
4578
+ inferences.push({ primary: undefined, secondary: undefined, isFixed: false });
4574
4579
}
4575
4580
return {
4576
- typeParameters: typeParameters,
4577
- inferUnionTypes: inferUnionTypes,
4578
- inferenceCount: 0,
4579
- inferences: inferences,
4581
+ typeParameters,
4582
+ inferUnionTypes,
4583
+ inferences,
4580
4584
inferredTypes: new Array(typeParameters.length),
4581
4585
};
4582
4586
}
@@ -4622,11 +4626,21 @@ module ts {
4622
4626
for (let i = 0; i < typeParameters.length; i++) {
4623
4627
if (target === typeParameters[i]) {
4624
4628
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;
4630
4644
}
4631
4645
}
4632
4646
}
@@ -4732,21 +4746,35 @@ module ts {
4732
4746
4733
4747
function getInferredType(context: InferenceContext, index: number): Type {
4734
4748
let inferredType = context.inferredTypes[index];
4749
+ let inferenceSucceeded: boolean;
4735
4750
if (!inferredType) {
4736
4751
let inferences = getInferenceCandidates(context, index);
4737
4752
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
4739
4754
let unionOrSuperType = context.inferUnionTypes ? getUnionType(inferences) : getCommonSupertype(inferences);
4740
- inferredType = unionOrSuperType ? getWidenedType(unionOrSuperType) : inferenceFailureType;
4755
+ inferredType = unionOrSuperType ? getWidenedType(unionOrSuperType) : unknownType;
4756
+ inferenceSucceeded = !!unionOrSuperType;
4741
4757
}
4742
4758
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.
4744
4763
inferredType = emptyObjectType;
4764
+ inferenceSucceeded = true;
4745
4765
}
4746
- if (inferredType !== inferenceFailureType) {
4766
+
4767
+ // Only do the constraint check if inference succeeded (to prevent cascading errors)
4768
+ if (inferenceSucceeded) {
4747
4769
let constraint = getConstraintOfTypeParameter(context.typeParameters[index]);
4748
4770
inferredType = constraint && !isTypeAssignableTo(inferredType, constraint) ? constraint : inferredType;
4749
4771
}
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
+ }
4750
4778
context.inferredTypes[index] = inferredType;
4751
4779
}
4752
4780
return inferredType;
@@ -6343,11 +6371,32 @@ module ts {
6343
6371
return getSignatureInstantiation(signature, getInferredTypes(context));
6344
6372
}
6345
6373
6346
- function inferTypeArguments(signature: Signature, args: Expression[], excludeArgument: boolean[]) : InferenceContext {
6374
+ function inferTypeArguments(signature: Signature, args: Expression[], excludeArgument: boolean[], context : InferenceContext): void {
6347
6375
let typeParameters = signature.typeParameters;
6348
- let context = createInferenceContext(typeParameters, /*inferUnionTypes*/ false);
6349
6376
let inferenceMapper = createInferenceMapper(context);
6350
6377
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
+
6351
6400
// We perform two passes over the arguments. In the first pass we infer from all arguments, but use
6352
6401
// wildcards for all context sensitive function expressions.
6353
6402
for (let i = 0; i < args.length; i++) {
@@ -6382,18 +6431,7 @@ module ts {
6382
6431
}
6383
6432
}
6384
6433
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);
6397
6435
}
6398
6436
6399
6437
function checkTypeArguments(signature: Signature, typeArguments: TypeNode[], typeArgumentResultTypes: Type[], reportErrors: boolean): boolean {
@@ -6627,15 +6665,17 @@ module ts {
6627
6665
return resolveErrorCall(node);
6628
6666
6629
6667
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 )) {
6632
6670
continue;
6633
6671
}
6634
-
6635
- let originalCandidate = current;
6636
- let inferenceResult: InferenceContext;
6672
+
6637
6673
let candidate: Signature;
6638
6674
let typeArgumentsAreValid: boolean;
6675
+ let inferenceContext = originalCandidate.typeParameters
6676
+ ? createInferenceContext(originalCandidate.typeParameters, /*inferUnionTypes*/ false)
6677
+ : undefined;
6678
+
6639
6679
while (true) {
6640
6680
candidate = originalCandidate;
6641
6681
if (candidate.typeParameters) {
@@ -6645,9 +6685,9 @@ module ts {
6645
6685
typeArgumentsAreValid = checkTypeArguments(candidate, typeArguments, typeArgumentTypes, /*reportErrors*/ false)
6646
6686
}
6647
6687
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;
6651
6691
}
6652
6692
if (!typeArgumentsAreValid) {
6653
6693
break;
@@ -6677,7 +6717,7 @@ module ts {
6677
6717
else {
6678
6718
candidateForTypeArgumentError = originalCandidate;
6679
6719
if (!typeArguments) {
6680
- resultOfFailedInference = inferenceResult ;
6720
+ resultOfFailedInference = inferenceContext ;
6681
6721
}
6682
6722
}
6683
6723
}
0 commit comments