@@ -1940,6 +1940,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1940
1940
const markerSubTypeForCheck = createTypeParameter();
1941
1941
markerSubTypeForCheck.constraint = markerSuperTypeForCheck;
1942
1942
1943
+ const preferInferType = createTypeParameter();
1944
+
1943
1945
const noTypePredicate = createTypePredicate(TypePredicateKind.Identifier, "<<unresolved>>", 0, anyType);
1944
1946
1945
1947
const anySignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None);
@@ -13260,6 +13262,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
13260
13262
type.flags & TypeFlags.IndexedAccess && isConstTypeVariable((type as IndexedAccessType).objectType));
13261
13263
}
13262
13264
13265
+ function isTypeVariablePreferringInference(typeParameter: TypeParameter): boolean {
13266
+ return some(typeParameter.symbol?.declarations, d => hasSyntacticModifier(d, ModifierFlags.PreferInfer));
13267
+ }
13268
+
13263
13269
function getConstraintOfIndexedAccess(type: IndexedAccessType) {
13264
13270
return hasNonCircularBaseConstraint(type) ? getConstraintFromIndexedAccess(type) : undefined;
13265
13271
}
@@ -14095,7 +14101,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
14095
14101
let minTypeArgumentCount = 0;
14096
14102
if (typeParameters) {
14097
14103
for (let i = 0; i < typeParameters.length; i++) {
14098
- if (!hasTypeParameterDefault(typeParameters[i])) {
14104
+ if (!hasTypeParameterDefault(typeParameters[i]) && !isTypeVariablePreferringInference(typeParameters[i]) ) {
14099
14105
minTypeArgumentCount = i + 1;
14100
14106
}
14101
14107
}
@@ -14127,7 +14133,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
14127
14133
}
14128
14134
const baseDefaultType = getDefaultTypeArgumentType(isJavaScriptImplicitAny);
14129
14135
for (let i = numTypeArguments; i < numTypeParameters; i++) {
14130
- let defaultType = getDefaultFromTypeParameter(typeParameters![i]);
14136
+ const typeParam = typeParameters![i];
14137
+ if (isTypeVariablePreferringInference(typeParam)) {
14138
+ result[i] = preferInferType;
14139
+ continue;
14140
+ }
14141
+ let defaultType = getDefaultFromTypeParameter(typeParam);
14131
14142
if (isJavaScriptImplicitAny && defaultType && (isTypeIdenticalTo(defaultType, unknownType) || isTypeIdenticalTo(defaultType, emptyObjectType))) {
14132
14143
defaultType = anyType;
14133
14144
}
@@ -31865,9 +31876,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
31865
31876
}
31866
31877
31867
31878
function checkTypeArguments(signature: Signature, typeArgumentNodes: readonly TypeNode[], reportErrors: boolean, headMessage?: DiagnosticMessage): Type[] | undefined {
31879
+ return checkTypeArgumentsTypes(signature, typeArgumentNodes, map(typeArgumentNodes, getTypeFromTypeNode), reportErrors, headMessage);
31880
+ }
31881
+
31882
+ function checkTypeArgumentsTypes(signature: Signature, typeArgumentNodes: readonly TypeNode[], typeArguments: readonly Type[], reportErrors: boolean, headMessage?: DiagnosticMessage): Type[] | undefined {
31868
31883
const isJavascript = isInJSFile(signature.declaration);
31869
31884
const typeParameters = signature.typeParameters!;
31870
- const typeArgumentTypes = fillMissingTypeArguments(map(typeArgumentNodes, getTypeFromTypeNode), typeParameters, getMinTypeArgumentCount(typeParameters), isJavascript);
31885
+ const typeArgumentTypes = fillMissingTypeArguments(typeArguments, typeParameters, getMinTypeArgumentCount(typeParameters), isJavascript);
31886
+ if (some(typeArgumentTypes, t => t === preferInferType)) {
31887
+ // Do validation once partial inference is complete
31888
+ return typeArgumentTypes;
31889
+ }
31871
31890
let mapper: TypeMapper | undefined;
31872
31891
for (let i = 0; i < typeArgumentNodes.length; i++) {
31873
31892
Debug.assert(typeParameters[i] !== undefined, "Should not call checkTypeArguments with too many type arguments");
@@ -32542,6 +32561,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
32542
32561
diagnostics.add(getArgumentArityError(node, [candidateForArgumentArityError], args));
32543
32562
}
32544
32563
else if (candidateForTypeArgumentError) {
32564
+ // andarist, we could error here - or using a new candidates~ array (?)
32545
32565
checkTypeArguments(candidateForTypeArgumentError, (node as CallExpression | TaggedTemplateExpression | JsxOpeningLikeElement).typeArguments!, /*reportErrors*/ true, fallbackError);
32546
32566
}
32547
32567
else {
@@ -32608,20 +32628,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
32608
32628
let inferenceContext: InferenceContext | undefined;
32609
32629
32610
32630
if (candidate.typeParameters) {
32631
+ const isJavascript = isInJSFile(candidate.declaration);
32611
32632
let typeArgumentTypes: Type[] | undefined;
32612
32633
if (some(typeArguments)) {
32613
32634
typeArgumentTypes = checkTypeArguments(candidate, typeArguments, /*reportErrors*/ false);
32614
32635
if (!typeArgumentTypes) {
32615
32636
candidateForTypeArgumentError = candidate;
32616
32637
continue;
32617
32638
}
32639
+ if (some(typeArgumentTypes, t => t === preferInferType)) {
32640
+ // There are implied inferences we must make, despite having type arguments
32641
+ const originalParams = candidate.typeParameters;
32642
+ const withOriginalArgs = map(typeArgumentTypes, (r, i) => r === preferInferType ? originalParams[i] : r);
32643
+ const uninferedInstantiation = getSignatureInstantiation(candidate, withOriginalArgs, isJavascript);
32644
+ inferenceContext = createInferenceContext(originalParams, uninferedInstantiation, isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None);
32645
+ for (let i = 0; i < inferenceContext.inferences.length; i++) {
32646
+ const correspondingArgument = typeArgumentTypes[i];
32647
+ if (correspondingArgument !== preferInferType) {
32648
+ const inference = inferenceContext.inferences[i];
32649
+ inference.inferredType = correspondingArgument;
32650
+ inference.isFixed = true;
32651
+ inference.priority = InferencePriority.None;
32652
+ }
32653
+ }
32654
+ typeArgumentTypes = inferTypeArguments(node, uninferedInstantiation, args, argCheckMode | CheckMode.SkipGenericFunctions, inferenceContext);
32655
+ // TODO: implement plumbing for error reporting
32656
+ // if (!checkTypeArgumentsTypes(candidate, typeArguments, typeArgumentTypes, /*reportErrors*/ false)) {
32657
+ // continue;
32658
+ // }
32659
+ argCheckMode |= inferenceContext.flags & InferenceFlags.SkippedGenericFunction ? CheckMode.SkipGenericFunctions : CheckMode.Normal;
32660
+ }
32618
32661
}
32619
32662
else {
32620
32663
inferenceContext = createInferenceContext(candidate.typeParameters, candidate, /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None);
32621
32664
typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode | CheckMode.SkipGenericFunctions, inferenceContext);
32622
32665
argCheckMode |= inferenceContext.flags & InferenceFlags.SkippedGenericFunction ? CheckMode.SkipGenericFunctions : CheckMode.Normal;
32623
32666
}
32624
- checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration) , inferenceContext && inferenceContext.inferredTypeParameters);
32667
+ checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isJavascript , inferenceContext && inferenceContext.inferredTypeParameters);
32625
32668
// If the original signature has a generic rest type, instantiation may produce a
32626
32669
// signature with different arity and we need to perform another arity check.
32627
32670
if (getNonArrayRestType(candidate) && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma)) {
@@ -45649,15 +45692,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
45649
45692
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_an_index_signature, tokenToString(modifier.kind));
45650
45693
}
45651
45694
}
45652
- if (modifier.kind !== SyntaxKind.InKeyword && modifier.kind !== SyntaxKind.OutKeyword && modifier.kind !== SyntaxKind.ConstKeyword) {
45695
+ if (modifier.kind !== SyntaxKind.InKeyword && modifier.kind !== SyntaxKind.OutKeyword && modifier.kind !== SyntaxKind.ConstKeyword && modifier.kind !== SyntaxKind.PreferInferKeyword ) {
45653
45696
if (node.kind === SyntaxKind.TypeParameter) {
45654
45697
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_type_parameter, tokenToString(modifier.kind));
45655
45698
}
45656
45699
}
45657
45700
switch (modifier.kind) {
45658
45701
case SyntaxKind.ConstKeyword:
45702
+ case SyntaxKind.PreferInferKeyword:
45659
45703
if (node.kind !== SyntaxKind.EnumDeclaration && node.kind !== SyntaxKind.TypeParameter) {
45660
- return grammarErrorOnNode(node, Diagnostics.A_class_member_cannot_have_the_0_keyword, tokenToString(SyntaxKind.ConstKeyword ));
45704
+ return grammarErrorOnNode(node, Diagnostics.A_class_member_cannot_have_the_0_keyword, tokenToString(modifier.kind ));
45661
45705
}
45662
45706
const parent = node.parent;
45663
45707
if (node.kind === SyntaxKind.TypeParameter && !(isFunctionLikeDeclaration(parent) || isClassLike(parent) || isFunctionTypeNode(parent) ||
0 commit comments