Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
use crate::{
ecmascript::{
abstract_operations::operations_on_objects::define_property_or_throw,
builtins::{
Array,
error::ErrorHeapData,
promise::Promise,
promise_objects::promise_abstract_operations::{
promise_capability_records::PromiseCapability,
promise_reaction_records::PromiseReactionType,
},
},
execution::Agent,
types::{BUILTIN_STRING_MEMORY, IntoValue, OrdinaryObject, Value},
execution::{Agent, agent::ExceptionType},
types::{BUILTIN_STRING_MEMORY, IntoValue, OrdinaryObject, PropertyDescriptor, Value},
},
engine::{
context::{Bindable, GcScope, NoGcScope, bindable_handle},
Expand All @@ -23,8 +25,9 @@ use crate::{

#[derive(Debug, Clone, Copy)]
pub enum PromiseGroupType {
PromiseAll,
PromiseAllSettled,
All,
AllSettled,
Any,
}

#[derive(Debug, Clone, Copy)]
Expand Down Expand Up @@ -64,30 +67,32 @@ impl<'a> PromiseGroup<'a> {
let record = self.get(agent);

match record.promise_group_type {
PromiseGroupType::PromiseAll => match reaction_type {
PromiseGroupType::All => match reaction_type {
PromiseReactionType::Fulfill => {
self.fulfill(agent, index, value.unbind(), gc.reborrow());
}
PromiseReactionType::Reject => {
self.reject(agent, value.unbind(), gc.nogc());
self.immediately_reject(agent, value.unbind(), gc.nogc());
}
},
PromiseGroupType::PromiseAllSettled => {
PromiseGroupType::AllSettled => {
let obj = self
.to_all_settled_obj(agent, reaction_type, value.unbind(), gc.nogc())
.bind(gc.nogc());
self.fulfill(agent, index, obj.unbind(), gc.reborrow());
}
PromiseGroupType::Any => match reaction_type {
PromiseReactionType::Fulfill => {
self.immediately_resolve(agent, value.unbind(), gc.reborrow());
}
PromiseReactionType::Reject => {
self.reject(agent, index, value.unbind(), gc.reborrow());
}
},
}
}

pub(crate) fn fulfill(
self,
agent: &mut Agent,
index: u32,
value: Value<'a>,
mut gc: GcScope<'a, '_>,
) {
fn fulfill(self, agent: &mut Agent, index: u32, value: Value<'a>, mut gc: GcScope<'a, '_>) {
let promise_group = self.bind(gc.nogc());
let value = value.bind(gc.nogc());

Expand All @@ -98,17 +103,72 @@ impl<'a> PromiseGroup<'a> {
elements[index as usize] = Some(value.unbind());

if let Some(promise_to_resolve) = promise_to_resolve {
promise_group.pop_empty_records(agent);

let capability = PromiseCapability::from_promise(promise_to_resolve, true);
capability.resolve(agent, result_array.into_value().unbind(), gc.reborrow());
}
}

pub(crate) fn reject(self, agent: &mut Agent, value: Value<'a>, gc: NoGcScope<'a, '_>) {
fn reject(self, agent: &mut Agent, index: u32, error: Value<'a>, mut gc: GcScope<'a, '_>) {
let promise_group = self.bind(gc.nogc());
let error = error.bind(gc.nogc());

let promise_group_record = promise_group.get_mut(agent);
let (result_array, promise_to_resolve) = promise_group_record.take_result_and_promise();

let elements = result_array.as_mut_slice(agent);
elements[index as usize] = Some(error.unbind());

if let Some(promise_to_resolve) = promise_to_resolve {
promise_group.pop_empty_records(agent);

let aggregate_error = agent.heap.create(ErrorHeapData::new(
ExceptionType::AggregateError,
None,
None,
));

let capability = PromiseCapability::from_promise(promise_to_resolve, true);
define_property_or_throw(
agent,
aggregate_error,
BUILTIN_STRING_MEMORY.errors.into(),
PropertyDescriptor {
value: Some(result_array.into_value().unbind()),
writable: Some(true),
get: None,
set: None,
enumerable: Some(true),
configurable: Some(true),
},
gc.reborrow(),
)
.unwrap();

capability.reject(agent, aggregate_error.into_value(), gc.nogc());
}
}

fn immediately_resolve(self, agent: &mut Agent, value: Value<'a>, gc: GcScope<'a, '_>) {
let value = value.bind(gc.nogc());
let promise_group = self.bind(gc.nogc());
let data = promise_group.get_mut(agent);

let capability = PromiseCapability::from_promise(data.promise, true);

promise_group.pop_empty_records(agent);
capability.resolve(agent, value.unbind(), gc);
}

fn immediately_reject(self, agent: &mut Agent, value: Value<'a>, gc: NoGcScope<'a, '_>) {
let value = value.bind(gc);
let promise_group = self.bind(gc);
let data = promise_group.get_mut(agent);

let capability = PromiseCapability::from_promise(data.promise, true);

promise_group.pop_empty_records(agent);
capability.reject(agent, value.unbind(), gc);
}

Expand All @@ -121,47 +181,35 @@ impl<'a> PromiseGroup<'a> {
) -> Value<'a> {
let value = value.bind(gc);

let obj = match reaction_type {
PromiseReactionType::Fulfill => OrdinaryObject::create_object(
agent,
Some(
agent
.current_realm_record()
.intrinsics()
.object_prototype()
.into(),
),
&[
ObjectEntry::new_data_entry(
BUILTIN_STRING_MEMORY.status.into(),
BUILTIN_STRING_MEMORY.fulfilled.into(),
),
ObjectEntry::new_data_entry(BUILTIN_STRING_MEMORY.value.into(), value.unbind()),
],
)
.bind(gc),
PromiseReactionType::Reject => OrdinaryObject::create_object(
agent,
Some(
agent
.current_realm_record()
.intrinsics()
.object_prototype()
.into(),
),
&[
ObjectEntry::new_data_entry(
BUILTIN_STRING_MEMORY.status.into(),
BUILTIN_STRING_MEMORY.rejected.into(),
),
ObjectEntry::new_data_entry(
BUILTIN_STRING_MEMORY.reason.into(),
value.unbind(),
),
],
)
.bind(gc),
};
let entries = vec![
ObjectEntry::new_data_entry(
BUILTIN_STRING_MEMORY.status.into(),
match reaction_type {
PromiseReactionType::Fulfill => BUILTIN_STRING_MEMORY.fulfilled.into(),
PromiseReactionType::Reject => BUILTIN_STRING_MEMORY.rejected.into(),
},
),
ObjectEntry::new_data_entry(
match reaction_type {
PromiseReactionType::Fulfill => BUILTIN_STRING_MEMORY.value.into(),
PromiseReactionType::Reject => BUILTIN_STRING_MEMORY.reason.into(),
},
value.unbind(),
),
];

let obj = OrdinaryObject::create_object(
agent,
Some(
agent
.current_realm_record()
.intrinsics()
.object_prototype()
.into(),
),
&entries,
)
.bind(gc);

obj.into_value().unbind()
}
Expand All @@ -186,6 +234,16 @@ impl<'a> PromiseGroup<'a> {
.expect("PromiseGroupRecord not found")
}

fn pop_empty_records(self, agent: &mut Agent) {
while let Some(last) = agent.heap.promise_group_records.last() {
if last.remaining_elements_count == 0 {
agent.heap.promise_group_records.pop();
} else {
break;
}
}
}

pub(crate) const _DEF: Self = { Self(BaseIndex::from_u32_index(0)) };
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,13 +236,7 @@ impl PromiseConstructor {
arguments: ArgumentsList,
gc: GcScope<'gc, '_>,
) -> JsResult<'gc, Value<'gc>> {
promise_group(
agent,
this_value,
arguments,
PromiseGroupType::PromiseAll,
gc,
)
promise_group(agent, this_value, arguments, PromiseGroupType::All, gc)
}

/// ### [27.2.4.2 Promise.allSettled ( iterable )](https://tc39.es/ecma262/#sec-promise.allsettled)
Expand All @@ -260,7 +254,7 @@ impl PromiseConstructor {
agent,
this_value,
arguments,
PromiseGroupType::PromiseAllSettled,
PromiseGroupType::AllSettled,
gc,
)
}
Expand All @@ -272,11 +266,11 @@ impl PromiseConstructor {
/// > constructor.
fn any<'gc>(
agent: &mut Agent,
_this_value: Value,
_arguments: ArgumentsList,
this_value: Value,
arguments: ArgumentsList,
gc: GcScope<'gc, '_>,
) -> JsResult<'gc, Value<'gc>> {
Err(agent.todo("Promise.any", gc.into_nogc()))
promise_group(agent, this_value, arguments, PromiseGroupType::Any, gc)
}

/// ### [27.2.4.5 Promise.race ( iterable )](https://tc39.es/ecma262/#sec-promise.race)
Expand Down Expand Up @@ -685,6 +679,7 @@ fn promise_group<'gc>(

/// ### [27.2.4.1.2 PerformPromiseAll ( iteratorRecord, constructor, resultCapability, promiseResolve )](https://tc39.es/ecma262/#sec-performpromiseall)
/// ### [27.2.4.2.1 PerformPromiseAllSettled ( iteratorRecord, constructor, resultCapability, promiseResolve )](https://tc39.es/ecma262/#sec-performpromiseallsettled)
/// ### [27.2.4.3.1 PerformPromiseAny ( iteratorRecord, constructor, resultCapability, promiseResolve )](https://tc39.es/ecma262/#sec-performpromiseany)
#[allow(clippy::too_many_arguments)]
fn perform_promise_group<'gc>(
agent: &mut Agent,
Expand Down
57 changes: 4 additions & 53 deletions tests/expectations.json
Original file line number Diff line number Diff line change
Expand Up @@ -1249,82 +1249,33 @@
"built-ins/Promise/any/ctx-ctor.js": "FAIL",
"built-ins/Promise/any/ctx-non-ctor.js": "FAIL",
"built-ins/Promise/any/ctx-non-object.js": "FAIL",
"built-ins/Promise/any/invoke-resolve-error-close.js": "FAIL",
"built-ins/Promise/any/invoke-resolve-error-reject.js": "FAIL",
"built-ins/Promise/any/invoke-resolve-get-error-reject.js": "FAIL",
"built-ins/Promise/any/invoke-resolve-get-error.js": "FAIL",
"built-ins/Promise/any/invoke-resolve-get-once-multiple-calls.js": "FAIL",
"built-ins/Promise/any/invoke-resolve-get-once-no-calls.js": "FAIL",
"built-ins/Promise/any/invoke-resolve-on-promises-every-iteration-of-custom.js": "FAIL",
"built-ins/Promise/any/invoke-resolve-on-promises-every-iteration-of-promise.js": "FAIL",
"built-ins/Promise/any/invoke-resolve-on-values-every-iteration-of-custom.js": "FAIL",
"built-ins/Promise/any/invoke-resolve-on-values-every-iteration-of-promise.js": "FAIL",
"built-ins/Promise/any/invoke-resolve-return.js": "FAIL",
"built-ins/Promise/any/invoke-resolve.js": "FAIL",
"built-ins/Promise/any/invoke-then-error-close.js": "FAIL",
"built-ins/Promise/any/invoke-then-error-close.js": "TIMEOUT",
"built-ins/Promise/any/invoke-then-error-reject.js": "FAIL",
"built-ins/Promise/any/invoke-then-get-error-close.js": "FAIL",
"built-ins/Promise/any/invoke-then-get-error-close.js": "TIMEOUT",
"built-ins/Promise/any/invoke-then-get-error-reject.js": "FAIL",
"built-ins/Promise/any/invoke-then-on-promises-every-iteration.js": "FAIL",
"built-ins/Promise/any/invoke-then.js": "FAIL",
"built-ins/Promise/any/invoke-then.js": "UNRESOLVED",
"built-ins/Promise/any/iter-arg-is-empty-iterable-reject.js": "FAIL",
"built-ins/Promise/any/iter-arg-is-empty-string-reject.js": "FAIL",
"built-ins/Promise/any/iter-arg-is-error-object-reject.js": "FAIL",
"built-ins/Promise/any/iter-arg-is-false-reject.js": "FAIL",
"built-ins/Promise/any/iter-arg-is-null-reject.js": "FAIL",
"built-ins/Promise/any/iter-arg-is-number-reject.js": "FAIL",
"built-ins/Promise/any/iter-arg-is-poisoned.js": "FAIL",
"built-ins/Promise/any/iter-arg-is-string-resolve.js": "FAIL",
"built-ins/Promise/any/iter-arg-is-symbol-reject.js": "FAIL",
"built-ins/Promise/any/iter-arg-is-true-reject.js": "FAIL",
"built-ins/Promise/any/iter-arg-is-undefined-reject.js": "FAIL",
"built-ins/Promise/any/iter-assigned-false-reject.js": "FAIL",
"built-ins/Promise/any/iter-assigned-null-reject.js": "FAIL",
"built-ins/Promise/any/iter-assigned-number-reject.js": "FAIL",
"built-ins/Promise/any/iter-assigned-string-reject.js": "FAIL",
"built-ins/Promise/any/iter-assigned-symbol-reject.js": "FAIL",
"built-ins/Promise/any/iter-assigned-true-reject.js": "FAIL",
"built-ins/Promise/any/iter-assigned-undefined-reject.js": "FAIL",
"built-ins/Promise/any/iter-next-val-err-no-close.js": "FAIL",
"built-ins/Promise/any/iter-next-val-err-reject.js": "FAIL",
"built-ins/Promise/any/iter-returns-false-reject.js": "FAIL",
"built-ins/Promise/any/iter-returns-null-reject.js": "FAIL",
"built-ins/Promise/any/iter-returns-number-reject.js": "FAIL",
"built-ins/Promise/any/iter-returns-string-reject.js": "FAIL",
"built-ins/Promise/any/iter-returns-symbol-reject.js": "FAIL",
"built-ins/Promise/any/iter-returns-true-reject.js": "FAIL",
"built-ins/Promise/any/iter-returns-undefined-reject.js": "FAIL",
"built-ins/Promise/any/iter-step-err-no-close.js": "FAIL",
"built-ins/Promise/any/iter-step-err-reject.js": "FAIL",
"built-ins/Promise/any/new-reject-function.js": "FAIL",
"built-ins/Promise/any/reject-all-mixed.js": "FAIL",
"built-ins/Promise/any/reject-deferred.js": "FAIL",
"built-ins/Promise/any/reject-element-function-extensible.js": "FAIL",
"built-ins/Promise/any/reject-element-function-length.js": "FAIL",
"built-ins/Promise/any/reject-element-function-name.js": "FAIL",
"built-ins/Promise/any/reject-element-function-nonconstructor.js": "FAIL",
"built-ins/Promise/any/reject-element-function-property-order.js": "FAIL",
"built-ins/Promise/any/reject-element-function-prototype.js": "FAIL",
"built-ins/Promise/any/reject-from-same-thenable.js": "FAIL",
"built-ins/Promise/any/reject-ignored-immed.js": "FAIL",
"built-ins/Promise/any/reject-immed.js": "FAIL",
"built-ins/Promise/any/resolve-before-loop-exit-from-same.js": "FAIL",
"built-ins/Promise/any/resolve-before-loop-exit.js": "FAIL",
"built-ins/Promise/any/resolve-from-reject-catch.js": "FAIL",
"built-ins/Promise/any/resolve-from-resolve-reject-catch.js": "FAIL",
"built-ins/Promise/any/resolve-from-same-thenable.js": "FAIL",
"built-ins/Promise/any/resolve-ignores-late-rejection-deferred.js": "FAIL",
"built-ins/Promise/any/resolve-ignores-late-rejection.js": "FAIL",
"built-ins/Promise/any/resolve-non-callable.js": "FAIL",
"built-ins/Promise/any/resolve-non-thenable.js": "FAIL",
"built-ins/Promise/any/resolve-not-callable-reject-with-typeerror.js": "FAIL",
"built-ins/Promise/any/resolve-throws-iterator-return-is-not-callable.js": "FAIL",
"built-ins/Promise/any/resolve-throws-iterator-return-null-or-undefined.js": "FAIL",
"built-ins/Promise/any/resolved-sequence-extra-ticks.js": "FAIL",
"built-ins/Promise/any/resolved-sequence-mixed.js": "FAIL",
"built-ins/Promise/any/resolved-sequence-with-rejections.js": "FAIL",
"built-ins/Promise/any/resolved-sequence.js": "FAIL",
"built-ins/Promise/any/returns-promise.js": "FAIL",
"built-ins/Promise/any/species-get-error.js": "FAIL",
"built-ins/Promise/exception-after-resolve-in-thenable-job.js": "FAIL",
"built-ins/Promise/executor-function-extensible.js": "FAIL",
Expand Down Expand Up @@ -8111,4 +8062,4 @@
"staging/sm/syntax/yield-as-identifier.js": "FAIL",
"staging/source-phase-imports/import-source-source-text-module.js": "FAIL",
"staging/top-level-await/tla-hang-entry.js": "FAIL"
}
}
Loading
Loading