diff options
author | Linus Groh <mail@linusgroh.de> | 2021-06-22 18:59:24 +0100 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2021-06-22 18:59:24 +0100 |
commit | 8a06a93ce22382c3bfd706c8040bc20c9f13626a (patch) | |
tree | 6f2f3ec165fc7d6cc7bd0b78a686df2f3ba4c559 /Userland | |
parent | 1f8b6ac3c3ffcdc2f3878486602a7336baaf187e (diff) | |
download | serenity-8a06a93ce22382c3bfd706c8040bc20c9f13626a.zip |
LibJS: Return non-object argument unaltered from Object.setPrototypeOf()
This was missing step 3 from the spec:
3. If Type(O) is not Object, return O.
Also use RequireObjectCoercible() for a better error message and make
the rest of the code a bit easier to read and more similar to the spec
text.
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/ObjectConstructor.cpp | 22 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Tests/builtins/Object/Object.setPrototypeOf.js | 7 |
2 files changed, 18 insertions, 11 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/ObjectConstructor.cpp b/Userland/Libraries/LibJS/Runtime/ObjectConstructor.cpp index 5af4c7250a..5807de05f5 100644 --- a/Userland/Libraries/LibJS/Runtime/ObjectConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/ObjectConstructor.cpp @@ -110,25 +110,25 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::get_prototype_of) // 20.1.2.21 Object.setPrototypeOf ( O, proto ), https://tc39.es/ecma262/#sec-object.setprototypeof JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::set_prototype_of) { - auto* object = vm.argument(0).to_object(global_object); + auto argument = require_object_coercible(global_object, vm.argument(0)); if (vm.exception()) return {}; auto prototype_value = vm.argument(1); - Object* prototype; - if (prototype_value.is_null()) { - prototype = nullptr; - } else if (prototype_value.is_object()) { - prototype = &prototype_value.as_object(); - } else { + if (!prototype_value.is_object() && !prototype_value.is_null()) { vm.throw_exception<TypeError>(global_object, ErrorType::ObjectPrototypeWrongType); return {}; } - if (!object->set_prototype(prototype)) { - if (!vm.exception()) - vm.throw_exception<TypeError>(global_object, ErrorType::ObjectSetPrototypeOfReturnedFalse); + if (!argument.is_object()) + return argument; + auto* prototype = prototype_value.is_null() ? nullptr : &prototype_value.as_object(); + auto status = argument.as_object().set_prototype(prototype); + if (vm.exception()) + return {}; + if (!status) { + vm.throw_exception<TypeError>(global_object, ErrorType::ObjectSetPrototypeOfReturnedFalse); return {}; } - return object; + return argument; } // 20.1.2.14 Object.isExtensible ( O ), https://tc39.es/ecma262/#sec-object.isextensible diff --git a/Userland/Libraries/LibJS/Tests/builtins/Object/Object.setPrototypeOf.js b/Userland/Libraries/LibJS/Tests/builtins/Object/Object.setPrototypeOf.js index 612c5929e6..787b7e610d 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Object/Object.setPrototypeOf.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Object/Object.setPrototypeOf.js @@ -9,6 +9,13 @@ describe("correct behavior", () => { expect(Object.setPrototypeOf(o, p)).toBe(o); expect(Object.getPrototypeOf(o)).toBe(p); }); + + test("non-object argument is returned without being coerced to object", () => { + let o = 42; + let p = {}; + expect(Object.setPrototypeOf(o, p)).toBe(o); + expect(Object.getPrototypeOf(o)).toBe(Number.prototype); + }); }); describe("errors", () => { |