Rollup merge of #123350 - compiler-errors:async-closure-by-move, r=oli-obk
Actually use the inferred `ClosureKind` from signature inference in coroutine-closures A follow-up to https://github.com/rust-lang/rust/pull/123349, which fixes another subtle bug: We were not taking into account the async closure kind we infer during closure signature inference. When I pass a closure directly to an arg like `fn(x: impl async FnOnce())`, that should have the side-effect of artificially restricting the kind of the async closure to `ClosureKind::FnOnce`. We weren't doing this -- that's a quick fix; however, it uncovers a second, more subtle bug with the way that `move`, async closures, and `FnOnce` interact. Specifically, when we have an async closure like: ``` let x = Struct; let c = infer_as_fnonce(async move || { println!("{x:?}"); } ``` The outer closure captures `x` by move, but the inner coroutine still immutably borrows `x` from the outer closure. Since we've forced the closure to by `async FnOnce()`, we can't actually *do* a self borrow, since the signature of `AsyncFnOnce::call_once` doesn't have a borrowed lifetime. This means that all `async move` closures that are constrained to `FnOnce` will fail borrowck. We can fix that by detecting this case specifically, and making the *inner* async closure `move` as well. This is always beneficial to closure analysis, since if we have an `async FnOnce()` that's `move`, there's no reason to ever borrow anything, so `move` isn't artificially restrictive.
This commit is contained in:
commit
02ee8a8cee
9 changed files with 182 additions and 55 deletions
|
|
@ -79,4 +79,38 @@ async fn async_main() {
|
|||
};
|
||||
call_once(c).await;
|
||||
}
|
||||
|
||||
fn force_fnonce<T>(f: impl async FnOnce() -> T) -> impl async FnOnce() -> T {
|
||||
f
|
||||
}
|
||||
|
||||
// Capture something with `move`, but infer to `AsyncFnOnce`
|
||||
{
|
||||
let x = Hello(6);
|
||||
let c = force_fnonce(async move || {
|
||||
println!("{x:?}");
|
||||
});
|
||||
call_once(c).await;
|
||||
|
||||
let x = &Hello(7);
|
||||
let c = force_fnonce(async move || {
|
||||
println!("{x:?}");
|
||||
});
|
||||
call_once(c).await;
|
||||
}
|
||||
|
||||
// Capture something by-ref, but infer to `AsyncFnOnce`
|
||||
{
|
||||
let x = Hello(8);
|
||||
let c = force_fnonce(async || {
|
||||
println!("{x:?}");
|
||||
});
|
||||
call_once(c).await;
|
||||
|
||||
let x = &Hello(9);
|
||||
let c = force_fnonce(async || {
|
||||
println!("{x:?}");
|
||||
});
|
||||
call_once(c).await;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,3 +8,7 @@ Hello(3)
|
|||
Hello(4)
|
||||
Hello(4)
|
||||
Hello(5)
|
||||
Hello(6)
|
||||
Hello(7)
|
||||
Hello(8)
|
||||
Hello(9)
|
||||
|
|
|
|||
|
|
@ -2,18 +2,22 @@
|
|||
|
||||
#![feature(async_closure)]
|
||||
|
||||
fn main() {
|
||||
fn needs_async_fn(_: impl async Fn()) {}
|
||||
fn needs_async_fn(_: impl async Fn()) {}
|
||||
|
||||
fn a() {
|
||||
let mut x = 1;
|
||||
needs_async_fn(async || {
|
||||
//~^ ERROR expected a closure that implements the `async Fn` trait, but this closure only implements `async FnMut`
|
||||
//~^ ERROR cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
|
||||
x += 1;
|
||||
});
|
||||
}
|
||||
|
||||
fn b() {
|
||||
let x = String::new();
|
||||
needs_async_fn(move || async move {
|
||||
//~^ ERROR expected a closure that implements the `async Fn` trait, but this closure only implements `async FnOnce`
|
||||
println!("{x}");
|
||||
});
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,5 @@
|
|||
error[E0525]: expected a closure that implements the `async Fn` trait, but this closure only implements `async FnMut`
|
||||
--> $DIR/wrong-fn-kind.rs:9:20
|
||||
|
|
||||
LL | needs_async_fn(async || {
|
||||
| -------------- -^^^^^^^
|
||||
| | |
|
||||
| _____|______________this closure implements `async FnMut`, not `async Fn`
|
||||
| | |
|
||||
| | required by a bound introduced by this call
|
||||
LL | |
|
||||
LL | | x += 1;
|
||||
| | - closure is `async FnMut` because it mutates the variable `x` here
|
||||
LL | | });
|
||||
| |_____- the requirement to implement `async Fn` derives from here
|
||||
|
|
||||
note: required by a bound in `needs_async_fn`
|
||||
--> $DIR/wrong-fn-kind.rs:6:31
|
||||
|
|
||||
LL | fn needs_async_fn(_: impl async Fn()) {}
|
||||
| ^^^^^^^^^^ required by this bound in `needs_async_fn`
|
||||
|
||||
error[E0525]: expected a closure that implements the `async Fn` trait, but this closure only implements `async FnOnce`
|
||||
--> $DIR/wrong-fn-kind.rs:15:20
|
||||
--> $DIR/wrong-fn-kind.rs:17:20
|
||||
|
|
||||
LL | needs_async_fn(move || async move {
|
||||
| -------------- -^^^^^^
|
||||
|
|
@ -35,11 +14,29 @@ LL | | });
|
|||
| |_____- the requirement to implement `async Fn` derives from here
|
||||
|
|
||||
note: required by a bound in `needs_async_fn`
|
||||
--> $DIR/wrong-fn-kind.rs:6:31
|
||||
--> $DIR/wrong-fn-kind.rs:5:27
|
||||
|
|
||||
LL | fn needs_async_fn(_: impl async Fn()) {}
|
||||
| ^^^^^^^^^^ required by this bound in `needs_async_fn`
|
||||
LL | fn needs_async_fn(_: impl async Fn()) {}
|
||||
| ^^^^^^^^^^ required by this bound in `needs_async_fn`
|
||||
|
||||
error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
|
||||
--> $DIR/wrong-fn-kind.rs:9:29
|
||||
|
|
||||
LL | fn needs_async_fn(_: impl async Fn()) {}
|
||||
| --------------- change this to accept `FnMut` instead of `Fn`
|
||||
...
|
||||
LL | needs_async_fn(async || {
|
||||
| _____--------------_--------_^
|
||||
| | | |
|
||||
| | | in this closure
|
||||
| | expects `Fn` instead of `FnMut`
|
||||
LL | |
|
||||
LL | | x += 1;
|
||||
| | - mutable borrow occurs due to use of `x` in closure
|
||||
LL | | });
|
||||
| |_____^ cannot borrow as mutable
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0525`.
|
||||
Some errors have detailed explanations: E0525, E0596.
|
||||
For more information about an error, try `rustc --explain E0525`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue