From dfd36202067766b34bd3ca1cd964efdea20c16c1 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 20 Nov 2017 11:28:21 -0800 Subject: [PATCH] Fix higher order inference on indexed access types --- src/compiler/checker.ts | 2 +- .../reference/indexedAccessCanBeHighOrder.js | 21 ++++++ .../indexedAccessCanBeHighOrder.symbols | 63 ++++++++++++++++ .../indexedAccessCanBeHighOrder.types | 75 +++++++++++++++++++ .../compiler/indexedAccessCanBeHighOrder.ts | 11 +++ 5 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/indexedAccessCanBeHighOrder.js create mode 100644 tests/baselines/reference/indexedAccessCanBeHighOrder.symbols create mode 100644 tests/baselines/reference/indexedAccessCanBeHighOrder.types create mode 100644 tests/cases/compiler/indexedAccessCanBeHighOrder.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index dc1bab72c38f5..79833e90316eb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11254,7 +11254,7 @@ namespace ts { return; } } - else if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target) { + if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target) { // If source and target are references to the same generic type, infer from type arguments const sourceTypes = (source).typeArguments || emptyArray; const targetTypes = (target).typeArguments || emptyArray; diff --git a/tests/baselines/reference/indexedAccessCanBeHighOrder.js b/tests/baselines/reference/indexedAccessCanBeHighOrder.js new file mode 100644 index 0000000000000..acd1e98dd093e --- /dev/null +++ b/tests/baselines/reference/indexedAccessCanBeHighOrder.js @@ -0,0 +1,21 @@ +//// [indexedAccessCanBeHighOrder.ts] +declare function get(x: U, y: Y): U[Y]; +declare function find(o: T[K]): [T, K]; + +function impl(a: A, b: B) { + const item = get(a, b); + return find(item); +} + +const o = {x: 42}; +const r = impl(o, "x"); +r[0][r[1]] = o[r[1]]; + +//// [indexedAccessCanBeHighOrder.js] +function impl(a, b) { + var item = get(a, b); + return find(item); +} +var o = { x: 42 }; +var r = impl(o, "x"); +r[0][r[1]] = o[r[1]]; diff --git a/tests/baselines/reference/indexedAccessCanBeHighOrder.symbols b/tests/baselines/reference/indexedAccessCanBeHighOrder.symbols new file mode 100644 index 0000000000000..3c6ce29fb7eef --- /dev/null +++ b/tests/baselines/reference/indexedAccessCanBeHighOrder.symbols @@ -0,0 +1,63 @@ +=== tests/cases/compiler/indexedAccessCanBeHighOrder.ts === +declare function get(x: U, y: Y): U[Y]; +>get : Symbol(get, Decl(indexedAccessCanBeHighOrder.ts, 0, 0)) +>U : Symbol(U, Decl(indexedAccessCanBeHighOrder.ts, 0, 21)) +>Y : Symbol(Y, Decl(indexedAccessCanBeHighOrder.ts, 0, 23)) +>U : Symbol(U, Decl(indexedAccessCanBeHighOrder.ts, 0, 21)) +>x : Symbol(x, Decl(indexedAccessCanBeHighOrder.ts, 0, 43)) +>U : Symbol(U, Decl(indexedAccessCanBeHighOrder.ts, 0, 21)) +>y : Symbol(y, Decl(indexedAccessCanBeHighOrder.ts, 0, 48)) +>Y : Symbol(Y, Decl(indexedAccessCanBeHighOrder.ts, 0, 23)) +>U : Symbol(U, Decl(indexedAccessCanBeHighOrder.ts, 0, 21)) +>Y : Symbol(Y, Decl(indexedAccessCanBeHighOrder.ts, 0, 23)) + +declare function find(o: T[K]): [T, K]; +>find : Symbol(find, Decl(indexedAccessCanBeHighOrder.ts, 0, 61)) +>T : Symbol(T, Decl(indexedAccessCanBeHighOrder.ts, 1, 22)) +>K : Symbol(K, Decl(indexedAccessCanBeHighOrder.ts, 1, 24)) +>T : Symbol(T, Decl(indexedAccessCanBeHighOrder.ts, 1, 22)) +>o : Symbol(o, Decl(indexedAccessCanBeHighOrder.ts, 1, 44)) +>T : Symbol(T, Decl(indexedAccessCanBeHighOrder.ts, 1, 22)) +>K : Symbol(K, Decl(indexedAccessCanBeHighOrder.ts, 1, 24)) +>T : Symbol(T, Decl(indexedAccessCanBeHighOrder.ts, 1, 22)) +>K : Symbol(K, Decl(indexedAccessCanBeHighOrder.ts, 1, 24)) + +function impl(a: A, b: B) { +>impl : Symbol(impl, Decl(indexedAccessCanBeHighOrder.ts, 1, 61)) +>A : Symbol(A, Decl(indexedAccessCanBeHighOrder.ts, 3, 14)) +>B : Symbol(B, Decl(indexedAccessCanBeHighOrder.ts, 3, 16)) +>A : Symbol(A, Decl(indexedAccessCanBeHighOrder.ts, 3, 14)) +>a : Symbol(a, Decl(indexedAccessCanBeHighOrder.ts, 3, 36)) +>A : Symbol(A, Decl(indexedAccessCanBeHighOrder.ts, 3, 14)) +>b : Symbol(b, Decl(indexedAccessCanBeHighOrder.ts, 3, 41)) +>B : Symbol(B, Decl(indexedAccessCanBeHighOrder.ts, 3, 16)) + + const item = get(a, b); +>item : Symbol(item, Decl(indexedAccessCanBeHighOrder.ts, 4, 9)) +>get : Symbol(get, Decl(indexedAccessCanBeHighOrder.ts, 0, 0)) +>a : Symbol(a, Decl(indexedAccessCanBeHighOrder.ts, 3, 36)) +>b : Symbol(b, Decl(indexedAccessCanBeHighOrder.ts, 3, 41)) + + return find(item); +>find : Symbol(find, Decl(indexedAccessCanBeHighOrder.ts, 0, 61)) +>item : Symbol(item, Decl(indexedAccessCanBeHighOrder.ts, 4, 9)) +} + +const o = {x: 42}; +>o : Symbol(o, Decl(indexedAccessCanBeHighOrder.ts, 8, 5)) +>x : Symbol(x, Decl(indexedAccessCanBeHighOrder.ts, 8, 11)) + +const r = impl(o, "x"); +>r : Symbol(r, Decl(indexedAccessCanBeHighOrder.ts, 9, 5)) +>impl : Symbol(impl, Decl(indexedAccessCanBeHighOrder.ts, 1, 61)) +>o : Symbol(o, Decl(indexedAccessCanBeHighOrder.ts, 8, 5)) + +r[0][r[1]] = o[r[1]]; +>r : Symbol(r, Decl(indexedAccessCanBeHighOrder.ts, 9, 5)) +>0 : Symbol(0) +>r : Symbol(r, Decl(indexedAccessCanBeHighOrder.ts, 9, 5)) +>1 : Symbol(1) +>o : Symbol(o, Decl(indexedAccessCanBeHighOrder.ts, 8, 5)) +>r : Symbol(r, Decl(indexedAccessCanBeHighOrder.ts, 9, 5)) +>1 : Symbol(1) + diff --git a/tests/baselines/reference/indexedAccessCanBeHighOrder.types b/tests/baselines/reference/indexedAccessCanBeHighOrder.types new file mode 100644 index 0000000000000..2b24210be7efa --- /dev/null +++ b/tests/baselines/reference/indexedAccessCanBeHighOrder.types @@ -0,0 +1,75 @@ +=== tests/cases/compiler/indexedAccessCanBeHighOrder.ts === +declare function get(x: U, y: Y): U[Y]; +>get : (x: U, y: Y) => U[Y] +>U : U +>Y : Y +>U : U +>x : U +>U : U +>y : Y +>Y : Y +>U : U +>Y : Y + +declare function find(o: T[K]): [T, K]; +>find : (o: T[K]) => [T, K] +>T : T +>K : K +>T : T +>o : T[K] +>T : T +>K : K +>T : T +>K : K + +function impl(a: A, b: B) { +>impl : (a: A, b: B) => [A, B] +>A : A +>B : B +>A : A +>a : A +>A : A +>b : B +>B : B + + const item = get(a, b); +>item : A[B] +>get(a, b) : A[B] +>get : (x: U, y: Y) => U[Y] +>a : A +>b : B + + return find(item); +>find(item) : [A, B] +>find : (o: T[K]) => [T, K] +>item : A[B] +} + +const o = {x: 42}; +>o : { x: number; } +>{x: 42} : { x: number; } +>x : number +>42 : 42 + +const r = impl(o, "x"); +>r : [{ x: number; }, "x"] +>impl(o, "x") : [{ x: number; }, "x"] +>impl : (a: A, b: B) => [A, B] +>o : { x: number; } +>"x" : "x" + +r[0][r[1]] = o[r[1]]; +>r[0][r[1]] = o[r[1]] : number +>r[0][r[1]] : number +>r[0] : { x: number; } +>r : [{ x: number; }, "x"] +>0 : 0 +>r[1] : "x" +>r : [{ x: number; }, "x"] +>1 : 1 +>o[r[1]] : number +>o : { x: number; } +>r[1] : "x" +>r : [{ x: number; }, "x"] +>1 : 1 + diff --git a/tests/cases/compiler/indexedAccessCanBeHighOrder.ts b/tests/cases/compiler/indexedAccessCanBeHighOrder.ts new file mode 100644 index 0000000000000..93420c2ae8ff6 --- /dev/null +++ b/tests/cases/compiler/indexedAccessCanBeHighOrder.ts @@ -0,0 +1,11 @@ +declare function get(x: U, y: Y): U[Y]; +declare function find(o: T[K]): [T, K]; + +function impl(a: A, b: B) { + const item = get(a, b); + return find(item); +} + +const o = {x: 42}; +const r = impl(o, "x"); +r[0][r[1]] = o[r[1]]; \ No newline at end of file