Skip to content

Commit d7df84d

Browse files
authored
Merge pull request #22850 from Microsoft/tupleTypeInference
Only make inferences from tuple types of right arity
2 parents fdc4689 + 63f98de commit d7df84d

File tree

5 files changed

+275
-3
lines changed

5 files changed

+275
-3
lines changed

Diff for: src/compiler/checker.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -11603,6 +11603,13 @@ namespace ts {
1160311603
return undefined;
1160411604
}
1160511605

11606+
function typesDefinitelyUnrelated(source: Type, target: Type) {
11607+
// Two tuple types with different arity are definitely unrelated.
11608+
// Two object types that each have a property that is unmatched in the other are definitely unrelated.
11609+
return isTupleType(source) && isTupleType(target) && getTypeReferenceArity(<TypeReference>source) !== getTypeReferenceArity(<TypeReference>target) ||
11610+
!!getUnmatchedProperty(source, target, /*requireOptionalProperties*/ false) && !!getUnmatchedProperty(target, source, /*requireOptionalProperties*/ false);
11611+
}
11612+
1160611613
function getTypeFromInference(inference: InferenceInfo) {
1160711614
return inference.candidates ? getUnionType(inference.candidates, UnionReduction.Subtype) :
1160811615
inference.contraCandidates ? getIntersectionType(inference.contraCandidates) :
@@ -11873,9 +11880,8 @@ namespace ts {
1187311880
return;
1187411881
}
1187511882
}
11876-
// Infer from the members of source and target only if the two types are possibly related. We check
11877-
// in both directions because we may be inferring for a co-variant or a contra-variant position.
11878-
if (!getUnmatchedProperty(source, target, /*requireOptionalProperties*/ false) || !getUnmatchedProperty(target, source, /*requireOptionalProperties*/ false)) {
11883+
// Infer from the members of source and target only if the two types are possibly related
11884+
if (!typesDefinitelyUnrelated(source, target)) {
1187911885
inferFromProperties(source, target);
1188011886
inferFromSignatures(source, target, SignatureKind.Call);
1188111887
inferFromSignatures(source, target, SignatureKind.Construct);

Diff for: tests/baselines/reference/tupleTypeInference2.js

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//// [tupleTypeInference2.ts]
2+
// Repro from #22564
3+
4+
type A<R> = [R] | [R, string];
5+
declare function f<T>(x: A<T>): T;
6+
f([undefined, ''] as [never, string]); // T: never
7+
f([undefined, ''] as [void, string]); // T: void
8+
9+
// Repro from #22563
10+
11+
type B<R, S> = [R] | [R, S];
12+
declare function g<T, U>(f: B<T, U>): U;
13+
g([[]] as [void[]]); // U: {}
14+
15+
type C<R, S> = [R[]] | [R[], S];
16+
declare function h<T, U>(f: C<T, U>): U;
17+
h([[]] as [void[]]); // U: {}
18+
19+
// Repro from #22562
20+
21+
type C2<R> = [R[]] | [R[], void];
22+
declare function h2<T>(f: C2<T>): T;
23+
h2([[]] as [never[]]); // T: never
24+
h2([[]] as [void[]]); // T: void
25+
26+
27+
//// [tupleTypeInference2.js]
28+
"use strict";
29+
// Repro from #22564
30+
f([undefined, '']); // T: never
31+
f([undefined, '']); // T: void
32+
g([[]]); // U: {}
33+
h([[]]); // U: {}
34+
h2([[]]); // T: never
35+
h2([[]]); // T: void
+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
=== tests/cases/compiler/tupleTypeInference2.ts ===
2+
// Repro from #22564
3+
4+
type A<R> = [R] | [R, string];
5+
>A : Symbol(A, Decl(tupleTypeInference2.ts, 0, 0))
6+
>R : Symbol(R, Decl(tupleTypeInference2.ts, 2, 7))
7+
>R : Symbol(R, Decl(tupleTypeInference2.ts, 2, 7))
8+
>R : Symbol(R, Decl(tupleTypeInference2.ts, 2, 7))
9+
10+
declare function f<T>(x: A<T>): T;
11+
>f : Symbol(f, Decl(tupleTypeInference2.ts, 2, 30))
12+
>T : Symbol(T, Decl(tupleTypeInference2.ts, 3, 19))
13+
>x : Symbol(x, Decl(tupleTypeInference2.ts, 3, 22))
14+
>A : Symbol(A, Decl(tupleTypeInference2.ts, 0, 0))
15+
>T : Symbol(T, Decl(tupleTypeInference2.ts, 3, 19))
16+
>T : Symbol(T, Decl(tupleTypeInference2.ts, 3, 19))
17+
18+
f([undefined, ''] as [never, string]); // T: never
19+
>f : Symbol(f, Decl(tupleTypeInference2.ts, 2, 30))
20+
>undefined : Symbol(undefined)
21+
22+
f([undefined, ''] as [void, string]); // T: void
23+
>f : Symbol(f, Decl(tupleTypeInference2.ts, 2, 30))
24+
>undefined : Symbol(undefined)
25+
26+
// Repro from #22563
27+
28+
type B<R, S> = [R] | [R, S];
29+
>B : Symbol(B, Decl(tupleTypeInference2.ts, 5, 37))
30+
>R : Symbol(R, Decl(tupleTypeInference2.ts, 9, 7))
31+
>S : Symbol(S, Decl(tupleTypeInference2.ts, 9, 9))
32+
>R : Symbol(R, Decl(tupleTypeInference2.ts, 9, 7))
33+
>R : Symbol(R, Decl(tupleTypeInference2.ts, 9, 7))
34+
>S : Symbol(S, Decl(tupleTypeInference2.ts, 9, 9))
35+
36+
declare function g<T, U>(f: B<T, U>): U;
37+
>g : Symbol(g, Decl(tupleTypeInference2.ts, 9, 28))
38+
>T : Symbol(T, Decl(tupleTypeInference2.ts, 10, 19))
39+
>U : Symbol(U, Decl(tupleTypeInference2.ts, 10, 21))
40+
>f : Symbol(f, Decl(tupleTypeInference2.ts, 10, 25))
41+
>B : Symbol(B, Decl(tupleTypeInference2.ts, 5, 37))
42+
>T : Symbol(T, Decl(tupleTypeInference2.ts, 10, 19))
43+
>U : Symbol(U, Decl(tupleTypeInference2.ts, 10, 21))
44+
>U : Symbol(U, Decl(tupleTypeInference2.ts, 10, 21))
45+
46+
g([[]] as [void[]]); // U: {}
47+
>g : Symbol(g, Decl(tupleTypeInference2.ts, 9, 28))
48+
49+
type C<R, S> = [R[]] | [R[], S];
50+
>C : Symbol(C, Decl(tupleTypeInference2.ts, 11, 20))
51+
>R : Symbol(R, Decl(tupleTypeInference2.ts, 13, 7))
52+
>S : Symbol(S, Decl(tupleTypeInference2.ts, 13, 9))
53+
>R : Symbol(R, Decl(tupleTypeInference2.ts, 13, 7))
54+
>R : Symbol(R, Decl(tupleTypeInference2.ts, 13, 7))
55+
>S : Symbol(S, Decl(tupleTypeInference2.ts, 13, 9))
56+
57+
declare function h<T, U>(f: C<T, U>): U;
58+
>h : Symbol(h, Decl(tupleTypeInference2.ts, 13, 32))
59+
>T : Symbol(T, Decl(tupleTypeInference2.ts, 14, 19))
60+
>U : Symbol(U, Decl(tupleTypeInference2.ts, 14, 21))
61+
>f : Symbol(f, Decl(tupleTypeInference2.ts, 14, 25))
62+
>C : Symbol(C, Decl(tupleTypeInference2.ts, 11, 20))
63+
>T : Symbol(T, Decl(tupleTypeInference2.ts, 14, 19))
64+
>U : Symbol(U, Decl(tupleTypeInference2.ts, 14, 21))
65+
>U : Symbol(U, Decl(tupleTypeInference2.ts, 14, 21))
66+
67+
h([[]] as [void[]]); // U: {}
68+
>h : Symbol(h, Decl(tupleTypeInference2.ts, 13, 32))
69+
70+
// Repro from #22562
71+
72+
type C2<R> = [R[]] | [R[], void];
73+
>C2 : Symbol(C2, Decl(tupleTypeInference2.ts, 15, 20))
74+
>R : Symbol(R, Decl(tupleTypeInference2.ts, 19, 8))
75+
>R : Symbol(R, Decl(tupleTypeInference2.ts, 19, 8))
76+
>R : Symbol(R, Decl(tupleTypeInference2.ts, 19, 8))
77+
78+
declare function h2<T>(f: C2<T>): T;
79+
>h2 : Symbol(h2, Decl(tupleTypeInference2.ts, 19, 33))
80+
>T : Symbol(T, Decl(tupleTypeInference2.ts, 20, 20))
81+
>f : Symbol(f, Decl(tupleTypeInference2.ts, 20, 23))
82+
>C2 : Symbol(C2, Decl(tupleTypeInference2.ts, 15, 20))
83+
>T : Symbol(T, Decl(tupleTypeInference2.ts, 20, 20))
84+
>T : Symbol(T, Decl(tupleTypeInference2.ts, 20, 20))
85+
86+
h2([[]] as [never[]]); // T: never
87+
>h2 : Symbol(h2, Decl(tupleTypeInference2.ts, 19, 33))
88+
89+
h2([[]] as [void[]]); // T: void
90+
>h2 : Symbol(h2, Decl(tupleTypeInference2.ts, 19, 33))
91+

Diff for: tests/baselines/reference/tupleTypeInference2.types

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
=== tests/cases/compiler/tupleTypeInference2.ts ===
2+
// Repro from #22564
3+
4+
type A<R> = [R] | [R, string];
5+
>A : A<R>
6+
>R : R
7+
>R : R
8+
>R : R
9+
10+
declare function f<T>(x: A<T>): T;
11+
>f : <T>(x: A<T>) => T
12+
>T : T
13+
>x : A<T>
14+
>A : A<R>
15+
>T : T
16+
>T : T
17+
18+
f([undefined, ''] as [never, string]); // T: never
19+
>f([undefined, ''] as [never, string]) : never
20+
>f : <T>(x: A<T>) => T
21+
>[undefined, ''] as [never, string] : [never, string]
22+
>[undefined, ''] : [undefined, string]
23+
>undefined : undefined
24+
>'' : ""
25+
26+
f([undefined, ''] as [void, string]); // T: void
27+
>f([undefined, ''] as [void, string]) : void
28+
>f : <T>(x: A<T>) => T
29+
>[undefined, ''] as [void, string] : [void, string]
30+
>[undefined, ''] : [undefined, string]
31+
>undefined : undefined
32+
>'' : ""
33+
34+
// Repro from #22563
35+
36+
type B<R, S> = [R] | [R, S];
37+
>B : B<R, S>
38+
>R : R
39+
>S : S
40+
>R : R
41+
>R : R
42+
>S : S
43+
44+
declare function g<T, U>(f: B<T, U>): U;
45+
>g : <T, U>(f: B<T, U>) => U
46+
>T : T
47+
>U : U
48+
>f : B<T, U>
49+
>B : B<R, S>
50+
>T : T
51+
>U : U
52+
>U : U
53+
54+
g([[]] as [void[]]); // U: {}
55+
>g([[]] as [void[]]) : {}
56+
>g : <T, U>(f: B<T, U>) => U
57+
>[[]] as [void[]] : [void[]]
58+
>[[]] : [never[]]
59+
>[] : never[]
60+
61+
type C<R, S> = [R[]] | [R[], S];
62+
>C : C<R, S>
63+
>R : R
64+
>S : S
65+
>R : R
66+
>R : R
67+
>S : S
68+
69+
declare function h<T, U>(f: C<T, U>): U;
70+
>h : <T, U>(f: C<T, U>) => U
71+
>T : T
72+
>U : U
73+
>f : C<T, U>
74+
>C : C<R, S>
75+
>T : T
76+
>U : U
77+
>U : U
78+
79+
h([[]] as [void[]]); // U: {}
80+
>h([[]] as [void[]]) : {}
81+
>h : <T, U>(f: C<T, U>) => U
82+
>[[]] as [void[]] : [void[]]
83+
>[[]] : [never[]]
84+
>[] : never[]
85+
86+
// Repro from #22562
87+
88+
type C2<R> = [R[]] | [R[], void];
89+
>C2 : C2<R>
90+
>R : R
91+
>R : R
92+
>R : R
93+
94+
declare function h2<T>(f: C2<T>): T;
95+
>h2 : <T>(f: C2<T>) => T
96+
>T : T
97+
>f : C2<T>
98+
>C2 : C2<R>
99+
>T : T
100+
>T : T
101+
102+
h2([[]] as [never[]]); // T: never
103+
>h2([[]] as [never[]]) : never
104+
>h2 : <T>(f: C2<T>) => T
105+
>[[]] as [never[]] : [never[]]
106+
>[[]] : [never[]]
107+
>[] : never[]
108+
109+
h2([[]] as [void[]]); // T: void
110+
>h2([[]] as [void[]]) : void
111+
>h2 : <T>(f: C2<T>) => T
112+
>[[]] as [void[]] : [void[]]
113+
>[[]] : [never[]]
114+
>[] : never[]
115+

Diff for: tests/cases/compiler/tupleTypeInference2.ts

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// @strict: true
2+
3+
// Repro from #22564
4+
5+
type A<R> = [R] | [R, string];
6+
declare function f<T>(x: A<T>): T;
7+
f([undefined, ''] as [never, string]); // T: never
8+
f([undefined, ''] as [void, string]); // T: void
9+
10+
// Repro from #22563
11+
12+
type B<R, S> = [R] | [R, S];
13+
declare function g<T, U>(f: B<T, U>): U;
14+
g([[]] as [void[]]); // U: {}
15+
16+
type C<R, S> = [R[]] | [R[], S];
17+
declare function h<T, U>(f: C<T, U>): U;
18+
h([[]] as [void[]]); // U: {}
19+
20+
// Repro from #22562
21+
22+
type C2<R> = [R[]] | [R[], void];
23+
declare function h2<T>(f: C2<T>): T;
24+
h2([[]] as [never[]]); // T: never
25+
h2([[]] as [void[]]); // T: void

0 commit comments

Comments
 (0)