Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rust incorrectly detects move'd async closure as FnOnce instead of Fn on nightly-2024-02-07 #120957

Closed
BigBadE opened this issue Feb 12, 2024 · 4 comments
Labels
C-bug Category: This is a bug. F-async_closure `#![feature(async_closure)]` T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.

Comments

@BigBadE
Copy link

BigBadE commented Feb 12, 2024

I tried this code:

#![feature(async_closure)]

use std::future::Future;

fn main() {
    let variable = 12;
    let reference = &variable;
    let example = async move || {
        println!("{}", reference);
    };
    test(example);
}

fn test<T: Future<Output = ()>, F: Fn() -> T>(given: F) {

}

I expected to see this happen: No compiler errors

Instead, this happened:

error[E0277]: expected a `Fn()` closure, found `{async closure@src\main.rs:8:19: 8:32}`
  --> src\main.rs:11:10
   |
11 |     test(example);
   |     ---- ^^^^^^^ expected an `Fn()` closure, found `{async closure@src\main.rs:8:19: 8:32}`
   |     |
   |     required by a bound introduced by this call
   |
   = help: the trait `Fn<()>` is not implemented for `{async closure@src\main.rs:8:19: 8:32}`
   = note: wrap the `{async closure@src\main.rs:8:19: 8:32}` in a closure with no arguments: `|| { /* code */ }`
   = note: `{async closure@src\main.rs:8:19: 8:32}` implements `FnOnce`, but it must implement `Fn`, which is more general

Meta

rustc --version --verbose:

rustc 1.78.0-nightly (1a648b397 2024-02-11)
binary: rustc
commit-hash: 1a648b397dedc98ada3dd3360f6d661ec2436c56
commit-date: 2024-02-11
host: x86_64-pc-windows-msvc
release: 1.78.0-nightly
LLVM version: 17.0.6

This bug was introduced between nightly-2024-02-06 (where the code builds correctly) and nightly-2024-02-27 (where the error happens), and is still present on nightly-2024-02-11 (the latest when this was released). This bug is likely related to #120886, which was fixed by #120712.

@BigBadE BigBadE added the C-bug Category: This is a bug. label Feb 12, 2024
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Feb 12, 2024
@Noratrieb
Copy link
Member

@compiler-errors more async closure fun :3

@Noratrieb Noratrieb added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. F-async_closure `#![feature(async_closure)]` WG-async Working group: Async & await T-types Relevant to the types team, which will review and decide on the PR/issue. and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. WG-async Working group: Async & await labels Feb 12, 2024
@compiler-errors
Copy link
Member

@BigBadE: This is somewhat expected behavior after the async closure refactor. Try writing your fn test like:

fn test(given: impl async Fn() -> T) {}

If this isn't working out in practice, pls share more information about what you're trying to use async closures for.

@BigBadE
Copy link
Author

BigBadE commented Feb 12, 2024

@BigBadE: This is somewhat expected behavior after the async closure refactor. Try writing your fn test like:

fn test(given: impl async Fn() -> T) {}

If this isn't working out in practice, pls share more information about what you're trying to use async closures for.

Okay, so async closures now are of the AsyncFn trait instead of the Fn trait, which breaks any code that previously expected them to be of the Fn trait. https://rust-lang.github.io/async-fundamentals-initiative/roadmap/async_closures.html explains the issue, but I can't help but wonder how async closures used to work when they did implement the Fn trait.

Either way, the problem is solved as long as this isn't considered a regression.

@compiler-errors
Copy link
Member

@BigBadE:

I can't help but wonder how async closures used to work when they did implement the Fn trait.

Async closures used to just be closures that return async blocks. In other words, another fix for your issue is to just write move || async move {} instead of async move || {}, since before I reworked them, that's literally just what they desugared to.

I do encourage you to try out "better" async closures; the where clause bounds for your test example function are pretty restrictive in practice, as you can't borrow any state from the closure, which should "just work" with the new async closures.

I'd love to hear more about how your project(s) are using async closures and whether you're able to express more with the new async Fn() bounds, though -- feel free to shoot me a message on Zulip if you've got more questions or comments.

@compiler-errors compiler-errors closed this as not planned Won't fix, can't repro, duplicate, stale Feb 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. F-async_closure `#![feature(async_closure)]` T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants