diff --git a/src/transformation/utils/annotations.ts b/src/transformation/utils/annotations.ts index a64b13788..7f7b19652 100644 --- a/src/transformation/utils/annotations.ts +++ b/src/transformation/utils/annotations.ts @@ -1,7 +1,5 @@ import * as ts from "typescript"; import { TransformationContext } from "../context"; -import { annotationDeprecated } from "./diagnostics"; -import { findFirstNodeAbove, inferAssignedType } from "./typescript"; export enum AnnotationKind { Extension = "extension", @@ -118,7 +116,6 @@ export function isTupleReturnCall(context: TransformationContext, node: ts.Node) const signature = context.checker.getResolvedSignature(node); if (signature) { if (getSignatureAnnotations(context, signature).has(AnnotationKind.TupleReturn)) { - context.diagnostics.push(annotationDeprecated(node, AnnotationKind.TupleReturn)); return true; } @@ -134,44 +131,7 @@ export function isTupleReturnCall(context: TransformationContext, node: ts.Node) } const type = context.checker.getTypeAtLocation(node.expression); - const result = getTypeAnnotations(type).has(AnnotationKind.TupleReturn); - - if (result) { - context.diagnostics.push(annotationDeprecated(node, AnnotationKind.TupleReturn)); - } - - return result; -} - -export function isInTupleReturnFunction(context: TransformationContext, node: ts.Node): boolean { - const declaration = findFirstNodeAbove(node, ts.isFunctionLike); - if (!declaration) { - return false; - } - - let functionType: ts.Type | undefined; - if (ts.isFunctionExpression(declaration) || ts.isArrowFunction(declaration)) { - functionType = inferAssignedType(context, declaration); - } else if (ts.isMethodDeclaration(declaration) && ts.isObjectLiteralExpression(declaration.parent)) { - // Manually lookup type for object literal properties declared with method syntax - const interfaceType = inferAssignedType(context, declaration.parent); - const propertySymbol = interfaceType.getProperty(declaration.name.getText()); - if (propertySymbol) { - functionType = context.checker.getTypeOfSymbolAtLocation(propertySymbol, declaration); - } - } - - if (functionType === undefined) { - functionType = context.checker.getTypeAtLocation(declaration); - } - - // Check all overloads for directive - const signatures = functionType.getCallSignatures(); - if (signatures?.some(s => getSignatureAnnotations(context, s).has(AnnotationKind.TupleReturn))) { - return true; - } - - return getTypeAnnotations(functionType).has(AnnotationKind.TupleReturn); + return getTypeAnnotations(type).has(AnnotationKind.TupleReturn); } export function isLuaIteratorType(context: TransformationContext, node: ts.Node): boolean { diff --git a/src/transformation/visitors/call.ts b/src/transformation/visitors/call.ts index 7add12ddc..e446675df 100644 --- a/src/transformation/visitors/call.ts +++ b/src/transformation/visitors/call.ts @@ -2,7 +2,7 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; import { transformBuiltinCallExpression } from "../builtins"; import { FunctionVisitor, TransformationContext } from "../context"; -import { AnnotationKind, getTypeAnnotations } from "../utils/annotations"; +import { AnnotationKind, getTypeAnnotations, isTupleReturnCall } from "../utils/annotations"; import { validateAssignment } from "../utils/assignment-validation"; import { ContextType, getDeclarationContextType } from "../utils/function-context"; import { createUnpackCall, wrapInTable } from "../utils/lua-ast"; @@ -249,6 +249,10 @@ export const transformCallExpression: FunctionVisitor = (node return wrapResultInTable ? wrapInTable(builtinResult) : builtinResult; } + if (isTupleReturnCall(context, node)) { + context.diagnostics.push(annotationRemoved(node, AnnotationKind.TupleReturn)); + } + if (isOperatorMapping(context, node)) { return transformOperatorMappingExpression(context, node); } diff --git a/src/transformation/visitors/errors.ts b/src/transformation/visitors/errors.ts index e05ed55f3..0f067c939 100644 --- a/src/transformation/visitors/errors.ts +++ b/src/transformation/visitors/errors.ts @@ -1,7 +1,6 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; import { FunctionVisitor } from "../context"; -import { isInTupleReturnFunction } from "../utils/annotations"; import { createUnpackCall } from "../utils/lua-ast"; import { findScope, ScopeType } from "../utils/scope"; import { transformScopeBlock } from "./block"; @@ -89,7 +88,7 @@ export const transformTryStatement: FunctionVisitor = (statemen returnValues.push(lua.createBooleanLiteral(true)); } - if (isInTupleReturnFunction(context, statement) || isInMultiReturnFunction(context, statement)) { + if (isInMultiReturnFunction(context, statement)) { returnValues.push(createUnpackCall(context, lua.cloneIdentifier(returnValueIdentifier))); } else { returnValues.push(lua.cloneIdentifier(returnValueIdentifier)); diff --git a/src/transformation/visitors/function.ts b/src/transformation/visitors/function.ts index cb1d29bfd..4afe816f3 100644 --- a/src/transformation/visitors/function.ts +++ b/src/transformation/visitors/function.ts @@ -2,6 +2,8 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; import { assert } from "../../utils"; import { FunctionVisitor, TransformationContext } from "../context"; +import { AnnotationKind, getNodeAnnotations } from "../utils/annotations"; +import { annotationRemoved } from "../utils/diagnostics"; import { createDefaultExportStringLiteral, hasDefaultExportModifier } from "../utils/export"; import { ContextType, getFunctionContextType } from "../utils/function-context"; import { @@ -220,6 +222,10 @@ export function transformFunctionLikeDeclaration( return lua.createNilLiteral(); } + if (getNodeAnnotations(node).has(AnnotationKind.TupleReturn)) { + context.diagnostics.push(annotationRemoved(node, AnnotationKind.TupleReturn)); + } + const [functionExpression, functionScope] = transformFunctionToExpression(context, node); // Handle named function expressions which reference themselves @@ -250,6 +256,10 @@ export function transformFunctionLikeDeclaration( } export const transformFunctionDeclaration: FunctionVisitor = (node, context) => { + if (getNodeAnnotations(node).has(AnnotationKind.TupleReturn)) { + context.diagnostics.push(annotationRemoved(node, AnnotationKind.TupleReturn)); + } + // Don't transform functions without body (overload declarations) if (node.body === undefined) { return undefined; diff --git a/src/transformation/visitors/language-extensions/multi.ts b/src/transformation/visitors/language-extensions/multi.ts index edf3a1650..a1c9c4030 100644 --- a/src/transformation/visitors/language-extensions/multi.ts +++ b/src/transformation/visitors/language-extensions/multi.ts @@ -4,7 +4,6 @@ import { TransformationContext } from "../../context"; import { findFirstNodeAbove } from "../../utils/typescript"; import { isIterableExpression } from "./iterable"; import { invalidMultiFunctionUse } from "../../utils/diagnostics"; -import { isTupleReturnCall } from "../../utils/annotations"; export function isMultiReturnType(type: ts.Type): boolean { return extensions.isExtensionType(type, extensions.ExtensionKind.MultiType); @@ -25,10 +24,7 @@ export function returnsMultiType(context: TransformationContext, node: ts.CallEx } export function isMultiReturnCall(context: TransformationContext, expression: ts.Expression) { - return ( - (ts.isCallExpression(expression) && returnsMultiType(context, expression)) || - isTupleReturnCall(context, expression) - ); + return ts.isCallExpression(expression) && returnsMultiType(context, expression); } export function isMultiFunctionNode(context: TransformationContext, node: ts.Node): boolean { @@ -47,7 +43,7 @@ export function isInMultiReturnFunction(context: TransformationContext, node: ts } export function shouldMultiReturnCallBeWrapped(context: TransformationContext, node: ts.CallExpression) { - if (!returnsMultiType(context, node) && !isTupleReturnCall(context, node)) { + if (!returnsMultiType(context, node)) { return false; } diff --git a/src/transformation/visitors/return.ts b/src/transformation/visitors/return.ts index a3eff9ec7..2ed0ebe3e 100644 --- a/src/transformation/visitors/return.ts +++ b/src/transformation/visitors/return.ts @@ -1,11 +1,9 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; import { FunctionVisitor, TransformationContext } from "../context"; -import { isInTupleReturnFunction } from "../utils/annotations"; import { validateAssignment } from "../utils/assignment-validation"; import { createUnpackCall, wrapInTable } from "../utils/lua-ast"; import { ScopeType, walkScopesUp } from "../utils/scope"; -import { isArrayType } from "../utils/typescript"; import { transformArguments } from "./call"; import { returnsMultiType, @@ -13,7 +11,6 @@ import { isMultiFunctionCall, isMultiReturnType, isInMultiReturnFunction, - isMultiReturnCall, canBeMultiReturnType, } from "./language-extensions/multi"; import { invalidMultiFunctionReturnType } from "../utils/diagnostics"; @@ -50,29 +47,7 @@ function transformExpressionsInReturn( return [createUnpackCall(context, context.transformExpression(node), node)]; } - if (!isInTupleReturnFunction(context, node)) { - return [context.transformExpression(node)]; - } - - let results: lua.Expression[]; - - // Parent function is a TupleReturn function - if (ts.isArrayLiteralExpression(node)) { - // If return expression is an array literal, leave out brackets. - results = node.elements.map(e => context.transformExpression(e)); - } else if (!isMultiReturnCall(context, node) && isArrayType(context, expressionType)) { - // If return expression is an array-type and not another TupleReturn call, unpack it - results = [createUnpackCall(context, context.transformExpression(node), node)]; - } else { - results = [context.transformExpression(node)]; - } - - // Wrap tupleReturn results when returning inside try/catch - if (insideTryCatch) { - results = [wrapInTable(...results)]; - } - - return results; + return [context.transformExpression(node)]; } export function transformExpressionBodyToReturnStatement( diff --git a/test/unit/annotations/__snapshots__/deprecated.spec.ts.snap b/test/unit/annotations/__snapshots__/deprecated.spec.ts.snap index d612bc478..6dacea3ad 100644 --- a/test/unit/annotations/__snapshots__/deprecated.spec.ts.snap +++ b/test/unit/annotations/__snapshots__/deprecated.spec.ts.snap @@ -98,6 +98,46 @@ __TS__ClassExtends(ClassB, ClassA)" 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."`; +exports[`tuplereturn lambda: code 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local function f() + return {3, 4} + end +end +return ____exports" +`; + +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."`; + +exports[`tuplereturn removed on function declaration: code 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local function tuple(self) + return {3, 5, 1} + end +end +return ____exports" +`; + +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."`; + +exports[`tuplereturn removed: code 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local function tuple(self) + return {3, 5, 1} + end + return tuple(nil)[3] +end +return ____exports" +`; + +exports[`tuplereturn removed: 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. +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." +`; + exports[`vararg removed: code 1`] = ` "function foo(self, ...) end diff --git a/test/unit/annotations/deprecated.spec.ts b/test/unit/annotations/deprecated.spec.ts index 2f0edb105..f7f0ac9b1 100644 --- a/test/unit/annotations/deprecated.spec.ts +++ b/test/unit/annotations/deprecated.spec.ts @@ -60,6 +60,27 @@ test("luaiterator removed", () => { `.expectDiagnosticsToMatchSnapshot([annotationRemoved.code]); }); +test("tuplereturn removed", () => { + util.testFunction` + /** @tupleReturn */ + function tuple(): [number, number, number] { return [3, 5, 1]; } + return tuple()[2]; + `.expectDiagnosticsToMatchSnapshot([annotationRemoved.code, annotationRemoved.code]); // One annotation on the function, one on the call +}); + +test("tuplereturn removed on function declaration", () => { + util.testFunction` + /** @tupleReturn */ + function tuple(): [number, number, number] { return [3, 5, 1]; } + `.expectDiagnosticsToMatchSnapshot([annotationRemoved.code]); +}); + +test("tuplereturn lambda", () => { + util.testFunction` + const f = /** @tupleReturn */ () => [3, 4]; + `.expectDiagnosticsToMatchSnapshot([annotationRemoved.code]); +}); + const tableLibClass = ` /** @luaTable */ declare class Table { diff --git a/test/unit/annotations/tupleReturn.spec.ts b/test/unit/annotations/tupleReturn.spec.ts deleted file mode 100644 index c5077a744..000000000 --- a/test/unit/annotations/tupleReturn.spec.ts +++ /dev/null @@ -1,466 +0,0 @@ -import { annotationDeprecated } from "../../../src/transformation/utils/diagnostics"; -import * as util from "../../util"; - -const expectNoUnpack: util.TapCallback = builder => expect(builder.getMainLuaCodeChunk()).not.toContain("unpack"); - -test("Tuple Return Access", () => { - util.testFunction` - /** @tupleReturn */ - function tuple(): [number, number, number] { return [3, 5, 1]; } - return tuple()[2]; - ` - .tap(expectNoUnpack) - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("Tuple Return Destruct Declaration", () => { - util.testFunction` - /** @tupleReturn */ - function tuple(): [number, number, number] { return [3,5,1]; } - const [,b,c] = tuple(); - return b; - ` - .tap(expectNoUnpack) - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("Tuple Return Destruct Assignment", () => { - util.testFunction` - /** @tupleReturn */ - function tuple(): [number, number] { return [3,6]; } - let [a,b] = [1,2]; - [b,a] = tuple(); - return a - b; - ` - .tap(expectNoUnpack) - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("Tuple Static Method Return Destruct", () => { - util.testFunction` - class Test { - /** @tupleReturn */ - static tuple(): [number, number, number] { return [3,5,1]; } - } - const [a,b,c] = Test.tuple(); - return b; - ` - .tap(expectNoUnpack) - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("Tuple Static Function Property Return Destruct", () => { - util.testFunction` - class Test { - /** @tupleReturn */ - static tuple: () => [number, number, number] = () => [3,5,1]; - } - const [a,b,c] = Test.tuple(); - return b; - ` - .tap(expectNoUnpack) - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("Tuple Non-Static Method Return Destruct", () => { - util.testFunction` - class Test { - /** @tupleReturn */ - tuple(): [number, number, number] { return [3,5,1]; } - } - const t = new Test(); - const [a,b,c] = t.tuple(); - return b; - ` - .tap(expectNoUnpack) - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("Tuple Non-Static Function Property Return Destruct", () => { - util.testFunction` - class Test { - /** @tupleReturn */ - tuple: () => [number, number, number] = () => [3,5,1]; - } - const t = new Test(); - const [a,b,c] = t.tuple(); - return b; - ` - .tap(expectNoUnpack) - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("Tuple Interface Method Return Destruct", () => { - util.testFunction` - interface Test { - /** @tupleReturn */ - tuple(): [number, number, number]; - } - const t: Test = { - tuple() { return [3,5,1]; } - }; - const [a,b,c] = t.tuple(); - return b; - ` - .tap(expectNoUnpack) - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("Tuple Interface Function Property Return Destruct", () => { - util.testFunction` - interface Test { - /** @tupleReturn */ - tuple: () => [number, number, number]; - } - const t: Test = { - tuple: () => [3,5,1] - }; - const [a,b,c] = t.tuple(); - return b; - ` - .tap(expectNoUnpack) - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("Tuple Object Literal Method Return Destruct", () => { - util.testFunction` - const t = { - /** @tupleReturn */ - tuple() { return [3,5,1]; } - }; - const [a,b,c] = t.tuple(); - return b; - ` - .tap(expectNoUnpack) - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("Tuple Object Literal Function Property Return Destruct", () => { - util.testFunction` - const t = { - /** @tupleReturn */ - tuple: () => [3,5,1] - }; - const [a,b,c] = t.tuple(); - return b; - ` - .tap(expectNoUnpack) - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("Tuple Return on Arrow Function", () => { - util.testFunction` - const fn = /** @tupleReturn */ (s: string) => [s, "bar"]; - const [a, b] = fn("foo"); - return a + b; - ` - .tap(expectNoUnpack) - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("Tuple Return Inference", () => { - util.testFunction` - /** @tupleReturn */ interface Fn { (s: string): [string, string] } - const fn: Fn = s => [s, "bar"]; - const [a, b] = fn("foo"); - return a + b; - ` - .tap(expectNoUnpack) - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("Tuple Return Inference as Argument", () => { - util.testFunction` - /** @tupleReturn */ interface Fn { (s: string): [string, string] } - function foo(fn: Fn) { - const [a, b] = fn("foo"); - return a + b; - } - return foo(s => [s, "bar"]); - ` - .tap(expectNoUnpack) - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("Tuple Return Inference as Elipsis Argument", () => { - util.testFunction` - /** @tupleReturn */ interface Fn { (s: string): [string, string] } - function foo(_: number, ...fn: Fn[]) { - const [a, b] = fn[0]("foo"); - return a + b; - } - return foo(0, s => [s, "bar"]); - ` - .tap(expectNoUnpack) - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("Tuple Return Inference as Elipsis Tuple Argument", () => { - util.testFunction` - /** @tupleReturn */ interface Fn { (s: string): [string, string] } - function foo(_: number, ...fn: [number, Fn]) { - const [a, b] = fn[1]("foo"); - return a + b; - } - return foo(0, 0, s => [s, "bar"]); - ` - .tap(expectNoUnpack) - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("Tuple Return in Spread", () => { - util.testFunction` - /** @tupleReturn */ function foo(): [string, string] { - return ["foo", "bar"]; - } - function bar(a: string, b: string) { - return a + b; - } - return bar(...foo()); - ` - .tap(expectNoUnpack) - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("Tuple Return on Type Alias", () => { - util.testFunction` - /** @tupleReturn */ type Fn = () => [number, number]; - const fn: Fn = () => [1, 2]; - const [a, b] = fn(); - return a + b; - ` - .tap(expectNoUnpack) - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("Tuple Return on Interface", () => { - util.testFunction` - /** @tupleReturn */ interface Fn { (): [number, number]; } - const fn: Fn = () => [1, 2]; - const [a, b] = fn(); - return a + b; - ` - .tap(expectNoUnpack) - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("Tuple Return on Interface Signature", () => { - util.testFunction` - interface Fn { - /** @tupleReturn */ (): [number, number]; - } - const fn: Fn = () => [1, 2]; - const [a, b] = fn(); - return a + b; - ` - .tap(expectNoUnpack) - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("Tuple Return on Overload", () => { - util.testFunction` - function fn(a: number): number; - /** @tupleReturn */ function fn(a: string, b: string): [string, string]; - function fn(a: number | string, b?: string): number | [string, string] { - if (typeof a === "number") { - return a; - } else { - return [a, b as string]; - } - } - const a = fn(3); - const [b, c] = fn("foo", "bar"); - return a + b + c - ` - .tap(expectNoUnpack) - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("Tuple Return on Interface Overload", () => { - util.testFunction` - interface Fn { - (a: number): number; - /** @tupleReturn */ (a: string, b: string): [string, string]; - } - const fn = ((a: number | string, b?: string): number | [string, string] => { - if (typeof a === "number") { - return a; - } else { - return [a, b as string]; - } - }) as Fn; - const a = fn(3); - const [b, c] = fn("foo", "bar"); - return a + b + c - ` - .tap(expectNoUnpack) - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("Tuple Return on Interface Method Overload", () => { - util.testFunction` - interface Foo { - foo(a: number): number; - /** @tupleReturn */ foo(a: string, b: string): [string, string]; - } - const bar = { - foo: (a: number | string, b?: string): number | [string, string] => { - if (typeof a === "number") { - return a; - } else { - return [a, b as string]; - } - } - } as Foo; - const a = bar.foo(3); - const [b, c] = bar.foo("foo", "bar"); - return a + b + c; - ` - .tap(expectNoUnpack) - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("Tuple Return vs Non-Tuple Return Overload", () => { - const luaHeader = ` - function fn(a, b) - if type(a) == "number" then - return {a, a + 1} - else - return a, b - end - end - `; - - const tsHeader = ` - declare function fn(this: void, a: number): [number, number]; - /** @tupleReturn */ declare function fn(this: void, a: string, b: string): [string, string]; - `; - - util.testFunction` - const [a, b] = fn(3); - const [c, d] = fn("foo", "bar"); - return (a + b) + c + d; - ` - .setTsHeader(tsHeader) - .setLuaHeader(luaHeader) - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToEqual("7foobar"); -}); - -test("TupleReturn assignment", () => { - util.testFunction` - /** @tupleReturn */ - function abc(this: void): number[] { - return [3, 5]; - } - let [a, b] = abc(); - return { a, b }; - ` - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("TupleReturn Single assignment", () => { - util.testFunction` - /** @tupleReturn */ - function abc(this: void): [number, string] { - return [3, "foo"]; - } - let a = abc(); - a = abc(); - return a; - ` - .expectToHaveDiagnostics([annotationDeprecated.code, annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("TupleReturn interface assignment", () => { - const lua = util.testFunction` - interface def { - /** @tupleReturn */ - abc(); - } declare const jkl : def; - let [a,b] = jkl.abc(); - `.getMainLuaCodeChunk(); - - expect(lua).toContain("local a, b = jkl:abc()"); -}); - -test("TupleReturn namespace assignment", () => { - const lua = util.testFunction` - declare namespace def { - /** @tupleReturn */ - function abc(this: void) {} - } - let [a,b] = def.abc(); - `.getMainLuaCodeChunk(); - - expect(lua).toContain("local a, b = def.abc()"); -}); - -test("TupleReturn method assignment", () => { - const lua = util.testFunction` - declare class def { - /** @tupleReturn */ - abc() { return [1,2,3]; } - } const jkl = new def(); - let [a,b] = jkl.abc(); - `.getMainLuaCodeChunk(); - - expect(lua).toContain("local a, b = jkl:abc()"); -}); - -test("TupleReturn functional", () => { - util.testFunction` - /** @tupleReturn */ - function abc(): [number, string] { return [3, "a"]; } - const [a, b] = abc(); - return b + a; - ` - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("TupleReturn single", () => { - util.testFunction` - /** @tupleReturn */ - function abc(): [number, string] { return [3, "a"]; } - const res = abc(); - return res.length - ` - .expectToHaveDiagnostics([annotationDeprecated.code]) - .expectToMatchJsResult(); -}); - -test("TupleReturn in expression", () => { - util.testFunction` - /** @tupleReturn */ - function abc(): [number, string] { return [3, "a"]; } - return abc()[1] + abc()[0]; - ` - .expectToHaveDiagnostics([annotationDeprecated.code, annotationDeprecated.code]) - .expectToMatchJsResult(); -});