Coverage Report

Created: 2025-12-18 07:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibJS/Runtime/PromiseConstructor.cpp
Line
Count
Source
1
/*
2
 * Copyright (c) 2021-2024, Linus Groh <linusg@serenityos.org>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#include <AK/Function.h>
8
#include <LibJS/Runtime/AbstractOperations.h>
9
#include <LibJS/Runtime/AggregateError.h>
10
#include <LibJS/Runtime/Array.h>
11
#include <LibJS/Runtime/Error.h>
12
#include <LibJS/Runtime/FunctionObject.h>
13
#include <LibJS/Runtime/GlobalObject.h>
14
#include <LibJS/Runtime/Iterator.h>
15
#include <LibJS/Runtime/Promise.h>
16
#include <LibJS/Runtime/PromiseCapability.h>
17
#include <LibJS/Runtime/PromiseConstructor.h>
18
#include <LibJS/Runtime/PromiseResolvingElementFunctions.h>
19
20
namespace JS {
21
22
JS_DEFINE_ALLOCATOR(PromiseConstructor);
23
24
// 27.2.4.1.1 GetPromiseResolve ( promiseConstructor ), https://tc39.es/ecma262/#sec-getpromiseresolve
25
static ThrowCompletionOr<Value> get_promise_resolve(VM& vm, Value constructor)
26
0
{
27
0
    VERIFY(constructor.is_constructor());
28
29
    // 1. Let promiseResolve be ? Get(promiseConstructor, "resolve").
30
0
    auto promise_resolve = TRY(constructor.get(vm, vm.names.resolve));
31
32
    // 2. If IsCallable(promiseResolve) is false, throw a TypeError exception.
33
0
    if (!promise_resolve.is_function())
34
0
        return vm.throw_completion<TypeError>(ErrorType::NotAFunction, promise_resolve.to_string_without_side_effects());
35
36
    // 3. Return promiseResolve.
37
0
    return promise_resolve;
38
0
}
39
40
using EndOfElementsCallback = Function<ThrowCompletionOr<Value>(PromiseValueList&)>;
41
using InvokeElementFunctionCallback = Function<ThrowCompletionOr<Value>(PromiseValueList&, RemainingElements&, Value, size_t)>;
42
43
static ThrowCompletionOr<Value> perform_promise_common(VM& vm, IteratorRecord& iterator_record, Value constructor, PromiseCapability const& result_capability, Value promise_resolve, EndOfElementsCallback end_of_list, InvokeElementFunctionCallback invoke_element_function)
44
0
{
45
0
    VERIFY(constructor.is_constructor());
46
0
    VERIFY(promise_resolve.is_function());
47
48
    // 1. Let values be a new empty List.
49
0
    auto values = vm.heap().allocate_without_realm<PromiseValueList>();
50
51
    // 2. Let remainingElementsCount be the Record { [[Value]]: 1 }.
52
0
    auto remaining_elements_count = vm.heap().allocate_without_realm<RemainingElements>(1);
53
54
    // 3. Let index be 0.
55
0
    size_t index = 0;
56
57
    // 4. Repeat,
58
0
    while (true) {
59
        // a. Let next be ? IteratorStepValue(iteratorRecord).
60
0
        auto next = TRY(iterator_step_value(vm, iterator_record));
61
62
        // b. If next is DONE, then
63
0
        if (!next.has_value()) {
64
            // i. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] - 1.
65
            // ii. If remainingElementsCount.[[Value]] = 0, then
66
0
            if (--remaining_elements_count->value == 0) {
67
                // 1-2. are handled in `end_of_list`
68
0
                return TRY(end_of_list(*values));
69
0
            }
70
71
            // iii. Return resultCapability.[[Promise]].
72
0
            return result_capability.promise();
73
0
        }
74
75
        // c. Append undefined to values.
76
0
        values->values().append(js_undefined());
77
78
        // d. Let nextPromise be ? Call(promiseResolve, constructor, « next »).
79
0
        auto next_promise = TRY(call(vm, promise_resolve.as_function(), constructor, next.release_value()));
80
81
        // e-l. are handled in `invoke_element_function`
82
83
        // m. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] + 1.
84
0
        ++remaining_elements_count->value;
85
86
        // n. Perform ? Invoke(nextPromise, "then", « ... »).
87
0
        TRY(invoke_element_function(*values, *remaining_elements_count, next_promise, index));
88
89
        // o. Set index to index + 1.
90
0
        ++index;
91
0
    }
92
0
}
93
94
// 27.2.4.1.2 PerformPromiseAll ( iteratorRecord, constructor, resultCapability, promiseResolve ), https://tc39.es/ecma262/#sec-performpromiseall
95
static ThrowCompletionOr<Value> perform_promise_all(VM& vm, IteratorRecord& iterator_record, Value constructor, PromiseCapability const& result_capability, Value promise_resolve)
96
0
{
97
0
    auto& realm = *vm.current_realm();
98
99
0
    return perform_promise_common(
100
0
        vm, iterator_record, constructor, result_capability, promise_resolve,
101
0
        [&](PromiseValueList& values) -> ThrowCompletionOr<Value> {
102
            // 1. Let valuesArray be CreateArrayFromList(values).
103
0
            auto values_array = Array::create_from(realm, values.values());
104
105
            // 2. Perform ? Call(resultCapability.[[Resolve]], undefined, « valuesArray »).
106
0
            TRY(call(vm, *result_capability.resolve(), js_undefined(), values_array));
107
108
            // iv. Return resultCapability.[[Promise]].
109
0
            return result_capability.promise();
110
0
        },
111
0
        [&](PromiseValueList& values, RemainingElements& remaining_elements_count, Value next_promise, size_t index) {
112
            // j. Let steps be the algorithm steps defined in Promise.all Resolve Element Functions.
113
            // k. Let length be the number of non-optional parameters of the function definition in Promise.all Resolve Element Functions.
114
            // l. Let onFulfilled be CreateBuiltinFunction(steps, length, "", « [[AlreadyCalled]], [[Index]], [[Values]], [[Capability]], [[RemainingElements]] »).
115
            // m. Set onFulfilled.[[AlreadyCalled]] to false.
116
            // n. Set onFulfilled.[[Index]] to index.
117
            // o. Set onFulfilled.[[Values]] to values.
118
            // p. Set onFulfilled.[[Capability]] to resultCapability.
119
            // q. Set onFulfilled.[[RemainingElements]] to remainingElementsCount.
120
0
            auto on_fulfilled = PromiseAllResolveElementFunction::create(realm, index, values, result_capability, remaining_elements_count);
121
0
            on_fulfilled->define_direct_property(vm.names.name, PrimitiveString::create(vm, String {}), Attribute::Configurable);
122
123
            // s. Perform ? Invoke(nextPromise, "then", « onFulfilled, resultCapability.[[Reject]] »).
124
0
            return next_promise.invoke(vm, vm.names.then, on_fulfilled, result_capability.reject());
125
0
        });
126
0
}
127
128
// 27.2.4.2.1 PerformPromiseAllSettled ( iteratorRecord, constructor, resultCapability, promiseResolve ), https://tc39.es/ecma262/#sec-performpromiseallsettled
129
static ThrowCompletionOr<Value> perform_promise_all_settled(VM& vm, IteratorRecord& iterator_record, Value constructor, PromiseCapability const& result_capability, Value promise_resolve)
130
0
{
131
0
    auto& realm = *vm.current_realm();
132
133
0
    return perform_promise_common(
134
0
        vm, iterator_record, constructor, result_capability, promise_resolve,
135
0
        [&](PromiseValueList& values) -> ThrowCompletionOr<Value> {
136
0
            auto values_array = Array::create_from(realm, values.values());
137
138
0
            TRY(call(vm, *result_capability.resolve(), js_undefined(), values_array));
139
140
0
            return result_capability.promise();
141
0
        },
142
0
        [&](PromiseValueList& values, RemainingElements& remaining_elements_count, Value next_promise, size_t index) {
143
            // j. Let stepsFulfilled be the algorithm steps defined in Promise.allSettled Resolve Element Functions.
144
            // k. Let lengthFulfilled be the number of non-optional parameters of the function definition in Promise.allSettled Resolve Element Functions.
145
            // l. Let onFulfilled be CreateBuiltinFunction(stepsFulfilled, lengthFulfilled, "", « [[AlreadyCalled]], [[Index]], [[Values]], [[Capability]], [[RemainingElements]] »).
146
            // m. Let alreadyCalled be the Record { [[Value]]: false }.
147
            // n. Set onFulfilled.[[AlreadyCalled]] to alreadyCalled.
148
            // o. Set onFulfilled.[[Index]] to index.
149
            // p. Set onFulfilled.[[Values]] to values.
150
            // q. Set onFulfilled.[[Capability]] to resultCapability.
151
            // r. Set onFulfilled.[[RemainingElements]] to remainingElementsCount.
152
0
            auto on_fulfilled = PromiseAllSettledResolveElementFunction::create(realm, index, values, result_capability, remaining_elements_count);
153
0
            on_fulfilled->define_direct_property(vm.names.name, PrimitiveString::create(vm, String {}), Attribute::Configurable);
154
155
            // s. Let stepsRejected be the algorithm steps defined in Promise.allSettled Reject Element Functions.
156
            // t. Let lengthRejected be the number of non-optional parameters of the function definition in Promise.allSettled Reject Element Functions.
157
            // u. Let onRejected be CreateBuiltinFunction(stepsRejected, lengthRejected, "", « [[AlreadyCalled]], [[Index]], [[Values]], [[Capability]], [[RemainingElements]] »).
158
            // v. Set onRejected.[[AlreadyCalled]] to alreadyCalled.
159
            // w. Set onRejected.[[Index]] to index.
160
            // x. Set onRejected.[[Values]] to values.
161
            // y. Set onRejected.[[Capability]] to resultCapability.
162
            // z. Set onRejected.[[RemainingElements]] to remainingElementsCount.
163
0
            auto on_rejected = PromiseAllSettledRejectElementFunction::create(realm, index, values, result_capability, remaining_elements_count);
164
0
            on_rejected->define_direct_property(vm.names.name, PrimitiveString::create(vm, String {}), Attribute::Configurable);
165
166
            // ab. Perform ? Invoke(nextPromise, "then", « onFulfilled, onRejected »).
167
0
            return next_promise.invoke(vm, vm.names.then, on_fulfilled, on_rejected);
168
0
        });
169
0
}
170
171
// 27.2.4.3.1 PerformPromiseAny ( iteratorRecord, constructor, resultCapability, promiseResolve ), https://tc39.es/ecma262/#sec-performpromiseany
172
static ThrowCompletionOr<Value> perform_promise_any(VM& vm, IteratorRecord& iterator_record, Value constructor, PromiseCapability& result_capability, Value promise_resolve)
173
0
{
174
0
    auto& realm = *vm.current_realm();
175
176
0
    return perform_promise_common(
177
0
        vm, iterator_record, constructor, result_capability, promise_resolve,
178
0
        [&](PromiseValueList& errors) -> ThrowCompletionOr<Value> {
179
            // 1. Let error be a newly created AggregateError object.
180
0
            auto error = AggregateError::create(realm);
181
182
            // 2. Perform ! DefinePropertyOrThrow(error, "errors", PropertyDescriptor { [[Configurable]]: true, [[Enumerable]]: false, [[Writable]]: true, [[Value]]: CreateArrayFromList(errors) }).
183
0
            auto errors_array = Array::create_from(realm, errors.values());
184
0
            MUST(error->define_property_or_throw(vm.names.errors, { .value = errors_array, .writable = true, .enumerable = false, .configurable = true }));
185
186
            // 3. Return ThrowCompletion(error).
187
0
            return throw_completion(error);
188
0
        },
189
0
        [&](PromiseValueList& errors, RemainingElements& remaining_elements_count, Value next_promise, size_t index) {
190
            // j. Let stepsRejected be the algorithm steps defined in Promise.any Reject Element Functions.
191
            // k. Let lengthRejected be the number of non-optional parameters of the function definition in Promise.any Reject Element Functions.
192
            // l. Let onRejected be CreateBuiltinFunction(stepsRejected, lengthRejected, "", « [[AlreadyCalled]], [[Index]], [[Errors]], [[Capability]], [[RemainingElements]] »).
193
            // m. Set onRejected.[[AlreadyCalled]] to false.
194
            // n. Set onRejected.[[Index]] to index.
195
            // o. Set onRejected.[[Errors]] to errors.
196
            // p. Set onRejected.[[Capability]] to resultCapability.
197
            // q. Set onRejected.[[RemainingElements]] to remainingElementsCount.
198
0
            auto on_rejected = PromiseAnyRejectElementFunction::create(realm, index, errors, result_capability, remaining_elements_count);
199
0
            on_rejected->define_direct_property(vm.names.name, PrimitiveString::create(vm, String {}), Attribute::Configurable);
200
201
            // s. Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], onRejected »).
202
0
            return next_promise.invoke(vm, vm.names.then, result_capability.resolve(), on_rejected);
203
0
        });
204
0
}
205
206
// 27.2.4.5.1 PerformPromiseRace ( iteratorRecord, constructor, resultCapability, promiseResolve ), https://tc39.es/ecma262/#sec-performpromiserace
207
static ThrowCompletionOr<Value> perform_promise_race(VM& vm, IteratorRecord& iterator_record, Value constructor, PromiseCapability const& result_capability, Value promise_resolve)
208
0
{
209
0
    return perform_promise_common(
210
0
        vm, iterator_record, constructor, result_capability, promise_resolve,
211
0
        [&](PromiseValueList&) -> ThrowCompletionOr<Value> {
212
            // ii. Return resultCapability.[[Promise]].
213
0
            return result_capability.promise();
214
0
        },
215
0
        [&](PromiseValueList&, RemainingElements&, Value next_promise, size_t) {
216
            // i. Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], resultCapability.[[Reject]] »).
217
0
            return next_promise.invoke(vm, vm.names.then, result_capability.resolve(), result_capability.reject());
218
0
        });
219
0
}
220
221
PromiseConstructor::PromiseConstructor(Realm& realm)
222
0
    : NativeFunction(realm.vm().names.Promise.as_string(), realm.intrinsics().function_prototype())
223
0
{
224
0
}
225
226
void PromiseConstructor::initialize(Realm& realm)
227
0
{
228
0
    auto& vm = this->vm();
229
0
    Base::initialize(realm);
230
231
    // 27.2.4.4 Promise.prototype, https://tc39.es/ecma262/#sec-promise.prototype
232
0
    define_direct_property(vm.names.prototype, realm.intrinsics().promise_prototype(), 0);
233
234
0
    u8 attr = Attribute::Writable | Attribute::Configurable;
235
0
    define_native_function(realm, vm.names.all, all, 1, attr);
236
0
    define_native_function(realm, vm.names.allSettled, all_settled, 1, attr);
237
0
    define_native_function(realm, vm.names.any, any, 1, attr);
238
0
    define_native_function(realm, vm.names.race, race, 1, attr);
239
0
    define_native_function(realm, vm.names.reject, reject, 1, attr);
240
0
    define_native_function(realm, vm.names.resolve, resolve, 1, attr);
241
0
    define_native_function(realm, vm.names.try_, try_, 1, attr);
242
0
    define_native_function(realm, vm.names.withResolvers, with_resolvers, 0, attr);
243
244
0
    define_native_accessor(realm, vm.well_known_symbol_species(), symbol_species_getter, {}, Attribute::Configurable);
245
246
0
    define_direct_property(vm.names.length, Value(1), Attribute::Configurable);
247
0
}
248
249
// 27.2.3.1 Promise ( executor ), https://tc39.es/ecma262/#sec-promise-executor
250
ThrowCompletionOr<Value> PromiseConstructor::call()
251
0
{
252
0
    auto& vm = this->vm();
253
254
    // 1. If NewTarget is undefined, throw a TypeError exception.
255
0
    return vm.throw_completion<TypeError>(ErrorType::ConstructorWithoutNew, vm.names.Promise);
256
0
}
257
258
// 27.2.3.1 Promise ( executor ), https://tc39.es/ecma262/#sec-promise-executor
259
ThrowCompletionOr<NonnullGCPtr<Object>> PromiseConstructor::construct(FunctionObject& new_target)
260
0
{
261
0
    auto& vm = this->vm();
262
263
0
    auto executor = vm.argument(0);
264
265
    // 2. If IsCallable(executor) is false, throw a TypeError exception.
266
0
    if (!executor.is_function())
267
0
        return vm.throw_completion<TypeError>(ErrorType::PromiseExecutorNotAFunction);
268
269
    // 3. Let promise be ? OrdinaryCreateFromConstructor(NewTarget, "%Promise.prototype%", « [[PromiseState]], [[PromiseResult]], [[PromiseFulfillReactions]], [[PromiseRejectReactions]], [[PromiseIsHandled]] »).
270
    // 4. Set promise.[[PromiseState]] to pending.
271
    // 5. Set promise.[[PromiseFulfillReactions]] to a new empty List.
272
    // 6. Set promise.[[PromiseRejectReactions]] to a new empty List.
273
    // 7. Set promise.[[PromiseIsHandled]] to false.
274
0
    auto promise = TRY(ordinary_create_from_constructor<Promise>(vm, new_target, &Intrinsics::promise_prototype));
275
276
    // 8. Let resolvingFunctions be CreateResolvingFunctions(promise).
277
0
    auto [resolve_function, reject_function] = promise->create_resolving_functions();
278
279
    // 9. Let completion be Completion(Call(executor, undefined, « resolvingFunctions.[[Resolve]], resolvingFunctions.[[Reject]] »)).
280
0
    auto completion = JS::call(vm, executor.as_function(), js_undefined(), resolve_function, reject_function);
281
282
    // 10. If completion is an abrupt completion, then
283
0
    if (completion.is_error()) {
284
        // a. Perform ? Call(resolvingFunctions.[[Reject]], undefined, « completion.[[Value]] »).
285
0
        TRY(JS::call(vm, *reject_function, js_undefined(), *completion.release_error().value()));
286
0
    }
287
288
    // 11. Return promise.
289
0
    return promise;
290
0
}
291
292
// 27.2.4.1 Promise.all ( iterable ), https://tc39.es/ecma262/#sec-promise.all
293
JS_DEFINE_NATIVE_FUNCTION(PromiseConstructor::all)
294
0
{
295
    // 1. Let C be the this value.
296
0
    auto constructor = TRY(vm.this_value().to_object(vm));
297
298
    // 2. Let promiseCapability be ? NewPromiseCapability(C).
299
0
    auto promise_capability = TRY(new_promise_capability(vm, constructor));
300
301
    // 3. Let promiseResolve be Completion(GetPromiseResolve(C)).
302
    // 4. IfAbruptRejectPromise(promiseResolve, promiseCapability).
303
0
    auto promise_resolve = TRY_OR_REJECT(vm, promise_capability, get_promise_resolve(vm, constructor));
304
305
    // 5. Let iteratorRecord be Completion(GetIterator(iterable, sync)).
306
    // 6. IfAbruptRejectPromise(iteratorRecord, promiseCapability).
307
0
    auto iterator_record = TRY_OR_REJECT(vm, promise_capability, get_iterator(vm, vm.argument(0), IteratorHint::Sync));
308
309
    // 7. Let result be Completion(PerformPromiseAll(iteratorRecord, C, promiseCapability, promiseResolve)).
310
0
    auto result = perform_promise_all(vm, iterator_record, constructor, promise_capability, promise_resolve);
311
312
    // 8. If result is an abrupt completion, then
313
0
    if (result.is_error()) {
314
        // a. If iteratorRecord.[[Done]] is false, set result to Completion(IteratorClose(iteratorRecord, result)).
315
0
        if (!iterator_record->done)
316
0
            result = iterator_close(vm, iterator_record, result.release_error());
317
318
        // b. IfAbruptRejectPromise(result, promiseCapability).
319
0
        TRY_OR_REJECT(vm, promise_capability, result);
320
0
    }
321
322
    // 9. Return ? result.
323
0
    return result;
324
0
}
325
326
// 27.2.4.2 Promise.allSettled ( iterable ), https://tc39.es/ecma262/#sec-promise.allsettled
327
JS_DEFINE_NATIVE_FUNCTION(PromiseConstructor::all_settled)
328
0
{
329
    // 1. Let C be the this value.
330
0
    auto constructor = TRY(vm.this_value().to_object(vm));
331
332
    // 2. Let promiseCapability be ? NewPromiseCapability(C).
333
0
    auto promise_capability = TRY(new_promise_capability(vm, constructor));
334
335
    // 3. Let promiseResolve be Completion(GetPromiseResolve(C)).
336
    // 4. IfAbruptRejectPromise(promiseResolve, promiseCapability).
337
0
    auto promise_resolve = TRY_OR_REJECT(vm, promise_capability, get_promise_resolve(vm, constructor));
338
339
    // 5. Let iteratorRecord be Completion(GetIterator(iterable, sync)).
340
    // 6. IfAbruptRejectPromise(iteratorRecord, promiseCapability).
341
0
    auto iterator_record = TRY_OR_REJECT(vm, promise_capability, get_iterator(vm, vm.argument(0), IteratorHint::Sync));
342
343
    // 7. Let result be Completion(PerformPromiseAllSettled(iteratorRecord, C, promiseCapability, promiseResolve)).
344
0
    auto result = perform_promise_all_settled(vm, iterator_record, constructor, promise_capability, promise_resolve);
345
346
    // 8. If result is an abrupt completion, then
347
0
    if (result.is_error()) {
348
        // a. If iteratorRecord.[[Done]] is false, set result to Completion(IteratorClose(iteratorRecord, result)).
349
0
        if (!iterator_record->done)
350
0
            result = iterator_close(vm, iterator_record, result.release_error());
351
352
        // b. IfAbruptRejectPromise(result, promiseCapability).
353
0
        TRY_OR_REJECT(vm, promise_capability, result);
354
0
    }
355
356
    // 9. Return ? result.
357
0
    return result;
358
0
}
359
360
// 27.2.4.3 Promise.any ( iterable ), https://tc39.es/ecma262/#sec-promise.any
361
JS_DEFINE_NATIVE_FUNCTION(PromiseConstructor::any)
362
0
{
363
    // 1. Let C be the this value.
364
0
    auto constructor = TRY(vm.this_value().to_object(vm));
365
366
    // 2. Let promiseCapability be ? NewPromiseCapability(C).
367
0
    auto promise_capability = TRY(new_promise_capability(vm, constructor));
368
369
    // 3. Let promiseResolve be Completion(GetPromiseResolve(C)).
370
    // 4. IfAbruptRejectPromise(promiseResolve, promiseCapability).
371
0
    auto promise_resolve = TRY_OR_REJECT(vm, promise_capability, get_promise_resolve(vm, constructor));
372
373
    // 5. Let iteratorRecord be Completion(GetIterator(iterable, sync)).
374
    // 6. IfAbruptRejectPromise(iteratorRecord, promiseCapability).
375
0
    auto iterator_record = TRY_OR_REJECT(vm, promise_capability, get_iterator(vm, vm.argument(0), IteratorHint::Sync));
376
377
    // 7. Let result be Completion(PerformPromiseAny(iteratorRecord, C, promiseCapability, promiseResolve)).
378
0
    auto result = perform_promise_any(vm, iterator_record, constructor, promise_capability, promise_resolve);
379
380
    // 8. If result is an abrupt completion, then
381
0
    if (result.is_error()) {
382
        // a. If iteratorRecord.[[Done]] is false, set result to Completion(IteratorClose(iteratorRecord, result)).
383
0
        if (!iterator_record->done)
384
0
            result = iterator_close(vm, iterator_record, result.release_error());
385
386
        // b. IfAbruptRejectPromise(result, promiseCapability).
387
0
        TRY_OR_REJECT(vm, promise_capability, result);
388
0
    }
389
390
    // 9. Return ? result.
391
0
    return result;
392
0
}
393
394
// 27.2.4.5 Promise.race ( iterable ), https://tc39.es/ecma262/#sec-promise.race
395
JS_DEFINE_NATIVE_FUNCTION(PromiseConstructor::race)
396
0
{
397
    // 1. Let C be the this value.
398
0
    auto constructor = TRY(vm.this_value().to_object(vm));
399
400
    // 2. Let promiseCapability be ? NewPromiseCapability(C).
401
0
    auto promise_capability = TRY(new_promise_capability(vm, constructor));
402
403
    // 3. Let promiseResolve be Completion(GetPromiseResolve(C)).
404
    // 4. IfAbruptRejectPromise(promiseResolve, promiseCapability).
405
0
    auto promise_resolve = TRY_OR_REJECT(vm, promise_capability, get_promise_resolve(vm, constructor));
406
407
    // 5. Let iteratorRecord be Completion(GetIterator(iterable, sync)).
408
    // 6. IfAbruptRejectPromise(iteratorRecord, promiseCapability).
409
0
    auto iterator_record = TRY_OR_REJECT(vm, promise_capability, get_iterator(vm, vm.argument(0), IteratorHint::Sync));
410
411
    // 7. Let result be Completion(PerformPromiseRace(iteratorRecord, C, promiseCapability, promiseResolve)).
412
0
    auto result = perform_promise_race(vm, iterator_record, constructor, promise_capability, promise_resolve);
413
414
    // 8. If result is an abrupt completion, then
415
0
    if (result.is_error()) {
416
        // a. If iteratorRecord.[[Done]] is false, set result to Completion(IteratorClose(iteratorRecord, result)).
417
0
        if (!iterator_record->done)
418
0
            result = iterator_close(vm, iterator_record, result.release_error());
419
420
        // b. IfAbruptRejectPromise(result, promiseCapability).
421
0
        TRY_OR_REJECT(vm, promise_capability, result);
422
0
    }
423
424
    // 9. Return ? result.
425
0
    return result;
426
0
}
427
428
// 27.2.4.6 Promise.reject ( r ), https://tc39.es/ecma262/#sec-promise.reject
429
JS_DEFINE_NATIVE_FUNCTION(PromiseConstructor::reject)
430
0
{
431
0
    auto reason = vm.argument(0);
432
433
    // 1. Let C be the this value.
434
0
    auto constructor = TRY(vm.this_value().to_object(vm));
435
436
    // 2. Let promiseCapability be ? NewPromiseCapability(C).
437
0
    auto promise_capability = TRY(new_promise_capability(vm, constructor));
438
439
    // 3. Perform ? Call(promiseCapability.[[Reject]], undefined, « r »).
440
0
    [[maybe_unused]] auto result = TRY(JS::call(vm, *promise_capability->reject(), js_undefined(), reason));
441
442
    // 4. Return promiseCapability.[[Promise]].
443
0
    return promise_capability->promise();
444
0
}
445
446
// 27.2.4.7 Promise.resolve ( x ), https://tc39.es/ecma262/#sec-promise.resolve
447
JS_DEFINE_NATIVE_FUNCTION(PromiseConstructor::resolve)
448
0
{
449
0
    auto value = vm.argument(0);
450
451
    // 1. Let C be the this value.
452
0
    auto constructor = vm.this_value();
453
454
    // 2. If Type(C) is not Object, throw a TypeError exception.
455
0
    if (!constructor.is_object())
456
0
        return vm.throw_completion<TypeError>(ErrorType::NotAnObject, constructor.to_string_without_side_effects());
457
458
    // 3. Return ? PromiseResolve(C, x).
459
0
    return TRY(promise_resolve(vm, constructor.as_object(), value));
460
0
}
461
462
// 27.2.4.8 Promise.try ( callback, ...args ), https://tc39.es/ecma262/#sec-promise.try
463
JS_DEFINE_NATIVE_FUNCTION(PromiseConstructor::try_)
464
0
{
465
0
    auto callback = vm.argument(0);
466
0
    Span<Value> args;
467
0
    if (vm.argument_count() > 1) {
468
0
        args = vm.running_execution_context().arguments.span().slice(1, vm.argument_count() - 1);
469
0
    }
470
471
    // 1. Let C be the this value.
472
0
    auto constructor = vm.this_value();
473
474
    // 2. If C is not an Object, throw a TypeError exception.
475
0
    if (!constructor.is_object())
476
0
        return vm.throw_completion<TypeError>(ErrorType::NotAnObject, constructor.to_string_without_side_effects());
477
478
    // 3. Let promiseCapability be ? NewPromiseCapability(C).
479
0
    auto promise_capability = TRY(new_promise_capability(vm, constructor));
480
481
    // 4. Let status be Completion(Call(callback, undefined, args)).
482
0
    auto status = JS::call(vm, callback, js_undefined(), args);
483
484
    // 5. If status is an abrupt completion, then
485
0
    if (status.is_throw_completion()) {
486
        // a. Perform ? Call(promiseCapability.[[Reject]], undefined, « status.[[Value]] »).
487
0
        TRY(JS::call(vm, *promise_capability->reject(), js_undefined(), *status.throw_completion().value()));
488
0
    }
489
    // 6. Else,
490
0
    else {
491
        // a. Perform ? Call(promiseCapability.[[Resolve]], undefined, « status.[[Value]] »).
492
0
        TRY(JS::call(vm, *promise_capability->resolve(), js_undefined(), status.value()));
493
0
    }
494
495
    // 7. Return promiseCapability.[[Promise]].
496
0
    return promise_capability->promise();
497
0
}
498
499
// 27.2.4.9 Promise.withResolvers ( ), https://tc39.es/ecma262/#sec-promise.withResolvers
500
JS_DEFINE_NATIVE_FUNCTION(PromiseConstructor::with_resolvers)
501
0
{
502
0
    auto& realm = *vm.current_realm();
503
504
    // 1. Let C be the this value.
505
0
    auto constructor = vm.this_value();
506
507
    // 2. Let promiseCapability be ? NewPromiseCapability(C).
508
0
    auto promise_capability = TRY(new_promise_capability(vm, constructor));
509
510
    // 3. Let obj be OrdinaryObjectCreate(%Object.prototype%).
511
0
    auto object = Object::create(realm, realm.intrinsics().object_prototype());
512
513
    // 4. Perform ! CreateDataPropertyOrThrow(obj, "promise", promiseCapability.[[Promise]]).
514
0
    MUST(object->create_data_property_or_throw(vm.names.promise, promise_capability->promise()));
515
516
    // 5. Perform ! CreateDataPropertyOrThrow(obj, "resolve", promiseCapability.[[Resolve]]).
517
0
    MUST(object->create_data_property_or_throw(vm.names.resolve, promise_capability->resolve()));
518
519
    // 6. Perform ! CreateDataPropertyOrThrow(obj, "reject", promiseCapability.[[Reject]]).
520
0
    MUST(object->create_data_property_or_throw(vm.names.reject, promise_capability->reject()));
521
522
    // 7. Return obj.
523
0
    return object;
524
0
}
525
526
// 27.2.4.10 get Promise [ @@species ], https://tc39.es/ecma262/#sec-get-promise-@@species
527
JS_DEFINE_NATIVE_FUNCTION(PromiseConstructor::symbol_species_getter)
528
0
{
529
    // 1. Return the this value.
530
0
    return vm.this_value();
531
0
}
532
533
}