From 4fe75376a0714852a2802b2c55f21f8692d88a43 Mon Sep 17 00:00:00 2001 From: Tom <26638278+tomblind@users.noreply.github.com> Date: Thu, 15 Jul 2021 04:59:46 +0800 Subject: [PATCH] fixed vararg optimization logic --- src/transformation/utils/scope.ts | 6 ++-- test/unit/__snapshots__/spread.spec.ts.snap | 33 +++++++++++++++++++++ test/unit/spread.spec.ts | 24 +++++++++++++++ 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/src/transformation/utils/scope.ts b/src/transformation/utils/scope.ts index dcb877db7..53169765a 100644 --- a/src/transformation/utils/scope.ts +++ b/src/transformation/utils/scope.ts @@ -92,9 +92,9 @@ export function popScope(context: TransformationContext): Scope { return scope; } -function isDeclaredInScope(symbol: ts.Symbol, scopeNode: ts.Node) { +function isHoistableFunctionDeclaredInScope(symbol: ts.Symbol, scopeNode: ts.Node) { return symbol?.declarations?.some( - d => findFirstNodeAbove(d, (n): n is ts.Node => n === scopeNode) && !ts.isParameter(d.parent) + d => ts.isFunctionDeclaration(d) && findFirstNodeAbove(d, (n): n is ts.Node => n === scopeNode) ); } @@ -109,7 +109,7 @@ export function hasReferencedUndefinedLocalFunction(context: TransformationConte if ( !scope.functionDefinitions?.has(symbolId) && type.getCallSignatures().length > 0 && - isDeclaredInScope(type.symbol, scope.node) + isHoistableFunctionDeclaredInScope(type.symbol, scope.node) ) { return true; } diff --git a/test/unit/__snapshots__/spread.spec.ts.snap b/test/unit/__snapshots__/spread.spec.ts.snap index 85d1c4ac3..0b49fd80a 100644 --- a/test/unit/__snapshots__/spread.spec.ts.snap +++ b/test/unit/__snapshots__/spread.spec.ts.snap @@ -81,6 +81,24 @@ end return ____exports" `; +exports[`vararg spread optimization curry with indirect type 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local function test(self, obj, ...) + local fn = obj.fn + return fn(nil, ...) + end + return test( + nil, + { + fn = function(____, arg) return arg end + }, + \\"foobar\\" + ) +end +return ____exports" +`; + exports[`vararg spread optimization finally clause 1`] = ` "local ____exports = {} function ____exports.__main(self) @@ -105,6 +123,21 @@ end return ____exports" `; +exports[`vararg spread optimization function type declared inside scope 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local function test(self, ...) + local function fn(____, ...) + local args = {...} + return args[1] + end + return fn(nil, ...) + end + test(nil, \\"foobar\\") +end +return ____exports" +`; + exports[`vararg spread optimization if statement 1`] = ` "local ____exports = {} function ____exports.__main(self) diff --git a/test/unit/spread.spec.ts b/test/unit/spread.spec.ts index e65ee7ee7..5d7ed93a7 100644 --- a/test/unit/spread.spec.ts +++ b/test/unit/spread.spec.ts @@ -241,6 +241,30 @@ describe("vararg spread optimization", () => { .expectLuaToMatchSnapshot() .expectToMatchJsResult(); }); + + test("curry with indirect type", () => { + util.testFunction` + function test(obj: {fn: (...args: A) => void}, ...args: A) { + const fn = obj.fn; + return fn(...args); + } + return test({fn: (arg: string) => arg}, "foobar"); + ` + .expectLuaToMatchSnapshot() + .expectToMatchJsResult(); + }); + + test("function type declared inside scope", () => { + util.testFunction` + function test(...args: A) { + const fn: (...args: A) => A[0] = (...args) => args[0]; + return fn(...args); + } + test("foobar"); + ` + .expectLuaToMatchSnapshot() + .expectToMatchJsResult(); + }); }); describe("vararg spread de-optimization", () => {