diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index 476dbbc07b..cd997b3be1 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -2510,8 +2510,13 @@ Bytecode::CodeGenerationErrorOr> TryStatement::gener if (m_finalizer) generator.end_boundary(Bytecode::Generator::BlockBoundaryType::ReturnToFinally); if (m_handler) { - if (!m_finalizer) - unwind_context.emplace(generator, OptionalNone()); + if (!m_finalizer) { + auto const* parent_unwind_context = generator.current_unwind_context(); + if (parent_unwind_context) + unwind_context.emplace(generator, parent_unwind_context->finalizer()); + else + unwind_context.emplace(generator, OptionalNone()); + } unwind_context->set_handler(handler_target.value()); } diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.h b/Userland/Libraries/LibJS/Bytecode/Generator.h index 1b9b81ae69..b1968961c1 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.h +++ b/Userland/Libraries/LibJS/Bytecode/Generator.h @@ -276,6 +276,8 @@ public: return Operand(Operand::Type::Constant, m_constants.size() - 1); } + UnwindContext const* current_unwind_context() const { return m_current_unwind_context; } + private: VM& m_vm; diff --git a/Userland/Libraries/LibJS/Tests/try-catch-finally-nested.js b/Userland/Libraries/LibJS/Tests/try-catch-finally-nested.js index da9ad2d438..7614b05483 100644 --- a/Userland/Libraries/LibJS/Tests/try-catch-finally-nested.js +++ b/Userland/Libraries/LibJS/Tests/try-catch-finally-nested.js @@ -53,3 +53,53 @@ test("Nested try/catch/finally with exceptions", () => { expect(level3CatchHasBeenExecuted).toBeTrue(); expect(level3FinallyHasBeenExecuted).toBeTrue(); }); + +test("Nested try/catch/finally with return in inner context", () => { + success = false; + (() => { + try { + try { + return; + } catch (e) { + expect().fail(); + } + } finally { + success = true; + } + expect().fail(); + })(); + expect(success).toBeTrue(); +}); + +test("Deeply nested try/catch/finally with return in inner context", () => { + success = 0; + (() => { + try { + try { + try { + try { + try { + return; + } catch (e) { + expect().fail(); + } finally { + success += 4; + } + } catch (e) { + expect().fail(); + } + } catch (e) { + expect().fail(); + } finally { + success += 2; + } + } catch (e) { + expect().fail(); + } + } finally { + success += 1; + } + expect().fail(); + })(); + expect(success).toBe(7); +});