Skip to content

Commit 22b6eba

Browse files
authored
Rollup merge of #127136 - compiler-errors:coroutine-closure-env-shim, r=oli-obk
Fix `FnMut::call_mut`/`Fn::call` shim for async closures that capture references I adjusted async closures to be able to implement `Fn` and `FnMut` *even if* they capture references, as long as those references did not need to borrow data from the closure captures themselves. See #125259. However, when I did this, I didn't actually relax an assertion in the `build_construct_coroutine_by_move_shim` shim code, which builds the `Fn`/`FnMut`/`FnOnce` implementations for async closures. Therefore, if we actually tried to *call* `FnMut`/`Fn` on async closures, it would ICE. This PR adjusts this assertion to ensure that we only capture immutable references in closures if they implement `Fn`/`FnMut`. It also adds a bunch of tests and makes more of the async-closure tests into `build-pass` since we often care about these tests actually generating the right closure shims and stuff. I think it might be excessive to *always* use build-pass here, but 🤷 it's not that big of a deal. Fixes #127019 Fixes #127012 r? oli-obk
2 parents 7fd4099 + 6c977b2 commit 22b6eba

File tree

2 files changed

+18
-9
lines changed

2 files changed

+18
-9
lines changed

tests/pass/async-closure.rs

+14-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#![feature(async_closure, noop_waker, async_fn_traits)]
2+
#![allow(unused)]
23

34
use std::future::Future;
4-
use std::ops::{AsyncFnMut, AsyncFnOnce};
5+
use std::ops::{AsyncFn, AsyncFnMut, AsyncFnOnce};
56
use std::pin::pin;
67
use std::task::*;
78

@@ -17,6 +18,10 @@ pub fn block_on<T>(fut: impl Future<Output = T>) -> T {
1718
}
1819
}
1920

21+
async fn call(f: &mut impl AsyncFn(i32)) {
22+
f(0).await;
23+
}
24+
2025
async fn call_mut(f: &mut impl AsyncFnMut(i32)) {
2126
f(0).await;
2227
}
@@ -26,10 +31,10 @@ async fn call_once(f: impl AsyncFnOnce(i32)) {
2631
}
2732

2833
async fn call_normal<F: Future<Output = ()>>(f: &impl Fn(i32) -> F) {
29-
f(0).await;
34+
f(1).await;
3035
}
3136

32-
async fn call_normal_once<F: Future<Output = ()>>(f: impl FnOnce(i32) -> F) {
37+
async fn call_normal_mut<F: Future<Output = ()>>(f: &mut impl FnMut(i32) -> F) {
3338
f(1).await;
3439
}
3540

@@ -39,14 +44,16 @@ pub fn main() {
3944
let mut async_closure = async move |a: i32| {
4045
println!("{a} {b}");
4146
};
47+
call(&mut async_closure).await;
4248
call_mut(&mut async_closure).await;
4349
call_once(async_closure).await;
4450

45-
// No-capture closures implement `Fn`.
46-
let async_closure = async move |a: i32| {
47-
println!("{a}");
51+
let b = 2i32;
52+
let mut async_closure = async |a: i32| {
53+
println!("{a} {b}");
4854
};
4955
call_normal(&async_closure).await;
50-
call_normal_once(async_closure).await;
56+
call_normal_mut(&mut async_closure).await;
57+
call_once(async_closure).await;
5158
});
5259
}

tests/pass/async-closure.stdout

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
0 2
2+
0 2
3+
1 2
4+
1 2
5+
1 2
26
1 2
3-
0
4-
1

0 commit comments

Comments
 (0)