Skip to content

Commit ad823da

Browse files
committed
Consistently defer generic functions to second type inference pass
1 parent bf326aa commit ad823da

File tree

2 files changed

+20
-8
lines changed

2 files changed

+20
-8
lines changed

src/compiler/checker.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20138,7 +20138,7 @@ namespace ts {
2013820138
const paramType = getTypeAtPosition(signature, i);
2013920139
// For context sensitive arguments we pass the identityMapper, which is a signal to treat all
2014020140
// context sensitive function expressions as wildcards
20141-
const checkMode = (excludeArgument && excludeArgument[i] ? CheckMode.SkipContextSensitive : 0) |
20141+
const checkMode = (excludeArgument && i < excludeArgument.length && excludeArgument[i] ? CheckMode.SkipContextSensitive : 0) |
2014220142
(excludeArgument ? CheckMode.SkipGenericFunctions : 0);
2014320143
const argType = checkExpressionWithContextualType(arg, paramType, context, checkMode);
2014420144
inferTypes(context.inferences, argType, paramType);
@@ -20241,7 +20241,7 @@ namespace ts {
2024120241
// However "context" and "updater" are implicit and can't be specify by users. Only the first parameter, props,
2024220242
// can be specified by users through attributes property.
2024320243
const paramType = getEffectiveFirstArgumentForJsxSignature(signature, node);
20244-
const checkMode = excludeArgument && excludeArgument[0] ? CheckMode.SkipContextSensitive : 0;
20244+
const checkMode = excludeArgument && excludeArgument.length > 0 && excludeArgument[0] ? CheckMode.SkipContextSensitive : 0;
2024520245
const attributesType = checkExpressionWithContextualType(node.attributes, paramType, /*contextualMapper*/ undefined, checkMode);
2024620246
return checkTypeRelatedToAndOptionallyElaborate(attributesType, paramType, relation, reportErrors ? node.tagName : undefined, node.attributes);
2024720247
}
@@ -20276,13 +20276,13 @@ namespace ts {
2027620276
const arg = args[i];
2027720277
if (arg.kind !== SyntaxKind.OmittedExpression) {
2027820278
const paramType = getTypeAtPosition(signature, i);
20279-
const checkMode = (excludeArgument && excludeArgument[i] ? CheckMode.SkipContextSensitive : 0) |
20279+
const checkMode = (excludeArgument && i < excludeArgument.length && excludeArgument[i] ? CheckMode.SkipContextSensitive : 0) |
2028020280
(excludeArgument ? CheckMode.SkipGenericFunctions : 0);
2028120281
const argType = checkExpressionWithContextualType(arg, paramType, /*contextualMapper*/ undefined, checkMode);
2028220282
// If one or more arguments are still excluded (as indicated by a non-null excludeArgument parameter),
2028320283
// we obtain the regular type of any object literal arguments because we may not have inferred complete
2028420284
// parameter types yet and therefore excess property checks may yield false positives (see #17041).
20285-
const checkArgType = excludeArgument ? getRegularTypeOfObjectLiteral(argType) : argType;
20285+
const checkArgType = excludeArgument && excludeArgument.length ? getRegularTypeOfObjectLiteral(argType) : argType;
2028620286
if (!checkTypeRelatedToAndOptionallyElaborate(checkArgType, paramType, relation, reportErrors ? arg : undefined, arg, headMessage)) {
2028720287
return false;
2028820288
}
@@ -20665,7 +20665,7 @@ namespace ts {
2066520665
}
2066620666
else {
2066720667
inferenceContext = createInferenceContext(candidate.typeParameters, candidate, /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None);
20668-
typeArgumentTypes = inferTypeArguments(node, candidate, args, excludeArgument, inferenceContext);
20668+
typeArgumentTypes = inferTypeArguments(node, candidate, args, excludeArgument || emptyArray, inferenceContext);
2066920669
}
2067020670
checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext && inferenceContext.inferredTypeParameters);
2067120671
// If the original signature has a generic rest type, instantiation may produce a
@@ -20678,14 +20678,14 @@ namespace ts {
2067820678
else {
2067920679
checkCandidate = candidate;
2068020680
}
20681-
if (!checkApplicableSignature(node, args, checkCandidate, relation, excludeArgument, /*reportErrors*/ false)) {
20681+
if (!checkApplicableSignature(node, args, checkCandidate, relation, excludeArgument || inferenceContext && emptyArray, /*reportErrors*/ false)) {
2068220682
// Give preference to error candidates that have no rest parameters (as they are more specific)
2068320683
if (!candidateForArgumentError || getEffectiveRestType(candidateForArgumentError) || !getEffectiveRestType(checkCandidate)) {
2068420684
candidateForArgumentError = checkCandidate;
2068520685
}
2068620686
continue;
2068720687
}
20688-
if (excludeArgument) {
20688+
if (excludeArgument || inferenceContext && inferenceContext.flags & InferenceFlags.SkippedGenericFunction) {
2068920689
// If one or more context sensitive arguments were excluded, we start including
2069020690
// them now (and keeping do so for any subsequent candidates) and perform a second
2069120691
// round of type inference and applicability checking for this particular candidate.
@@ -20830,7 +20830,7 @@ namespace ts {
2083020830

2083120831
function inferSignatureInstantiationForOverloadFailure(node: CallLikeExpression, typeParameters: ReadonlyArray<TypeParameter>, candidate: Signature, args: ReadonlyArray<Expression>): Signature {
2083220832
const inferenceContext = createInferenceContext(typeParameters, candidate, /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None);
20833-
const typeArgumentTypes = inferTypeArguments(node, candidate, args, getExcludeArgument(args), inferenceContext);
20833+
const typeArgumentTypes = inferTypeArguments(node, candidate, args, getExcludeArgument(args) || emptyArray, inferenceContext);
2083420834
return createSignatureInstantiation(candidate, typeArgumentTypes);
2083520835
}
2083620836

@@ -20932,6 +20932,7 @@ namespace ts {
2093220932
// sensitive arguments are being deferred) and every call signature is generic and returns a function type,
2093320933
// we return resolvingSignature here. This result will be propagated out and turned into anyFunctionType.
2093420934
if (checkMode & CheckMode.SkipGenericFunctions && callSignatures.every(isGenericFunctionReturningFunction)) {
20935+
skippedGenericFunction(node, checkMode);
2093520936
return resolvingSignature;
2093620937
}
2093720938
// If the function is explicitly marked with `@class`, then it must be constructed.
@@ -23387,6 +23388,7 @@ namespace ts {
2338723388
const signature = getSingleCallSignature(type);
2338823389
if (signature && signature.typeParameters) {
2338923390
if (checkMode & CheckMode.SkipGenericFunctions) {
23391+
skippedGenericFunction(node, checkMode);
2339023392
return anyFunctionType;
2339123393
}
2339223394
const contextualType = getApparentTypeOfContextualType(<Expression>node);
@@ -23429,6 +23431,15 @@ namespace ts {
2342923431
return type;
2343023432
}
2343123433

23434+
function skippedGenericFunction(node: Node, checkMode: CheckMode) {
23435+
if (checkMode & CheckMode.Inferential) {
23436+
// We have skipped a generic function during inferential typing. Obtain the inference context and
23437+
// indicate this has occurred such that we know a second pass of inference is be needed.
23438+
const context = <InferenceContext>getContextualMapper(node);
23439+
context.flags |= InferenceFlags.SkippedGenericFunction;
23440+
}
23441+
}
23442+
2343223443
function hasInferenceCandidates(info: InferenceInfo) {
2343323444
return !!(info.candidates || info.contraCandidates);
2343423445
}

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4362,6 +4362,7 @@ namespace ts {
43624362
NoDefault = 1 << 0, // Infer unknownType for no inferences (otherwise anyType or emptyObjectType)
43634363
AnyDefault = 1 << 1, // Infer anyType for no inferences (otherwise emptyObjectType)
43644364
NoFixing = 1 << 2, // Disable type parameter fixing
4365+
SkippedGenericFunction = 1 << 3,
43654366
}
43664367

43674368
/**

0 commit comments

Comments
 (0)