rust-lang / rust-lang/rust

Confusing diagnostic for closures

Open
#147,264 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
use std::io::Read;

pub trait HttpClient {
    fn get(&self, url: &str) -> Result<Box<dyn Read>, std::io::Error>;
}

struct DummyHttpClient<T> {
    responder: T,
}

impl<T> HttpClient for DummyHttpClient<T>
where
    T: Fn(&str) -> Result<Box<dyn Read>, std::io::Error>,
{
    fn get(&self, url: &str) -> Result<Box<dyn Read>, std::io::Error> {
        (self.responder)(url)
    }
}

struct UserBuilder {
    client: Option<Box<dyn HttpClient>>,
}

impl UserBuilder {
    pub fn new() -> Self {
        Self { client: None }
    }

    /// Set the HTTP client to use for requests.
    pub fn http_client(mut self, client: Box<dyn HttpClient>) -> Self {
        self.client = Some(client);
        self
    }
}

fn test_custom_http_client() {
    let http_client = Box::new(DummyHttpClient {
        responder: |url| {
            Err(std::io::Error::new(
                std::io::ErrorKind::Other,
                format!("DummyHttpClient cannot fetch {url}"),
            ))
        },
    });
    let client = UserBuilder::new().http_client(http_client);
}
Current output
error: implementation of `FnOnce` is not general enough
  --> src/lib.rs:45:49
   |
45 |     let client = UserBuilder::new().http_client(http_client);
   |                                                 ^^^^^^^^^^^ implementation of `FnOnce` is not general enough
   |
   = note: closure with signature `fn(&'2 str) -> Result<Box<dyn std::io::Read>, std::io::Error>` must implement `FnOnce<(&'1 str,)>`, for any lifetime `'1`...
   = note: ...but it actually implements `FnOnce<(&'2 str,)>`, for some specific lifetime `'2`

error: implementation of `Fn` is not general enough
  --> src/lib.rs:45:49
   |
45 |     let client = UserBuilder::new().http_client(http_client);
   |                                                 ^^^^^^^^^^^ implementation of `Fn` is not general enough
   |
   = note: closure with signature `fn(&'2 str) -> Result<Box<dyn std::io::Read>, std::io::Error>` must implement `Fn<(&'1 str,)>`, for any lifetime `'1`...
   = note: ...but it actually implements `Fn<(&'2 str,)>`, for some specific lifetime `'2`
Desired output

It should suggest that adding explicit type annotation &str to the argument of the closure would fix the issue. Or that you could add

  where
    T: Fn(&str) -> Result<Box<dyn Read>, std::io::Error>,

to the struct itself. That also fixes the issue.

Rationale and extra context

The current diagnostic is highly confusing and not helpful.

Other cases

Rust Version
❯ rustc --version --verbose
rustc 1.90.0 (1159e78c4 2025-09-14)
binary: rustc
commit-hash: 1159e78c4747b02ef996e55082b704c09b970588
commit-date: 2025-09-14
host: x86_64-unknown-linux-gnu
release: 1.90.0
LLVM version: 20.1.8
Anything else?

Originally reported here: https://users.rust-lang.org/t/strange-type-inference-around-fnonce-fn/134342

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

Reproduce the example in src/lib.rs with the reported rustc 1.90.0 toolchain and start at the diagnostic emitted on line 45. Trace the compiler diagnostic path for the not-general-enough Fn and FnOnce messages; done means the output explains the lifetime mismatch and suggests annotating the closure argument or constraining T on the struct.

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.