Skip to content

unhelpful error when giving an instance method to a generic function requiring a function #162033

Description

@quantenzitrone

Code

fn call<C>(f: C)
where
    C: Fn(),
{
    f()
}

struct FooPrinter {}

impl FooPrinter {
    fn print(&self) {
        println!("foo");
    }
    fn new() -> Self {
        FooPrinter {}
    }
}

fn print_foo() {
    println!("foo");
}

fn main() {
    // passing a normal function
    call(print_foo);

    // clippy lints this
    call(|| print_foo());

    // doesn't work
    call(FooPrinter::new().print);

    // fixed looks like clippy would lint this
    call(|| FooPrinter::new().print());
}

Current output

error[E0615]: attempted to take value of method `print` on type `FooPrinter`
  --> src/main.rs:21:28
   |
21 |     call(FooPrinter::new().print);
   |                            ^^^^^ method, not a field
   |
help: use parentheses to call the method
   |
21 |     call(FooPrinter::new().print());
   |                                 ++

For more information about this error, try `rustc --explain E0615`.

Desired output

error[E0615]: cannot use `print` on instance of type `FooPrinter` for generic
  --> src/main.rs:21:28
   |
21 |     call(FooPrinter::new().print);
   |                            ^^^^^ method on instance
   |
help: wrap it into a closure
   |
21 |     call(|| FooPrinter::new().print());
   |          +++                       ++

Rationale and extra context

As pointed out in the code example this kinda stems from the clippy lint redundant closure lint.
I had a case where I was very confused why clippy wouldn't lint this and when I removed the lamda, it gave me this error.
It also stems from a desire to have neat code and especially when the called function has many arguments, copying all the argument types into the lamda is kinda ugly. But I get why it is required for instance methods.

Other cases

a case where adding the closure actually makes the code more ugly

mod my_external_crate {
    pub type AVeryVeryVeryVeryVeryVeryVeryLongType = ();

    pub fn call<C>(f: C)
    where
        C: Fn(AVeryVeryVeryVeryVeryVeryVeryLongType, AVeryVeryVeryVeryVeryVeryVeryLongType),
    {
        f((), ())
    }

    pub struct FooPrinter {}

    impl FooPrinter {
        pub fn print(
            &self,
            _: AVeryVeryVeryVeryVeryVeryVeryLongType,
            _: AVeryVeryVeryVeryVeryVeryVeryLongType,
        ) {
            println!("foo");
        }
        pub fn new() -> Self {
            FooPrinter {}
        }
    }

    pub fn print_foo(
        _: AVeryVeryVeryVeryVeryVeryVeryLongType,
        _: AVeryVeryVeryVeryVeryVeryVeryLongType,
    ) {
        println!("foo");
    }
}

use my_external_crate::*;

fn main() {
    // passing a normal function
    call(print_foo);

    // clippy actually does not lint this, but i think it should
    call(
        |x: AVeryVeryVeryVeryVeryVeryVeryLongType, y: AVeryVeryVeryVeryVeryVeryVeryLongType| {
            print_foo(x, y)
        },
    );

    // doesn't work
    call(FooPrinter::new().print);

    // fixed looks like clippy would lint this
    call(
        |x: AVeryVeryVeryVeryVeryVeryVeryLongType, y: AVeryVeryVeryVeryVeryVeryVeryLongType| {
            FooPrinter::new().print(x, y)
        },
    );
}

Rust Version

rustc 1.97.1 (8bab26f4f 2026-07-14) (built from a source tarball) // from nixpkgs
binary: rustc
commit-hash: 8bab26f4f68e0e26f0bb7960be334d5b520ea452
commit-date: 2026-07-14
host: x86_64-unknown-linux-gnu
release: 1.97.1
LLVM version: 21.1.8

Anything else?

Sorry if my rust lingo is not on point, i still consider myself a beginner or at most intermediate in rust.

Metadata

Metadata

Assignees

No one assigned

    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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions