Skip to content

Commit 57f17bb

Browse files
committed
Fix type parameter comparability to consistently allow comparisons on unconstrained type parameters
1 parent 273a567 commit 57f17bb

File tree

57 files changed

+537
-381
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+537
-381
lines changed

src/compiler/checker.ts

+17-3
Original file line numberDiff line numberDiff line change
@@ -19338,6 +19338,20 @@ namespace ts {
1933819338
}
1933919339
}
1934019340
}
19341+
if (relation === comparableRelation && sourceFlags & TypeFlags.TypeParameter) {
19342+
// This is a carve-out in comparability to essentially forbid comparing a type parameter
19343+
// with another type parameter unless one extends the other. (Remember: comparability is mostly bidirectional!)
19344+
let constraint = getConstraintOfTypeParameter(source);
19345+
if (constraint && hasNonCircularBaseConstraint(source)) {
19346+
while (constraint && constraint.flags & TypeFlags.TypeParameter) {
19347+
if (result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false)) {
19348+
return result;
19349+
}
19350+
constraint = getConstraintOfTypeParameter(constraint);
19351+
}
19352+
}
19353+
return Ternary.False;
19354+
}
1934119355
}
1934219356
else if (targetFlags & TypeFlags.Index) {
1934319357
const targetType = (target as IndexType).type;
@@ -19549,7 +19563,7 @@ namespace ts {
1954919563
if (sourceFlags & TypeFlags.TypeVariable) {
1955019564
// IndexedAccess comparisons are handled above in the `targetFlags & TypeFlage.IndexedAccess` branch
1955119565
if (!(sourceFlags & TypeFlags.IndexedAccess && targetFlags & TypeFlags.IndexedAccess)) {
19552-
const constraint = getConstraintOfType(source as TypeVariable);
19566+
const constraint = getConstraintOfType(source as TypeVariable) || unknownType;
1955319567
if (!strictNullChecks && (!constraint || (sourceFlags & TypeFlags.TypeParameter && constraint.flags & TypeFlags.Any))) {
1955419568
// A type variable with no constraint is not related to the non-primitive object type.
1955519569
if (result = isRelatedTo(emptyObjectType, extractTypesOfKind(target, ~TypeFlags.NonPrimitive), RecursionFlags.Both)) {
@@ -19558,12 +19572,12 @@ namespace ts {
1955819572
}
1955919573
}
1956019574
// hi-speed no-this-instantiation check (less accurate, but avoids costly `this`-instantiation when the constraint will suffice), see #28231 for report on why this is needed
19561-
else if (constraint && (result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState))) {
19575+
else if (result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState)) {
1956219576
resetErrorInfo(saveErrorInfo);
1956319577
return result;
1956419578
}
1956519579
// slower, fuller, this-instantiated check (necessary when comparing raw `this` types from base classes), see `subclassWithPolymorphicThisIsAssignable.ts` test for example
19566-
else if (constraint && (result = isRelatedTo(getTypeWithThisArgument(constraint, source), target, RecursionFlags.Source, reportErrors && !(targetFlags & sourceFlags & TypeFlags.TypeParameter), /*headMessage*/ undefined, intersectionState))) {
19580+
else if (result = isRelatedTo(getTypeWithThisArgument(constraint, source), target, RecursionFlags.Source, reportErrors && !(targetFlags & sourceFlags & TypeFlags.TypeParameter), /*headMessage*/ undefined, intersectionState)) {
1956719581
resetErrorInfo(saveErrorInfo);
1956819582
return result;
1956919583
}

tests/baselines/reference/assignmentCompatWithCallSignatures3.errors.txt

+10
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures3.ts(47,1): error TS2322: Type '(x: number) => number[]' is not assignable to type '<T>(x: T) => T[]'.
22
Types of parameters 'x' and 'x' are incompatible.
33
Type 'T' is not assignable to type 'number'.
4+
Type 'unknown' is not assignable to type 'number'.
45
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures3.ts(50,1): error TS2322: Type '(x: number) => string[]' is not assignable to type '<T>(x: T) => string[]'.
56
Types of parameters 'x' and 'x' are incompatible.
67
Type 'T' is not assignable to type 'number'.
8+
Type 'unknown' is not assignable to type 'number'.
79
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures3.ts(53,1): error TS2322: Type '(x: number) => void' is not assignable to type '<T>(x: T) => T'.
810
Types of parameters 'x' and 'x' are incompatible.
911
Type 'T' is not assignable to type 'number'.
12+
Type 'unknown' is not assignable to type 'number'.
1013
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures3.ts(56,1): error TS2322: Type '(x: string, y: number) => string' is not assignable to type '<T, U>(x: T, y: U) => T'.
1114
Types of parameters 'x' and 'x' are incompatible.
1215
Type 'T' is not assignable to type 'string'.
16+
Type 'unknown' is not assignable to type 'string'.
1317
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures3.ts(59,1): error TS2322: Type '(x: (arg: string) => number) => string' is not assignable to type '<T, U>(x: (arg: T) => U) => T'.
1418
Types of parameters 'x' and 'x' are incompatible.
1519
Types of parameters 'arg' and 'arg' are incompatible.
@@ -60,6 +64,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
6064
Type '{ a: T; b: T; }' is not assignable to type '{ a: string; b: number; }'.
6165
Types of property 'a' are incompatible.
6266
Type 'T' is not assignable to type 'string'.
67+
Type 'unknown' is not assignable to type 'string'.
6368

6469

6570
==== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures3.ts (15 errors) ====
@@ -114,27 +119,31 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
114119
!!! error TS2322: Type '(x: number) => number[]' is not assignable to type '<T>(x: T) => T[]'.
115120
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
116121
!!! error TS2322: Type 'T' is not assignable to type 'number'.
122+
!!! error TS2322: Type 'unknown' is not assignable to type 'number'.
117123
var b2: <T>(x: T) => string[];
118124
a2 = b2; // ok
119125
b2 = a2; // ok
120126
~~
121127
!!! error TS2322: Type '(x: number) => string[]' is not assignable to type '<T>(x: T) => string[]'.
122128
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
123129
!!! error TS2322: Type 'T' is not assignable to type 'number'.
130+
!!! error TS2322: Type 'unknown' is not assignable to type 'number'.
124131
var b3: <T>(x: T) => T;
125132
a3 = b3; // ok
126133
b3 = a3; // ok
127134
~~
128135
!!! error TS2322: Type '(x: number) => void' is not assignable to type '<T>(x: T) => T'.
129136
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
130137
!!! error TS2322: Type 'T' is not assignable to type 'number'.
138+
!!! error TS2322: Type 'unknown' is not assignable to type 'number'.
131139
var b4: <T, U>(x: T, y: U) => T;
132140
a4 = b4; // ok
133141
b4 = a4; // ok
134142
~~
135143
!!! error TS2322: Type '(x: string, y: number) => string' is not assignable to type '<T, U>(x: T, y: U) => T'.
136144
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
137145
!!! error TS2322: Type 'T' is not assignable to type 'string'.
146+
!!! error TS2322: Type 'unknown' is not assignable to type 'string'.
138147
var b5: <T, U>(x: (arg: T) => U) => T;
139148
a5 = b5; // ok
140149
b5 = a5; // ok
@@ -227,6 +236,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
227236
!!! error TS2322: Type '{ a: T; b: T; }' is not assignable to type '{ a: string; b: number; }'.
228237
!!! error TS2322: Types of property 'a' are incompatible.
229238
!!! error TS2322: Type 'T' is not assignable to type 'string'.
239+
!!! error TS2322: Type 'unknown' is not assignable to type 'string'.
230240
var b15: <T>(x: T) => T[];
231241
a15 = b15; // ok
232242
b15 = a15; // ok

tests/baselines/reference/assignmentCompatWithCallSignatures4.errors.txt

+8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures4.ts(45,9): error TS2322: Type '(x: number) => string[]' is not assignable to type '<T, U>(x: T) => U[]'.
22
Types of parameters 'x' and 'x' are incompatible.
33
Type 'T' is not assignable to type 'number'.
4+
Type 'unknown' is not assignable to type 'number'.
45
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures4.ts(49,9): error TS2322: Type '(x: (arg: Base) => Derived) => (r: Base) => Derived2' is not assignable to type '<T extends Base, U extends Derived, V extends Derived2>(x: (arg: T) => U) => (r: T) => V'.
56
Types of parameters 'x' and 'x' are incompatible.
67
Types of parameters 'arg' and 'arg' are incompatible.
@@ -36,6 +37,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
3637
Type '{ a: T; b: T; }' is not assignable to type '{ a: string; b: number; }'.
3738
Types of property 'a' are incompatible.
3839
Type 'T' is not assignable to type 'string'.
40+
Type 'unknown' is not assignable to type 'string'.
3941
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures4.ts(73,9): error TS2322: Type '<T extends Base>(x: { a: T; b: T; }) => number' is not assignable to type '(x: { a: string; b: number; }) => number'.
4042
Types of parameters 'x' and 'x' are incompatible.
4143
Type '{ a: string; b: number; }' is not assignable to type '{ a: Base; b: Base; }'.
@@ -54,9 +56,11 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
5456
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures4.ts(90,9): error TS2322: Type '<T>(x: T) => T[]' is not assignable to type '<T>(x: T) => string[]'.
5557
Type 'T[]' is not assignable to type 'string[]'.
5658
Type 'T' is not assignable to type 'string'.
59+
Type 'unknown' is not assignable to type 'string'.
5760
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures4.ts(95,9): error TS2322: Type '<T>(x: T) => T[]' is not assignable to type '<T>(x: T) => string[]'.
5861
Type 'T[]' is not assignable to type 'string[]'.
5962
Type 'T' is not assignable to type 'string'.
63+
Type 'unknown' is not assignable to type 'string'.
6064
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures4.ts(96,9): error TS2322: Type '<T>(x: T) => string[]' is not assignable to type '<T>(x: T) => T[]'.
6165
Type 'string[]' is not assignable to type 'T[]'.
6266
Type 'string' is not assignable to type 'T'.
@@ -113,6 +117,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
113117
!!! error TS2322: Type '(x: number) => string[]' is not assignable to type '<T, U>(x: T) => U[]'.
114118
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
115119
!!! error TS2322: Type 'T' is not assignable to type 'number'.
120+
!!! error TS2322: Type 'unknown' is not assignable to type 'number'.
116121

117122
var b7: <T extends Base, U extends Derived, V extends Derived2>(x: (arg: T) => U) => (r: T) => V;
118123
a7 = b7;
@@ -181,6 +186,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
181186
!!! error TS2322: Type '{ a: T; b: T; }' is not assignable to type '{ a: string; b: number; }'.
182187
!!! error TS2322: Types of property 'a' are incompatible.
183188
!!! error TS2322: Type 'T' is not assignable to type 'string'.
189+
!!! error TS2322: Type 'unknown' is not assignable to type 'string'.
184190

185191
var b15a: <T extends Base>(x: { a: T; b: T }) => number;
186192
a15 = b15a;
@@ -223,6 +229,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
223229
!!! error TS2322: Type '<T>(x: T) => T[]' is not assignable to type '<T>(x: T) => string[]'.
224230
!!! error TS2322: Type 'T[]' is not assignable to type 'string[]'.
225231
!!! error TS2322: Type 'T' is not assignable to type 'string'.
232+
!!! error TS2322: Type 'unknown' is not assignable to type 'string'.
226233

227234
// target type has generic call signature
228235
var a3: <T>(x: T) => string[];
@@ -232,6 +239,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
232239
!!! error TS2322: Type '<T>(x: T) => T[]' is not assignable to type '<T>(x: T) => string[]'.
233240
!!! error TS2322: Type 'T[]' is not assignable to type 'string[]'.
234241
!!! error TS2322: Type 'T' is not assignable to type 'string'.
242+
!!! error TS2322: Type 'unknown' is not assignable to type 'string'.
235243
b3 = a3;
236244
~~
237245
!!! error TS2322: Type '<T>(x: T) => string[]' is not assignable to type '<T>(x: T) => T[]'.

tests/baselines/reference/assignmentCompatWithCallSignatures5.errors.txt

+3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
1818
Type '{ a: U; b: V; }' is not assignable to type '{ a: Base; b: Base; }'.
1919
Types of property 'a' are incompatible.
2020
Type 'U' is not assignable to type 'Base'.
21+
Property 'foo' is missing in type '{}' but required in type 'Base'.
2122

2223

2324
==== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures5.ts (4 errors) ====
@@ -103,6 +104,8 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
103104
!!! error TS2322: Type '{ a: U; b: V; }' is not assignable to type '{ a: Base; b: Base; }'.
104105
!!! error TS2322: Types of property 'a' are incompatible.
105106
!!! error TS2322: Type 'U' is not assignable to type 'Base'.
107+
!!! error TS2322: Property 'foo' is missing in type '{}' but required in type 'Base'.
108+
!!! related TS2728 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures5.ts:3:14: 'foo' is declared here.
106109
var b17: <T>(x: (a: T) => T) => T[];
107110
a17 = b17; // ok
108111
b17 = a17; // ok

tests/baselines/reference/assignmentCompatWithCallSignatures6.errors.txt

+4-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
1212
Type '{ a: T; b: T; }' is not assignable to type '{ a: Base; b: Base; }'.
1313
Types of property 'a' are incompatible.
1414
Type 'T' is not assignable to type 'Base'.
15+
Property 'foo' is missing in type '{}' but required in type 'Base'.
1516

1617

1718
==== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures6.ts (3 errors) ====
@@ -73,4 +74,6 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
7374
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
7475
!!! error TS2322: Type '{ a: T; b: T; }' is not assignable to type '{ a: Base; b: Base; }'.
7576
!!! error TS2322: Types of property 'a' are incompatible.
76-
!!! error TS2322: Type 'T' is not assignable to type 'Base'.
77+
!!! error TS2322: Type 'T' is not assignable to type 'Base'.
78+
!!! error TS2322: Property 'foo' is missing in type '{}' but required in type 'Base'.
79+
!!! related TS2728 tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignatures6.ts:3:14: 'foo' is declared here.

0 commit comments

Comments
 (0)