diff --git a/Userland/Libraries/LibJS/AST.cpp b/Userland/Libraries/LibJS/AST.cpp index cae39745392..ba34ce824a2 100644 --- a/Userland/Libraries/LibJS/AST.cpp +++ b/Userland/Libraries/LibJS/AST.cpp @@ -220,7 +220,14 @@ Value CallExpression::execute(Interpreter& interpreter, GlobalObject& global_obj if (result.is_object()) new_object = &result.as_object(); } else if (is(*m_callee)) { - auto* super_constructor = interpreter.current_environment()->current_function()->prototype(); + // FIXME: This is merely a band-aid to make super() inside catch {} work (which constructs + // a new LexicalEnvironment without current function). Implement GetSuperConstructor() + // and subsequently GetThisEnvironment() instead. + auto* function_environment = interpreter.current_environment(); + if (!function_environment->current_function()) + function_environment = static_cast(function_environment->parent()); + + auto* super_constructor = function_environment->current_function()->prototype(); // FIXME: Functions should track their constructor kind. if (!super_constructor || !super_constructor->is_function()) { vm.throw_exception(global_object, ErrorType::NotAConstructor, "Super constructor"); @@ -230,7 +237,7 @@ Value CallExpression::execute(Interpreter& interpreter, GlobalObject& global_obj if (vm.exception()) return {}; - interpreter.current_environment()->bind_this_value(global_object, result); + function_environment->bind_this_value(global_object, result); } else { result = vm.call(function, this_value, move(arguments)); } diff --git a/Userland/Libraries/LibJS/Tests/classes/class-inheritance.js b/Userland/Libraries/LibJS/Tests/classes/class-inheritance.js index 0e6778dbf56..421e6a0c95e 100644 --- a/Userland/Libraries/LibJS/Tests/classes/class-inheritance.js +++ b/Userland/Libraries/LibJS/Tests/classes/class-inheritance.js @@ -131,3 +131,24 @@ test("super constructor call from child class with argument", () => { expect(p.x).toBe(3); expect(c.x).toBe(10); }); + +test("issue #7045, super constructor call from child class in catch {}", () => { + class Parent { + constructor(x) { + this.x = x; + } + } + + class Child extends Parent { + constructor() { + try { + throw new Error("Error in Child constructor"); + } catch (e) { + super(e.message); + } + } + } + + const c = new Child(); + expect(c.x).toBe("Error in Child constructor"); +});