Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement changes for "avoid mostly-redundant await in async yield*" #3619

Merged
merged 4 commits into from Sep 6, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,41 @@
// Copyright (C) 2022 Kevin Gibbons. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-generator-function-definitions-runtime-semantics-evaluation
description: >
`yield*` in an async generator does not await promises returned by a manually implemented async iterator.
flags: [async]
features: [async-iteration]
---*/

var innerPromise = Promise.resolve("unwrapped value");

var asyncIter = {
[Symbol.asyncIterator]() {
return this;
},
next() {
return {
done: false,
value: innerPromise,
};
},
get return() {
throw new Test262Error(".return should not be accessed");
},
get throw() {
throw new Test262Error(".throw should not be accessed");
Copy link
Contributor

Choose a reason for hiding this comment

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

In cases like this, I prefer to observe execution with "flag" variables that are then asserted at the end of the test. Reason being: the exception handling mechanisms are themselves being validated, so there's a risk that whatever bug causes this statement to be evaluated would also cause the failure not to be reported.

That said, async tests are fundamentally dependent on asynchronous exception handling semantics, so I don't feel this risk is large enough to warrant another round of review. (I'm sharing my perspective anyway in case it's relevant for future tests and in case anyone out there can explain why I should reconsider.)

},
};

async function* f() {
yield* asyncIter;
}

f()
.next()
.then(v => {
assert.sameValue(v.value, innerPromise, "yield* should not unwrap promises from manually-implemented async iterators");
})
.then($DONE, $DONE)
Expand Up @@ -6,7 +6,7 @@ esid: sec-generator-function-definitions-runtime-semantics-evaluation
description: >
Return resumption value is awaited upon and hence is treated as a thenable.
info: |
14.4.14 Runtime Semantics: Evaluation
15.5.5 Runtime Semantics: Evaluation
YieldExpression : yield* AssignmentExpression

...
Expand All @@ -27,46 +27,49 @@ info: |
2. Return Completion(received).
...

25.5.3.7 AsyncGeneratorYield ( value )
27.6.3.8 AsyncGeneratorYield ( value )
...
5. Set value to ? Await(value).
...
8. Set the code evaluation state of genContext such that when evaluation is resumed with a
Completion resumptionValue the following steps will be performed:
...
b. Let awaited be Await(resumptionValue.[[Value]]).
12. If queue is not empty, then
...
e. Return Completion { [[Type]]: return, [[Value]]: awaited.[[Value]], [[Target]]: empty }.
13. Else,
...
c. Set the code evaluation state of genContext such that when evaluation is resumed with a
Completion resumptionValue the following steps will be performed:
i. Return ? AsyncGeneratorUnwrapYieldResumption(resumptionValue).

27.6.3.7 AsyncGeneratorUnwrapYieldResumption ( resumptionValue )
...
2. Let awaited be Completion(Await(resumptionValue.[[Value]])).
...

6.2.3.1 Await
...
2. Let promise be ? PromiseResolve(%Promise%, « value »).
...

25.6.4.5.1 PromiseResolve ( C, x )
27.2.4.7.1 PromiseResolve ( C, x )
...
3. Let promiseCapability be ? NewPromiseCapability(C).
4. Perform ? Call(promiseCapability.[[Resolve]], undefined, « x »).
2. Let promiseCapability be ? NewPromiseCapability(C).
3. Perform ? Call(promiseCapability.[[Resolve]], undefined, « x »).
...

25.6.1.5 NewPromiseCapability ( C )
27.2.1.5 NewPromiseCapability ( C )
...
7. Let promise be ? Construct(C, « executor »).
...

25.6.3.1 Promise ( executor )
27.2.3.1 Promise ( executor )
...
8. Let resolvingFunctions be CreateResolvingFunctions(promise).
...

25.6.1.3 CreateResolvingFunctions ( promise )
27.2.1.3 CreateResolvingFunctions ( promise )
...
2. Let stepsResolve be the algorithm steps defined in Promise Resolve Functions (25.6.1.3.2).
3. Let resolve be CreateBuiltinFunction(stepsResolve, « [[Promise]], [[AlreadyResolved]] »).
...

25.6.1.3.2 Promise Resolve Functions
27.2.1.3.2 Promise Resolve Functions
...
9. Let then be Get(resolution, "then").
...
Expand All @@ -82,14 +85,11 @@ var expected = [
// `Await(innerResult)` promise resolved.
"tick 1",

// `Await(value)` promise resolved.
"tick 2",

// "then" of `resumptionValue.[[Value]]` accessed.
"get then",

// `Await(resumptionValue.[[Value]])` promise resolved.
"tick 3",
"tick 2",

// Get iterator "return" method.
"get return",
Expand All @@ -98,7 +98,7 @@ var expected = [
"get then",

// `Await(received.[[Value]])` promise resolved.
"tick 4",
"tick 3",
];

var actual = [];
Expand Down Expand Up @@ -127,7 +127,6 @@ Promise.resolve(0)
.then(() => actual.push("tick 1"))
.then(() => actual.push("tick 2"))
.then(() => actual.push("tick 3"))
.then(() => actual.push("tick 4"))
.then(() => {
assert.compareArray(actual, expected, "Ticks for return with thenable getter");
}).then($DONE, $DONE);
Expand Down