@@ -24,6 +24,7 @@ use crate::{
24
24
promise_objects:: {
25
25
promise_abstract_operations:: {
26
26
promise_all_record:: PromiseAllRecord ,
27
+ promise_all_settled_record:: PromiseAllSettledRecord ,
27
28
promise_capability_records:: if_abrupt_reject_promise_m,
28
29
promise_reaction_records:: PromiseReactionHandler ,
29
30
} ,
@@ -350,11 +351,115 @@ impl PromiseConstructor {
350
351
/// > constructor.
351
352
fn all_settled < ' gc > (
352
353
agent : & mut Agent ,
353
- _this_value : Value ,
354
- _arguments : ArgumentsList ,
355
- gc : GcScope < ' gc , ' _ > ,
354
+ this_value : Value ,
355
+ arguments : ArgumentsList ,
356
+ mut gc : GcScope < ' gc , ' _ > ,
356
357
) -> JsResult < ' gc , Value < ' gc > > {
357
- Err ( agent. todo ( "Promise.allSettled" , gc. into_nogc ( ) ) )
358
+ let this_value = this_value. bind ( gc. nogc ( ) ) ;
359
+ let arguments = arguments. bind ( gc. nogc ( ) ) ;
360
+ let iterable = arguments. get ( 0 ) . scope ( agent, gc. nogc ( ) ) ;
361
+
362
+ // 1. Let C be the this value.
363
+ if this_value
364
+ != agent
365
+ . current_realm_record ( )
366
+ . intrinsics ( )
367
+ . promise ( )
368
+ . into_value ( )
369
+ {
370
+ return Err ( throw_promise_subclassing_not_supported (
371
+ agent,
372
+ gc. into_nogc ( ) ,
373
+ ) ) ;
374
+ }
375
+
376
+ // 2. Let promiseCapability be ? NewPromiseCapability(C).
377
+ let Some ( constructor) = is_constructor ( agent, this_value) else {
378
+ return Err ( agent. throw_exception_with_static_message (
379
+ ExceptionType :: TypeError ,
380
+ "Expected the this value to be a constructor." ,
381
+ gc. into_nogc ( ) ,
382
+ ) ) ;
383
+ } ;
384
+ let constructor = constructor. scope ( agent, gc. nogc ( ) ) ;
385
+ let promise_capability = PromiseCapability :: new ( agent, gc. nogc ( ) ) ;
386
+ let promise = promise_capability. promise ( ) . scope ( agent, gc. nogc ( ) ) ;
387
+
388
+ // 3. Let promiseResolve be Completion(GetPromiseResolve(C)).
389
+ let promise_resolve = get_promise_resolve ( agent, constructor. get ( agent) , gc. reborrow ( ) )
390
+ . unbind ( )
391
+ . bind ( gc. nogc ( ) ) ;
392
+
393
+ // 4. IfAbruptRejectPromise(promiseResolve, promiseCapability).
394
+ let promise_capability = PromiseCapability {
395
+ promise : promise. get ( agent) . bind ( gc. nogc ( ) ) ,
396
+ must_be_unresolved : true ,
397
+ } ;
398
+ let promise_resolve =
399
+ if_abrupt_reject_promise_m ! ( agent, promise_resolve, promise_capability, gc) ;
400
+ let promise_resolve = promise_resolve. scope ( agent, gc. nogc ( ) ) ;
401
+
402
+ // 5. Let iteratorRecord be Completion(GetIterator(iterable, sync)).
403
+ let iterator_record = get_iterator ( agent, iterable. get ( agent) , false , gc. reborrow ( ) )
404
+ . unbind ( )
405
+ . bind ( gc. nogc ( ) ) ;
406
+
407
+ // 6. IfAbruptRejectPromise(iteratorRecord, promiseCapability).
408
+ let promise_capability = PromiseCapability {
409
+ promise : promise. get ( agent) . bind ( gc. nogc ( ) ) ,
410
+ must_be_unresolved : true ,
411
+ } ;
412
+ let MaybeInvalidIteratorRecord {
413
+ iterator,
414
+ next_method,
415
+ } = if_abrupt_reject_promise_m ! ( agent, iterator_record, promise_capability, gc) ;
416
+
417
+ let iterator = iterator. scope ( agent, gc. nogc ( ) ) ;
418
+
419
+ // 7. Let result be Completion(PerformPromiseAll(iteratorRecord, C, promiseCapability, promiseResolve)).
420
+ let mut iterator_done = false ;
421
+ let result = perform_promise_all_settled (
422
+ agent,
423
+ iterator. clone ( ) ,
424
+ next_method. unbind ( ) ,
425
+ constructor,
426
+ promise_capability. unbind ( ) ,
427
+ promise_resolve,
428
+ & mut iterator_done,
429
+ gc. reborrow ( ) ,
430
+ )
431
+ . unbind ( )
432
+ . bind ( gc. nogc ( ) ) ;
433
+
434
+ // 8. If result is an abrupt completion, then
435
+ let result = match result {
436
+ Err ( mut result) => {
437
+ // a. If iteratorRecord.[[Done]] is false, set result to Completion(IteratorClose(iteratorRecord, result)).
438
+ if !iterator_done {
439
+ result = iterator_close_with_error (
440
+ agent,
441
+ iterator. get ( agent) ,
442
+ result. unbind ( ) ,
443
+ gc. reborrow ( ) ,
444
+ )
445
+ . unbind ( )
446
+ . bind ( gc. nogc ( ) ) ;
447
+ }
448
+
449
+ // b. IfAbruptRejectPromise(result, promiseCapability).
450
+ let promise_capability = PromiseCapability {
451
+ promise : promise. get ( agent) . bind ( gc. nogc ( ) ) ,
452
+ must_be_unresolved : true ,
453
+ } ;
454
+ // a. Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
455
+ promise_capability. reject ( agent, result. value ( ) . unbind ( ) , gc. nogc ( ) ) ;
456
+ // b. Return capability.[[Promise]].
457
+ promise_capability. promise ( )
458
+ }
459
+ Ok ( result) => result,
460
+ } ;
461
+ // 9. Return ! result.
462
+ Ok ( result. into_value ( ) . unbind ( ) )
358
463
}
359
464
360
465
/// ### [27.2.4.3 Promise.any ( iterable )](https://tc39.es/ecma262/#sec-promise.any)
@@ -801,6 +906,150 @@ fn perform_promise_all<'gc>(
801
906
}
802
907
}
803
908
909
+ /// ### [27.2.4.2.1 PerformPromiseAllSettled ( iteratorRecord, constructor, resultCapability, promiseResolve )](https://tc39.es/ecma262/#sec-performpromiseallsettled)
910
+ #[ allow( clippy:: too_many_arguments) ]
911
+ fn perform_promise_all_settled < ' gc > (
912
+ agent : & mut Agent ,
913
+ iterator : Scoped < Object > ,
914
+ next_method : Option < Function > ,
915
+ constructor : Scoped < Function > ,
916
+ result_capability : PromiseCapability ,
917
+ promise_resolve : Scoped < Function > ,
918
+ iterator_done : & mut bool ,
919
+ mut gc : GcScope < ' gc , ' _ > ,
920
+ ) -> JsResult < ' gc , Promise < ' gc > > {
921
+ let result_capability = result_capability. bind ( gc. nogc ( ) ) ;
922
+
923
+ let Some ( next_method) = next_method else {
924
+ return Err ( throw_not_callable ( agent, gc. into_nogc ( ) ) ) ;
925
+ } ;
926
+
927
+ let next_method = next_method. scope ( agent, gc. nogc ( ) ) ;
928
+
929
+ // 1. Let values be a new empty List.
930
+ let capacity = match iterator. get ( agent) {
931
+ Object :: Array ( array) => array. len ( agent) ,
932
+ Object :: Map ( map) => agent[ map] . size ( ) ,
933
+ Object :: Set ( set) => agent[ set] . size ( ) ,
934
+ _ => 0 ,
935
+ } ;
936
+
937
+ let result_array = array_create ( agent, 0 , capacity as usize , None , gc. nogc ( ) )
938
+ . unbind ( ) ?
939
+ . bind ( gc. nogc ( ) ) ;
940
+ let result_array = result_array. scope ( agent, gc. nogc ( ) ) ;
941
+
942
+ // 2. Let remainingElementsCount be the Record { [[Value]]: 1 }.
943
+ let promise = result_capability. promise . scope ( agent, gc. nogc ( ) ) ;
944
+ let promise_all_settled_reference = agent
945
+ . heap
946
+ . create ( PromiseAllSettledRecord {
947
+ remaining_elements_count : 1 ,
948
+ result_array : result_array. get ( agent) ,
949
+ promise : promise. get ( agent) ,
950
+ } )
951
+ . scope ( agent, gc. nogc ( ) ) ;
952
+
953
+ // 3. Let index be 0.
954
+ let mut index = 0 ;
955
+
956
+ // 4. Repeat,
957
+ loop {
958
+ let iterator_record = IteratorRecord {
959
+ iterator : iterator. get ( agent) ,
960
+ next_method : next_method. get ( agent) ,
961
+ }
962
+ . bind ( gc. nogc ( ) ) ;
963
+
964
+ // a. Let next be ? IteratorStepValue(iteratorRecord).
965
+ let next = iterator_step_value ( agent, iterator_record. unbind ( ) , gc. reborrow ( ) )
966
+ . unbind ( ) ?
967
+ . bind ( gc. nogc ( ) ) ;
968
+
969
+ // b. If next is done, then
970
+ let Some ( next) = next else {
971
+ * iterator_done = true ;
972
+ let promise_all = promise_all_settled_reference. get ( agent) . bind ( gc. nogc ( ) ) ;
973
+ let data = promise_all. get_mut ( agent) ;
974
+ // i. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] - 1.
975
+ data. remaining_elements_count -= 1 ;
976
+ // ii. If remainingElementsCount.[[Value]] = 0, then
977
+ if data. remaining_elements_count == 0 {
978
+ // 1. Let valuesArray be CreateArrayFromList(values).
979
+ let values_array = result_array. get ( agent) . bind ( gc. nogc ( ) ) ;
980
+ // 2. Perform ? Call(resultCapability.[[Resolve]], undefined, « valuesArray »).
981
+ let result_capability = PromiseCapability {
982
+ promise : promise. get ( agent) . bind ( gc. nogc ( ) ) ,
983
+ must_be_unresolved : true ,
984
+ } ;
985
+ result_capability. unbind ( ) . resolve (
986
+ agent,
987
+ values_array. into_value ( ) . unbind ( ) ,
988
+ gc. reborrow ( ) ,
989
+ ) ;
990
+ }
991
+
992
+ // iii. Return resultCapability.[[Promise]].
993
+ return Ok ( promise. get ( agent) ) ;
994
+ } ;
995
+
996
+ // c. Append undefined to values.
997
+ let temp_array = result_array. get ( agent) . bind ( gc. nogc ( ) ) ;
998
+ if let Err ( err) = temp_array. reserve ( agent, 1 ) {
999
+ return Err ( agent. throw_allocation_exception ( err, gc. into_nogc ( ) ) ) ;
1000
+ }
1001
+ // SAFETY: reserve did not fail.
1002
+ unsafe { temp_array. set_len ( agent, index + 1 ) } ;
1003
+
1004
+ // d. Let nextPromise be ? Call(promiseResolve, constructor, « next »).
1005
+ let call_result = call_function (
1006
+ agent,
1007
+ promise_resolve. get ( agent) ,
1008
+ constructor. get ( agent) . into_value ( ) ,
1009
+ Some ( ArgumentsList :: from_mut_value ( & mut next. unbind ( ) ) ) ,
1010
+ gc. reborrow ( ) ,
1011
+ )
1012
+ . unbind ( ) ?
1013
+ . bind ( gc. nogc ( ) ) ;
1014
+
1015
+ // Note: as we don't yet support Promise subclassing, if we see a
1016
+ // non-Promise return we wrap it inside a resolved Promise to get
1017
+ // then-chaining.
1018
+ let next_promise = match call_result {
1019
+ Value :: Promise ( next_promise) => next_promise,
1020
+ _ => Promise :: new_resolved ( agent, call_result) ,
1021
+ } ;
1022
+
1023
+ // e. Let steps be the algorithm steps defined in Promise.all Resolve Element Functions.
1024
+ // f. Let length be the number of non-optional parameters of the function definition in Promise.all Resolve Element Functions.
1025
+ // g. Let onFulfilled be CreateBuiltinFunction(steps, length, "", « [[AlreadyCalled]], [[Index]], [[Values]], [[Capability]], [[RemainingElements]] »).
1026
+ // h. Set onFulfilled.[[AlreadyCalled]] to false.
1027
+ // i. Set onFulfilled.[[Index]] to index.
1028
+ // j. Set onFulfilled.[[Values]] to values.
1029
+ let promise_all_settled = promise_all_settled_reference. get ( agent) . bind ( gc. nogc ( ) ) ;
1030
+ let reaction = PromiseReactionHandler :: PromiseAllSettled {
1031
+ index,
1032
+ promise_all_settled,
1033
+ } ;
1034
+ // k. Set onFulfilled.[[Capability]] to resultCapability.
1035
+ // l. Set onFulfilled.[[RemainingElements]] to remainingElementsCount.
1036
+ // m. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] + 1.
1037
+ promise_all_settled. get_mut ( agent) . remaining_elements_count += 1 ;
1038
+ // n. Perform ? Invoke(nextPromise, "then", « onFulfilled, resultCapability.[[Reject]] »).
1039
+ inner_promise_then (
1040
+ agent,
1041
+ next_promise. unbind ( ) ,
1042
+ reaction. unbind ( ) ,
1043
+ reaction. unbind ( ) ,
1044
+ None ,
1045
+ gc. nogc ( ) ,
1046
+ ) ;
1047
+
1048
+ // o. Set index to index + 1.
1049
+ index += 1 ;
1050
+ }
1051
+ }
1052
+
804
1053
fn throw_promise_subclassing_not_supported < ' a > (
805
1054
agent : & mut Agent ,
806
1055
gc : NoGcScope < ' a , ' _ > ,
0 commit comments