summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorLinus Groh <mail@linusgroh.de>2021-06-22 18:59:24 +0100
committerLinus Groh <mail@linusgroh.de>2021-06-22 18:59:24 +0100
commit8a06a93ce22382c3bfd706c8040bc20c9f13626a (patch)
tree6f2f3ec165fc7d6cc7bd0b78a686df2f3ba4c559 /Userland
parent1f8b6ac3c3ffcdc2f3878486602a7336baaf187e (diff)
downloadserenity-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.cpp22
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/Object/Object.setPrototypeOf.js7
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", () => {