Skip to content

Commit 2317daa

Browse files
committed
fixed checker and test results
1 parent d1cfec5 commit 2317daa

5 files changed

+109
-141
lines changed

src/compiler/checker.ts

+90-63
Original file line numberDiff line numberDiff line change
@@ -1487,6 +1487,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
14871487
var lastGetCombinedModifierFlagsNode: Declaration | undefined;
14881488
var lastGetCombinedModifierFlagsResult = ModifierFlags.None;
14891489

1490+
var chooseOverloadRecursionLevel = -1; // #56013
1491+
var chooseOverloadFlushNodesSignaturesReq: (Set<Node> | undefined)[] = []; // #56013
1492+
14901493
// for public members that accept a Node or one of its subtypes, we must guard against
14911494
// synthetic nodes created during transformations by calling `getParseTreeNode`.
14921495
// for most of these, we perform the guard only on `checker` to avoid any possible
@@ -34310,87 +34313,95 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3431034313
}
3431134314

3431234315
function chooseOverload(candidates: Signature[], relation: Map<string, RelationComparisonResult>, isSingleNonGenericCandidate: boolean, signatureHelpTrailingComma = false) {
34313-
candidatesForArgumentError = undefined;
34314-
candidateForArgumentArityError = undefined;
34315-
candidateForTypeArgumentError = undefined;
34316-
34317-
if (isSingleNonGenericCandidate) {
34318-
const candidate = candidates[0];
34319-
if (some(typeArguments) || !hasCorrectArity(node, args, candidate, signatureHelpTrailingComma)) {
34320-
return undefined;
34321-
}
34322-
if (getSignatureApplicabilityError(node, args, candidate, relation, CheckMode.Normal, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) {
34323-
candidatesForArgumentError = [candidate];
34324-
return undefined;
34316+
chooseOverloadRecursionLevel++; // #56013
34317+
chooseOverloadFlushNodesSignaturesReq[chooseOverloadRecursionLevel] = undefined;
34318+
const result = (() => {
34319+
candidatesForArgumentError = undefined;
34320+
candidateForArgumentArityError = undefined;
34321+
candidateForTypeArgumentError = undefined;
34322+
34323+
if (isSingleNonGenericCandidate) {
34324+
const candidate = candidates[0];
34325+
if (some(typeArguments) || !hasCorrectArity(node, args, candidate, signatureHelpTrailingComma)) {
34326+
return undefined;
34327+
}
34328+
if (getSignatureApplicabilityError(node, args, candidate, relation, CheckMode.Normal, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) {
34329+
candidatesForArgumentError = [candidate];
34330+
return undefined;
34331+
}
34332+
return candidate;
3432534333
}
34326-
return candidate;
34327-
}
3432834334

34329-
for (let candidateIndex = 0; candidateIndex < candidates.length; candidateIndex++) {
34330-
const candidate = candidates[candidateIndex];
34331-
if (!hasCorrectTypeArgumentArity(candidate, typeArguments) || !hasCorrectArity(node, args, candidate, signatureHelpTrailingComma)) {
34332-
continue;
34333-
}
34335+
for (let candidateIndex = 0; candidateIndex < candidates.length; candidateIndex++) {
34336+
if (candidateIndex > 0) chooseOverloadFlushNodesSignaturesReq[chooseOverloadRecursionLevel] = new Set(); // #56013
34337+
const candidate = candidates[candidateIndex];
34338+
if (!hasCorrectTypeArgumentArity(candidate, typeArguments) || !hasCorrectArity(node, args, candidate, signatureHelpTrailingComma)) {
34339+
continue;
34340+
}
3433434341

34335-
let checkCandidate: Signature;
34336-
let inferenceContext: InferenceContext | undefined;
34342+
let checkCandidate: Signature;
34343+
let inferenceContext: InferenceContext | undefined;
3433734344

34338-
if (candidate.typeParameters) {
34339-
let typeArgumentTypes: Type[] | undefined;
34340-
if (some(typeArguments)) {
34341-
typeArgumentTypes = checkTypeArguments(candidate, typeArguments, /*reportErrors*/ false);
34342-
if (!typeArgumentTypes) {
34343-
candidateForTypeArgumentError = candidate;
34344-
continue;
34345+
if (candidate.typeParameters) {
34346+
let typeArgumentTypes: Type[] | undefined;
34347+
if (some(typeArguments)) {
34348+
typeArgumentTypes = checkTypeArguments(candidate, typeArguments, /*reportErrors*/ false);
34349+
if (!typeArgumentTypes) {
34350+
candidateForTypeArgumentError = candidate;
34351+
continue;
34352+
}
3434534353
}
34346-
}
34347-
else {
34348-
inferenceContext = createInferenceContext(candidate.typeParameters, candidate, /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None);
34349-
typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode | CheckMode.SkipGenericFunctions, inferenceContext);
34350-
argCheckMode |= inferenceContext.flags & InferenceFlags.SkippedGenericFunction ? CheckMode.SkipGenericFunctions : CheckMode.Normal;
34351-
}
34352-
checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext && inferenceContext.inferredTypeParameters);
34353-
// If the original signature has a generic rest type, instantiation may produce a
34354-
// signature with different arity and we need to perform another arity check.
34355-
if (getNonArrayRestType(candidate) && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma)) {
34356-
candidateForArgumentArityError = checkCandidate;
34357-
continue;
34358-
}
34359-
}
34360-
else {
34361-
checkCandidate = candidate;
34362-
}
34363-
if (getSignatureApplicabilityError(node, args, checkCandidate, relation, argCheckMode, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) {
34364-
// Give preference to error candidates that have no rest parameters (as they are more specific)
34365-
(candidatesForArgumentError || (candidatesForArgumentError = [])).push(checkCandidate);
34366-
continue;
34367-
}
34368-
if (argCheckMode) {
34369-
// If one or more context sensitive arguments were excluded, we start including
34370-
// them now (and keeping do so for any subsequent candidates) and perform a second
34371-
// round of type inference and applicability checking for this particular candidate.
34372-
argCheckMode = CheckMode.Normal;
34373-
if (inferenceContext) {
34374-
const typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode, inferenceContext);
34375-
checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext.inferredTypeParameters);
34354+
else {
34355+
inferenceContext = createInferenceContext(candidate.typeParameters, candidate, /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None);
34356+
typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode | CheckMode.SkipGenericFunctions, inferenceContext);
34357+
argCheckMode |= inferenceContext.flags & InferenceFlags.SkippedGenericFunction ? CheckMode.SkipGenericFunctions : CheckMode.Normal;
34358+
}
34359+
checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext && inferenceContext.inferredTypeParameters);
3437634360
// If the original signature has a generic rest type, instantiation may produce a
3437734361
// signature with different arity and we need to perform another arity check.
3437834362
if (getNonArrayRestType(candidate) && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma)) {
3437934363
candidateForArgumentArityError = checkCandidate;
3438034364
continue;
3438134365
}
3438234366
}
34367+
else {
34368+
checkCandidate = candidate;
34369+
}
3438334370
if (getSignatureApplicabilityError(node, args, checkCandidate, relation, argCheckMode, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) {
3438434371
// Give preference to error candidates that have no rest parameters (as they are more specific)
3438534372
(candidatesForArgumentError || (candidatesForArgumentError = [])).push(checkCandidate);
3438634373
continue;
3438734374
}
34375+
if (argCheckMode) {
34376+
// If one or more context sensitive arguments were excluded, we start including
34377+
// them now (and keeping do so for any subsequent candidates) and perform a second
34378+
// round of type inference and applicability checking for this particular candidate.
34379+
argCheckMode = CheckMode.Normal;
34380+
if (inferenceContext) {
34381+
const typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode, inferenceContext);
34382+
checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext.inferredTypeParameters);
34383+
// If the original signature has a generic rest type, instantiation may produce a
34384+
// signature with different arity and we need to perform another arity check.
34385+
if (getNonArrayRestType(candidate) && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma)) {
34386+
candidateForArgumentArityError = checkCandidate;
34387+
continue;
34388+
}
34389+
}
34390+
if (getSignatureApplicabilityError(node, args, checkCandidate, relation, argCheckMode, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) {
34391+
// Give preference to error candidates that have no rest parameters (as they are more specific)
34392+
(candidatesForArgumentError || (candidatesForArgumentError = [])).push(checkCandidate);
34393+
continue;
34394+
}
34395+
}
34396+
candidates[candidateIndex] = checkCandidate;
34397+
return checkCandidate;
3438834398
}
34389-
candidates[candidateIndex] = checkCandidate;
34390-
return checkCandidate;
34391-
}
3439234399

34393-
return undefined;
34400+
return undefined;
34401+
})();
34402+
chooseOverloadFlushNodesSignaturesReq[chooseOverloadRecursionLevel] = undefined;
34403+
chooseOverloadRecursionLevel--;
34404+
return result;
3439434405
}
3439534406
}
3439634407

@@ -35159,14 +35170,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3515935170
// since resolving such signature leads to resolving the potential outer signature, its arguments and thus the very same signature
3516035171
// it's possible that this inner resolution sets the resolvedSignature first.
3516135172
// In such a case we ignore the local result and reuse the correct one that was cached.
35162-
if (links.resolvedSignature !== resolvingSignature) {
35173+
// [cph 56013] This is buggy - links.resolvedSignature could be `undefined`. Unfortunately flow did not warn us.
35174+
// if (links.resolvedSignature !== resolvingSignature) {
35175+
// result = links.resolvedSignature;
35176+
// }
35177+
if (links.resolvedSignature /* #56013 */ && links.resolvedSignature !== resolvingSignature) {
3516335178
result = links.resolvedSignature;
3516435179
}
3516535180
// If signature resolution originated in control flow type analysis (for example to compute the
3516635181
// assigned type in a flow assignment) we don't cache the result as it may be based on temporary
3516735182
// types from the control flow analysis.
3516835183
links.resolvedSignature = flowLoopStart === flowLoopCount ? result : cached;
3516935184
}
35185+
Debug.assert(result); // [cph] #56013
3517035186
return result;
3517135187
}
3517235188

@@ -35361,6 +35377,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3536135377
}
3536235378

3536335379
function checkDeprecatedSignature(signature: Signature, node: CallLikeExpression) {
35380+
Debug.assert(signature);
3536435381
if (signature.flags & SignatureFlags.IsSignatureCandidateForOverloadFailure) return;
3536535382
if (signature.declaration && signature.declaration.flags & NodeFlags.Deprecated) {
3536635383
const suggestionNode = getDeprecatedSuggestionNode(node);
@@ -38932,6 +38949,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3893238949
const saveCurrentNode = currentNode;
3893338950
currentNode = node;
3893438951
instantiationCount = 0;
38952+
// #56013
38953+
if (node.kind === SyntaxKind.CallExpression && chooseOverloadRecursionLevel >= 0) {
38954+
let setOfNode: Set<Node> | undefined;
38955+
if (chooseOverloadRecursionLevel >= 0 && (setOfNode = chooseOverloadFlushNodesSignaturesReq[chooseOverloadRecursionLevel])) {
38956+
if (!setOfNode.has(node)) {
38957+
getNodeLinks(node).resolvedSignature = undefined;
38958+
setOfNode.add(node);
38959+
}
38960+
}
38961+
}
3893538962
const uninstantiatedType = checkExpressionWorker(node, checkMode, forceTuple);
3893638963
const type = instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, checkMode);
3893738964
if (isConstEnumObjectType(type)) {

tests/baselines/reference/arrayFilterBooleanExternalOverload2.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ declare const maybe: boolean;
7272
>'bar' : "bar"
7373
>undefined : undefined
7474
>filter : { <S extends string | undefined>(predicate: (value: string | undefined, index: number, array: (string | undefined)[]) => value is S, thisArg?: any): S[]; (predicate: (value: string | undefined, index: number, array: (string | undefined)[]) => unknown, thisArg?: any): (string | undefined)[]; (predicate: BooleanConstructor & { prototype: unique symbol; }): string[]; }
75-
>id() : (t: unknown) => boolean
75+
>id() : (t: string | undefined) => boolean
7676
>id : <T>() => (t: T) => boolean
7777

7878
result2;

tests/baselines/reference/arrayFilterBooleanExternalOverload4.errors.txt

-59
This file was deleted.

tests/baselines/reference/arrayFilterBooleanExternalOverload4.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,6 @@ interface F2<T extends number, U extends number> {
4949
type ID = <I>() => (i: I) => I;
5050
declare const id: ID;
5151
declare const t11: 11;
52-
declare const t12: never;
53-
declare const t21: never;
54-
declare const t22: never;
52+
declare const t12: 19;
53+
declare const t21: 91;
54+
declare const t22: 99;

tests/baselines/reference/arrayFilterBooleanExternalOverload4.types

+15-15
Original file line numberDiff line numberDiff line change
@@ -49,37 +49,37 @@ const t11 = (0 as any as F2<1,1>)(id(),id());
4949
>id : ID
5050

5151
const t12 = (0 as any as F2<1,2>)(id(),id());
52-
>t12 : never
53-
>(0 as any as F2<1,2>)(id(),id()) : never
52+
>t12 : 19
53+
>(0 as any as F2<1,2>)(id(),id()) : 19
5454
>(0 as any as F2<1,2>) : F2<1, 2>
5555
>0 as any as F2<1,2> : F2<1, 2>
5656
>0 as any : any
5757
>0 : 0
5858
>id() : (i: 1) => 1
5959
>id : ID
60-
>id() : (i: 1) => 1
60+
>id() : (i: 2) => 2
6161
>id : ID
6262

6363
const t21 = (0 as any as F2<2,1>)(id(),id());
64-
>t21 : never
65-
>(0 as any as F2<2,1>)(id(),id()) : never
64+
>t21 : 91
65+
>(0 as any as F2<2,1>)(id(),id()) : 91
6666
>(0 as any as F2<2,1>) : F2<2, 1>
6767
>0 as any as F2<2,1> : F2<2, 1>
6868
>0 as any : any
6969
>0 : 0
70-
>id() : (i: 1) => 1
70+
>id() : (i: 2) => 2
7171
>id : ID
7272
>id() : (i: 1) => 1
7373
>id : ID
7474

7575
const t22 = (0 as any as F2<2,2>)(id(),id());
76-
>t22 : never
77-
>(0 as any as F2<2,2>)(id(),id()) : never
76+
>t22 : 99
77+
>(0 as any as F2<2,2>)(id(),id()) : 99
7878
>(0 as any as F2<2,2>) : F2<2, 2>
7979
>0 as any as F2<2,2> : F2<2, 2>
8080
>0 as any : any
8181
>0 : 0
82-
>id() : (i: 1) => 1
82+
>id() : (i: 2) => 2
8383
>id : ID
8484
>id() : (i: 2) => 2
8585
>id : ID
@@ -89,15 +89,15 @@ t11 satisfies 11;
8989
>t11 : 11
9090

9191
t12 satisfies 19;
92-
>t12 satisfies 19 : never
93-
>t12 : never
92+
>t12 satisfies 19 : 19
93+
>t12 : 19
9494

9595
t21 satisfies 91;
96-
>t21 satisfies 91 : never
97-
>t21 : never
96+
>t21 satisfies 91 : 91
97+
>t21 : 91
9898

9999
t22 satisfies 99;
100-
>t22 satisfies 99 : never
101-
>t22 : never
100+
>t22 satisfies 99 : 99
101+
>t22 : 99
102102

103103

0 commit comments

Comments
 (0)