Skip to content
Open
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
Expand Up @@ -409,11 +409,28 @@ pub(crate) fn async_generator_await_return(
// a. Perform AsyncGeneratorCompleteStep(generator, promiseCompletion, true).
// b. Perform AsyncGeneratorDrainQueue(generator).
// c. Return unused.
let return_value = value.unbind().bind(gc.nogc());
let promise_completion = Promise::resolve_maybe_abrupt(agent, return_value.unbind(), gc.reborrow())
.map(|promise| promise.unbind())
.map_err(|err| err.unbind());
let promise = match promise_completion {
Err(err) => {
let generator = scoped_generator.get(agent).bind(gc.nogc());
async_generator_complete_step(
agent,
generator.unbind(),
AsyncGeneratorRequestCompletion::Err(err.unbind()),
true,
None,
gc.nogc(),
);
async_generator_drain_queue(agent, scoped_generator, gc);
return;
}
Ok(promise) => promise.unbind().bind(gc.nogc()),
};
// 9. Assert: promiseCompletion is a normal completion.
// 10. Let promise be promiseCompletion.[[Value]].
let promise = Promise::resolve(agent, value.unbind(), gc.reborrow())
.unbind()
.bind(gc.nogc());
// 11. ... onFulfilled ...
// 12. Let onFulfilled be CreateBuiltinFunction(fulfilledClosure, 1, "", « »).
// 13. ... onRejected ...
Expand Down
43 changes: 41 additions & 2 deletions nova_vm/src/ecmascript/builtins/promise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ pub(crate) use data::*;

use crate::{
ecmascript::{
Agent, InternalMethods, InternalSlots, JsError, JsResult, OrdinaryObject,
PromiseCapability, ProtoIntrinsics, Value, object_handle,
Agent, BUILTIN_STRING_MEMORY, InternalMethods, InternalSlots, JsError, JsResult,
OrdinaryObject, PromiseCapability, ProtoIntrinsics, Value, get, object_handle,
},
engine::{Bindable, GcScope, NoGcScope, Scopable},
heap::{
Expand All @@ -25,6 +25,45 @@ object_handle!(Promise);
arena_vec_access!(Promise, 'a, PromiseHeapData, promises);

impl<'a> Promise<'a> {
/// ### [27.2.4.7.1 PromiseResolve ( C, x )](https://tc39.es/ecma262/#sec-promise-resolve)
///
/// Internal variant for call sites that must handle abrupt completion from
/// `PromiseResolve(%Promise%, x)`.
pub fn resolve_maybe_abrupt(
agent: &mut Agent,
x: Value,
mut gc: GcScope<'a, '_>,
) -> JsResult<'a, Self> {
// 1. If IsPromise(x) is true, then
if let Value::Promise(promise) = x {
let scoped_promise = promise.scope(agent, gc.nogc());
// a. Let xConstructor be ? Get(x, "constructor").
let x_constructor = match get(
agent,
promise,
BUILTIN_STRING_MEMORY.constructor.into(),
gc.reborrow(),
) {
Ok(value) => value.unbind().bind(gc.nogc()),
Err(err) => return Err(err.unbind().bind(gc.into_nogc())),
};
// b. If SameValue(xConstructor, C) is true, return x.
// NOTE: Ignoring subclasses.
if x_constructor == agent.current_realm_record().intrinsics().promise().into() {
return Ok(scoped_promise.get(agent).bind(gc.into_nogc()));
}
}
// 2. Let promiseCapability be ? NewPromiseCapability(C).
let promise_capability = PromiseCapability::new(agent, gc.nogc());
let promise = promise_capability.promise().scope(agent, gc.nogc());
// 3. Perform ? Call(promiseCapability.[[Resolve]], undefined, « x »).
// NOTE: Promise capability resolve never throws in Nova's internal model.
promise_capability.unbind().resolve(agent, x, gc.reborrow());
// 4. Return promiseCapability.[[Promise]].
// SAFETY: Not shared.
Ok(unsafe { promise.take(agent) }.bind(gc.into_nogc()))
}

/// Create a new resolved Promise.
pub(crate) fn new_resolved(agent: &mut Agent, value: Value<'a>) -> Self {
agent.heap.create(PromiseHeapData {
Expand Down
5 changes: 1 addition & 4 deletions tests/expectations.json
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,6 @@
"built-ins/AsyncGeneratorFunction/proto-from-ctor-realm-prototype.js": "FAIL",
"built-ins/AsyncGeneratorFunction/proto-from-ctor-realm.js": "FAIL",
"built-ins/AsyncGeneratorFunction/prototype/constructor.js": "FAIL",
"built-ins/AsyncGeneratorPrototype/return/return-state-completed-broken-promise.js": "FAIL",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: Nice!

"built-ins/AsyncGeneratorPrototype/return/return-suspendedStart-broken-promise.js": "FAIL",
"built-ins/AsyncGeneratorPrototype/return/return-suspendedYield-broken-promise-try-catch.js": "FAIL",
"built-ins/AsyncIteratorPrototype/Symbol.asyncDispose/invokes-return.js": "FAIL",
"built-ins/AsyncIteratorPrototype/Symbol.asyncDispose/is-function.js": "FAIL",
"built-ins/AsyncIteratorPrototype/Symbol.asyncDispose/length.js": "FAIL",
Expand Down Expand Up @@ -7505,4 +7502,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