Support move expressions in coroutine closures - #157738
Conversation
|
Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt |
|
|
b119411 to
219db1c
Compare
This comment has been minimized.
This comment has been minimized.
219db1c to
0f62aac
Compare
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Hmm. Something seems off here. I think we need more tests around nested-move and async blocks, async closures, and gen blocks. For example I'd expect:
let c: Arc<String> = Default::default();
let future = async {
let f = async {
move(c.clone());
};
assert!( /* c ref count is 2 */ );
f.await;
assert!( /* c ref count is 1 */ );
drop(c);
};let c: Arc<String> = Default::default();
let future = async {
let f = async {
move(c.clone());
};
f.await;
drop(c);
};
println!("{c}"); // <-- ERROR: c is movedlet c: Arc<String> = Default::default();
let future = async {
let f = async {
move(move(c.clone()));
};
assert!( /* c ref count is 3 */ );
f.await;
assert!( /* c ref count is 2 */ );
drop(c);
};
println!("{c}"); // OK, prints ""
This comment has been minimized.
This comment has been minimized.
d7ddf08 to
cb24d7e
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
| @@ -0,0 +1,77 @@ | |||
| //@ edition: 2021 | |||
There was a problem hiding this comment.
✅ These match my expectations.
| }); | ||
| n | ||
| }; | ||
| assert_eq!(created.get(), 0); |
There was a problem hiding this comment.
❌ But this does not. I expected the move to execute when the closure was created. In other words, I expect these to be equivalent
let created = Cell::new(0);
let c = || {
let n = move({ created.set(created.get() + 1); created.get() });
n
};
assert_eq!(created.get(), 1);
assert_eq!(c(), 1);
assert_eq!(c(), 1);
assert_eq!(created.get(), 1);and
let created = Cell::new(0);
let c = async || {
let n = move({ created.set(created.get() + 1); created.get() });
n
};
assert_eq!(created.get(), 1);
assert_eq!(c().await, 1);
assert_eq!(c().await, 1);
assert_eq!(created.get(), 1);I think we are leaking the "desugaring" of async closures here somehow.
| yield n; | ||
| yield n + 1; | ||
| }); | ||
| assert_eq!(created.get(), 1); |
There was a problem hiding this comment.
✅ This matches my expectations
| PendingOnce::new().await; | ||
| yield Arc::strong_count(&value); | ||
| }); | ||
| assert_eq!(Arc::strong_count(&x), 2); |
| }); | ||
| yield ready_next(inner.as_mut()).unwrap(); | ||
| }); | ||
| assert_eq!(weak.strong_count(), 2); |
| }; | ||
| yield inner.next().unwrap(); | ||
| }; | ||
| assert_eq!(weak.strong_count(), 2); |
|
|
||
| fn main() { | ||
| let _ = || move(move(0)); | ||
| //~^ ERROR nested `move(expr)` requires another enclosing closure |
There was a problem hiding this comment.
✅ These errors match my expectations
| let value = move(z.clone()); | ||
| yield Arc::strong_count(&value); | ||
| }; | ||
| assert_eq!(Arc::strong_count(&z), 2); |
| f.await; | ||
| drop(c); | ||
| }; | ||
| println!("{c}"); //~ ERROR the type `Arc` does not implement `Copy` |
| let inner = outer(); | ||
| assert_eq!(Arc::strong_count(&v), 2); | ||
| assert_eq!(inner(), v.len()); | ||
| assert_eq!(Arc::strong_count(&v), 1); |
There was a problem hiding this comment.
✅ Interesting example
This adds
move(expr)support for coroutine closures.RFC: rust-lang/rfcs#3968
Tracking issue: #155050
Project goal:
r? @nikomatsakis