Skip to content
Closed
27 changes: 16 additions & 11 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9920,7 +9920,7 @@ namespace ts {
bestSupertypeScore = score;
}

// types.length - 1 is the maximum score, given that getCommonSupertype returned false
Debug.assert(bestSupertypeScore < types.length, "types.length - 1 is the maximum score, given that getCommonSuperType returned false");
if (bestSupertypeScore === types.length - 1) {
break;
}
Expand Down Expand Up @@ -10631,6 +10631,19 @@ namespace ts {
return type.flags & TypeFlags.Union ? getUnionType(reducedTypes) : getIntersectionType(reducedTypes);
}

/**
* We widen inferred literal types if
* all inferences were made to top-level ocurrences of the type parameter, and
* the type parameter has no constraint or its constraint includes no primitive or literal types, and
* the type parameter was fixed during inference or does not occur at top-level in the return type.
*/
function widenInferenceCandidates(inference: InferenceInfo, signature: Signature) {
const widenLiteralTypes = inference.topLevel &&
!hasPrimitiveConstraint(inference.typeParameter) &&
(inference.isFixed || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), inference.typeParameter));
return widenLiteralTypes ? sameMap(inference.candidates, getWidenedLiteralType) : inference.candidates;
}

function hasPrimitiveConstraint(type: TypeParameter): boolean {
const constraint = getConstraintOfTypeParameter(type);
return constraint && maybeTypeOfKind(constraint, TypeFlags.Primitive | TypeFlags.Index);
Expand All @@ -10642,15 +10655,7 @@ namespace ts {
let inferenceSucceeded: boolean;
if (!inferredType) {
if (inference.candidates) {
// We widen inferred literal types if
// all inferences were made to top-level ocurrences of the type parameter, and
// the type parameter has no constraint or its constraint includes no primitive or literal types, and
// the type parameter was fixed during inference or does not occur at top-level in the return type.
const signature = context.signature;
const widenLiteralTypes = inference.topLevel &&
!hasPrimitiveConstraint(inference.typeParameter) &&
(inference.isFixed || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), inference.typeParameter));
const baseCandidates = widenLiteralTypes ? sameMap(inference.candidates, getWidenedLiteralType) : inference.candidates;
const baseCandidates = widenInferenceCandidates(inference, context.signature);
// Infer widened union or supertype, or the unknown type for no common supertype. We infer union types
// for inferences coming from return types in order to avoid common supertype failures.
const unionOrSuperType = context.flags & InferenceFlags.InferUnionTypes || inference.priority & InferencePriority.ReturnType ?
Expand Down Expand Up @@ -15649,7 +15654,7 @@ namespace ts {
else {
Debug.assert(resultOfFailedInference.failedTypeParameterIndex >= 0);
const failedTypeParameter = candidateForTypeArgumentError.typeParameters[resultOfFailedInference.failedTypeParameterIndex];
const inferenceCandidates = resultOfFailedInference.inferences[resultOfFailedInference.failedTypeParameterIndex].candidates;
const inferenceCandidates = widenInferenceCandidates(resultOfFailedInference.inferences[resultOfFailedInference.failedTypeParameterIndex], resultOfFailedInference.signature);

let diagnosticChainHead = chainDiagnosticMessages(/*details*/ undefined, // details will be provided by call to reportNoCommonSupertypeError
Diagnostics.The_type_argument_for_type_parameter_0_cannot_be_inferred_from_the_usage_Consider_specifying_the_type_arguments_explicitly,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
tests/cases/compiler/fixTypeParameterInSignatureWithRestParameters.ts(2,1): error TS2453: The type argument for type parameter 'T' cannot be inferred from the usage. Consider specifying the type arguments explicitly.
Type argument candidate '1' is not a valid type argument because it is not a supertype of candidate '""'.
Type argument candidate 'number' is not a valid type argument because it is not a supertype of candidate 'string'.


==== tests/cases/compiler/fixTypeParameterInSignatureWithRestParameters.ts (1 errors) ====
function bar<T>(item1: T, item2: T) { }
bar(1, ""); // Should be ok
~~~
!!! error TS2453: The type argument for type parameter 'T' cannot be inferred from the usage. Consider specifying the type arguments explicitly.
!!! error TS2453: Type argument candidate '1' is not a valid type argument because it is not a supertype of candidate '""'.
!!! error TS2453: Type argument candidate 'number' is not a valid type argument because it is not a supertype of candidate 'string'.
8 changes: 4 additions & 4 deletions tests/baselines/reference/genericRestArgs.errors.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
tests/cases/compiler/genericRestArgs.ts(2,12): error TS2453: The type argument for type parameter 'T' cannot be inferred from the usage. Consider specifying the type arguments explicitly.
Type argument candidate '1' is not a valid type argument because it is not a supertype of candidate '""'.
Type argument candidate 'number' is not a valid type argument because it is not a supertype of candidate 'string'.
tests/cases/compiler/genericRestArgs.ts(5,34): error TS2345: Argument of type '""' is not assignable to parameter of type 'number'.
tests/cases/compiler/genericRestArgs.ts(10,12): error TS2453: The type argument for type parameter 'T' cannot be inferred from the usage. Consider specifying the type arguments explicitly.
Type argument candidate '1' is not a valid type argument because it is not a supertype of candidate '""'.
Type argument candidate 'number' is not a valid type argument because it is not a supertype of candidate 'string'.
tests/cases/compiler/genericRestArgs.ts(12,30): error TS2345: Argument of type '1' is not assignable to parameter of type 'any[]'.


Expand All @@ -11,7 +11,7 @@ tests/cases/compiler/genericRestArgs.ts(12,30): error TS2345: Argument of type '
var a1Ga = makeArrayG(1, ""); // no error
~~~~~~~~~~
!!! error TS2453: The type argument for type parameter 'T' cannot be inferred from the usage. Consider specifying the type arguments explicitly.
!!! error TS2453: Type argument candidate '1' is not a valid type argument because it is not a supertype of candidate '""'.
!!! error TS2453: Type argument candidate 'number' is not a valid type argument because it is not a supertype of candidate 'string'.
var a1Gb = makeArrayG<any>(1, "");
var a1Gc = makeArrayG<Object>(1, "");
var a1Gd = makeArrayG<number>(1, ""); // error
Expand All @@ -24,7 +24,7 @@ tests/cases/compiler/genericRestArgs.ts(12,30): error TS2345: Argument of type '
var a2Ga = makeArrayGOpt(1, "");
~~~~~~~~~~~~~
!!! error TS2453: The type argument for type parameter 'T' cannot be inferred from the usage. Consider specifying the type arguments explicitly.
!!! error TS2453: Type argument candidate '1' is not a valid type argument because it is not a supertype of candidate '""'.
!!! error TS2453: Type argument candidate 'number' is not a valid type argument because it is not a supertype of candidate 'string'.
var a2Gb = makeArrayG<any>(1, "");
var a2Gc = makeArrayG<any[]>(1, ""); // error
~
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
tests/cases/compiler/noCommonSupertypeTypeInferenceMatchesReporting.ts(4,5): error TS2453: The type argument for type parameter 'T' cannot be inferred from the usage. Consider specifying the type arguments explicitly.
Type argument candidate '12 | undefined' is not a valid type argument because it is not a supertype of candidate 'number'.
tests/cases/compiler/noCommonSupertypeTypeInferenceMatchesReporting.ts(5,5): error TS2453: The type argument for type parameter 'T' cannot be inferred from the usage. Consider specifying the type arguments explicitly.
Type argument candidate 'number' is not a valid type argument because it is not a supertype of candidate '12 | undefined'.
Type 'undefined' is not assignable to type 'number'.


==== tests/cases/compiler/noCommonSupertypeTypeInferenceMatchesReporting.ts (2 errors) ====
// Fixes #15116, which asserted on line 5 but not 6
declare function f<T>(a: T, b: T): boolean;
function g(gut: { n: 12 | undefined }) {
f(gut.n, 12); // ok, T = number | undefined
~
!!! error TS2453: The type argument for type parameter 'T' cannot be inferred from the usage. Consider specifying the type arguments explicitly.
!!! error TS2453: Type argument candidate '12 | undefined' is not a valid type argument because it is not a supertype of candidate 'number'.
f(12, gut.n); // ok, T = number | undefined
~
!!! error TS2453: The type argument for type parameter 'T' cannot be inferred from the usage. Consider specifying the type arguments explicitly.
!!! error TS2453: Type argument candidate 'number' is not a valid type argument because it is not a supertype of candidate '12 | undefined'.
!!! error TS2453: Type 'undefined' is not assignable to type 'number'.
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//// [noCommonSupertypeTypeInferenceMatchesReporting.ts]
// Fixes #15116, which asserted on line 5 but not 6
declare function f<T>(a: T, b: T): boolean;
function g(gut: { n: 12 | undefined }) {
f(gut.n, 12); // ok, T = number | undefined
f(12, gut.n); // ok, T = number | undefined
}


//// [noCommonSupertypeTypeInferenceMatchesReporting.js]
function g(gut) {
f(gut.n, 12); // ok, T = number | undefined
f(12, gut.n); // ok, T = number | undefined
}
4 changes: 2 additions & 2 deletions tests/baselines/reference/parser15.4.4.14-9-2.errors.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
tests/cases/conformance/parser/ecmascript5/parser15.4.4.14-9-2.ts(16,15): error TS2453: The type argument for type parameter 'T' cannot be inferred from the usage. Consider specifying the type arguments explicitly.
Type argument candidate 'number' is not a valid type argument because it is not a supertype of candidate 'false'.
Type argument candidate 'number' is not a valid type argument because it is not a supertype of candidate 'boolean'.
tests/cases/conformance/parser/ecmascript5/parser15.4.4.14-9-2.ts(25,1): error TS2304: Cannot find name 'runTestCase'.


Expand All @@ -22,7 +22,7 @@ tests/cases/conformance/parser/ecmascript5/parser15.4.4.14-9-2.ts(25,1): error T
var a = new Array(false,undefined,null,"0",obj,-1.3333333333333, "str",-0,true,+0, one, 1,0, false, _float, -(4/3));
~~~~~
!!! error TS2453: The type argument for type parameter 'T' cannot be inferred from the usage. Consider specifying the type arguments explicitly.
!!! error TS2453: Type argument candidate 'number' is not a valid type argument because it is not a supertype of candidate 'false'.
!!! error TS2453: Type argument candidate 'number' is not a valid type argument because it is not a supertype of candidate 'boolean'.
if (a.indexOf(-(4/3)) === 14 && // a[14]=_float===-(4/3)
a.indexOf(0) === 7 && // a[7] = +0, 0===+0
a.indexOf(-0) === 7 && // a[7] = +0, -0===+0
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// @strictNullChecks: true
// Fixes #15116, which asserted on line 5 but not 6
declare function f<T>(a: T, b: T): boolean;
function g(gut: { n: 12 | undefined }) {
f(gut.n, 12); // ok, T = number | undefined
f(12, gut.n); // ok, T = number | undefined
}