I have a trait Foo<'a>: 'a
, and a closure F: FnOnce(&'a Bar) -> R where R: Foo<'a>
. I'm trying to convert it to a boxed one which looks like this:
Box<dyn for<'a> FnOnce(&'a Bar) -> Box<dyn Foo<'a> + 'a>>
The problem is, it is not possible to use HRTBs for both F
and R
, so I have to use a workaround. Here is my try:
trait Foo<'a>: 'a {}
struct Bar;
trait Helper<'a> {
type R: Foo<'a>;
}
impl<'a, F, R> Helper<'a> for F
where
F: FnOnce(&'a Bar) -> R,
R: Foo<'a>,
{
type R = R;
}
fn poly<F>(f: F) -> Box<dyn for<'a> FnOnce(&'a Bar) -> Box<dyn Foo<'a> + 'a>>
where
for<'a> F: 'static + Helper<'a> + FnOnce(&'a Bar) -> <F as Helper<'a>>::R,
{
Box::new(move |b| Box::new(f(b)))
}
fn main() {
struct FooEx<'a>(&'a Bar);
impl<'a> Foo<'a> for FooEx<'a> {}
let _ = poly(|x| FooEx(x));
}
I get a weird error:
error[E0644]: closure/generator type that references itself
--> src/main.rs:26:18
|
26 | let _ = poly(|x| FooEx(x));
| ^^^^^^^^^^^^ cyclic type of infinite size
|
= note: closures cannot capture themselves or take themselves as argument;
this error may be the result of a recent compiler bug-fix,
see issue #46062 <https://github.com/rust-lang/rust/issues/46062>
for more information
Clearly the closure doesn't reference itself. Adding let () = x
shows that x
is in fact &Bar
as expected. So the error message seems as a compiler bug (I've tried both stable and nightly).
The question is, how do I implement this poly
function in a way that works and keeps the lifetime relationship between the argument and the return value.