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

async/await: cannot move out of captured variable in an Fn closure #59971

Open
leinlawun opened this issue Apr 14, 2019 · 5 comments
Open

async/await: cannot move out of captured variable in an Fn closure #59971

leinlawun opened this issue Apr 14, 2019 · 5 comments
Labels
A-async-await Area: Async & Await A-closures Area: Closures (`|…| { … }`) AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. fixed-by-async-closures Fixed by `#![feature(async_closure)]` requires-nightly This issue requires a nightly compiler in some way. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@leinlawun
Copy link

leinlawun commented Apr 14, 2019

Hello,
recently faced with strange behavior, please comment, is this a bug, or not?
Compiler version: 1.35.0-nightly 2019-04-12 99da733

#![feature(futures_api, async_await, await_macro)]

use std::future::Future;

struct Task<T> {
    task: T,
}

impl<T> Task<T>
where
    T: Fn(),
{
    fn new(task: T) -> Self {
        Self { task }
    }

    fn execute(&self) {
        (self.task)();
    }
}

struct AsyncTask<T> {
    task: T,
}

impl<T, F> AsyncTask<T>
where
    T: Fn() -> F,
    F: Future<Output = ()>,
{
    fn new(task: T) -> Self {
        Self { task }
    }

    async fn execute(&self) {
        await!((self.task)());
    }
}

fn main() {
    let string = "Hello, World!".to_string();
    let _task = Task::new(move || {
        println!("{}", string);
    });

    let string = "Hello, World!".to_string();
    let _async_task = AsyncTask::new(async move || {
        println!("{}", string);
    });
}

(Playground)
(Updated Playground

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0507]: cannot move out of captured variable in an `Fn` closure
  --> src/main.rs:47:52
   |
46 |       let string = "Hello, World!".to_string();
   |           ------ captured outer variable
47 |       let _async_task = AsyncTask::new(async move || {
   |  ____________________________________________________^
48 | |         println!("{}", string);
49 | |     });
   | |_____^ cannot move out of captured variable in an `Fn` closure

error: aborting due to previous errors

For more information about this error, try `rustc --explain E0507`.
error: Could not compile `playground`.

To learn more, run the command again with --verbose.

@jonas-schievink jonas-schievink added A-async-await Area: Async & Await A-closures Area: Closures (`|…| { … }`) labels Apr 14, 2019
@nikomatsakis nikomatsakis added AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Apr 16, 2019
@nikomatsakis
Copy link
Contributor

Marking as deferred -- async-await closures are not part of the core async fn functionality we expect to stabilize.

@leinlawun -- I'm not sure precisely what the problem is here, but in general async closures don't really work correctly.

@Centril Centril added F-async_await F-async_closure `#![feature(async_closure)]` requires-nightly This issue requires a nightly compiler in some way. and removed F-async_await labels Jul 28, 2019
@compiler-errors
Copy link
Member

This is expressible now with reworked async closures (#120361) and async Fn() bounds:

#![feature(async_closure)]
#![allow(unused)]

struct Task<T> {
    task: T,
}

impl<T> Task<T>
where
    T: Fn(),
{
    fn new(task: T) -> Self {
        Self { task }
    }

    fn execute(&self) {
        (self.task)();
    }
}

struct AsyncTask<T> {
    task: T,
}

impl<T> AsyncTask<T>
where
    T: async Fn(),
{
    fn new(task: T) -> Self {
        Self { task }
    }

    async fn execute(&self) {
        (self.task)().await;
    }
}

fn main() {
    let string = "Hello, World!".to_string();
    let _task = Task::new(move || {
        println!("{}", string);
    });

    let string = "Hello, World!".to_string();
    let _async_task = AsyncTask::new(async move || {
        println!("{}", string);
    });
}

@dev-ardi
Copy link
Contributor

Shouldn't this be closed then?

@compiler-errors
Copy link
Member

@dev-ardi: No. Async closures are not stable.

@dev-ardi
Copy link
Contributor

Is that how it works?
If an issue in stable 1.78 is fixed in release 1.80 when is the issue closed? When the fixing PR is closed, at the beta release or when the fix becomes stable?

@compiler-errors compiler-errors added fixed-by-async-closures Fixed by `#![feature(async_closure)]` and removed F-async_closure `#![feature(async_closure)]` labels Nov 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-async-await Area: Async & Await A-closures Area: Closures (`|…| { … }`) AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. fixed-by-async-closures Fixed by `#![feature(async_closure)]` requires-nightly This issue requires a nightly compiler in some way. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

6 participants