8000 Fix cast exception when transforming compound length assignment (#1398) · TypeScriptToLua/TypeScriptToLua@96e76ca · GitHub
[go: up one dir, main page]

Skip to content

Commit 96e76ca

Browse files
authored
Fix cast exception when transforming compound length assignment (#1398)
1 parent 1e6fbfc commit 96e76ca

File tree

3 files changed

+104
-11
lines changed

3 files changed

+104
-11
lines changed

src/transformation/utils/preceding-statements.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import * as lua from "../../LuaAST";
22
import { TransformationContext } from "../context";
33

4+
export interface WithPrecedingStatements<
5+
T extends lua.Statement | lua.Statement[] | lua.Expression | lua.Expression[]
6+
> {
7+
precedingStatements: lua.Statement[];
8+
result: T;
9+
}
10+
411
export function transformInPrecedingStatementScope<
512
TReturn extends lua.Statement | lua.Statement[] | lua.Expression | lua.Expression[]
613
>(context: TransformationContext, transformer: () => TReturn): [lua.Statement[], TReturn] {

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

Lines changed: 80 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ import * as ts from "typescript";
22
import * as lua from "../../../LuaAST";
33
import { cast, assertNever } from "../../../utils";
44
import { TransformationContext } from "../../context";
5-
import { transformInPrecedingStatementScope } from "../../utils/preceding-statements";
5+
import { transformInPrecedingStatementScope, WithPrecedingStatements } from "../../utils/preceding-statements";
66
import { transformBinaryOperation } from "./index";
77
import { transformAssignmentWithRightPrecedingStatements } from "./assignments";
8+
import { isArrayLength } from "./destructuring-assignments";
9+
import { LuaLibFeature, transformLuaLibFunction } from "../../utils/lualib";
810

911
function isLuaExpressionWithSideEffect(expression: lua.Expression) {
1012
return !(lua.isLiteral(expression) || lua.isIdentifier(expression));
@@ -63,14 +65,26 @@ export const isCompoundAssignmentToken = (token: ts.BinaryOperator): token is ts
6365
export const unwrapCompoundAssignmentToken = (token: ts.CompoundAssignmentOperator): CompoundAssignmentToken =>
6466
compoundToAssignmentTokens[token];
6567

66-
export function transformCompoundAssignment(
68+
function transformCompoundAssignment(
6769
context: TransformationContext,
6870
expression: ts.Expression,
6971
lhs: ts.Expression,
7072
rhs: ts.Expression,
7173
operator: CompoundAssignmentToken,
7274
isPostfix: boolean
73-
) {
75+
): WithPrecedingStatements<lua.Expression> {
76+
if (isArrayLength(context, lhs)) {
77+
const { precedingStatements, result: lengthSetterStatement } = transformCompoundLengthSetter(
78+
context,
79+
expression,
80+
lhs,
81+
rhs,
82+
operator
83+
);
84+
85+
return { precedingStatements, result: lengthSetterStatement.expression };
86+
}
87+
7488
const left = cast(context.transformExpression(lhs), lua.isAssignmentLeftHandSideExpression);
7589
const [rightPrecedingStatements, right] = transformInPrecedingStatementScope(context, () =>
7690
context.transformExpression(rhs)
@@ -101,13 +115,13 @@ export function transformCompoundAssignment(
101115
);
102116
const assignStatement = lua.createAssignmentStatement(accessExpression, operatorExpression);
103117
return {
104-
statements: [objAndIndexDeclaration, ...precedingStatements, tmpDeclaration, assignStatement],
118+
precedingStatements: [objAndIndexDeclaration, ...precedingStatements, tmpDeclaration, assignStatement],
105119
result: tmp,
106120
};
107121
} else {
108122
if (isSetterSkippingCompoundAssignmentOperator(operator)) {
109123
return {
110-
statements: [
124+
precedingStatements: [
111125
objAndIndexDeclaration,
112126
...transformSetterSkippingCompoundAssignment(
113127
accessExpression,
@@ -133,7 +147,7 @@ export function transformCompoundAssignment(
133147
const tmpDeclaration = lua.createVariableDeclarationStatement(tmp, operatorExpression);
134148
const assignStatement = lua.createAssignmentStatement(accessExpression, tmp);
135149
return {
136-
statements: [objAndIndexDeclaration, ...precedingStatements, tmpDeclaration, assignStatement],
150+
precedingStatements: [objAndIndexDeclaration, ...precedingStatements, tmpDeclaration, assignStatement],
137151
result: tmp,
138152
};
139153
}
@@ -158,11 +172,19 @@ export function transformCompoundAssignment(
158172
operatorExpression,
159173
rightPrecedingStatements
160174
);
161-
return { statements: [tmpDeclaration, ...precedingStatements, ...assignStatements], result: tmpIdentifier };
175+
return {
176+
precedingStatements: [tmpDeclaration, ...precedingStatements, ...assignStatements],
177+
result: tmpIdentifier,
178+
};
162179
} else {
163180
if (rightPrecedingStatements.length > 0 && isSetterSkippingCompoundAssignmentOperator(operator)) {
164181
return {
165-
statements: transformSetterSkippingCompoundAssignment(left, operator, right, rightPrecedingStatements),
182+
precedingStatements: transformSetterSkippingCompoundAssignment(
183+
left,
184+
operator,
185+
right,
186+
rightPrecedingStatements
187+
),
166188
result: left,
167189
};
168190
}
@@ -183,7 +205,7 @@ export function transformCompoundAssignment(
183205
operatorExpression,
184206
precedingStatements
185207
);
186-
return { statements, result: left };
208+
return { precedingStatements: statements, result: left };
187209
}
188210
}
189211

@@ -196,8 +218,15 @@ export function transformCompoundAssignmentExpression(
196218
operator: CompoundAssignmentToken,
197219
isPostfix: boolean
198220
): lua.Expression {
199-
const { statements, result } = transformCompoundAssignment(context, expression, lhs, rhs, operator, isPostfix);
200-
context.addPrecedingStatements(statements);
221+
const { precedingStatements, result } = transformCompoundAssignment(
222+
context,
223+
expression,
224+
lhs,
225+
rhs,
226+
operator,
227+
isPostfix
228+
);
229+
context.addPrecedingStatements(precedingStatements);
201230
return result;
202231
}
203232

@@ -208,6 +237,18 @@ export function transformCompoundAssignmentStatement(
208237
rhs: ts.Expression,
209238
operator: CompoundAssignmentToken
210239
): lua.Statement[] {
240+
if (isArrayLength(context, lhs)) {
241+
const { precedingStatements, result: lengthSetterStatement } = transformCompoundLengthSetter(
242+
context,
243+
node,
244+
lhs,
245+
rhs,
246+
operator
247+
);
248+
249+
return [...precedingStatements, lengthSetterStatement];
250+
}
251+
211252
const left = cast(context.transformExpression(lhs), lua.isAssignmentLeftHandSideExpression);
212253
let [rightPrecedingStatements, right] = transformInPrecedingStatementScope(context, () =>
213254
context.transformExpression(rhs)
@@ -319,3 +360,31 @@ function transformSetterSkippingCompoundAssignment(
319360
),
320361
];
321362
}
363+
364+
function transformCompoundLengthSetter(
365+
context: TransformationContext,
366+
node: ts.Node,
367+
lhs: ts.PropertyAccessExpression | ts.ElementAccessExpression,
368+
rhs: ts.Expression,
369+
operator: CompoundAssignmentToken
370+
): WithPrecedingStatements<lua.ExpressionStatement> {
371+
const [rightPrecedingStatements, right] = transformInPrecedingStatementScope(context, () =>
372+
context.transformExpression(rhs)
373+
);
374+
const table = context.transformExpression(lhs.expression);
375+
const lengthExpression = lua.createUnaryExpression(table, lua.SyntaxKind.LengthOperator, lhs);
376+
const [precedingStatements, operatorExpression] = transformBinaryOperation(
377+
context,
378+
lengthExpression,
379+
right,
380+
rightPrecedingStatements,
381+
operator,
382+
node
383+
);
384+
385+
const arrayLengthAssignment = lua.createExpressionStatement(
386+
transformLuaLibFunction(context, LuaLibFeature.ArraySetLength, node, table, operatorExpression)
387+
);
388+
389+
return { precedingStatements, result: arrayLengthAssignment };
390+
}

test/unit/builtins/array.spec.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,23 @@ describe("array.length", () => {
176176
`.expectToEqual(new util.ExecutionError(`invalid array length: ${luaSpecialValueString}`));
177177
});
178178

179+
// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1395
180+
test("in compound assignment (#1395)", () => {
181+
util.testFunction`
182+
const arr = [1,2,3,4];
183+
const returnVal = arr.length -= 2;
184+
return { arr, returnVal };
185+
`.expectToMatchJsResult();
186+
});
187+
188+
test("as standalone compound assignment (#1395)", () => {
189+
util.testFunction`
190+
const arr = [1,2,3,4];
191+
arr.length -= 2;
192+
return arr;
193+
`.expectToMatchJsResult();
194+
});
195+
179196
test("in array destructuring", () => {
180197
util.testFunction`
181198
const array = [0, 1, 2];

0 commit comments

Comments
 (0)
0