Skip to content

Commit 4e96d98

Browse files
committed
Separate unmeasurable from unreliable to reduce the impact of this change, for now
1 parent 093cc72 commit 4e96d98

8 files changed

+448
-61
lines changed

src/compiler/checker.ts

Lines changed: 48 additions & 44 deletions
Large diffs are not rendered by default.

src/compiler/types.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3735,7 +3735,7 @@ namespace ts {
37353735
specifierCache?: Map<string>; // For symbols corresponding to external modules, a cache of incoming path -> module specifier name mappings
37363736
extendedContainers?: Symbol[]; // Containers (other than the parent) which this symbol is aliased in
37373737
extendedContainersByFile?: Map<Symbol[]>; // Containers (other than the parent) which this symbol is aliased in
3738-
variances?: Variance[]; // Alias symbol type argument variance cache
3738+
variances?: VarianceFlags[]; // Alias symbol type argument variance cache
37393739
}
37403740

37413741
/* @internal */
@@ -4131,21 +4131,24 @@ namespace ts {
41314131
}
41324132

41334133
/* @internal */
4134-
export const enum Variance {
4135-
Invariant = 0, // Neither covariant nor contravariant
4136-
Covariant = 1, // Covariant
4137-
Contravariant = 2, // Contravariant
4138-
Bivariant = 3, // Both covariant and contravariant
4139-
Independent = 4, // Unwitnessed type parameter
4140-
Unmeasurable = 5, // Variance result is unusable - relationship relies on structural comparisons which are not reflected in generic relationships
4134+
export const enum VarianceFlags {
4135+
Invariant = 0, // Neither covariant nor contravariant
4136+
Covariant = 1 << 0, // Covariant
4137+
Contravariant = 1 << 1, // Contravariant
4138+
Bivariant = Covariant | Contravariant, // Both covariant and contravariant
4139+
Independent = 1 << 2, // Unwitnessed type parameter
4140+
VarianceMask = Invariant | Covariant | Contravariant | Independent, // Mask containing all measured variances without the unmeasurable flag
4141+
Unmeasurable = 1 << 3, // Variance result is unusable - relationship relies on structural comparisons which are not reflected in generic relationships
4142+
Unreliable = 1 << 4, // Variance result is unreliable - relationship relies on structural comparisons which are not reflected in generic relationships
4143+
AllowsStructuralFallback = Unmeasurable | Unreliable,
41414144
}
41424145

41434146
// Generic class and interface types
41444147
export interface GenericType extends InterfaceType, TypeReference {
41454148
/* @internal */
41464149
instantiations: Map<TypeReference>; // Generic instantiation cache
41474150
/* @internal */
4148-
variances?: Variance[]; // Variance of each type parameter
4151+
variances?: VarianceFlags[]; // Variance of each type parameter
41494152
}
41504153

41514154
export interface TupleType extends GenericType {

tests/baselines/reference/conditionalTypes1.errors.txt

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,8 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(103,5): error TS2
1717
tests/cases/conformance/types/conditional/conditionalTypes1.ts(104,5): error TS2322: Type 'Pick<T, { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]>' is not assignable to type 'T'.
1818
tests/cases/conformance/types/conditional/conditionalTypes1.ts(106,5): error TS2322: Type 'Pick<T, { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]>' is not assignable to type 'Pick<T, { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]>'.
1919
Type 'T[keyof T] extends Function ? keyof T : never' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'.
20-
Type 'keyof T' is not assignable to type 'never'.
21-
Type 'string | number | symbol' is not assignable to type 'never'.
22-
Type 'string' is not assignable to type 'never'.
2320
tests/cases/conformance/types/conditional/conditionalTypes1.ts(108,5): error TS2322: Type 'Pick<T, { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]>' is not assignable to type 'Pick<T, { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]>'.
2421
Type 'T[keyof T] extends Function ? never : keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'.
25-
Type 'keyof T' is not assignable to type 'never'.
2622
tests/cases/conformance/types/conditional/conditionalTypes1.ts(114,5): error TS2322: Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'.
2723
Type 'string | number | symbol' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'.
2824
Type 'string' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'.
@@ -187,15 +183,11 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(288,43): error TS
187183
~
188184
!!! error TS2322: Type 'Pick<T, { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]>' is not assignable to type 'Pick<T, { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]>'.
189185
!!! error TS2322: Type 'T[keyof T] extends Function ? keyof T : never' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'.
190-
!!! error TS2322: Type 'keyof T' is not assignable to type 'never'.
191-
!!! error TS2322: Type 'string | number | symbol' is not assignable to type 'never'.
192-
!!! error TS2322: Type 'string' is not assignable to type 'never'.
193186
z = x;
194187
z = y; // Error
195188
~
196189
!!! error TS2322: Type 'Pick<T, { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]>' is not assignable to type 'Pick<T, { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]>'.
197190
!!! error TS2322: Type 'T[keyof T] extends Function ? never : keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'.
198-
!!! error TS2322: Type 'keyof T' is not assignable to type 'never'.
199191
}
200192

201193
function f8<T>(x: keyof T, y: FunctionPropertyNames<T>, z: NonFunctionPropertyNames<T>) {
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts(18,5): error TS2741: Property 'a' is missing in type 'Record<string, string>' but required in type 'Record2<"a", string>'.
2+
tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts(22,5): error TS2741: Property 'a' is missing in type 'Record2<string, string>' but required in type 'Record<"a", string>'.
3+
tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts(34,5): error TS2741: Property 'a' is missing in type 'Record<string, T>' but required in type 'Record2<"a", T>'.
4+
tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts(38,5): error TS2741: Property 'a' is missing in type 'Record2<string, T>' but required in type 'Record<"a", T>'.
5+
6+
7+
==== tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts (4 errors) ====
8+
// TODO: FIXME: All the below cases labeled `no error` _should be an error_, and are only prevented from so being
9+
// by incorrect variance-based relationships
10+
// Ref: https://github.com/Microsoft/TypeScript/issues/29698
11+
12+
type Record2<K extends keyof any, T> = {
13+
[P in K]: T;
14+
};
15+
16+
function defaultRecord(x: Record<'a', string>, y: Record<string, string>) {
17+
x = y; // no error, but error expected.
18+
}
19+
20+
function customRecord(x: Record2<'a', string>, y: Record2<string, string>) {
21+
x = y; // no error, but error expected.
22+
}
23+
24+
function mixed1(x: Record2<'a', string>, y: Record<string, string>) {
25+
x = y; // error
26+
~
27+
!!! error TS2741: Property 'a' is missing in type 'Record<string, string>' but required in type 'Record2<"a", string>'.
28+
}
29+
30+
function mixed2(x: Record<'a', string>, y: Record2<string, string>) {
31+
x = y; // error
32+
~
33+
!!! error TS2741: Property 'a' is missing in type 'Record2<string, string>' but required in type 'Record<"a", string>'.
34+
}
35+
36+
function defaultRecord2<T>(x: Record<'a', T>, y: Record<string, T>) {
37+
x = y; // no error, but error expected.
38+
}
39+
40+
function customRecord2<T>(x: Record2<'a', T>, y: Record2<string, T>) {
41+
x = y; // no error, but error expected.
42+
}
43+
44+
function mixed3<T>(x: Record2<'a', T>, y: Record<string, T>) {
45+
x = y; // error
46+
~
47+
!!! error TS2741: Property 'a' is missing in type 'Record<string, T>' but required in type 'Record2<"a", T>'.
48+
}
49+
50+
function mixed4<T>(x: Record<'a', T>, y: Record2<string, T>) {
51+
x = y; // error
52+
~
53+
!!! error TS2741: Property 'a' is missing in type 'Record2<string, T>' but required in type 'Record<"a", T>'.
54+
}
55+
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
//// [consistentAliasVsNonAliasRecordBehavior.ts]
2+
// TODO: FIXME: All the below cases labeled `no error` _should be an error_, and are only prevented from so being
3+
// by incorrect variance-based relationships
4+
// Ref: https://github.com/Microsoft/TypeScript/issues/29698
5+
6+
type Record2<K extends keyof any, T> = {
7+
[P in K]: T;
8+
};
9+
10+
function defaultRecord(x: Record<'a', string>, y: Record<string, string>) {
11+
x = y; // no error, but error expected.
12+
}
13+
14+
function customRecord(x: Record2<'a', string>, y: Record2<string, string>) {
15+
x = y; // no error, but error expected.
16+
}
17+
18+
function mixed1(x: Record2<'a', string>, y: Record<string, string>) {
19+
x = y; // error
20+
}
21+
22+
function mixed2(x: Record<'a', string>, y: Record2<string, string>) {
23+
x = y; // error
24+
}
25+
26+
function defaultRecord2<T>(x: Record<'a', T>, y: Record<string, T>) {
27+
x = y; // no error, but error expected.
28+
}
29+
30+
function customRecord2<T>(x: Record2<'a', T>, y: Record2<string, T>) {
31+
x = y; // no error, but error expected.
32+
}
33+
34+
function mixed3<T>(x: Record2<'a', T>, y: Record<string, T>) {
35+
x = y; // error
36+
}
37+
38+
function mixed4<T>(x: Record<'a', T>, y: Record2<string, T>) {
39+
x = y; // error
40+
}
41+
42+
43+
//// [consistentAliasVsNonAliasRecordBehavior.js]
44+
// TODO: FIXME: All the below cases labeled `no error` _should be an error_, and are only prevented from so being
45+
// by incorrect variance-based relationships
46+
// Ref: https://github.com/Microsoft/TypeScript/issues/29698
47+
function defaultRecord(x, y) {
48+
x = y; // no error, but error expected.
49+
}
50+
function customRecord(x, y) {
51+
x = y; // no error, but error expected.
52+
}
53+
function mixed1(x, y) {
54+
x = y; // error
55+
}
56+
function mixed2(x, y) {
57+
x = y; // error
58+
}
59+
function defaultRecord2(x, y) {
60+
x = y; // no error, but error expected.
61+
}
62+
function customRecord2(x, y) {
63+
x = y; // no error, but error expected.
64+
}
65+
function mixed3(x, y) {
66+
x = y; // error
67+
}
68+
function mixed4(x, y) {
69+
x = y; // error
70+
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
=== tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts ===
2+
// TODO: FIXME: All the below cases labeled `no error` _should be an error_, and are only prevented from so being
3+
// by incorrect variance-based relationships
4+
// Ref: https://github.com/Microsoft/TypeScript/issues/29698
5+
6+
type Record2<K extends keyof any, T> = {
7+
>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0))
8+
>K : Symbol(K, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 4, 13))
9+
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 4, 33))
10+
11+
[P in K]: T;
12+
>P : Symbol(P, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 5, 5))
13+
>K : Symbol(K, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 4, 13))
14+
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 4, 33))
15+
16+
};
17+
18+
function defaultRecord(x: Record<'a', string>, y: Record<string, string>) {
19+
>defaultRecord : Symbol(defaultRecord, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 6, 2))
20+
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 8, 23))
21+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
22+
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 8, 46))
23+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
24+
25+
x = y; // no error, but error expected.
26+
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 8, 23))
27+
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 8, 46))
28+
}
29+
30+
function customRecord(x: Record2<'a', string>, y: Record2<string, string>) {
31+
>customRecord : Symbol(customRecord, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 10, 1))
32+
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 12, 22))
33+
>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0))
34+
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 12, 46))
35+
>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0))
36+
37+
x = y; // no error, but error expected.
38+
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 12, 22))
39+
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 12, 46))
40+
}
41+
42+
function mixed1(x: Record2<'a', string>, y: Record<string, string>) {
43+
>mixed1 : Symbol(mixed1, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 14, 1))
44+
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 16, 16))
45+
>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0))
46+
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 16, 40))
47+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
48+
49+
x = y; // error
50+
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 16, 16))
51+
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 16, 40))
52+
}
53+
54+
function mixed2(x: Record<'a', string>, y: Record2<string, string>) {
55+
>mixed2 : Symbol(mixed2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 18, 1))
56+
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 20, 16))
57+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
58+
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 20, 39))
59+
>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0))
60+
61+
x = y; // error
62+
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 20, 16))
63+
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 20, 39))
64+
}
65+
66+
function defaultRecord2<T>(x: Record<'a', T>, y: Record<string, T>) {
67+
>defaultRecord2 : Symbol(defaultRecord2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 22, 1))
68+
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 24, 24))
69+
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 24, 27))
70+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
71+
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 24, 24))
72+
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 24, 45))
73+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
74+
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 24, 24))
75+
76+
x = y; // no error, but error expected.
77+
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 24, 27))
78+
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 24, 45))
79+
}
80+
81+
function customRecord2<T>(x: Record2<'a', T>, y: Record2<string, T>) {
82+
>customRecord2 : Symbol(customRecord2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 26, 1))
83+
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 28, 23))
84+
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 28, 26))
85+
>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0))
86+
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 28, 23))
87+
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 28, 45))
88+
>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0))
89+
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 28, 23))
90+
91+
x = y; // no error, but error expected.
92+
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 28, 26))
93+
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 28, 45))
94+
}
95+
96+
function mixed3<T>(x: Record2<'a', T>, y: Record<string, T>) {
97+
>mixed3 : Symbol(mixed3, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 30, 1))
98+
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 32, 16))
99+
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 32, 19))
100+
>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0))
101+
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 32, 16))
102+
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 32, 38))
103+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
104+
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 32, 16))
105+
106+
x = y; // error
107+
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 32, 19))
108+
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 32, 38))
109+
}
110+
111+
function mixed4<T>(x: Record<'a', T>, y: Record2<string, T>) {
112+
>mixed4 : Symbol(mixed4, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 34, 1))
113+
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 36, 16))
114+
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 36, 19))
115+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
116+
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 36, 16))
117+
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 36, 37))
118+
>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0))
119+
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 36, 16))
120+
121+
x = y; // error
122+
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 36, 19))
123+
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 36, 37))
124+
}
125+

0 commit comments

Comments
 (0)