3

I want to register Gen::my_g as a callback. The simple way is to implement trait Foo for Gen, but I do not want to implement trait Foo for Gen.

In other words, I want to comment out the code marked as B!!! and uncomment the code marked as A!!!.

This is not my code; I can not modify this:

struct S1;

struct TT;
trait MyRes {}

trait Foo {
    fn g<'a>(&self, ecx: &'a mut S1, tt: &[TT]) -> Box<MyRes + 'a>;
}

impl<F> Foo for F
where
    F: for<'a> Fn(&'a mut S1, &[TT]) -> Box<MyRes + 'a>,
{
    fn g<'a>(&self, ecx: &'a mut S1, tt: &[TT]) -> Box<MyRes + 'a> {
        (*self)(ecx, tt)
    }
}

fn f1<F>(name: &str, extension: F)
where
    F: Foo + 'static,
{
}

This is my code:

struct Gen {}
impl Gen {
    fn register(self) {

        //        f1("aaa", move |ecx, tt| self.my_g(ecx, tt));//A!!!

        f1("aaa", self); //B!!!
    }

    fn my_g<'a>(&self, ecx: &'a mut S1, tt: &[TT]) -> Box<MyRes + 'a> {
        unimplemented!();
    }
}

impl Foo for Gen {
    fn g<'a>(&self, ecx: &'a mut S1, tt: &[TT]) -> Box<MyRes + 'a> {
        self.my_g(ecx, tt)
    }
}

If I uncomment //A!!!, the compiler tells me something that I do not understand:

error[E0271]: type mismatch resolving `for<'a, 'r> <[closure@src/main.rs:29:19: 29:52 self:_] as std::ops::FnOnce<(&'a mut S1, &'r [TT])>>::Output == std::boxed::Box<MyRes + 'a>`
  --> src/main.rs:29:9
   |
29 |         f1("aaa", move |ecx, tt| self.my_g(ecx, tt)); //A!!!
   |         ^^ expected bound lifetime parameter, found concrete lifetime
   |
   = note: concrete lifetime that was found is lifetime '_#12r
   = note: required because of the requirements on the impl of `Foo` for `[closure@src/main.rs:29:19: 29:52 self:_]`
   = note: required by `f1`

error[E0281]: type mismatch: `[closure@src/main.rs:29:19: 29:52 self:_]` implements the trait `std::ops::Fn<(&mut S1, &[TT])>`, but the trait `for<'a, 'r> std::ops::Fn<(&'a mut S1, &'r [TT])>` is required
  --> src/main.rs:29:9
   |
29 |         f1("aaa", move |ecx, tt| self.my_g(ecx, tt)); //A!!!
   |         ^^        --------------------------------- implements `std::ops::Fn<(&mut S1, &[TT])>`
   |         |
   |         requires `for<'a, 'r> std::ops::Fn<(&'a mut S1, &'r [TT])>`
   |         expected concrete lifetime, found bound lifetime parameter
   |
   = note: required because of the requirements on the impl of `Foo` for `[closure@src/main.rs:29:19: 29:52 self:_]`
   = note: required by `f1`
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
user1244932
  • 7,352
  • 5
  • 46
  • 103
  • Duplicate of https://stackoverflow.com/q/31362206/2731452 In your case you can use `fn constrain_handler(f: F) -> F where F: for<'a> Fn(&'a mut S1, &[TT]) -> Box { f }` – red75prime Jul 24 '17 at 07:30

1 Answers1

1

This is a known issue:

The Rust compiler currently cannot infer that a closure is valid for any lifetime (which is what the type of Foo::g requires). It will infer any concrete lifetime, but does not generalize beyond that.

Florian Weimer
  • 32,022
  • 3
  • 48
  • 92