Closed
Description
Unused arguments to async fn
are not moved into the resulting generator so are dropped before the future runs, here's some example psuedo-code demonstrating this (full running playground example here):
async fn foo(log1: DropLog, _log2: DropLog) {
println!("Got log1: {:?}", log1);
}
fn bar(log1: DropLog, _log2: DropLog) {
println!("Got log1: {:?}", log1);
}
fn main() {
foo(DropLog(1), DropLog(2)).poll(...);
println!();
bar(DropLog(3), DropLog(4));
}
which gives the output:
Dropped DropLog(2)
Got log1: DropLog(1)
Dropped DropLog(1)
Got log1: DropLog(3)
Dropped DropLog(4)
Dropped DropLog(3)
I found this because of a related issue with futures-await(0.1)
posted to urlo, it's at the very least surprising behaviour that needs documenting if not a bug.
Activity
nikomatsakis commentedon Mar 5, 2019
Marking this as blocking stabilization of async-await. Obviously, changing the semantics here would alter the semantics of stable code. Moreover, there's a good case to be made that the current semantics are incorrect. @cramertj and I (along with a few others) discussed this in a recent meeting. Our conclusion was that we effectively wanted a desugaring like the following:
where
x
is a kind of "fresh name" not visible to the user.Some of the key test cases we want to consider would be:
async fn foo(_: Foo)
-- theFoo
value should be dropped after the future is "waited"async fn foo(_x: Foo)
-- sameThis is quite analogous then to the behavior for
fn foo(_: Foo)
and friends -- basically after the "return" executes, the parameters are dropped (whereas current behavior drops before the body of the function even begins (i.e., before the future is polled)).nikomatsakis commentedon Mar 5, 2019
Tagging as E-needs-mentor as we need to write up some notes on how to alter the desugaring here. One bit I can see being complex is that the HIR presently has no way to "name" a parameter apart from entering a pattern.
async fn
arguments in async block #59135cramertj commentedon Apr 2, 2019
(nominating for discussion in T-lang to resolve the desired behavior)
cramertj commentedon Apr 2, 2019
Summary of the current issues by @davidtwco can be found on Zulip.
17 remaining items
najamelan commentedon Apr 19, 2019
@cramertj Sorry if this is a noob question, but is the drop order for non-async functions:
_
=> drop early,_ident
=> drop late? And will that be consistent behaviour everywhere, with the user being able to opt into perf gain by using just_
?cramertj commentedon Apr 19, 2019
No, the performance gain being discussed here is not achievable by using
_
in argument position._
bindings in argument position drop at the end of the function, not at the start (or, in this case, prior to the future even having started).CAD97 commentedon Apr 19, 2019
Would that be a viable future change (for sync and async) to put through Crater? (As iirc parameter drop order isn't actually specified and it would make it more consistent with
let
.)It doesn't need to be, but it seems desirable on the surface.
cramertj commentedon Apr 19, 2019
@CAD97 That would be a breaking change to a pretty significant amount of existing code, a significant chunk of which is probably
unsafe
(e.g. functions using_: Mutex<()>
as a guard, as I mentioned above).comex commentedon Apr 20, 2019
OTOH, if the behavior were changed in an edition, it would be a relatively straightforward automatic migration...
davidtwco commentedon Apr 21, 2019
Assigning myself again since I have an open PR for this.
Rollup merge of rust-lang#59823 - davidtwco:issue-54716, r=cramertj
Rollup merge of rust-lang#59823 - davidtwco:issue-54716, r=cramertj
Rollup merge of rust-lang#59823 - davidtwco:issue-54716, r=cramertj
async fn
matchesfn
and that users cannot refer to generated arguments. #60437