Skip to content

"implementation of Fn is not general enough" on some conditions when using closures #135004

Open
@Alogani

Description

@Alogani

Hello rust team!

I crossed the following compiler error.
There is a lifetime elision problem on closures on some specific conditions

  • they accept as input a struct with a lifetime
  • they are transmited to a function accepting multiple of them as generics

Quite hard to explain with words, so here is the simplified example:

The code:

pub struct InodeMapper;

pub struct ValueCreatorParams<'a> {
    pub child_name: &'a u32,
}

impl InodeMapper {
    pub fn batch_insert<F, G>(
        &self,
        f1: F,
        f2: G
    )
    where
        F: for <'a> Fn(ValueCreatorParams<'a>) -> u32,
        G: for <'b> Fn(ValueCreatorParams<'b>) -> i32
    {
        todo!()
    }
}

fn test_batch_insert_large_entries_varying_depths() {
    let mapper = InodeMapper{};
    let f1 = |_| 1;
    let f2 = |_| 2;

    // *** ERROR ON FOLLOWING LINE ***
    mapper.batch_insert(f1, f2);
}

The error

implementation of `Fn` is not general enough
closure with signature `fn(test::ValueCreatorParams<'2>) -> u32` must implement `Fn<(test::ValueCreatorParams<'1>,)>`, for any lifetime `'1`...
...but it actually implements `Fn<(test::ValueCreatorParams<'2>,)>`, for some specific lifetime `'2`rustc[Click for full compiler diagnostic](rust-analyzer-diagnostics-view:/diagnostic%20message%20[4]?4#file:///home/alogani/Coding/easy_fuser/src/types/test.rs)
implementation of `FnOnce` is not general enough
closure with signature `fn(test::ValueCreatorParams<'2>) -> u32` must implement `FnOnce<(test::ValueCreatorParams<'1>,)>`, for any lifetime `'1`...
...but it actually implements `FnOnce<(test::ValueCreatorParams<'2>,)>`, for some specific lifetime `'2`rustc[Click for full compiler diagnostic](rust-analyzer-diagnostics-view:/diagnostic%20message%20[5]?5#file:///home/alogani/Coding/easy_fuser/src/types/test.rs)

The solution:

Fully qualify the types of the closure arguments (for both)!

fn test_batch_insert_large_entries_varying_depths() {
    let mapper = InodeMapper{};
    let f1 = |_: ValueCreatorParams| 1;
    let f2 = |_: ValueCreatorParams| 2;

    mapper.batch_insert(f1, f2);
}

And now it works like a charm !

Meta

rustc --version --verbose:

rustc 1.82.0 (f6e511eec 2024-10-15)
binary: rustc
commit-hash: f6e511eec7342f59a25f7c0534f1dbea00d01b14
commit-date: 2024-10-15
host: x86_64-unknown-linux-gnu
release: 1.82.0
LLVM version: 19.1.1

## Suggestions

Obviously, it has a solution, but I fill the bug report, because:

  • this is a situation where I don't understand why the compiler can't infer the lifetime. (Maybe there is a reason a good reason and it shall not be corrected? To be honest, I am not sure to understand the intrinsics)
  • the error is not explicit (it took me several hours to isolate correctly the cause of the problem in my more complex codebase, I thought the problem were on signatures of the receiving function). So is there an improvement possible on compiler message ? Especially the compiler don't say how it infers a different lifetime for the two closures to help resolve the problem.

Thanks!

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsA-lifetimesArea: Lifetimes / regionsC-bugCategory: This is a bug.T-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