Skip to content

Commit 7a4808a

Browse files
authored
Merge pull request #19774 from Microsoft/fixInvariantGenericErrors
Fix invariant generic error elaboration logic
2 parents 445001e + baafe51 commit 7a4808a

6 files changed

+273
-2
lines changed

src/compiler/checker.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9451,6 +9451,7 @@ namespace ts {
94519451

94529452
function structuredTypeRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary {
94539453
let result: Ternary;
9454+
let originalErrorInfo: DiagnosticMessageChain;
94549455
const saveErrorInfo = errorInfo;
94559456
if (target.flags & TypeFlags.TypeParameter) {
94569457
// A source type { [P in keyof T]: X } is related to a target type T if X is related to T[P].
@@ -9530,6 +9531,7 @@ namespace ts {
95309531
// if we have indexed access types with identical index types, see if relationship holds for
95319532
// the two object types.
95329533
if (result = isRelatedTo((<IndexedAccessType>source).objectType, (<IndexedAccessType>target).objectType, reportErrors)) {
9534+
errorInfo = saveErrorInfo;
95339535
return result;
95349536
}
95359537
}
@@ -9561,6 +9563,10 @@ namespace ts {
95619563
if (!(reportErrors && some(variances, v => v === Variance.Invariant))) {
95629564
return Ternary.False;
95639565
}
9566+
// We remember the original error information so we can restore it in case the structural
9567+
// comparison unexpectedly succeeds. This can happen when the structural comparison result
9568+
// is a Ternary.Maybe for example caused by the recursion depth limiter.
9569+
originalErrorInfo = errorInfo;
95649570
errorInfo = saveErrorInfo;
95659571
}
95669572
}
@@ -9599,8 +9605,11 @@ namespace ts {
95999605
}
96009606
}
96019607
if (result) {
9602-
errorInfo = saveErrorInfo;
9603-
return result;
9608+
if (!originalErrorInfo) {
9609+
errorInfo = saveErrorInfo;
9610+
return result;
9611+
}
9612+
errorInfo = originalErrorInfo;
96049613
}
96059614
}
96069615
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
tests/cases/compiler/invariantGenericErrorElaboration.ts(3,7): error TS2322: Type 'Num' is not assignable to type 'Runtype<any>'.
2+
Types of property 'constraint' are incompatible.
3+
Type 'Constraint<Num>' is not assignable to type 'Constraint<Runtype<any>>'.
4+
Types of property 'constraint' are incompatible.
5+
Type 'Constraint<Constraint<Num>>' is not assignable to type 'Constraint<Constraint<Runtype<any>>>'.
6+
Types of property 'constraint' are incompatible.
7+
Type 'Constraint<Constraint<Constraint<Num>>>' is not assignable to type 'Constraint<Constraint<Constraint<Runtype<any>>>>'.
8+
Type 'Constraint<Constraint<Runtype<any>>>' is not assignable to type 'Constraint<Constraint<Num>>'.
9+
Types of property 'underlying' are incompatible.
10+
Type 'Constraint<Runtype<any>>' is not assignable to type 'Constraint<Num>'.
11+
tests/cases/compiler/invariantGenericErrorElaboration.ts(4,17): error TS2345: Argument of type '{ foo: Num; }' is not assignable to parameter of type '{ [_: string]: Runtype<any>; }'.
12+
Property 'foo' is incompatible with index signature.
13+
Type 'Num' is not assignable to type 'Runtype<any>'.
14+
15+
16+
==== tests/cases/compiler/invariantGenericErrorElaboration.ts (2 errors) ====
17+
// Repro from #19746
18+
19+
const wat: Runtype<any> = Num;
20+
~~~
21+
!!! error TS2322: Type 'Num' is not assignable to type 'Runtype<any>'.
22+
!!! error TS2322: Types of property 'constraint' are incompatible.
23+
!!! error TS2322: Type 'Constraint<Num>' is not assignable to type 'Constraint<Runtype<any>>'.
24+
!!! error TS2322: Types of property 'constraint' are incompatible.
25+
!!! error TS2322: Type 'Constraint<Constraint<Num>>' is not assignable to type 'Constraint<Constraint<Runtype<any>>>'.
26+
!!! error TS2322: Types of property 'constraint' are incompatible.
27+
!!! error TS2322: Type 'Constraint<Constraint<Constraint<Num>>>' is not assignable to type 'Constraint<Constraint<Constraint<Runtype<any>>>>'.
28+
!!! error TS2322: Type 'Constraint<Constraint<Runtype<any>>>' is not assignable to type 'Constraint<Constraint<Num>>'.
29+
!!! error TS2322: Types of property 'underlying' are incompatible.
30+
!!! error TS2322: Type 'Constraint<Runtype<any>>' is not assignable to type 'Constraint<Num>'.
31+
const Foo = Obj({ foo: Num })
32+
~~~~~~~~~~~~
33+
!!! error TS2345: Argument of type '{ foo: Num; }' is not assignable to parameter of type '{ [_: string]: Runtype<any>; }'.
34+
!!! error TS2345: Property 'foo' is incompatible with index signature.
35+
!!! error TS2345: Type 'Num' is not assignable to type 'Runtype<any>'.
36+
37+
interface Runtype<A> {
38+
constraint: Constraint<this>
39+
witness: A
40+
}
41+
42+
interface Num extends Runtype<number> {
43+
tag: 'number'
44+
}
45+
declare const Num: Num
46+
47+
interface Obj<O extends { [_ in string]: Runtype<any> }> extends Runtype<{[K in keyof O]: O[K]['witness'] }> {}
48+
declare function Obj<O extends { [_: string]: Runtype<any> }>(fields: O): Obj<O>;
49+
50+
interface Constraint<A extends Runtype<any>> extends Runtype<A['witness']> {
51+
underlying: A,
52+
check: (x: A['witness']) => void,
53+
}
54+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//// [invariantGenericErrorElaboration.ts]
2+
// Repro from #19746
3+
4+
const wat: Runtype<any> = Num;
5+
const Foo = Obj({ foo: Num })
6+
7+
interface Runtype<A> {
8+
constraint: Constraint<this>
9+
witness: A
10+
}
11+
12+
interface Num extends Runtype<number> {
13+
tag: 'number'
14+
}
15+
declare const Num: Num
16+
17+
interface Obj<O extends { [_ in string]: Runtype<any> }> extends Runtype<{[K in keyof O]: O[K]['witness'] }> {}
18+
declare function Obj<O extends { [_: string]: Runtype<any> }>(fields: O): Obj<O>;
19+
20+
interface Constraint<A extends Runtype<any>> extends Runtype<A['witness']> {
21+
underlying: A,
22+
check: (x: A['witness']) => void,
23+
}
24+
25+
26+
//// [invariantGenericErrorElaboration.js]
27+
"use strict";
28+
// Repro from #19746
29+
var wat = Num;
30+
var Foo = Obj({ foo: Num });
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
=== tests/cases/compiler/invariantGenericErrorElaboration.ts ===
2+
// Repro from #19746
3+
4+
const wat: Runtype<any> = Num;
5+
>wat : Symbol(wat, Decl(invariantGenericErrorElaboration.ts, 2, 5))
6+
>Runtype : Symbol(Runtype, Decl(invariantGenericErrorElaboration.ts, 3, 29))
7+
>Num : Symbol(Num, Decl(invariantGenericErrorElaboration.ts, 8, 1), Decl(invariantGenericErrorElaboration.ts, 13, 13))
8+
9+
const Foo = Obj({ foo: Num })
10+
>Foo : Symbol(Foo, Decl(invariantGenericErrorElaboration.ts, 3, 5))
11+
>Obj : Symbol(Obj, Decl(invariantGenericErrorElaboration.ts, 13, 22), Decl(invariantGenericErrorElaboration.ts, 15, 111))
12+
>foo : Symbol(foo, Decl(invariantGenericErrorElaboration.ts, 3, 17))
13+
>Num : Symbol(Num, Decl(invariantGenericErrorElaboration.ts, 8, 1), Decl(invariantGenericErrorElaboration.ts, 13, 13))
14+
15+
interface Runtype<A> {
16+
>Runtype : Symbol(Runtype, Decl(invariantGenericErrorElaboration.ts, 3, 29))
17+
>A : Symbol(A, Decl(invariantGenericErrorElaboration.ts, 5, 18))
18+
19+
constraint: Constraint<this>
20+
>constraint : Symbol(Runtype.constraint, Decl(invariantGenericErrorElaboration.ts, 5, 22))
21+
>Constraint : Symbol(Constraint, Decl(invariantGenericErrorElaboration.ts, 16, 81))
22+
23+
witness: A
24+
>witness : Symbol(Runtype.witness, Decl(invariantGenericErrorElaboration.ts, 6, 30))
25+
>A : Symbol(A, Decl(invariantGenericErrorElaboration.ts, 5, 18))
26+
}
27+
28+
interface Num extends Runtype<number> {
29+
>Num : Symbol(Num, Decl(invariantGenericErrorElaboration.ts, 8, 1), Decl(invariantGenericErrorElaboration.ts, 13, 13))
30+
>Runtype : Symbol(Runtype, Decl(invariantGenericErrorElaboration.ts, 3, 29))
31+
32+
tag: 'number'
33+
>tag : Symbol(Num.tag, Decl(invariantGenericErrorElaboration.ts, 10, 39))
34+
}
35+
declare const Num: Num
36+
>Num : Symbol(Num, Decl(invariantGenericErrorElaboration.ts, 8, 1), Decl(invariantGenericErrorElaboration.ts, 13, 13))
37+
>Num : Symbol(Num, Decl(invariantGenericErrorElaboration.ts, 8, 1), Decl(invariantGenericErrorElaboration.ts, 13, 13))
38+
39+
interface Obj<O extends { [_ in string]: Runtype<any> }> extends Runtype<{[K in keyof O]: O[K]['witness'] }> {}
40+
>Obj : Symbol(Obj, Decl(invariantGenericErrorElaboration.ts, 13, 22), Decl(invariantGenericErrorElaboration.ts, 15, 111))
41+
>O : Symbol(O, Decl(invariantGenericErrorElaboration.ts, 15, 14))
42+
>_ : Symbol(_, Decl(invariantGenericErrorElaboration.ts, 15, 27))
43+
>Runtype : Symbol(Runtype, Decl(invariantGenericErrorElaboration.ts, 3, 29))
44+
>Runtype : Symbol(Runtype, Decl(invariantGenericErrorElaboration.ts, 3, 29))
45+
>K : Symbol(K, Decl(invariantGenericErrorElaboration.ts, 15, 75))
46+
>O : Symbol(O, Decl(invariantGenericErrorElaboration.ts, 15, 14))
47+
>O : Symbol(O, Decl(invariantGenericErrorElaboration.ts, 15, 14))
48+
>K : Symbol(K, Decl(invariantGenericErrorElaboration.ts, 15, 75))
49+
50+
declare function Obj<O extends { [_: string]: Runtype<any> }>(fields: O): Obj<O>;
51+
>Obj : Symbol(Obj, Decl(invariantGenericErrorElaboration.ts, 13, 22), Decl(invariantGenericErrorElaboration.ts, 15, 111))
52+
>O : Symbol(O, Decl(invariantGenericErrorElaboration.ts, 16, 21))
53+
>_ : Symbol(_, Decl(invariantGenericErrorElaboration.ts, 16, 34))
54+
>Runtype : Symbol(Runtype, Decl(invariantGenericErrorElaboration.ts, 3, 29))
55+
>fields : Symbol(fields, Decl(invariantGenericErrorElaboration.ts, 16, 62))
56+
>O : Symbol(O, Decl(invariantGenericErrorElaboration.ts, 16, 21))
57+
>Obj : Symbol(Obj, Decl(invariantGenericErrorElaboration.ts, 13, 22), Decl(invariantGenericErrorElaboration.ts, 15, 111))
58+
>O : Symbol(O, Decl(invariantGenericErrorElaboration.ts, 16, 21))
59+
60+
interface Constraint<A extends Runtype<any>> extends Runtype<A['witness']> {
61+
>Constraint : Symbol(Constraint, Decl(invariantGenericErrorElaboration.ts, 16, 81))
62+
>A : Symbol(A, Decl(invariantGenericErrorElaboration.ts, 18, 21))
63+
>Runtype : Symbol(Runtype, Decl(invariantGenericErrorElaboration.ts, 3, 29))
64+
>Runtype : Symbol(Runtype, Decl(invariantGenericErrorElaboration.ts, 3, 29))
65+
>A : Symbol(A, Decl(invariantGenericErrorElaboration.ts, 18, 21))
66+
67+
underlying: A,
68+
>underlying : Symbol(Constraint.underlying, Decl(invariantGenericErrorElaboration.ts, 18, 76))
69+
>A : Symbol(A, Decl(invariantGenericErrorElaboration.ts, 18, 21))
70+
71+
check: (x: A['witness']) => void,
72+
>check : Symbol(Constraint.check, Decl(invariantGenericErrorElaboration.ts, 19, 16))
73+
>x : Symbol(x, Decl(invariantGenericErrorElaboration.ts, 20, 10))
74+
>A : Symbol(A, Decl(invariantGenericErrorElaboration.ts, 18, 21))
75+
}
76+
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
=== tests/cases/compiler/invariantGenericErrorElaboration.ts ===
2+
// Repro from #19746
3+
4+
const wat: Runtype<any> = Num;
5+
>wat : Runtype<any>
6+
>Runtype : Runtype<A>
7+
>Num : Num
8+
9+
const Foo = Obj({ foo: Num })
10+
>Foo : any
11+
>Obj({ foo: Num }) : any
12+
>Obj : <O extends { [_: string]: Runtype<any>; }>(fields: O) => Obj<O>
13+
>{ foo: Num } : { foo: Num; }
14+
>foo : Num
15+
>Num : Num
16+
17+
interface Runtype<A> {
18+
>Runtype : Runtype<A>
19+
>A : A
20+
21+
constraint: Constraint<this>
22+
>constraint : Constraint<this>
23+
>Constraint : Constraint<A>
24+
25+
witness: A
26+
>witness : A
27+
>A : A
28+
}
29+
30+
interface Num extends Runtype<number> {
31+
>Num : Num
32+
>Runtype : Runtype<A>
33+
34+
tag: 'number'
35+
>tag : "number"
36+
}
37+
declare const Num: Num
38+
>Num : Num
39+
>Num : Num
40+
41+
interface Obj<O extends { [_ in string]: Runtype<any> }> extends Runtype<{[K in keyof O]: O[K]['witness'] }> {}
42+
>Obj : Obj<O>
43+
>O : O
44+
>_ : _
45+
>Runtype : Runtype<A>
46+
>Runtype : Runtype<A>
47+
>K : K
48+
>O : O
49+
>O : O
50+
>K : K
51+
52+
declare function Obj<O extends { [_: string]: Runtype<any> }>(fields: O): Obj<O>;
53+
>Obj : <O extends { [_: string]: Runtype<any>; }>(fields: O) => Obj<O>
54+
>O : O
55+
>_ : string
56+
>Runtype : Runtype<A>
57+
>fields : O
58+
>O : O
59+
>Obj : Obj<O>
60+
>O : O
61+
62+
interface Constraint<A extends Runtype<any>> extends Runtype<A['witness']> {
63+
>Constraint : Constraint<A>
64+
>A : A
65+
>Runtype : Runtype<A>
66+
>Runtype : Runtype<A>
67+
>A : A
68+
69+
underlying: A,
70+
>underlying : A
71+
>A : A
72+
73+
check: (x: A['witness']) => void,
74+
>check : (x: A["witness"]) => void
75+
>x : A["witness"]
76+
>A : A
77+
}
78+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// @strict: true
2+
3+
// Repro from #19746
4+
5+
const wat: Runtype<any> = Num;
6+
const Foo = Obj({ foo: Num })
7+
8+
interface Runtype<A> {
9+
constraint: Constraint<this>
10+
witness: A
11+
}
12+
13+
interface Num extends Runtype<number> {
14+
tag: 'number'
15+
}
16+
declare const Num: Num
17+
18+
interface Obj<O extends { [_ in string]: Runtype<any> }> extends Runtype<{[K in keyof O]: O[K]['witness'] }> {}
19+
declare function Obj<O extends { [_: string]: Runtype<any> }>(fields: O): Obj<O>;
20+
21+
interface Constraint<A extends Runtype<any>> extends Runtype<A['witness']> {
22+
underlying: A,
23+
check: (x: A['witness']) => void,
24+
}

0 commit comments

Comments
 (0)