Skip to content

E0594 suggests changing an unrelated return type when assigning to a captured variable in a nested Fn closure #155727

@rustily-indecisive

Description

@rustily-indecisive

Code

use rayon::prelude::*;

fn main() {}

struct BadCounter {
    counter: i32,
}

impl BadCounter {
    fn count(mut self) -> i32 {
        (0..8).into_par_iter().map(|_| self.counter += 1);
        self.counter
    }
}

struct EvilCounter {
    counter: i32,
}

impl EvilCounter {
    fn count(mut self) -> i32 {
        (0..8)
            .into_par_iter()
            .flat_map(|_| (0..8).into_par_iter().map(|_| self.counter += 1));
        self.counter
    }
}

Current output

error[E0594]: cannot assign to `self.counter`, as it is a captured variable in a `Fn` closure
  --> src/main.rs:11:40
   |
11 |         (0..8).into_par_iter().map(|_| self.counter += 1);
   |                                    --- ^^^^^^^^^^^^^^^^^ cannot assign
   |                                    |
   |                                    in this closure

error[E0594]: cannot assign to `self.counter`, as it is a captured variable in a `Fn` closure
  --> src/main.rs:24:58
   |
21 |     fn count(mut self) -> i32 {
   |        -----              --- change this to return `FnMut` instead of `Fn`
...
24 |             .flat_map(|_| (0..8).into_par_iter().map(|_| self.counter += 1));
   |                                                      --- ^^^^^^^^^^^^^^^^^ cannot assign
   |                                                      |
   |                                                      in this closure

error: lifetime may not live long enough
  --> src/main.rs:24:27
   |
24 |             .flat_map(|_| (0..8).into_par_iter().map(|_| self.counter += 1));
   |                       --- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
   |                       | |
   |                       | return type of closure `rayon::iter::Map<rayon::range::Iter<i32>, {closure@src/main.rs:24:54: 24:57}>` contains a lifetime `'2`
   |                       lifetime `'1` represents this closure's body
   |
   = note: closure implements `Fn`, so references to captured variables can't escape the closure
help: consider adding 'move' keyword before the nested closure
   |
24 |             .flat_map(|_| (0..8).into_par_iter().map(move |_| self.counter += 1));
   |                                                      ++++

error[E0596]: cannot borrow `self.counter` as mutable, as it is a captured variable in a `Fn` closure
  --> src/main.rs:24:54
   |
24 |             .flat_map(|_| (0..8).into_par_iter().map(|_| self.counter += 1));
   |                       ---                            ^^^ ------------ mutable borrow occurs due to use of `self.counter` in closure
   |                       |                              |
   |                       in this closure                cannot borrow as mutable

Some errors have detailed explanations: E0594, E0596.
For more information about an error, try `rustc --explain E0594`.
error: could not compile `playground` (bin "playground") due to 4 previous errors

Desired output

No suggestion to "change this to return `FnMut` instead of `Fn`" for `EvilCounter::count`

Explanation that the argument to `rayon::ParallelIterator::map` is a `Fn` closure (so assignment is impossible) for both E0594 cases

Rationale and extra context

Issue only occurs on EvilCounter where the error is within a nested closure.

Seems related to #119985 and #125325.

In the context where I noticed this, the function in question returned an unrelated Fn closure, making the message very confusing. Being relatively new to Rust, it took me a while to realise that the error was in fact due to the map function requiring Fn. Referring to this in the error message (for both cases) would be very helpful for new users.

Other cases

Rust Version

rustc 1.97.0-nightly (36ba2c771 2026-04-23)
binary: rustc
commit-hash: 36ba2c7712052d731a7082d0eba5ed3d9d56c133
commit-date: 2026-04-23
host: x86_64-unknown-linux-gnu
release: 1.97.0-nightly
LLVM version: 22.1.2

Anything else?

No response

Metadata

Metadata

Assignees

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
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions