mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 08:37:45 +00:00
LibJS: Fix return value of TryStatement with finalizer
Previously we would always return the result of executing the finalizer, however the spec dictates the finalizer result must only be returned for a non-normal completion. I added some more comments along the way, which should make it more clear what's going on - the unwinding and exception flow isn't super straightforward here.
This commit is contained in:
parent
e8cbcc2fbf
commit
7cbede4342
2 changed files with 34 additions and 7 deletions
|
@ -1988,8 +1988,22 @@ Value TryStatement::execute(Interpreter& interpreter, GlobalObject& global_objec
|
|||
// execute() the finalizer without an exception in our way.
|
||||
auto* previous_exception = interpreter.exception();
|
||||
interpreter.vm().clear_exception();
|
||||
|
||||
// Remember what scope type we were unwinding to, and temporarily
|
||||
// clear it as well (e.g. return from handler).
|
||||
auto unwind_until = interpreter.vm().unwind_until();
|
||||
interpreter.vm().stop_unwind();
|
||||
result = m_finalizer->execute(interpreter, global_object);
|
||||
|
||||
auto finalizer_result = m_finalizer->execute(interpreter, global_object);
|
||||
if (interpreter.vm().should_unwind()) {
|
||||
// This was NOT a 'normal' completion (e.g. return from finalizer).
|
||||
result = finalizer_result;
|
||||
} else {
|
||||
// Continue unwinding to whatever we found ourselves unwinding
|
||||
// to when the finalizer was entered (e.g. return from handler,
|
||||
// which is unaffected by normal completion from finalizer).
|
||||
interpreter.vm().unwind(unwind_until);
|
||||
|
||||
// If we previously had an exception and the finalizer didn't
|
||||
// throw a new one, restore the old one.
|
||||
// FIXME: This will print debug output in throw_exception() for
|
||||
|
@ -1997,6 +2011,7 @@ Value TryStatement::execute(Interpreter& interpreter, GlobalObject& global_objec
|
|||
if (previous_exception && !interpreter.exception())
|
||||
interpreter.vm().throw_exception(previous_exception);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -32,3 +32,15 @@ test("return from finally block", () => {
|
|||
}
|
||||
expect(foo()).toBe("baz");
|
||||
});
|
||||
|
||||
test("return from catch block with empty finally", () => {
|
||||
function foo() {
|
||||
try {
|
||||
throw "foo";
|
||||
} catch {
|
||||
return "bar";
|
||||
} finally {
|
||||
}
|
||||
}
|
||||
expect(foo()).toBe("bar");
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue