@@ -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
@@ -3519,6 +3518,7 @@ module ts {
3519
3518
return t => {
3520
3519
for (let i = 0; i < context.typeParameters.length; i++) {
3521
3520
if (t === context.typeParameters[i]) {
3521
+ context.inferences[i].isFixed = true;
3522
3522
return getInferredType(context, i);
3523
3523
}
3524
3524
}
@@ -4377,8 +4377,11 @@ module ts {
4377
4377
}
4378
4378
4379
4379
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.
4380
4383
let bestSupertype: Type;
4381
- let bestSupertypeDownfallType: Type; // The type that caused bestSupertype not to be the common supertype
4384
+ let bestSupertypeDownfallType: Type;
4382
4385
let bestSupertypeScore = 0;
4383
4386
4384
4387
for (let i = 0; i < types.length; i++) {
@@ -4393,6 +4396,8 @@ module ts {
4393
4396
}
4394
4397
}
4395
4398
4399
+ Debug.assert(!!downfallType, "If there is no common supertype, each type should have a downfallType");
4400
+
4396
4401
if (score > bestSupertypeScore) {
4397
4402
bestSupertype = types[i];
4398
4403
bestSupertypeDownfallType = downfallType;
@@ -4575,13 +4580,12 @@ module ts {
4575
4580
function createInferenceContext(typeParameters: TypeParameter[], inferUnionTypes: boolean): InferenceContext {
4576
4581
let inferences: TypeInferences[] = [];
4577
4582
for (let unused of typeParameters) {
4578
- inferences.push({ primary: undefined, secondary: undefined });
4583
+ inferences.push({ primary: undefined, secondary: undefined, isFixed: false });
4579
4584
}
4580
4585
return {
4581
- typeParameters: typeParameters,
4582
- inferUnionTypes: inferUnionTypes,
4583
- inferenceCount: 0,
4584
- inferences: inferences,
4586
+ typeParameters,
4587
+ inferUnionTypes,
4588
+ inferences,
4585
4589
inferredTypes: new Array(typeParameters.length),
4586
4590
};
4587
4591
}
@@ -4627,11 +4631,21 @@ module ts {
4627
4631
for (let i = 0; i < typeParameters.length; i++) {
4628
4632
if (target === typeParameters[i]) {
4629
4633
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;
4635
4649
}
4636
4650
}
4637
4651
}
@@ -4737,21 +4751,35 @@ module ts {
4737
4751
4738
4752
function getInferredType(context: InferenceContext, index: number): Type {
4739
4753
let inferredType = context.inferredTypes[index];
4754
+ let inferenceSucceeded: boolean;
4740
4755
if (!inferredType) {
4741
4756
let inferences = getInferenceCandidates(context, index);
4742
4757
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
4744
4759
let unionOrSuperType = context.inferUnionTypes ? getUnionType(inferences) : getCommonSupertype(inferences);
4745
- inferredType = unionOrSuperType ? getWidenedType(unionOrSuperType) : inferenceFailureType;
4760
+ inferredType = unionOrSuperType ? getWidenedType(unionOrSuperType) : unknownType;
4761
+ inferenceSucceeded = !!unionOrSuperType;
4746
4762
}
4747
4763
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.
4749
4768
inferredType = emptyObjectType;
4769
+ inferenceSucceeded = true;
4750
4770
}
4751
- if (inferredType !== inferenceFailureType) {
4771
+
4772
+ // Only do the constraint check if inference succeeded (to prevent cascading errors)
4773
+ if (inferenceSucceeded) {
4752
4774
let constraint = getConstraintOfTypeParameter(context.typeParameters[index]);
4753
4775
inferredType = constraint && !isTypeAssignableTo(inferredType, constraint) ? constraint : inferredType;
4754
4776
}
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
+ }
4755
4783
context.inferredTypes[index] = inferredType;
4756
4784
}
4757
4785
return inferredType;
@@ -6348,11 +6376,32 @@ module ts {
6348
6376
return getSignatureInstantiation(signature, getInferredTypes(context));
6349
6377
}
6350
6378
6351
- function inferTypeArguments(signature: Signature, args: Expression[], excludeArgument: boolean[]) : InferenceContext {
6379
+ function inferTypeArguments(signature: Signature, args: Expression[], excludeArgument: boolean[], context : InferenceContext): void {
6352
6380
let typeParameters = signature.typeParameters;
6353
- let context = createInferenceContext(typeParameters, /*inferUnionTypes*/ false);
6354
6381
let inferenceMapper = createInferenceMapper(context);
6355
6382
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
+
6356
6405
// We perform two passes over the arguments. In the first pass we infer from all arguments, but use
6357
6406
// wildcards for all context sensitive function expressions.
6358
6407
for (let i = 0; i < args.length; i++) {
@@ -6387,18 +6436,7 @@ module ts {
6387
6436
}
6388
6437
}
6389
6438
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);
6402
6440
}
6403
6441
6404
6442
function checkTypeArguments(signature: Signature, typeArguments: TypeNode[], typeArgumentResultTypes: Type[], reportErrors: boolean): boolean {
@@ -6632,15 +6670,17 @@ module ts {
6632
6670
return resolveErrorCall(node);
6633
6671
6634
6672
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 )) {
6637
6675
continue;
6638
6676
}
6639
-
6640
- let originalCandidate = current;
6641
- let inferenceResult: InferenceContext;
6677
+
6642
6678
let candidate: Signature;
6643
6679
let typeArgumentsAreValid: boolean;
6680
+ let inferenceContext = originalCandidate.typeParameters
6681
+ ? createInferenceContext(originalCandidate.typeParameters, /*inferUnionTypes*/ false)
6682
+ : undefined;
6683
+
6644
6684
while (true) {
6645
6685
candidate = originalCandidate;
6646
6686
if (candidate.typeParameters) {
@@ -6650,9 +6690,9 @@ module ts {
6650
6690
typeArgumentsAreValid = checkTypeArguments(candidate, typeArguments, typeArgumentTypes, /*reportErrors*/ false)
6651
6691
}
6652
6692
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;
6656
6696
}
6657
6697
if (!typeArgumentsAreValid) {
6658
6698
break;
@@ -6682,7 +6722,7 @@ module ts {
6682
6722
else {
6683
6723
candidateForTypeArgumentError = originalCandidate;
6684
6724
if (!typeArguments) {
6685
- resultOfFailedInference = inferenceResult ;
6725
+ resultOfFailedInference = inferenceContext ;
6686
6726
}
6687
6727
}
6688
6728
}
0 commit comments