Skip to content

Commit 8e9dfe8

Browse files
tomblindPerryvw
authored andcommitted
Fixes to return for TupleReturn functions (#232)
* TupleReturn functions now correctly unpack return values or forward results from other TupleReturn call * indentation fix
1 parent 62f50d0 commit 8e9dfe8

File tree

4 files changed

+63
-17
lines changed

4 files changed

+63
-17
lines changed

src/TSHelper.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,20 @@ export class TSHelper {
8282
}
8383
}
8484

85+
public static isInTupleReturnFunction(node: ts.Node, checker: ts.TypeChecker): boolean {
86+
const declaration = this.findFirstNodeAbove(node, (n): n is ts.Node =>
87+
ts.isFunctionDeclaration(n) || ts.isMethodDeclaration(n));
88+
if (declaration) {
89+
const decorators = this.getCustomDecorators(
90+
checker.getTypeAtLocation(declaration),
91+
checker
92+
);
93+
return decorators.has(DecoratorKind.TupleReturn);
94+
} else {
95+
return false;
96+
}
97+
}
98+
8599
public static getCustomDecorators(type: ts.Type, checker: ts.TypeChecker): Map<DecoratorKind, Decorator> {
86100
if (type.symbol) {
87101
const comments = type.symbol.getDocumentationComment(checker);

src/Transpiler.ts

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -685,20 +685,15 @@ export abstract class LuaTranspiler {
685685

686686
public transpileReturn(node: ts.ReturnStatement): string {
687687
if (node.expression) {
688-
// If parent function is a TupleReturn function
689-
// and return expression is an array literal, leave out brackets.
690-
const declaration = tsHelper.findFirstNodeAbove(node, (n): n is ts.Node =>
691-
ts.isFunctionDeclaration(n) || ts.isMethodDeclaration(n));
692-
let isTupleReturn = false;
693-
if (declaration) {
694-
const decorators = tsHelper.getCustomDecorators(
695-
this.checker.getTypeAtLocation(declaration),
696-
this.checker
697-
);
698-
isTupleReturn = decorators.has(DecoratorKind.TupleReturn);
699-
}
700-
if (isTupleReturn && ts.isArrayLiteralExpression(node.expression)) {
701-
return "return " + node.expression.elements.map(elem => this.transpileExpression(elem)).join(",");
688+
if (tsHelper.isInTupleReturnFunction(node, this.checker)) {
689+
// Parent function is a TupleReturn function
690+
if (ts.isArrayLiteralExpression(node.expression)) {
691+
// If return expression is an array literal, leave out brackets.
692+
return "return " + node.expression.elements.map(elem => this.transpileExpression(elem)).join(",");
693+
} else if (!tsHelper.isTupleReturnCall(node.expression, this.checker)) {
694+
// If return expression is not another TupleReturn call, unpack it
695+
return `return ${this.transpileDestructingAssignmentValue(node.expression)}`;
696+
}
702697
}
703698

704699
return "return " + this.transpileExpression(node.expression);
@@ -1085,12 +1080,15 @@ export abstract class LuaTranspiler {
10851080
let callPath;
10861081

10871082
const isTupleReturn = tsHelper.isTupleReturnCall(node, this.checker);
1083+
const isTupleReturnForward = node.parent && ts.isReturnStatement(node.parent)
1084+
&& tsHelper.isInTupleReturnFunction(node, this.checker);
10881085
const isInDestructingAssignment = tsHelper.isInDestructingAssignment(node);
10891086
const returnValueIsUsed = node.parent && !ts.isExpressionStatement(node.parent);
10901087

10911088
if (ts.isPropertyAccessExpression(node.expression)) {
10921089
const result = this.transpilePropertyCall(node);
1093-
return isTupleReturn && !isInDestructingAssignment && returnValueIsUsed ? `({ ${result} })` : result;
1090+
return isTupleReturn && !isTupleReturnForward && !isInDestructingAssignment && returnValueIsUsed
1091+
? `({ ${result} })` : result;
10941092
}
10951093

10961094
// Handle super calls properly
@@ -1102,7 +1100,7 @@ export abstract class LuaTranspiler {
11021100

11031101
callPath = this.transpileExpression(node.expression);
11041102
params = this.transpileArguments(node.arguments);
1105-
return isTupleReturn && !isInDestructingAssignment && returnValueIsUsed
1103+
return isTupleReturn && !isTupleReturnForward && !isInDestructingAssignment && returnValueIsUsed
11061104
? `({ ${callPath}(${params}) })` : `${callPath}(${params})`;
11071105
}
11081106

test/translation/lua/tupleReturn.lua

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
function tupleReturn()
2+
return 0,"foobar"
3+
end
14
tupleReturn();
25
noTupleReturn();
36
local a,b=tupleReturn();
@@ -10,3 +13,16 @@ e = ({ tupleReturn() });
1013
f = noTupleReturn();
1114
foo(({ tupleReturn() }));
1215
foo(noTupleReturn());
16+
function tupleReturnFromVar()
17+
local r = {1,"baz"};
18+
return table.unpack(r)
19+
end
20+
function tupleReturnForward()
21+
return tupleReturn()
22+
end
23+
function tupleNoForward()
24+
return ({ tupleReturn() })
25+
end
26+
function tupleReturnUnpack()
27+
return table.unpack(tupleNoForward())
28+
end

test/translation/ts/tupleReturn.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
/** !TupleReturn */
2-
declare function tupleReturn(): [number, string];
2+
function tupleReturn(): [number, string] {
3+
return [0, "foobar"];
4+
}
35
declare function noTupleReturn(): [number, string];
46
declare function foo(a: [number, string]): void;
57
tupleReturn();
@@ -14,3 +16,19 @@ e = tupleReturn();
1416
f = noTupleReturn();
1517
foo(tupleReturn());
1618
foo(noTupleReturn());
19+
/** !TupleReturn */
20+
function tupleReturnFromVar(): [number, string] {
21+
const r: [number, string] = [1, "baz"];
22+
return r;
23+
}
24+
/** !TupleReturn */
25+
function tupleReturnForward(): [number, string] {
26+
return tupleReturn();
27+
}
28+
function tupleNoForward(): [number, string] {
29+
return tupleReturn();
30+
}
31+
/** !TupleReturn */
32+
function tupleReturnUnpack(): [number, string] {
33+
return tupleNoForward();
34+
}

0 commit comments

Comments
 (0)