diagnostic blames variance for simple lifetime error involving struct referenced in closure if it happens to have &mut parameter
Nobody has claimed this yet.
- 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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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