Skip to content

Commit a013476

Browse files
authored
Remove tupleReturn annotation (#1090)
* Remove tupleReturn annotation * Change places tuplereturn diagnostics are added
1 parent 3d1720f commit a013476

File tree

9 files changed

+81
-542
lines changed

9 files changed

+81
-542
lines changed

src/transformation/utils/annotations.ts

Lines changed: 1 addition & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import * as ts from "typescript";
22
import { TransformationContext } from "../context";
3-
import { annotationDeprecated } from "./diagnostics";
4-
import { findFirstNodeAbove, inferAssignedType } from "./typescript";
53

64
export enum AnnotationKind {
75
Extension = "extension",
@@ -118,7 +116,6 @@ export function isTupleReturnCall(context: TransformationContext, node: ts.Node)
118116
const signature = context.checker.getResolvedSignature(node);
119117
if (signature) {
120118
if (getSignatureAnnotations(context, signature).has(AnnotationKind.TupleReturn)) {
121-
context.diagnostics.push(annotationDeprecated(node, AnnotationKind.TupleReturn));
122119
return true;
123120
}
124121

@@ -134,44 +131,7 @@ export function isTupleReturnCall(context: TransformationContext, node: ts.Node)
134131
}
135132

136133
const type = context.checker.getTypeAtLocation(node.expression);
137-
const result = getTypeAnnotations(type).has(AnnotationKind.TupleReturn);
138-
139-
if (result) {
140-
context.diagnostics.push(annotationDeprecated(node, AnnotationKind.TupleReturn));
141-
}
142-
143-
return result;
144-
}
145-
146-
export function isInTupleReturnFunction(context: TransformationContext, node: ts.Node): boolean {
147-
const declaration = findFirstNodeAbove(node, ts.isFunctionLike);
148-
if (!declaration) {
149-
return false;
150-
}
151-
152-
let functionType: ts.Type | undefined;
153-
if (ts.isFunctionExpression(declaration) || ts.isArrowFunction(declaration)) {
154-
functionType = inferAssignedType(context, declaration);
155-
} else if (ts.isMethodDeclaration(declaration) && ts.isObjectLiteralExpression(declaration.parent)) {
156-
// Manually lookup type for object literal properties declared with method syntax
157-
const interfaceType = inferAssignedType(context, declaration.parent);
158-
const propertySymbol = interfaceType.getProperty(declaration.name.getText());
159-
if (propertySymbol) {
160-
functionType = context.checker.getTypeOfSymbolAtLocation(propertySymbol, declaration);
161-
}
162-
}
163-
164-
if (functionType === undefined) {
165-
functionType = context.checker.getTypeAtLocation(declaration);
166-
}
167-
168-
// Check all overloads for directive
169-
const signatures = functionType.getCallSignatures();
170-
if (signatures?.some(s => getSignatureAnnotations(context, s).has(AnnotationKind.TupleReturn))) {
171-
return true;
172-
}
173-
174-
return getTypeAnnotations(functionType).has(AnnotationKind.TupleReturn);
134+
return getTypeAnnotations(type).has(AnnotationKind.TupleReturn);
175135
}
176136

177137
export function isLuaIteratorType(context: TransformationContext, node: ts.Node): boolean {

src/transformation/visitors/call.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as ts from "typescript";
22
import * as lua from "../../LuaAST";
33
import { transformBuiltinCallExpression } from "../builtins";
44
import { FunctionVisitor, TransformationContext } from "../context";
5-
import { AnnotationKind, getTypeAnnotations } from "../utils/annotations";
5+
import { AnnotationKind, getTypeAnnotations, isTupleReturnCall } from "../utils/annotations";
66
import { validateAssignment } from "../utils/assignment-validation";
77
import { ContextType, getDeclarationContextType } from "../utils/function-context";
88
import { createUnpackCall, wrapInTable } from "../utils/lua-ast";
@@ -250,6 +250,10 @@ export const transformCallExpression: FunctionVisitor<ts.CallExpression> = (node
250250
return wrapResultInTable ? wrapInTable(builtinResult) : builtinResult;
251251
}
252252

253+
if (isTupleReturnCall(context, node)) {
254+
context.diagnostics.push(annotationRemoved(node, AnnotationKind.TupleReturn));
255+
}
256+
253257
if (isOperatorMapping(context, node)) {
254258
return transformOperatorMappingExpression(context, node);
255259
}

src/transformation/visitors/errors.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import * as ts from "typescript";
22
import * as lua from "../../LuaAST";
33
import { FunctionVisitor } from "../context";
4-
import { isInTupleReturnFunction } from "../utils/annotations";
54
import { createUnpackCall } from "../utils/lua-ast";
65
import { findScope, ScopeType } from "../utils/scope";
76
import { transformScopeBlock } from "./block";
@@ -89,7 +88,7 @@ export const transformTryStatement: FunctionVisitor<ts.TryStatement> = (statemen
8988
returnValues.push(lua.createBooleanLiteral(true));
9089
}
9190

92-
if (isInTupleReturnFunction(context, statement) || isInMultiReturnFunction(context, statement)) {
91+
if (isInMultiReturnFunction(context, statement)) {
9392
returnValues.push(createUnpackCall(context, lua.cloneIdentifier(returnValueIdentifier)));
9493
} else {
9594
returnValues.push(lua.cloneIdentifier(returnValueIdentifier));

src/transformation/visitors/function.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import * as ts from "typescript";
22
import * as lua from "../../LuaAST";
33
import { assert } from "../../utils";
44
import { FunctionVisitor, TransformationContext } from "../context";
5+
import { AnnotationKind, getNodeAnnotations } from "../utils/annotations";
6+
import { annotationRemoved } from "../utils/diagnostics";
57
import { createDefaultExportStringLiteral, hasDefaultExportModifier } from "../utils/export";
68
import { ContextType, getFunctionContextType } from "../utils/function-context";
79
import {
@@ -225,6 +227,10 @@ export function transformFunctionLikeDeclaration(
225227
return lua.createNilLiteral();
226228
}
227229

230+
if (getNodeAnnotations(node).has(AnnotationKind.TupleReturn)) {
231+
context.diagnostics.push(annotationRemoved(node, AnnotationKind.TupleReturn));
232+
}
233+
228234
const [functionExpression, functionScope] = transformFunctionToExpression(context, node);
229235

230236
// Handle named function expressions which reference themselves
@@ -255,6 +261,10 @@ export function transformFunctionLikeDeclaration(
255261
}
256262

257263
export const transformFunctionDeclaration: FunctionVisitor<ts.FunctionDeclaration> = (node, context) => {
264+
if (getNodeAnnotations(node).has(AnnotationKind.TupleReturn)) {
265+
context.diagnostics.push(annotationRemoved(node, AnnotationKind.TupleReturn));
266+
}
267+
258268
// Don't transform functions without body (overload declarations)
259269
if (node.body === undefined) {
260270
return undefined;

src/transformation/visitors/language-extensions/multi.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { TransformationContext } from "../../context";
44
import { findFirstNodeAbove } from "../../utils/typescript";
55
import { isIterableExpression } from "./iterable";
66
import { invalidMultiFunctionUse } from "../../utils/diagnostics";
7-
import { isTupleReturnCall } from "../../utils/annotations";
87

98
export function isMultiReturnType(type: ts.Type): boolean {
109
return extensions.isExtensionType(type, extensions.ExtensionKind.MultiType);
@@ -25,10 +24,7 @@ export function returnsMultiType(context: TransformationContext, node: ts.CallEx
2524
}
2625

2726
export function isMultiReturnCall(context: TransformationContext, expression: ts.Expression) {
28-
return (
29-
(ts.isCallExpression(expression) && returnsMultiType(context, expression)) ||
30-
isTupleReturnCall(context, expression)
31-
);
27+
return ts.isCallExpression(expression) && returnsMultiType(context, expression);
3228
}
3329

3430
export function isMultiFunctionNode(context: TransformationContext, node: ts.Node): boolean {
@@ -47,7 +43,7 @@ export function isInMultiReturnFunction(context: TransformationContext, node: ts
4743
}
4844

4945
export function shouldMultiReturnCallBeWrapped(context: TransformationContext, node: ts.CallExpression) {
50-
if (!returnsMultiType(context, node) && !isTupleReturnCall(context, node)) {
46+
if (!returnsMultiType(context, node)) {
5147
return false;
5248
}
5349

src/transformation/visitors/return.ts

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
11
import * as ts from "typescript";
22
import * as lua from "../../LuaAST";
33
import { FunctionVisitor, TransformationContext } from "../context";
4-
import { isInTupleReturnFunction } from "../utils/annotations";
54
import { validateAssignment } from "../utils/assignment-validation";
65
import { createUnpackCall, wrapInTable } from "../utils/lua-ast";
76
import { ScopeType, walkScopesUp } from "../utils/scope";
8-
import { isArrayType } from "../utils/typescript";
97
import { transformArguments } from "./call";
108
import {
119
returnsMultiType,
1210
shouldMultiReturnCallBeWrapped,
1311
isMultiFunctionCall,
1412
isMultiReturnType,
1513
isInMultiReturnFunction,
16-
isMultiReturnCall,
1714
canBeMultiReturnType,
1815
} from "./language-extensions/multi";
1916
import { invalidMultiFunctionReturnType } from "../utils/diagnostics";
@@ -50,29 +47,7 @@ function transformExpressionsInReturn(
5047
return [createUnpackCall(context, context.transformExpression(node), node)];
5148
}
5249

53-
if (!isInTupleReturnFunction(context, node)) {
54-
return [context.transformExpression(node)];
55-
}
56-
57-
let results: lua.Expression[];
58-
59-
// Parent function is a TupleReturn function
60-
if (ts.isArrayLiteralExpression(node)) {
61-
// If return expression is an array literal, leave out brackets.
62-
results = node.elements.map(e => context.transformExpression(e));
63-
} else if (!isMultiReturnCall(context, node) && isArrayType(context, expressionType)) {
64-
// If return expression is an array-type and not another TupleReturn call, unpack it
65-
results = [createUnpackCall(context, context.transformExpression(node), node)];
66-
} else {
67-
results = [context.transformExpression(node)];
68-
}
69-
70-
// Wrap tupleReturn results when returning inside try/catch
71-
if (insideTryCatch) {
72-
results = [wrapInTable(...results)];
73-
}
74-
75-
return results;
50+
return [context.transformExpression(node)];
7651
}
7752

7853
export function transformExpressionBodyToReturnStatement(

test/unit/annotations/__snapshots__/deprecated.spec.ts.snap

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,46 @@ __TS__ClassExtends(ClassB, ClassA)"
9898

9999
exports[`pureAbstract removed: diagnostics 1`] = `"main.ts(4,22): error TSTL: '@pureAbstract' has been removed and will no longer have any effect.See https://typescripttolua.github.io/docs/advanced/compiler-annotations#pureabstract for more information."`;
100100

101+
exports[`tuplereturn lambda: code 1`] = `
102+
"local ____exports = {}
103+
function ____exports.__main(self)
104+
local function f()
105+
return {3, 4}
106+
end
107+
end
108+
return ____exports"
109+
`;
110+
111+
exports[`tuplereturn lambda: diagnostics 1`] = `"main.ts(2,39): error TSTL: '@tupleReturn' has been removed and will no longer have any effect.See https://typescripttolua.github.io/docs/advanced/compiler-annotations#tuplereturn for more information."`;
112+
113+
exports[`tuplereturn removed on function declaration: code 1`] = `
114+
"local ____exports = {}
115+
function ____exports.__main(self)
116+
local function tuple(self)
117+
return {3, 5, 1}
118+
end
119+
end
120+
return ____exports"
121+
`;
122+
123+
exports[`tuplereturn removed on function declaration: diagnostics 1`] = `"main.ts(3,9): error TSTL: '@tupleReturn' has been removed and will no longer have any effect.See https://typescripttolua.github.io/docs/advanced/compiler-annotations#tuplereturn for more information."`;
124+
125+
exports[`tuplereturn removed: code 1`] = `
126+
"local ____exports = {}
127+
function ____exports.__main(self)
128+
local function tuple(self)
129+
return {3, 5, 1}
130+
end
131+
return tuple(nil)[3]
132+
end
133+
return ____exports"
134+
`;
135+
136+
exports[`tuplereturn removed: diagnostics 1`] = `
137+
"main.ts(3,9): error TSTL: '@tupleReturn' has been removed and will no longer have any effect.See https://typescripttolua.github.io/docs/advanced/compiler-annotations#tuplereturn for more information.
138+
main.ts(4,16): error TSTL: '@tupleReturn' has been removed and will no longer have any effect.See https://typescripttolua.github.io/docs/advanced/compiler-annotations#tuplereturn for more information."
139+
`;
140+
101141
exports[`vararg removed: code 1`] = `
102142
"function foo(self, ...)
103143
end

test/unit/annotations/deprecated.spec.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,27 @@ test("luaiterator removed", () => {
6060
`.expectDiagnosticsToMatchSnapshot([annotationRemoved.code]);
6161
});
6262

63+
test("tuplereturn removed", () => {
64+
util.testFunction`
65+
/** @tupleReturn */
66+
function tuple(): [number, number, number] { return [3, 5, 1]; }
67+
return tuple()[2];
68+
`.expectDiagnosticsToMatchSnapshot([annotationRemoved.code, annotationRemoved.code]); // One annotation on the function, one on the call
69+
});
70+
71+
test("tuplereturn removed on function declaration", () => {
72+
util.testFunction`
73+
/** @tupleReturn */
74+
function tuple(): [number, number, number] { return [3, 5, 1]; }
75+
`.expectDiagnosticsToMatchSnapshot([annotationRemoved.code]);
76+
});
77+
78+
test("tuplereturn lambda", () => {
79+
util.testFunction`
80+
const f = /** @tupleReturn */ () => [3, 4];
81+
`.expectDiagnosticsToMatchSnapshot([annotationRemoved.code]);
82+
});
83+
6384
const tableLibClass = `
6485
/** @luaTable */
6586
declare class Table<K extends {} = {}, V = any> {

0 commit comments

Comments
 (0)