rust-lang / rust-lang/rust

diagnostic blames variance for simple lifetime error involving struct referenced in closure if it happens to have &mut parameter

Open
#146,359 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-diagnostics T-compiler
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

Code
// This is a bit contrived as a minimization of real code
type Handler = dyn Fn(&mut i32) + Send + Sync;
struct RandAdder {
    addends: Vec<i32>
}
impl RandAdder {
    fn make_handler(&self) -> Box<Handler> {
        Box::new(move |x| {
            // Random number, chosen by dice roll
            // (fixed for easier minimization)
            let addend = self.addends[4];
            *x = *x + addend;
        })
    }
}
Current output
Compiling playground v0.0.1 (/playground)
error: lifetime may not live long enough
  --> src/lib.rs:8:9
   |
 7 |       fn make_handler(&self) -> Box<Handler> {
   |                       - let's call the lifetime of this reference `'1`
 8 | /         Box::new(move |x| {
 9 | |             // Random number, chosen by dice roll
10 | |             // (fixed for easier minimization)
11 | |             let addend = self.addends[4];
12 | |             *x = *x + addend;
13 | |         })
   | |__________^ returning this value requires that `'1` must outlive `'static`
   |
   = note: requirement occurs because of a mutable reference to `i32`
   = note: mutable references are invariant over their type parameter
   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

error: could not compile `playground` (lib) due to 1 previous error
Desired output
Compiling playground v0.0.1 (/playground)
error: lifetime may not live long enough
  --> src/lib.rs:8:9
   |
 7 |       fn make_handler(&self) -> Box<Handler> {
   |                       - let's call the lifetime of this reference `'1`
 8 | /         Box::new(move |x| {
 9 | |             // Random number, chosen by dice roll
10 | |             // (fixed for easier minimization)
11 | |             let addend = self.addends[4];
12 | |             *x = *x + addend;
13 | |         })
   | |__________^ returning this value requires that `'1` must outlive `'static`
   |
Rationale and extra context

The explanation of the error mentions variance and the mutable reference in the closure parameters, but this seems to be a red herring - the real issue is the misuse of self.addends in a move |...| closure when self is taken by reference. It is enough to take self by value, or clone addends explicitly.

Other cases
The following code gets a correct diagnostic that doesn't mention subtyping or variance


type Handler = dyn Fn(i32) -> i32 + Send + Sync;

struct RandAdder {
    addends: Vec<i32>
}
impl RandAdder {
    fn make_handler(&self) -> Box<Handler> {
        Box::new(move |x| {
            // Random number, chosen by dice roll
            // (fixed for easier minimization)
            let addend = self.addends[4];
            x + addend
        })
    }
}
Rust Version
Using the playground w/ nightly: 1.91.0-nightly(2025-09-08 9c27f27ea3bab79a2fec) (I don't see a way to run `rustc --version --verbose`
Anything else?

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the minimized Rust example and comparing its diagnostic with the non-mutable-parameter example in the report. Trace the compiler diagnostic path for lifetime errors involving closures, then adjust the output so the variance and mutable-reference explanation is omitted when it is misleading. Done means the first example reports only the lifetime requirement while the other case retains its correct diagnostic.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.