Pārlūkot izejas kodu

LibJS: Convert ordinary_to_primitive() to ThrowCompletionOr

Also add spec step comments to it while we're here.
Linus Groh 3 gadi atpakaļ
vecāks
revīzija
fa2ac5b759

+ 1 - 1
Userland/Libraries/LibJS/Runtime/DatePrototype.cpp

@@ -887,7 +887,7 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::symbol_to_primitive)
         vm.throw_exception<TypeError>(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));
 }
 
 }

+ 21 - 8
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<Value> 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<PropertyName, 2> method_names;
-    if (preferred_type == Value::PreferredType::String)
+
+    // 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
+    } 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<Object*>(this)));
+            // i. Let result be ? Call(method, O).
+            auto result = TRY(vm.call(method.as_function(), const_cast<Object*>(this)));
+
+            // ii. If Type(result) is not Object, return result.
             if (!result.is_object())
                 return result;
         }
     }
-    vm.throw_exception<TypeError>(global_object(), ErrorType::Convert, "object", preferred_type == Value::PreferredType::String ? "string" : "number");
-    return {};
+
+    // 4. Throw a TypeError exception.
+    return vm.throw_completion<TypeError>(global_object(), ErrorType::Convert, "object", preferred_type == Value::PreferredType::String ? "string" : "number");
 }
 
 }

+ 1 - 1
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<Value> ordinary_to_primitive(Value::PreferredType preferred_type) const;
 
     // 7.2 Testing and Comparison Operations, https://tc39.es/ecma262/#sec-testing-and-comparison-operations
 

+ 1 - 1
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;
 }