Rework the ByMoveBody shim to actually work correctly

This commit is contained in:
Michael Goulet 2024-04-05 15:12:34 -04:00
parent 1921968cc5
commit 3674032eb2
5 changed files with 336 additions and 36 deletions

View file

@ -0,0 +1,29 @@
after call
after await
fixed
uncaptured
after call
after await
fixed
uncaptured
after call
after await
fixed
uncaptured
after call
after await
fixed
untouched
after call
drop first
after await
uncaptured
after call
drop first
after await
uncaptured

View file

@ -0,0 +1,29 @@
after call
after await
fixed
uncaptured
after call
after await
fixed
uncaptured
after call
fixed
after await
uncaptured
after call
after await
fixed
untouched
after call
drop first
after await
uncaptured
after call
drop first
after await
uncaptured

View file

@ -0,0 +1,29 @@
after call
after await
fixed
uncaptured
after call
after await
fixed
uncaptured
after call
fixed
after await
uncaptured
after call
after await
fixed
untouched
after call
drop first
after await
uncaptured
after call
drop first
after await
uncaptured

View file

@ -0,0 +1,157 @@
//@ aux-build:block-on.rs
//@ edition:2021
//@ run-pass
//@ check-run-results
//@ revisions: call call_once force_once
// call - Call the closure regularly.
// call_once - Call the closure w/ `async FnOnce`, so exercising the by_move shim.
// force_once - Force the closure mode to `FnOnce`, so exercising what was fixed
// in <https://github.com/rust-lang/rust/pull/123350>.
#![feature(async_closure)]
#![allow(unused_mut)]
extern crate block_on;
#[cfg(any(call, force_once))]
macro_rules! call {
($c:expr) => { ($c)() }
}
#[cfg(call_once)]
async fn call_once(f: impl async FnOnce()) {
f().await
}
#[cfg(call_once)]
macro_rules! call {
($c:expr) => { call_once($c) }
}
#[cfg(not(force_once))]
macro_rules! guidance {
($c:expr) => { $c }
}
#[cfg(force_once)]
fn infer_fnonce(c: impl async FnOnce()) -> impl async FnOnce() { c }
#[cfg(force_once)]
macro_rules! guidance {
($c:expr) => { infer_fnonce($c) }
}
#[derive(Debug)]
struct Drop(&'static str);
impl std::ops::Drop for Drop {
fn drop(&mut self) {
println!("{}", self.0);
}
}
struct S {
a: i32,
b: Drop,
c: Drop,
}
async fn async_main() {
// Precise capture struct
{
let mut s = S { a: 1, b: Drop("fix me up"), c: Drop("untouched") };
let mut c = guidance!(async || {
s.a = 2;
let w = &mut s.b;
w.0 = "fixed";
});
s.c.0 = "uncaptured";
let fut = call!(c);
println!("after call");
fut.await;
println!("after await");
}
println!();
// Precise capture &mut struct
{
let s = &mut S { a: 1, b: Drop("fix me up"), c: Drop("untouched") };
let mut c = guidance!(async || {
s.a = 2;
let w = &mut s.b;
w.0 = "fixed";
});
s.c.0 = "uncaptured";
let fut = call!(c);
println!("after call");
fut.await;
println!("after await");
}
println!();
// Precise capture struct by move
{
let mut s = S { a: 1, b: Drop("fix me up"), c: Drop("untouched") };
let mut c = guidance!(async move || {
s.a = 2;
let w = &mut s.b;
w.0 = "fixed";
});
s.c.0 = "uncaptured";
let fut = call!(c);
println!("after call");
fut.await;
println!("after await");
}
println!();
// Precise capture &mut struct by move
{
let s = &mut S { a: 1, b: Drop("fix me up"), c: Drop("untouched") };
let mut c = guidance!(async move || {
s.a = 2;
let w = &mut s.b;
w.0 = "fixed";
});
// `s` is still captured fully as `&mut S`.
let fut = call!(c);
println!("after call");
fut.await;
println!("after await");
}
println!();
// Precise capture struct, consume field
{
let mut s = S { a: 1, b: Drop("drop first"), c: Drop("untouched") };
let c = guidance!(async move || {
// s.a = 2; // FIXME(async_closures): Figure out why this fails
drop(s.b);
});
s.c.0 = "uncaptured";
let fut = call!(c);
println!("after call");
fut.await;
println!("after await");
}
println!();
// Precise capture struct by move, consume field
{
let mut s = S { a: 1, b: Drop("drop first"), c: Drop("untouched") };
let c = guidance!(async move || {
// s.a = 2; // FIXME(async_closures): Figure out why this fails
drop(s.b);
});
s.c.0 = "uncaptured";
let fut = call!(c);
println!("after call");
fut.await;
println!("after await");
}
}
fn main() {
block_on::block_on(async_main());
}