Skip to content

Commit 7ad0d7b

Browse files
authored
Fix higher order inference on indexed access types (microsoft#20165)
1 parent 00450f0 commit 7ad0d7b

5 files changed

Lines changed: 171 additions & 1 deletion

File tree

src/compiler/checker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11400,7 +11400,7 @@ namespace ts {
1140011400
return;
1140111401
}
1140211402
}
11403-
else if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (<TypeReference>source).target === (<TypeReference>target).target) {
11403+
if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (<TypeReference>source).target === (<TypeReference>target).target) {
1140411404
// If source and target are references to the same generic type, infer from type arguments
1140511405
const sourceTypes = (<TypeReference>source).typeArguments || emptyArray;
1140611406
const targetTypes = (<TypeReference>target).typeArguments || emptyArray;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//// [indexedAccessCanBeHighOrder.ts]
2+
declare function get<U, Y extends keyof U>(x: U, y: Y): U[Y];
3+
declare function find<T, K extends keyof T>(o: T[K]): [T, K];
4+
5+
function impl<A, B extends keyof A>(a: A, b: B) {
6+
const item = get(a, b);
7+
return find(item);
8+
}
9+
10+
const o = {x: 42};
11+
const r = impl(o, "x");
12+
r[0][r[1]] = o[r[1]];
13+
14+
//// [indexedAccessCanBeHighOrder.js]
15+
function impl(a, b) {
16+
var item = get(a, b);
17+
return find(item);
18+
}
19+
var o = { x: 42 };
20+
var r = impl(o, "x");
21+
r[0][r[1]] = o[r[1]];
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
=== tests/cases/compiler/indexedAccessCanBeHighOrder.ts ===
2+
declare function get<U, Y extends keyof U>(x: U, y: Y): U[Y];
3+
>get : Symbol(get, Decl(indexedAccessCanBeHighOrder.ts, 0, 0))
4+
>U : Symbol(U, Decl(indexedAccessCanBeHighOrder.ts, 0, 21))
5+
>Y : Symbol(Y, Decl(indexedAccessCanBeHighOrder.ts, 0, 23))
6+
>U : Symbol(U, Decl(indexedAccessCanBeHighOrder.ts, 0, 21))
7+
>x : Symbol(x, Decl(indexedAccessCanBeHighOrder.ts, 0, 43))
8+
>U : Symbol(U, Decl(indexedAccessCanBeHighOrder.ts, 0, 21))
9+
>y : Symbol(y, Decl(indexedAccessCanBeHighOrder.ts, 0, 48))
10+
>Y : Symbol(Y, Decl(indexedAccessCanBeHighOrder.ts, 0, 23))
11+
>U : Symbol(U, Decl(indexedAccessCanBeHighOrder.ts, 0, 21))
12+
>Y : Symbol(Y, Decl(indexedAccessCanBeHighOrder.ts, 0, 23))
13+
14+
declare function find<T, K extends keyof T>(o: T[K]): [T, K];
15+
>find : Symbol(find, Decl(indexedAccessCanBeHighOrder.ts, 0, 61))
16+
>T : Symbol(T, Decl(indexedAccessCanBeHighOrder.ts, 1, 22))
17+
>K : Symbol(K, Decl(indexedAccessCanBeHighOrder.ts, 1, 24))
18+
>T : Symbol(T, Decl(indexedAccessCanBeHighOrder.ts, 1, 22))
19+
>o : Symbol(o, Decl(indexedAccessCanBeHighOrder.ts, 1, 44))
20+
>T : Symbol(T, Decl(indexedAccessCanBeHighOrder.ts, 1, 22))
21+
>K : Symbol(K, Decl(indexedAccessCanBeHighOrder.ts, 1, 24))
22+
>T : Symbol(T, Decl(indexedAccessCanBeHighOrder.ts, 1, 22))
23+
>K : Symbol(K, Decl(indexedAccessCanBeHighOrder.ts, 1, 24))
24+
25+
function impl<A, B extends keyof A>(a: A, b: B) {
26+
>impl : Symbol(impl, Decl(indexedAccessCanBeHighOrder.ts, 1, 61))
27+
>A : Symbol(A, Decl(indexedAccessCanBeHighOrder.ts, 3, 14))
28+
>B : Symbol(B, Decl(indexedAccessCanBeHighOrder.ts, 3, 16))
29+
>A : Symbol(A, Decl(indexedAccessCanBeHighOrder.ts, 3, 14))
30+
>a : Symbol(a, Decl(indexedAccessCanBeHighOrder.ts, 3, 36))
31+
>A : Symbol(A, Decl(indexedAccessCanBeHighOrder.ts, 3, 14))
32+
>b : Symbol(b, Decl(indexedAccessCanBeHighOrder.ts, 3, 41))
33+
>B : Symbol(B, Decl(indexedAccessCanBeHighOrder.ts, 3, 16))
34+
35+
const item = get(a, b);
36+
>item : Symbol(item, Decl(indexedAccessCanBeHighOrder.ts, 4, 9))
37+
>get : Symbol(get, Decl(indexedAccessCanBeHighOrder.ts, 0, 0))
38+
>a : Symbol(a, Decl(indexedAccessCanBeHighOrder.ts, 3, 36))
39+
>b : Symbol(b, Decl(indexedAccessCanBeHighOrder.ts, 3, 41))
40+
41+
return find(item);
42+
>find : Symbol(find, Decl(indexedAccessCanBeHighOrder.ts, 0, 61))
43+
>item : Symbol(item, Decl(indexedAccessCanBeHighOrder.ts, 4, 9))
44+
}
45+
46+
const o = {x: 42};
47+
>o : Symbol(o, Decl(indexedAccessCanBeHighOrder.ts, 8, 5))
48+
>x : Symbol(x, Decl(indexedAccessCanBeHighOrder.ts, 8, 11))
49+
50+
const r = impl(o, "x");
51+
>r : Symbol(r, Decl(indexedAccessCanBeHighOrder.ts, 9, 5))
52+
>impl : Symbol(impl, Decl(indexedAccessCanBeHighOrder.ts, 1, 61))
53+
>o : Symbol(o, Decl(indexedAccessCanBeHighOrder.ts, 8, 5))
54+
55+
r[0][r[1]] = o[r[1]];
56+
>r : Symbol(r, Decl(indexedAccessCanBeHighOrder.ts, 9, 5))
57+
>0 : Symbol(0)
58+
>r : Symbol(r, Decl(indexedAccessCanBeHighOrder.ts, 9, 5))
59+
>1 : Symbol(1)
60+
>o : Symbol(o, Decl(indexedAccessCanBeHighOrder.ts, 8, 5))
61+
>r : Symbol(r, Decl(indexedAccessCanBeHighOrder.ts, 9, 5))
62+
>1 : Symbol(1)
63+
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
=== tests/cases/compiler/indexedAccessCanBeHighOrder.ts ===
2+
declare function get<U, Y extends keyof U>(x: U, y: Y): U[Y];
3+
>get : <U, Y extends keyof U>(x: U, y: Y) => U[Y]
4+
>U : U
5+
>Y : Y
6+
>U : U
7+
>x : U
8+
>U : U
9+
>y : Y
10+
>Y : Y
11+
>U : U
12+
>Y : Y
13+
14+
declare function find<T, K extends keyof T>(o: T[K]): [T, K];
15+
>find : <T, K extends keyof T>(o: T[K]) => [T, K]
16+
>T : T
17+
>K : K
18+
>T : T
19+
>o : T[K]
20+
>T : T
21+
>K : K
22+
>T : T
23+
>K : K
24+
25+
function impl<A, B extends keyof A>(a: A, b: B) {
26+
>impl : <A, B extends keyof A>(a: A, b: B) => [A, B]
27+
>A : A
28+
>B : B
29+
>A : A
30+
>a : A
31+
>A : A
32+
>b : B
33+
>B : B
34+
35+
const item = get(a, b);
36+
>item : A[B]
37+
>get(a, b) : A[B]
38+
>get : <U, Y extends keyof U>(x: U, y: Y) => U[Y]
39+
>a : A
40+
>b : B
41+
42+
return find(item);
43+
>find(item) : [A, B]
44+
>find : <T, K extends keyof T>(o: T[K]) => [T, K]
45+
>item : A[B]
46+
}
47+
48+
const o = {x: 42};
49+
>o : { x: number; }
50+
>{x: 42} : { x: number; }
51+
>x : number
52+
>42 : 42
53+
54+
const r = impl(o, "x");
55+
>r : [{ x: number; }, "x"]
56+
>impl(o, "x") : [{ x: number; }, "x"]
57+
>impl : <A, B extends keyof A>(a: A, b: B) => [A, B]
58+
>o : { x: number; }
59+
>"x" : "x"
60+
61+
r[0][r[1]] = o[r[1]];
62+
>r[0][r[1]] = o[r[1]] : number
63+
>r[0][r[1]] : number
64+
>r[0] : { x: number; }
65+
>r : [{ x: number; }, "x"]
66+
>0 : 0
67+
>r[1] : "x"
68+
>r : [{ x: number; }, "x"]
69+
>1 : 1
70+
>o[r[1]] : number
71+
>o : { x: number; }
72+
>r[1] : "x"
73+
>r : [{ x: number; }, "x"]
74+
>1 : 1
75+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
declare function get<U, Y extends keyof U>(x: U, y: Y): U[Y];
2+
declare function find<T, K extends keyof T>(o: T[K]): [T, K];
3+
4+
function impl<A, B extends keyof A>(a: A, b: B) {
5+
const item = get(a, b);
6+
return find(item);
7+
}
8+
9+
const o = {x: 42};
10+
const r = impl(o, "x");
11+
r[0][r[1]] = o[r[1]];

0 commit comments

Comments
 (0)