-
Notifications
You must be signed in to change notification settings - Fork 13.6k
Point at the Fn()
or FnMut()
bound that coerced a closure, which caused a move error
#144558
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
base: master
Are you sure you want to change the base?
Conversation
…caused a move error When encountering a move error involving a closure because the captured value isn't `Copy`, and the obligation comes from a bound on a type parameter that requires `Fn` or `FnMut`, we point at it and explain that an `FnOnce` wouldn't cause the move error. ``` error[E0507]: cannot move out of `foo`, a captured variable in an `Fn` closure --> f111.rs:15:25 | 14 | fn do_stuff(foo: Option<Foo>) { | --- ----------- move occurs because `foo` has type `Option<Foo>`, which does not implement the `Copy` trait | | | captured outer variable 15 | require_fn_trait(|| async { | -- ^^^^^ `foo` is moved here | | | captured by this `Fn` closure 16 | if foo.map_or(false, |f| f.foo()) { | --- variable moved due to use in coroutine | help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once --> f111.rs:12:53 | 12 | fn require_fn_trait<F: Future<Output = ()>>(_: impl Fn() -> F) {} | ^^^^^^^^^ help: consider cloning the value if the performance cost is acceptable | 16 | if foo.clone().map_or(false, |f| f.foo()) { | ++++++++ ```
This PR modifies |
This comment was marked as resolved.
This comment was marked as resolved.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I personally don't think this change is worth it 🤔
I think that most functions which require an Fn/FnMut
do so as they intend to call it multiple times, so suggesting to weaken this bound is likely to be incorrect.
While I think adding a note which explains that FnMut
closures may be called multiple times and therefore must not consume their captured values could be useful to some users, I worry that these error messages are already very large: playground
error[E0507]: cannot move out of `foo`, a captured variable in an `Fn` closure
--> src/lib.rs:11:25
|
10 | fn do_stuff(foo: Option<Foo>) {
| --- ----------- move occurs because `foo` has type `Option<Foo>`, which does not implement the `Copy` trait
| |
| captured outer variable
11 | require_fn_trait(|| async {
| -- ^^^^^ `foo` is moved here
| |
| captured by this `Fn` closure
12 | if foo.map_or(false, |f| f.foo()) {
| --- variable moved due to use in coroutine
|
note: if `Foo` implemented `Clone`, you could clone the value
--> src/lib.rs:1:1
|
1 | struct Foo;
| ^^^^^^^^^^ consider implementing `Clone` for this type
...
12 | if foo.map_or(false, |f| f.foo()) {
| --- you could clone this value
I think the main issue here is that we're pointing to Foo
not being Clone
instead of the fact that map_or
moves the Option
. We should extend our "use .as_ref()
" suggestion to extend to this snippet but not add any additional information about the way Fn/FnMut
closures work as while potentially useful, I think it's not worth the noise for most users (and stops being useful after seeing it for the first few times)
I agree that the diagnostic for these cases is getting a bit long, my rule of thumb is that the more uncommon a diagnostic is the less problematic it is to be more communicative. For this case in particular there are 3 possibilities that a person would follow: 1) clone the value (what we already suggest), 2) use
I think that cloning is the most natural thing someone would try, getting ahead of them and letting them know that the type isn't I'm just concerned with not showing information that is needed in a subset of cases because it is always adding to the verbosity. Specially for ownership errors, which can be notoriously tricky to understand when not given enough information. For errors that happen more often (E0277, E0308), I'd be more concerned with optimizing for terse output. |
CC #47850, which is the same case handled here for function calls but for methods. |
When encountering a move error involving a closure because the captured value isn't
Copy
, and the obligation comes from a bound on a type parameter that requiresFn
orFnMut
, we point at it and explain that anFnOnce
wouldn't cause the move error.Fix #68119, by pointing at
Fn
andFnMut
bounds involved in move errors.