Skip to content

When FnMut or Fn closure is moved and then used, the compiler should suggest borrowing it instead #90828

Closed
@WaffleLapkin

Description

@WaffleLapkin

Given the following code: (playground)

fn takes_fn(f: impl Fn()) {
    takes_fnonce(f);
    takes_fnonce(f);
}

fn takes_fnmut(f: impl FnMut()) {
    takes_fnonce(f);
    takes_fnonce(f);
}

// Could also be Fn[Mut], here it doesn't matter
fn takes_fnonce(_: impl FnOnce()) {}

The current output is:

error[E0382]: use of moved value: `f`
 --> src/lib.rs:3:18
  |
1 | fn takes_fn(f: impl Fn()) {
  |             - move occurs because `f` has type `impl Fn()`, which does not implement the `Copy` trait
2 |     takes_fnonce(f);
  |                  - value moved here
3 |     takes_fnonce(f);
  |                  ^ value used here after move
  |
help: consider further restricting this bound
  |
1 | fn takes_fn(f: impl Fn() + Copy) {
  |                          ++++++

error[E0382]: use of moved value: `f`
 --> src/lib.rs:8:18
  |
6 | fn takes_fnmut(f: impl FnMut()) {
  |                - move occurs because `f` has type `impl FnMut()`, which does not implement the `Copy` trait
7 |     takes_fnonce(f);
  |                  - value moved here
8 |     takes_fnonce(f);
  |                  ^ value used here after move
  |
help: consider further restricting this bound
  |
6 | fn takes_fnmut(f: impl FnMut() + Copy) {
  |                                ++++++

While suggestions make the code compile, they restrict the arguments. This can be avoided by borrowing functions instead.

Ideally, the output should look like this:

error[E0382]: use of moved value: `f`
 --> src/lib.rs:3:18
  |
1 | fn takes_fn(f: impl Fn()) {
  |             - move occurs because `f` has type `impl Fn()`, which does not implement the `Copy` trait
2 |     takes_fnonce(f);
  |                  - value moved here
3 |     takes_fnonce(f);
  |                  ^ value used here after move
  |
help: consider borrowing `f`
  |
2 |     takes_fnonce(&f);
  |                  +

error[E0382]: use of moved value: `f`
 --> src/lib.rs:8:18
  |
6 | fn takes_fnmut(f: impl FnMut()) {
  |                - move occurs because `f` has type `impl FnMut()`, which does not implement the `Copy` trait
7 |     takes_fnonce(f);
  |                  - value moved here
8 |     takes_fnonce(f);
  |                  ^ value used here after move
  |
help: consider borrowing `f`
  |
7 |     takes_fnonce(&mut f);
  |                  ++++

For the record, here is an example found "in the wild" where I noticed the problem: (playground)

Metadata

Metadata

Labels

A-diagnosticsArea: Messages for errors, warnings, and lintsT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions