diff --git a/src/transformation/visitors/errors.ts b/src/transformation/visitors/errors.ts index f81519e4c..7233d709c 100644 --- a/src/transformation/visitors/errors.ts +++ b/src/transformation/visitors/errors.ts @@ -146,6 +146,10 @@ export const transformTryStatement: FunctionVisitor = (statemen returnedIdentifier, lua.SyntaxKind.AndOperator ); + } else if (statement.finallyBlock) { + // try without catch, but with finally — need to capture error for re-throw + const errorIdentifier = lua.createIdentifier("____error"); + result.push(lua.createVariableDeclarationStatement([tryResultIdentifier, errorIdentifier], tryCall)); } else { // try without return or catch result.push(lua.createExpressionStatement(tryCall)); @@ -155,6 +159,22 @@ export const transformTryStatement: FunctionVisitor = (statemen result.push(...context.transformStatements(statement.finallyBlock)); } + // Re-throw error if try had no catch but had a finally + if (!statement.catchClause && statement.finallyBlock) { + const notTryCondition = lua.createUnaryExpression( + lua.cloneIdentifier(tryResultIdentifier), + lua.SyntaxKind.NotOperator + ); + const errorIdentifier = lua.createIdentifier("____error"); + const rethrow = lua.createExpressionStatement( + lua.createCallExpression(lua.createIdentifier("error"), [ + lua.cloneIdentifier(errorIdentifier), + lua.createNumericLiteral(0), + ]) + ); + result.push(lua.createIfStatement(notTryCondition, lua.createBlock([rethrow]))); + } + if (returnCondition && returnedIdentifier) { const returnValues: lua.Expression[] = []; diff --git a/test/unit/error.spec.ts b/test/unit/error.spec.ts index af69d7e1d..78444c60a 100644 --- a/test/unit/error.spec.ts +++ b/test/unit/error.spec.ts @@ -256,6 +256,28 @@ test("multi return from catch->finally", () => { .expectToMatchJsResult(); }); +test("throw propagates through finally to outer catch", () => { + util.testFunction` + function thrower() { + try { + throw "Error"; + } finally { + } + } + + function caller() { + try { + thrower(); + return "NoCatch"; + } catch (e) { + return e; + } + } + + return caller(); + `.expectToMatchJsResult(); +}); + test("return from nested finally", () => { util.testFunction` let x = "";