-
Notifications
You must be signed in to change notification settings - Fork 39
Reduce unnecessary Awaits for nullish values in blocks containing await using
#219
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
Conversation
|
A preview of this PR can be found at https://tc39.es/proposal-explicit-resource-management/pr/219. |
|
In example 2, if Did you mean to say that in step 3 there is only an |
I agree, in principle. My concern is this: should
Example 3, steps 2 and 3:
Step 3 performs an Essentially, this ensures that the following code will Await at least once, but up to twice depending on whether {
using A = syncNonNull;
await using B = null, C = null, D = undefined, E = asyncNonNull;
}As we unwind disposal, we do the following:
|
|
Consensus in plenary was to collapse all Awaits for |
|
@nicolo-ribaudo, you asked to review the proposed changes here before this could reach consensus. I'd appreciate if you could review these changes as of the most recent commits. The intent behind these changes is as follows:
This has the following effects: Given, {
await using x = null, y = null;
}we record an Await is needed when disposing Given, {
await using x = null, y = asyncDisposable, z = null;
}we record an Await is needed when disposing Given, {
await using x = null, y = syncThrowInAsyncDispose, z = null;
}we record an Await is needed when disposing Given, {
await using x = null, y = null, z = asyncDisposable;
}we record an Await is needed when disposing Given, {
using a = syncDisposable;
await using x = null, y = null;
}we record an Await is needed when disposing Given, {
using a = syncDisposable;
await using x = null, y = asyncDisposable, z = null;
}we record an Await is needed when disposing Given, {
using a = syncDisposable;
await using x = null, y = syncThrowInAsyncDispose, z = null;
}we record an Await is needed when disposing Given, {
using a = syncDisposable;
await using x = null, y = null, z = asyncDisposable;
}we record an Await is needed when disposing |
|
I'd also appreciate additional reviews from @syg, @waldemarhorwat, @michaelficarra, and @bakkot. |
|
How can I see a rendered form of this? |
The first comment on this PR contains a link to the rendered spec text. The specific section in question is here: https://tc39.es/proposal-explicit-resource-management/pr/219/#sec-disposeresources |
nicolo-ribaudo
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me.
It's not explicit from the examples, but awaits are also collapsed across subsequent separate await using declarations right?
await using x = null;
await using y = null;Keeps being the same as
await using x = null, y = null;
Correct. I called this out:
|
I keep wondering if it wouldn't be simpler to always |
That would not simplify the algorithm, it would make it more complex. I also see no reason to break with how |
|
This reached consensus during the June 2024 TC39 plenary session. |
|
It looks like there may be a case in the algorithm that still introduces an extraneous Await in the case of: {
await using x = null;
using y = res;
await using z = null;
}When we dispose I expect we still only really need a single Await in this case, in which case Step 3.d.ii should instead read "Set hasAwaited to true". |
This CL reduces unnecessary Awaits for nullish values in blocks containing `await using` and in `AsyncDisposableStack` tc39/proposal-explicit-resource-management#219 Bug: 42203814 Change-Id: Ia94755bd19a217512d308b5b4f524471b8321d63 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5819755 Reviewed-by: Shu-yu Guo <[email protected]> Commit-Queue: Rezvan Mahdavi Hezaveh <[email protected]> Cr-Commit-Position: refs/heads/main@{#95982}
This reverts commit f054729. Reason for revert: https://issues.chromium.org/u/1/issues/365060988 Original change's description: > [explicit-resource-management] Avoid unnecessary awaits > > This CL reduces unnecessary Awaits for nullish values in blocks containing `await using` and in `AsyncDisposableStack` > tc39/proposal-explicit-resource-management#219 > > > Bug: 42203814 > Change-Id: Ia94755bd19a217512d308b5b4f524471b8321d63 > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5819755 > Reviewed-by: Shu-yu Guo <[email protected]> > Commit-Queue: Rezvan Mahdavi Hezaveh <[email protected]> > Cr-Commit-Position: refs/heads/main@{#95982} Bug: 42203814 Change-Id: I932341e117fd02299bda224ab5ff694372006ac0 No-Presubmit: true No-Tree-Checks: true No-Try: true Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5840443 Bot-Commit: Rubber Stamper <[email protected]> Owners-Override: Rezvan Mahdavi Hezaveh <[email protected]> Commit-Queue: Rezvan Mahdavi Hezaveh <[email protected]> Cr-Commit-Position: refs/heads/main@{#95998}
This is a reland of commit f054729 `performPromiseThen` was mistakenly attached to the promise.protorype previously. In this cl we fix that issue. Original change's description: > [explicit-resource-management] Avoid unnecessary awaits > > This CL reduces unnecessary Awaits for nullish values in blocks containing `await using` and in `AsyncDisposableStack` > tc39/proposal-explicit-resource-management#219 > > > Bug: 42203814 > Change-Id: Ia94755bd19a217512d308b5b4f524471b8321d63 > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5819755 > Reviewed-by: Shu-yu Guo <[email protected]> > Commit-Queue: Rezvan Mahdavi Hezaveh <[email protected]> > Cr-Commit-Position: refs/heads/main@{#95982} Bug: 42203814 Change-Id: Ice3c6438f8c8230c9edd0853a225feb8c6ed592d Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5842565 Reviewed-by: Shu-yu Guo <[email protected]> Commit-Queue: Rezvan Mahdavi Hezaveh <[email protected]> Cr-Commit-Position: refs/heads/main@{#96002}
This is an alternative to #216 and is based on another fix in #218.
Per #196 (comment), this reduces the number of
Awaits in blocks containingawait usingand inAsyncDisposableStackby collapsing theAwaits introduced fornullorundefinedresources to a singleAwait.As currently specified, the following code results in three
Awaits when only one is necessary:This was also the case in an
AsyncDisposableStackcontaining synchronous disposables:This PR changes this behavior such that we only need an implicit
Awaitin the following cases:nullorundefinedasync-from-sync resource to an async resource, non-nullish async-from-sync resource, or sync resource3.nullorundeifnedasync-from-sync resource is the last disposal performed for a scope.Example 1
Cisundefinedso no disposal happens, but we track that anAwaitmust occur. [+0 turns]Bisnullso no disposal happens, but we track that anAwaitmust occur. [+0 turns]Ais neithernullnorundefinedand we have tracked that anAwaitmust occur, so weAwait(undefined). [+1 turn]A[@@dispose]()is invoked in the following turn. [+0 turns]HAPPENS_AFTERhappens in the same turn asA[@@dispose](), but a turn afterHAPPENS_BEFORE.Example 2
Cis neithernullnorundefinedso we invoke its@@asyncDisposemethod. If it completes normally weAwaitthe result [+1 turns], but if it throws we continue on the same turn [+0 turns].Bisnullso no disposal happens, but we track that anAwaitmust occur. [+0 turns]Ais neithernullnorundefinedand we have tracked that anAwaitmust occur, so weAwait(undefined). [+1 turns]A[@@dispose]()is invoked in the following turn. [+0 turns]HAPPENS_AFTERhappens in the same turn asA[@@dispose](), but between 1-2 turns afterHAPPENS_BEFORE.Example 3
Cisnullso no disposal happens, but we track that anAwaitmust occur. [+0 turns]Bis neithernullnorundefinedand we have tracked that anAwaitmust occur, so weAwait(undefined). [+1 turns]B's@@asyncDisposemethod. If it completes normally weAwaitthe result [+1 turns], but if it throws we continue on the same turn [+0 turns].Ais neithernullnorundefinedso we invokeA[@@dispose]()either on the turn afterB's disposal (if it was normal), or on the same turn (if it threw). [+0 turns]HAPPENS_AFTERhappens in the same turn asA[@@dispose](), but between 1-2 turns afterHAPPENS_BEFORE.It is important to note that a synchronous throw completion from a call to
@@asyncDisposewill result in theAwaitbeing passed over, but this is consistent withfor awaitandAsyncIterator.next()behavior. Following #218, this is unlikely to occur for a@@disposemethod as it will be automatically wrapped in a newPromiseCapability, though it is still possible to throw synchronously ifPromise.prototype.thenis patched to throw an exception synchronously.This PR also removes unnecessary
Awaits fornull/undefinedresources inAsyncDisposableStack.prototype.disposeAsync().The PR against ecma262 is being tracked in rbuckton/ecma262#10
Fixes #196
Fixes #208
Footnotes
An async resource is an object with an
@@asyncDisposemethod initialized in anawait usingdeclaration. ↩An sync-from-sync resource is either
null,undefined, or an object with a@@disposemethod (but not an@@asyncDisposemethod) initialized in anawait usingdeclaration. ↩A sync resource is either
null,undefined, or an object with a@@disposemethod initialized in ausingdeclaration. ↩