Bug 1331092 - Part 7: Implement Async Generator yield*.

Tag #1287
This commit is contained in:
Gaming4JC 2019-12-14 09:16:32 -05:00 committed by Roy Tam
commit 142e8bf444
14 changed files with 451 additions and 43 deletions

View file

@ -2329,6 +2329,165 @@ js::AsyncGeneratorAwait(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj
return PerformPromiseThenWithReaction(cx, promise, reaction);
}
// Async Iteration proposal 6.1.3.2.1 %AsyncFromSyncIteratorPrototype%.next
// Async Iteration proposal 6.1.3.2.2 %AsyncFromSyncIteratorPrototype%.return
// Async Iteration proposal 6.1.3.2.3 %AsyncFromSyncIteratorPrototype%.throw
bool
js::AsyncFromSyncIteratorMethod(JSContext* cx, CallArgs& args, CompletionKind completionKind)
{
// Step 1.
RootedValue thisVal(cx, args.thisv());
// Step 2.
RootedObject resultPromise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
if (!resultPromise)
return false;
// Step 3.
if (!thisVal.isObject() || !thisVal.toObject().is<AsyncFromSyncIteratorObject>()) {
// Step 3.a.
RootedValue badGeneratorError(cx);
if (!GetTypeError(cx, JSMSG_NOT_AN_ASYNC_ITERATOR, &badGeneratorError))
return false;
// Step 3.b.
if (!RejectMaybeWrappedPromise(cx, resultPromise, badGeneratorError))
return false;
// Step 3.c.
args.rval().setObject(*resultPromise);
return true;
}
Rooted<AsyncFromSyncIteratorObject*> asyncIter(
cx, &thisVal.toObject().as<AsyncFromSyncIteratorObject>());
// Step 4.
RootedObject iter(cx, asyncIter->iterator());
RootedValue resultVal(cx);
RootedValue func(cx);
if (completionKind == CompletionKind::Normal) {
// 6.1.3.2.1 steps 5-6 (partially).
if (!GetProperty(cx, iter, iter, cx->names().next, &func))
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
} else if (completionKind == CompletionKind::Return) {
// 6.1.3.2.2 steps 5-6.
if (!GetProperty(cx, iter, iter, cx->names().return_, &func))
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
// Step 7.
if (func.isNullOrUndefined()) {
// Step 7.a.
RootedObject resultObj(cx, CreateIterResultObject(cx, args.get(0), true));
if (!resultObj)
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
RootedValue resultVal(cx, ObjectValue(*resultObj));
// Step 7.b.
if (!ResolvePromiseInternal(cx, resultPromise, resultVal))
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
// Step 7.c.
args.rval().setObject(*resultPromise);
return true;
}
} else {
// 6.1.3.2.3 steps 5-6.
MOZ_ASSERT(completionKind == CompletionKind::Throw);
if (!GetProperty(cx, iter, iter, cx->names().throw_, &func))
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
// Step 7.
if (func.isNullOrUndefined()) {
// Step 7.a.
if (!RejectMaybeWrappedPromise(cx, resultPromise, args.get(0)))
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
// Step 7.b.
args.rval().setObject(*resultPromise);
return true;
}
}
// 6.1.3.2.1 steps 5-6 (partially).
// 6.1.3.2.2, 6.1.3.2.3 steps 8-9.
RootedValue iterVal(cx, ObjectValue(*iter));
FixedInvokeArgs<1> args2(cx);
args2[0].set(args.get(0));
if (!js::Call(cx, func, iterVal, args2, &resultVal))
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
// 6.1.3.2.1 steps 5-6 (partially).
// 6.1.3.2.2, 6.1.3.2.3 steps 10.
if (!resultVal.isObject()) {
CheckIsObjectKind kind;
switch (completionKind) {
case CompletionKind::Normal:
kind = CheckIsObjectKind::IteratorNext;
break;
case CompletionKind::Throw:
kind = CheckIsObjectKind::IteratorThrow;
break;
case CompletionKind::Return:
kind = CheckIsObjectKind::IteratorReturn;
break;
}
MOZ_ALWAYS_FALSE(ThrowCheckIsObject(cx, kind));
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
}
RootedObject resultObj(cx, &resultVal.toObject());
// Following step numbers are for 6.1.3.2.1.
// For 6.1.3.2.2 and 6.1.3.2.3, steps 7-16 corresponds to steps 11-20.
// Steps 7-8.
RootedValue value(cx);
if (!GetProperty(cx, resultObj, resultObj, cx->names().value, &value))
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
// Steps 9-10.
RootedValue doneVal(cx);
if (!GetProperty(cx, resultObj, resultObj, cx->names().done, &doneVal))
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
bool done = ToBoolean(doneVal);
// Step 11.
Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
if (!promise)
return false;
// Step 12.
if (!ResolvePromiseInternal(cx, promise, value))
return false;
// Steps 13-14.
RootedValue onFulfilled(cx, Int32Value(done
? PromiseHandlerAsyncIteratorValueUnwrapDone
: PromiseHandlerAsyncIteratorValueUnwrapNotDone));
RootedObject incumbentGlobal(cx);
if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobal))
return false;
// Step 15.
Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultPromise, onFulfilled,
UndefinedHandleValue,
nullptr, nullptr,
incumbentGlobal));
if (!reaction)
return false;
if (!PerformPromiseThenWithReaction(cx, promise, reaction))
return false;
// Step 16.
args.rval().setObject(*resultPromise);
return true;
}
// Async Iteration proposal 6.4.3.3.
MOZ_MUST_USE bool
js::AsyncGeneratorResolve(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,