Skip to content

Commit 5acd109

Browse files
authored
Limit unpack call in destructuring assignments to only required elements (#1655)
1 parent 8a43f43 commit 5acd109

File tree

4 files changed

+46
-5
lines changed

4 files changed

+46
-5
lines changed

src/transformation/utils/lua-ast.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,35 @@ export function createUnpackCall(
8181
return lua.setNodeFlags(lua.createCallExpression(unpack, [expression], tsOriginal), lua.NodeFlags.TableUnpackCall);
8282
}
8383

84+
export function createBoundedUnpackCall(
85+
context: TransformationContext,
86+
expression: lua.Expression,
87+
maxUnpackItem: number,
88+
tsOriginal?: ts.Node
89+
): lua.Expression {
90+
if (context.luaTarget === LuaTarget.Universal) {
91+
return transformLuaLibFunction(context, LuaLibFeature.Unpack, tsOriginal, expression);
92+
}
93+
94+
// Lua 5.0 does not support this signature, so don't add the arguments there
95+
const extraArgs =
96+
context.luaTarget === LuaTarget.Lua50
97+
? []
98+
: [lua.createNumericLiteral(1), lua.createNumericLiteral(maxUnpackItem)];
99+
100+
const unpack =
101+
context.luaTarget === LuaTarget.Lua50 ||
102+
context.luaTarget === LuaTarget.Lua51 ||
103+
context.luaTarget === LuaTarget.LuaJIT
104+
? lua.createIdentifier("unpack")
105+
: lua.createTableIndexExpression(lua.createIdentifier("table"), lua.createStringLiteral("unpack"));
106+
107+
return lua.setNodeFlags(
108+
lua.createCallExpression(unpack, [expression, ...extraArgs], tsOriginal),
109+
lua.NodeFlags.TableUnpackCall
110+
);
111+
}
112+
84113
export function isUnpackCall(node: lua.Node): boolean {
85114
return lua.isCallExpression(node) && (node.flags & lua.NodeFlags.TableUnpackCall) !== 0;
86115
}

src/transformation/visitors/binary-expression/assignments.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import * as lua from "../../../LuaAST";
44
import { TransformationContext } from "../../context";
55
import { validateAssignment } from "../../utils/assignment-validation";
66
import { createExportedIdentifier, getDependenciesOfSymbol, isSymbolExported } from "../../utils/export";
7-
import { createUnpackCall, wrapInTable } from "../../utils/lua-ast";
7+
import { createBoundedUnpackCall, wrapInTable } from "../../utils/lua-ast";
88
import { LuaLibFeature, transformLuaLibFunction } from "../../utils/lualib";
99
import { isArrayType, isDestructuringAssignment } from "../../utils/typescript";
1010
import { isArrayLength, transformDestructuringAssignment } from "./destructuring-assignments";
@@ -252,7 +252,7 @@ export function transformAssignmentStatement(
252252
} else {
253253
right = context.transformExpression(expression.right);
254254
if (!isMultiReturnCall(context, expression.right) && isArrayType(context, rightType)) {
255-
right = createUnpackCall(context, right, expression.right);
255+
right = createBoundedUnpackCall(context, right, expression.left.elements.length, expression.right);
256256
}
257257
}
258258

src/transformation/visitors/variable-declaration.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { FunctionVisitor, TransformationContext } from "../context";
55
import { validateAssignment } from "../utils/assignment-validation";
66
import { unsupportedVarDeclaration } from "../utils/diagnostics";
77
import { addExportToIdentifier } from "../utils/export";
8-
import { createLocalOrExportedOrGlobalDeclaration, createUnpackCall, wrapInTable } from "../utils/lua-ast";
8+
import { createBoundedUnpackCall, createLocalOrExportedOrGlobalDeclaration, wrapInTable } from "../utils/lua-ast";
99
import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib";
1010
import { transformInPrecedingStatementScope } from "../utils/preceding-statements";
1111
import { createCallableTable, isFunctionTypeWithProperties } from "./function";
@@ -209,10 +209,11 @@ export function transformBindingVariableDeclaration(
209209
: lua.createNilLiteral();
210210
statements.push(...createLocalOrExportedOrGlobalDeclaration(context, vars, values, initializer));
211211
} else {
212-
// local vars = this.transpileDestructingAssignmentValue(node.initializer);
213-
const unpackedInitializer = createUnpackCall(
212+
// use unpack(thing, 1, #bindingItems) to unpack
213+
const unpackedInitializer = createBoundedUnpackCall(
214214
context,
215215
context.transformExpression(initializer),
216+
bindingPattern.elements.length,
216217
initializer
217218
);
218219
statements.push(

test/unit/destructuring.spec.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,17 @@ describe("array destructuring optimization", () => {
195195
.expectToMatchJsResult();
196196
});
197197

198+
util.testEachVersion(
199+
"array versions",
200+
() =>
201+
util.testFunction`
202+
const array = [3, 5, 1];
203+
const [a, b, c] = array;
204+
return { a, b, c };
205+
`,
206+
util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult())
207+
);
208+
198209
test("array literal", () => {
199210
util.testFunction`
200211
const [a, b, c] = [3, 5, 1];

0 commit comments

Comments
 (0)