Skip to content

Conversation

@agentcooper
Copy link

Fixes #23858, #23731.

function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
function step(r) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Per the spec, yield will always await. We already handle this behavior for yield* via __asyncDelegator. Rather than changing the helper here, we could handle this by changing the emit for the async generator body to replace yield x with yield yield __await(x).

Copy link
Author

@agentcooper agentcooper May 5, 2018

Choose a reason for hiding this comment

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

@rbuckton makes sense! I gave it a try and updated the PR. Could you take another look?

Choose a reason for hiding this comment

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

yield yield __await looks to me like you're rewriting yield x into yield await x. I'm not sure those are the right semantics, even if they appear to work.

Copy link
Contributor

Choose a reason for hiding this comment

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

@Kovensky, they actually are the correct semantics per the spec, specifically in 25.5.3.7 AsyncGeneratorYield:

  1. Set value to ? Await(value).

return setOriginalNode(
setTextRange(
createYield(
createDownlevelAwait(node.expression)
Copy link
Contributor

Choose a reason for hiding this comment

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

With any transformation you need to ensure you continue visiting the subtree, so this should be createDownlevelAwait(visitNode(node.expression, visitor, isExpression))

Copy link
Author

Choose a reason for hiding this comment

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

@rbuckton done

);
}

if (node.expression && node.expression.kind !== SyntaxKind.AwaitExpression) {
Copy link
Contributor

Choose a reason for hiding this comment

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

The actual ECMAScript specs don't care whether you are already awaiting the operand to yield, e.g. in yield await x, you await twice: once for the await and once for the yield. It also doesn't matter if yield has an expression. Rather, yield is treated as yield undefined, and as a result we still have to await undefined before we actually yield.

It seems inefficient, but the runtime semantics would be observably different. If we don't have the same number of underling Awaits as the spec, then you could end up with observable differences in resolution timing between our downlevel emit and uplevel ECMAScript runtime behavior for the same code.

@DanielRosenwasser, @bterlson: Any thoughts?

Copy link
Contributor

Choose a reason for hiding this comment

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

@agentcooper: in practice this would mean replacing line 151 with node.expression ? visitNode(node.expression, visitor, isExpression) : createVoidZero() and removing the if condition on line 146.

Copy link
Author

Choose a reason for hiding this comment

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

@rbuckton got it. should I go ahead with the change or are we waiting for others to reply?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, go ahead and make the change.

@rbuckton rbuckton merged commit f17bf54 into microsoft:master May 9, 2018
@rbuckton
Copy link
Contributor

rbuckton commented May 9, 2018

Looks good, thanks for the contribution!

@microsoft microsoft locked and limited conversation to collaborators Jul 31, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants