diff --git a/Libraries/LibJS/Runtime/AbstractOperations.h b/Libraries/LibJS/Runtime/AbstractOperations.h index 401f010d3a9..f9450e60d0f 100644 --- a/Libraries/LibJS/Runtime/AbstractOperations.h +++ b/Libraries/LibJS/Runtime/AbstractOperations.h @@ -237,22 +237,16 @@ ThrowCompletionOr group_by(VM& vm, Value items, Value callback_funct auto value = next.release_value(); // e. Let key be Completion(Call(callbackfn, undefined, « value, 𝔽(k) »)). - auto key = call(vm, callback_function, js_undefined(), value, Value(k)); - // f. IfAbruptCloseIterator(key, iteratorRecord). - if (key.is_error()) - return Completion { TRY(iterator_close(vm, iterator_record, key.release_error())) }; + auto key = TRY_OR_CLOSE_ITERATOR(vm, iterator_record, call(vm, callback_function, js_undefined(), value, Value(k))); // g. If keyCoercion is property, then if constexpr (IsSame) { // i. Set key to Completion(ToPropertyKey(key)). - auto property_key = key.value().to_property_key(vm); - // ii. IfAbruptCloseIterator(key, iteratorRecord). - if (property_key.is_error()) - return Completion { TRY(iterator_close(vm, iterator_record, property_key.release_error())) }; + auto property_key = TRY_OR_CLOSE_ITERATOR(vm, iterator_record, key.to_property_key(vm)); - add_value_to_keyed_group(vm, groups, property_key.release_value(), value); + add_value_to_keyed_group(vm, groups, move(property_key), value); } // h. Else, else { @@ -260,9 +254,9 @@ ThrowCompletionOr group_by(VM& vm, Value items, Value callback_funct static_assert(IsSame); // ii. Set key to CanonicalizeKeyedCollectionKey(key). - key = canonicalize_keyed_collection_key(key.value()); + key = canonicalize_keyed_collection_key(key); - add_value_to_keyed_group(vm, groups, make_root(key.release_value()), value); + add_value_to_keyed_group(vm, groups, make_root(key), value); } // i. Perform AddValueToKeyedGroup(groups, key, value). diff --git a/Libraries/LibJS/Runtime/ArrayConstructor.cpp b/Libraries/LibJS/Runtime/ArrayConstructor.cpp index fad1ae76190..22957e44600 100644 --- a/Libraries/LibJS/Runtime/ArrayConstructor.cpp +++ b/Libraries/LibJS/Runtime/ArrayConstructor.cpp @@ -214,12 +214,8 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayConstructor::from) // v. If mapping is true, then if (mapfn) { // 1. Let mappedValue be Completion(Call(mapfn, thisArg, « nextValue, 𝔽(k) »)). - auto mapped_value_or_error = JS::call(vm, *mapfn, this_arg, next.release_value(), Value(k)); - // 2. IfAbruptCloseIterator(mappedValue, iteratorRecord). - if (mapped_value_or_error.is_error()) - return TRY(iterator_close(vm, iterator, mapped_value_or_error.release_error())); - mapped_value = mapped_value_or_error.release_value(); + mapped_value = TRY_OR_CLOSE_ITERATOR(vm, iterator, JS::call(vm, *mapfn, this_arg, next.release_value(), Value(k))); } // vi. Else, let mappedValue be nextValue. else { @@ -227,11 +223,8 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayConstructor::from) } // vii. Let defineStatus be Completion(CreateDataPropertyOrThrow(A, Pk, mappedValue)). - auto result_or_error = array->create_data_property_or_throw(property_key, mapped_value); - // viii. IfAbruptCloseIterator(defineStatus, iteratorRecord). - if (result_or_error.is_error()) - return TRY(iterator_close(vm, iterator, result_or_error.release_error())); + TRY_OR_CLOSE_ITERATOR(vm, iterator, array->create_data_property_or_throw(property_key, mapped_value)); // ix. Set k to k + 1. } diff --git a/Libraries/LibJS/Runtime/Iterator.h b/Libraries/LibJS/Runtime/Iterator.h index cbad51bdd75..5de60f0c6e7 100644 --- a/Libraries/LibJS/Runtime/Iterator.h +++ b/Libraries/LibJS/Runtime/Iterator.h @@ -67,6 +67,24 @@ enum class PrimitiveHandling { RejectPrimitives, }; +// 7.4.12 IfAbruptCloseIterator ( value, iteratorRecord ), https://tc39.es/ecma262/#sec-ifabruptcloseiterator +#define TRY_OR_CLOSE_ITERATOR(vm, iterator_record, expression) \ + ({ \ + auto&& _temporary_try_or_close_result = (expression); \ + \ + /* 1. Assert: value is a Completion Record. */ \ + /* 2. If value is an abrupt completion, return ? IteratorClose(iteratorRecord, value). */ \ + if (_temporary_try_or_close_result.is_error()) { \ + return iterator_close(vm, iterator_record, _temporary_try_or_close_result.release_error()); \ + } \ + \ + static_assert(!::AK::Detail::IsLvalueReference, \ + "Do not return a reference from a fallible expression"); \ + \ + /* 3. Else, set value to ! value. */ \ + _temporary_try_or_close_result.release_value(); \ + }) + ThrowCompletionOr> get_iterator_direct(VM&, Object&); ThrowCompletionOr> get_iterator_from_method(VM&, Value, GC::Ref); ThrowCompletionOr> get_iterator(VM&, Value, IteratorHint);