Skip to content

Commit 63f5568

Browse files
tomblindPerryvw
authored andcommitted
Fixed @tupleReturn on interface function properties (#582)
* Fixed @tupleReturn on interface function properties Also fixed detection of @tupleReturn on object literal methods/function-properties that are assigned to interaces. * unpack checks in tuple tests, destructuring array literals doesn't pack+unpack anymore, and addressed feedback * revised destructuring array literals so right side is always evaluated
1 parent 9faa80d commit 63f5568

File tree

3 files changed

+185
-24
lines changed

3 files changed

+185
-24
lines changed

src/LuaTransformer.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1882,16 +1882,28 @@ export class LuaTransformer {
18821882
tstl.isIdentifier)
18831883
: tstl.createAnonymousIdentifier(statement.name);
18841884

1885-
// Don't unpack TupleReturn decorated functions
18861885
if (statement.initializer) {
18871886
if (tsHelper.isTupleReturnCall(statement.initializer, this.checker)) {
1887+
// Don't unpack TupleReturn decorated functions
18881888
statements.push(
18891889
...this.createLocalOrExportedOrGlobalDeclaration(
18901890
vars,
18911891
this.transformExpression(statement.initializer),
18921892
statement
18931893
)
18941894
);
1895+
} else if (ts.isArrayLiteralExpression(statement.initializer)) {
1896+
// Don't unpack array literals
1897+
const values = statement.initializer.elements.length > 0
1898+
? statement.initializer.elements.map(e => this.transformExpression(e))
1899+
: tstl.createNilLiteral();
1900+
statements.push(
1901+
...this.createLocalOrExportedOrGlobalDeclaration(
1902+
vars,
1903+
values,
1904+
statement
1905+
)
1906+
);
18951907
} else {
18961908
// local vars = this.transpileDestructingAssignmentValue(node.initializer);
18971909
const initializer = this.createUnpackCall(
@@ -4873,7 +4885,7 @@ export class LuaTransformer {
48734885

48744886
protected createLocalOrExportedOrGlobalDeclaration(
48754887
lhs: tstl.Identifier | tstl.Identifier[],
4876-
rhs?: tstl.Expression,
4888+
rhs?: tstl.Expression | tstl.Expression[],
48774889
tsOriginal?: ts.Node,
48784890
parent?: tstl.Node
48794891
): tstl.Statement[]

src/TSHelper.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,10 +183,18 @@ export class TSHelper {
183183
public static isInTupleReturnFunction(node: ts.Node, checker: ts.TypeChecker): boolean {
184184
const declaration = TSHelper.findFirstNodeAbove(node, ts.isFunctionLike);
185185
if (declaration) {
186-
let functionType: ts.Type;
186+
let functionType: ts.Type | undefined;
187187
if (ts.isFunctionExpression(declaration) || ts.isArrowFunction(declaration)) {
188188
functionType = TSHelper.inferAssignedType(declaration, checker);
189-
} else {
189+
} else if (ts.isMethodDeclaration(declaration) && ts.isObjectLiteralExpression(declaration.parent)) {
190+
// Manually lookup type for object literal properties declared with method syntax
191+
const interfaceType = TSHelper.inferAssignedType(declaration.parent, checker);
192+
const propertySymbol = interfaceType.getProperty(declaration.name.getText());
193+
if (propertySymbol) {
194+
functionType = checker.getTypeOfSymbolAtLocation(propertySymbol, declaration);
195+
}
196+
}
197+
if (functionType === undefined) {
190198
functionType = checker.getTypeAtLocation(declaration);
191199
}
192200

@@ -279,6 +287,16 @@ export class TSHelper {
279287
{
280288
const directivesMap = new Map<DecoratorKind, Decorator>();
281289
TSHelper.collectCustomDecorators(signature, checker, directivesMap);
290+
291+
// Function properties on interfaces have the JSDoc tags on the parent PropertySignature
292+
const declaration = signature.getDeclaration();
293+
if (declaration && declaration.parent && ts.isPropertySignature(declaration.parent)) {
294+
const symbol = checker.getSymbolAtLocation(declaration.parent.name);
295+
if (symbol) {
296+
TSHelper.collectCustomDecorators(symbol, checker, directivesMap);
297+
}
298+
}
299+
282300
return directivesMap;
283301
}
284302

test/unit/tuples.spec.ts

Lines changed: 151 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,30 @@ test("Tuple Destruct", () => {
6464
expect(result).toBe(5);
6565
});
6666

67+
test("Tuple Destruct Array Literal", () => {
68+
const code = `
69+
const [a,b,c] = [3,5,1];
70+
return b;`;
71+
72+
const lua = util.transpileString(code);
73+
expect(lua).not.toContain("unpack");
74+
const result = util.executeLua(lua);
75+
expect(result).toBe(5);
76+
});
77+
78+
test("Tuple Destruct Array Literal Extra Values", () => {
79+
const code = `
80+
let result = "";
81+
const set = () => { result = "bar"; };
82+
const [a] = ["foo", set()];
83+
return a + result;`;
84+
85+
const lua = util.transpileString(code);
86+
expect(lua).not.toContain("unpack");
87+
const result = util.executeLua(lua);
88+
expect(result).toBe("foobar");
89+
});
90+
6791
test("Tuple length", () => {
6892
const result = util.transpileAndExecute(
6993
`const tuple: [number, number, number] = [3,5,1];
@@ -74,62 +98,169 @@ test("Tuple length", () => {
7498
});
7599

76100
test("Tuple Return Access", () => {
77-
const result = util.transpileAndExecute(
78-
`/** @tupleReturn */
101+
const code = `
102+
/** @tupleReturn */
79103
function tuple(): [number, number, number] { return [3,5,1]; }
80-
return tuple()[2];`,
81-
);
104+
return tuple()[2];`;
82105

106+
const lua = util.transpileString(code);
107+
expect(lua).not.toContain("unpack");
108+
const result = util.executeLua(lua);
83109
expect(result).toBe(1);
84110
});
85111

86112
test("Tuple Return Destruct Declaration", () => {
87-
const result = util.transpileAndExecute(
88-
`/** @tupleReturn */
113+
const code = `
114+
/** @tupleReturn */
89115
function tuple(): [number, number, number] { return [3,5,1]; }
90116
const [a,b,c] = tuple();
91-
return b;`,
92-
);
117+
return b;`;
93118

119+
const lua = util.transpileString(code);
120+
expect(lua).not.toContain("unpack");
121+
const result = util.executeLua(lua);
94122
expect(result).toBe(5);
95123
});
96124

97125
test("Tuple Return Destruct Assignment", () => {
98-
const result = util.transpileAndExecute(
99-
`/** @tupleReturn */
126+
const code = `
127+
/** @tupleReturn */
100128
function tuple(): [number, number] { return [3,6]; }
101129
let [a,b] = [1,2];
102130
[b,a] = tuple();
103-
return a - b;`,
104-
);
131+
return a - b;`;
105132

133+
const lua = util.transpileString(code);
134+
expect(lua).not.toContain("unpack");
135+
const result = util.executeLua(lua);
106136
expect(result).toBe(3);
107137
});
108138

109139
test("Tuple Static Method Return Destruct", () => {
110-
const result = util.transpileAndExecute(
111-
`class Test {
140+
const code = `
141+
class Test {
112142
/** @tupleReturn */
113143
static tuple(): [number, number, number] { return [3,5,1]; }
114144
}
115145
const [a,b,c] = Test.tuple();
116-
return b;`,
117-
);
146+
return b;`;
147+
148+
const lua = util.transpileString(code);
149+
expect(lua).not.toContain("unpack");
150+
const result = util.executeLua(lua);
151+
expect(result).toBe(5);
152+
});
153+
154+
test("Tuple Static Function Property Return Destruct", () => {
155+
const code = `
156+
class Test {
157+
/** @tupleReturn */
158+
static tuple: () => [number, number, number] = () => [3,5,1];
159+
}
160+
const [a,b,c] = Test.tuple();
161+
return b;`;
118162

163+
const lua = util.transpileString(code);
164+
expect(lua).not.toContain("unpack");
165+
const result = util.executeLua(lua);
119166
expect(result).toBe(5);
120167
});
121168

122169
test("Tuple Non-Static Method Return Destruct", () => {
123-
const result = util.transpileAndExecute(
124-
`class Test {
170+
const code = `
171+
class Test {
125172
/** @tupleReturn */
126173
tuple(): [number, number, number] { return [3,5,1]; }
127174
}
128175
const t = new Test();
129176
const [a,b,c] = t.tuple();
130-
return b;`,
131-
);
177+
return b;`;
132178

179+
const lua = util.transpileString(code);
180+
expect(lua).not.toContain("unpack");
181+
const result = util.executeLua(lua);
182+
expect(result).toBe(5);
183+
});
184+
185+
test("Tuple Non-Static Function Property Return Destruct", () => {
186+
const code = `
187+
class Test {
188+
/** @tupleReturn */
189+
tuple: () => [number, number, number] = () => [3,5,1];
190+
}
191+
const t = new Test();
192+
const [a,b,c] = t.tuple();
193+
return b;`;
194+
195+
const lua = util.transpileString(code);
196+
expect(lua).not.toContain("unpack");
197+
const result = util.executeLua(lua);
198+
expect(result).toBe(5);
199+
});
200+
201+
test("Tuple Interface Method Return Destruct", () => {
202+
const code = `
203+
interface Test {
204+
/** @tupleReturn */
205+
tuple(): [number, number, number];
206+
}
207+
const t: Test = {
208+
tuple() { return [3,5,1]; }
209+
};
210+
const [a,b,c] = t.tuple();
211+
return b;`;
212+
213+
const lua = util.transpileString(code);
214+
expect(lua).not.toContain("unpack");
215+
const result = util.executeLua(lua);
216+
expect(result).toBe(5);
217+
});
218+
219+
test("Tuple Interface Function Property Return Destruct", () => {
220+
const code = `
221+
interface Test {
222+
/** @tupleReturn */
223+
tuple: () => [number, number, number];
224+
}
225+
const t: Test = {
226+
tuple: () => [3,5,1]
227+
};
228+
const [a,b,c] = t.tuple();
229+
return b;`;
230+
231+
const lua = util.transpileString(code);
232+
expect(lua).not.toContain("unpack");
233+
const result = util.executeLua(lua);
234+
expect(result).toBe(5);
235+
});
236+
237+
test("Tuple Object Literal Method Return Destruct", () => {
238+
const code = `
239+
const t = {
240+
/** @tupleReturn */
241+
tuple() { return [3,5,1]; }
242+
};
243+
const [a,b,c] = t.tuple();
244+
return b;`;
245+
246+
const lua = util.transpileString(code);
247+
expect(lua).not.toContain("unpack");
248+
const result = util.executeLua(lua);
249+
expect(result).toBe(5);
250+
});
251+
252+
test("Tuple Object Literal Function Property Return Destruct", () => {
253+
const code = `
254+
const t = {
255+
/** @tupleReturn */
256+
tuple: () => [3,5,1]
257+
};
258+
const [a,b,c] = t.tuple();
259+
return b;`;
260+
261+
const lua = util.transpileString(code);
262+
expect(lua).not.toContain("unpack");
263+
const result = util.executeLua(lua);
133264
expect(result).toBe(5);
134265
});
135266

0 commit comments

Comments
 (0)