Skip to content

Commit cfb6e2b

Browse files
authored
fix try/finally not re-throwing errors when there is no catch clause (#1692)
* fix try/finally not re-throwing errors when there is no catch clause (#1667) When a try block had a finally but no catch, pcall's error result was discarded, silently swallowing the exception. Now the error is captured and re-thrown after the finally block executes. * Nicer test return values
1 parent 1bdbed8 commit cfb6e2b

File tree

2 files changed

+42
-0
lines changed

2 files changed

+42
-0
lines changed

src/transformation/visitors/errors.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@ export const transformTryStatement: FunctionVisitor<ts.TryStatement> = (statemen
146146
returnedIdentifier,
147147
lua.SyntaxKind.AndOperator
148148
);
149+
} else if (statement.finallyBlock) {
150+
// try without catch, but with finally — need to capture error for re-throw
151+
const errorIdentifier = lua.createIdentifier("____error");
152+
result.push(lua.createVariableDeclarationStatement([tryResultIdentifier, errorIdentifier], tryCall));
149153
} else {
150154
// try without return or catch
151155
result.push(lua.createExpressionStatement(tryCall));
@@ -155,6 +159,22 @@ export const transformTryStatement: FunctionVisitor<ts.TryStatement> = (statemen
155159
result.push(...context.transformStatements(statement.finallyBlock));
156160
}
157161

162+
// Re-throw error if try had no catch but had a finally
163+
if (!statement.catchClause && statement.finallyBlock) {
164+
const notTryCondition = lua.createUnaryExpression(
165+
lua.cloneIdentifier(tryResultIdentifier),
166+
lua.SyntaxKind.NotOperator
167+
);
168+
const errorIdentifier = lua.createIdentifier("____error");
169+
const rethrow = lua.createExpressionStatement(
170+
lua.createCallExpression(lua.createIdentifier("error"), [
171+
lua.cloneIdentifier(errorIdentifier),
172+
lua.createNumericLiteral(0),
173+
])
174+
);
175+
result.push(lua.createIfStatement(notTryCondition, lua.createBlock([rethrow])));
176+
}
177+
158178
if (returnCondition && returnedIdentifier) {
159179
const returnValues: lua.Expression[] = [];
160180

test/unit/error.spec.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,28 @@ test("multi return from catch->finally", () => {
256256
.expectToMatchJsResult();
257257
});
258258

259+
test("throw propagates through finally to outer catch", () => {
260+
util.testFunction`
261+
function thrower() {
262+
try {
263+
throw "Error";
264+
} finally {
265+
}
266+
}
267+
268+
function caller() {
269+
try {
270+
thrower();
271+
return "NoCatch";
272+
} catch (e) {
273+
return e;
274+
}
275+
}
276+
277+
return caller();
278+
`.expectToMatchJsResult();
279+
});
280+
259281
test("return from nested finally", () => {
260282
util.testFunction`
261283
let x = "";

0 commit comments

Comments
 (0)