diff --git a/Userland/Libraries/LibJS/Runtime/DatePrototype.cpp b/Userland/Libraries/LibJS/Runtime/DatePrototype.cpp index 905052fd0d..18ef237146 100644 --- a/Userland/Libraries/LibJS/Runtime/DatePrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/DatePrototype.cpp @@ -887,7 +887,7 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::symbol_to_primitive) vm.throw_exception(global_object, ErrorType::InvalidHint, hint); return {}; } - return this_value.as_object().ordinary_to_primitive(try_first); + return TRY_OR_DISCARD(this_value.as_object().ordinary_to_primitive(try_first)); } } diff --git a/Userland/Libraries/LibJS/Runtime/Object.cpp b/Userland/Libraries/LibJS/Runtime/Object.cpp index fc8e677580..26d2aeff45 100644 --- a/Userland/Libraries/LibJS/Runtime/Object.cpp +++ b/Userland/Libraries/LibJS/Runtime/Object.cpp @@ -1146,30 +1146,43 @@ void Object::visit_edges(Cell::Visitor& visitor) } // 7.1.1.1 OrdinaryToPrimitive ( O, hint ), https://tc39.es/ecma262/#sec-ordinarytoprimitive -Value Object::ordinary_to_primitive(Value::PreferredType preferred_type) const +ThrowCompletionOr Object::ordinary_to_primitive(Value::PreferredType preferred_type) const { VERIFY(preferred_type == Value::PreferredType::String || preferred_type == Value::PreferredType::Number); auto& vm = this->vm(); AK::Array method_names; - if (preferred_type == Value::PreferredType::String) - method_names = { vm.names.toString, vm.names.valueOf }; - else - method_names = { vm.names.valueOf, vm.names.toString }; + // 1. If hint is string, then + if (preferred_type == Value::PreferredType::String) { + // a. Let methodNames be « "toString", "valueOf" ». + method_names = { vm.names.toString, vm.names.valueOf }; + } else { + // a. Let methodNames be « "valueOf", "toString" ». + method_names = { vm.names.valueOf, vm.names.toString }; + } + + // 3. For each element name of methodNames, do for (auto& method_name : method_names) { + // a. Let method be ? Get(O, name). auto method = get(method_name); - if (vm.exception()) - return {}; + if (auto* exception = vm.exception()) + return throw_completion(exception->value()); + + // b. If IsCallable(method) is true, then if (method.is_function()) { - auto result = TRY_OR_DISCARD(vm.call(method.as_function(), const_cast(this))); + // i. Let result be ? Call(method, O). + auto result = TRY(vm.call(method.as_function(), const_cast(this))); + + // ii. If Type(result) is not Object, return result. if (!result.is_object()) return result; } } - vm.throw_exception(global_object(), ErrorType::Convert, "object", preferred_type == Value::PreferredType::String ? "string" : "number"); - return {}; + + // 4. Throw a TypeError exception. + return vm.throw_completion(global_object(), ErrorType::Convert, "object", preferred_type == Value::PreferredType::String ? "string" : "number"); } } diff --git a/Userland/Libraries/LibJS/Runtime/Object.h b/Userland/Libraries/LibJS/Runtime/Object.h index cfeaecc7a6..ccd29941b5 100644 --- a/Userland/Libraries/LibJS/Runtime/Object.h +++ b/Userland/Libraries/LibJS/Runtime/Object.h @@ -67,7 +67,7 @@ public: // 7.1 Type Conversion, https://tc39.es/ecma262/#sec-type-conversion - Value ordinary_to_primitive(Value::PreferredType preferred_type) const; + ThrowCompletionOr ordinary_to_primitive(Value::PreferredType preferred_type) const; // 7.2 Testing and Comparison Operations, https://tc39.es/ecma262/#sec-testing-and-comparison-operations diff --git a/Userland/Libraries/LibJS/Runtime/Value.cpp b/Userland/Libraries/LibJS/Runtime/Value.cpp index 406518807c..17c5a32475 100644 --- a/Userland/Libraries/LibJS/Runtime/Value.cpp +++ b/Userland/Libraries/LibJS/Runtime/Value.cpp @@ -437,7 +437,7 @@ Value Value::to_primitive(GlobalObject& global_object, PreferredType preferred_t } if (preferred_type == PreferredType::Default) preferred_type = PreferredType::Number; - return as_object().ordinary_to_primitive(preferred_type); + return TRY_OR_DISCARD(as_object().ordinary_to_primitive(preferred_type)); } return *this; }