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.
This commit is contained in:
Linus Groh 2021-06-22 18:59:24 +01:00
parent 1f8b6ac3c3
commit 8a06a93ce2
Notes: sideshowbarker 2024-07-18 11:39:42 +09:00
2 changed files with 18 additions and 11 deletions

View file

@ -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

View file

@ -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", () => {