rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
97.26k stars 12.57k forks source link

Associated functions of generic types are not static #89667

Open camsteffen opened 2 years ago

camsteffen commented 2 years ago
trait Trait {
    fn fun();
}

fn takes_static_fn(_: impl Fn() + 'static) {}

fn test<T: Trait>() {
    // these work
    takes_static_fn(|| T::fun());
    takes_static_fn(T::fun as fn());

    // this seems like it ought to work
    takes_static_fn(T::fun);
}
error[E0310]: the parameter type `T` may not live long enough
  --> src/lib.rs:12:5
   |
7  | fn test<T: Trait>() {
   |         -- help: consider adding an explicit lifetime bound...: `T: 'static +`
...
12 |     takes_static_fn(T::fun);
   |     ^^^^^^^^^^^^^^^ ...so that the type `fn() {<T as Trait>::fun}` will meet its required lifetime bounds

For more information about this error, try `rustc --explain E0310`.
QuineDot commented 2 years ago

T::fun is a projection through T and thus is lifetime-limited by the lifetime of T as per RFC 1214. This is what E0310 is talking about in your example, and why it recommends adding a T: 'static bound.

This works as, per RFC 401, function types coerce to function pointers with the same argument signatures:

takes_static_fn(T::fun as fn());

And this is fine because it always calls the lifetime-limited function item, but doesn't capture environment and thus also coerces as per RFC 401:

takes_static_fn(|| T::fun());

Edit: Ehh, not coerces, but implements Fn() statically.

Enselic commented 3 months ago

Triage: Since the behavior is following RFC 1214, changing this would presumably require a new RFC that complements RFC 1214. I added a needs-rfc label.

Enselic commented 2 months ago

Triage: https://github.com/rust-lang/rust/issues/85456 is older, but this issue is more succinct, so I closed that issue as duplicate to this one.