rust/tests/ui/async-await/async-closures/precise-captures.rs

158 lines
3.7 KiB
Rust

//@ 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());
}