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

Error message for closure with async block needs improvement #68119

Open
tmandry opened this issue Jan 11, 2020 · 3 comments
Open

Error message for closure with async block needs improvement #68119

tmandry opened this issue Jan 11, 2020 · 3 comments
Labels
A-async-await A-closures A-diagnostics AsyncAwait-Triaged C-enhancement D-confusing P-medium T-compiler

Comments

@tmandry
Copy link
Contributor

@tmandry tmandry commented Jan 11, 2020

Playground

fn do_stuff(foo: Option<Foo>) {
    require_fn_trait(|| async {
        if foo.map_or(false, |f| f.foo()) {
            panic!("foo");
        }
        //ready(())
    })
}

gives

error[E0507]: cannot move out of `foo`, a captured variable in an `Fn` closure
  --> src/lib.rs:14:31
   |
13 |   fn do_stuff(foo: Option<Foo>) {
   |               --- captured outer variable
14 |       require_fn_trait(|| async {
   |  _______________________________^
15 | |         if foo.map_or(false, |f| f.foo()) {
   | |            ---
   | |            |
   | |            move occurs because `foo` has type `std::option::Option<Foo>`, which does not implement the `Copy` trait
   | |            move occurs due to use in generator
16 | |             panic!("foo");
17 | |         }
18 | |         //ready(())
19 | |     })
   | |_____^ move out of `foo` occurs here
   |
help: consider borrowing the `Option`'s content
   |
14 |     require_fn_trait(|| async {
15 |         if foo.map_or(false, |f| f.foo()) {
16 |             panic!("foo");
17 |         }
18 |         //ready(())
19 |     }.as_ref())
   |

Note move occurs due to use in generator. Also, the code is being output twice, for some reason.

If you take this out of the async context by removing async and uncommenting ready(()), you get a better suggestion to use as_ref() and an all-around cleaner error message:

error[E0507]: cannot move out of `foo`, a captured variable in an `Fn` closure
  --> src/lib.rs:15:12
   |
13 | fn do_stuff(foo: Option<Foo>) {
   |             --- captured outer variable
14 |     require_fn_trait(|| {
15 |         if foo.map_or(false, |f| f.foo()) {
   |            ^^^
   |            |
   |            move occurs because `foo` has type `std::option::Option<Foo>`, which does not implement the `Copy` trait
   |            help: consider borrowing the `Option`'s content: `foo.as_ref()`

Thanks to @JakeEhrlich for originally reporting this.

@jonas-schievink jonas-schievink added A-async-await A-closures A-diagnostics T-compiler labels Jan 11, 2020
@JohnTitor JohnTitor added the C-enhancement label Jan 12, 2020
@tmandry tmandry changed the title Error message for closure with async block mentions generators Error message for closure with async block needs improvement Jan 13, 2020
@nikomatsakis
Copy link
Contributor

@nikomatsakis nikomatsakis commented Jan 14, 2020

It took me a while to process what's going on here. I guess the biggest problem is the "move of foo occurs here" that highlights the whole async block.

In contrast, we don't show (for closures) the "closure creation" as the point of a move (although it technically is). We just show the point within the closure body that's responsible.

Looking more closely at the example, it seems like there are actually several moves happening

  • into the outer closure
  • into the async block
  • then into map_or call

and so I guess we are suppressing one but not the rest. I'd have to go digging a bit to give more specifics on how to fix.

@tmandry
Copy link
Contributor Author

@tmandry tmandry commented Jan 14, 2020

@rustbot modify labels to +AsyncAwait-OnDeck

Good diagnostics are a priority

@tmandry tmandry added the AsyncAwait-Triaged label Jan 14, 2020
@tmandry tmandry added this to To do in wg-async work Feb 11, 2020
@tmandry tmandry added D-confusing P-medium labels Mar 3, 2020
@tmandry tmandry removed this from To do in wg-async work Mar 3, 2020
@folex
Copy link
Contributor

@folex folex commented Jan 12, 2021

I also got bitten by this error message
link to playground

    arr.into_iter().map(move |_e| {
        async move {
            let value = cloned_value.clone();
            println!("{:?}", value.lock().ok())
        }
    })

And the error got me confused because I'm not familiar with the "generator" concept - I have seen it in some blog posts but never met it in practice.

move occurs due to use in generator

Consider a very similar situation

    arr.into_iter().map(move |_e| {
        move || {
            let value = cloned_value.clone();
            println!("{:?}", value.lock().ok())
        }
    })

which yields

move occurs due to use in closure

I've much more accustomed to thinking about closures - these I imagine as structures that capture the context in their fields. So this leads me to a solution much faster.

However, note that E0507 talks about a borrowed value, but here it is hard to see where it is borrowed since everything is marked as move

E0507 A borrowed value was moved out.

These are just my thoughts on a topic, hope that might help you! Thanks a lot for your tremendous works!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-async-await A-closures A-diagnostics AsyncAwait-Triaged C-enhancement D-confusing P-medium T-compiler
Projects
None yet
Development

No branches or pull requests

6 participants