Reposting from SO: rust - Trait objects force higher-ranked trait bounds, which break nested closures - Stack Overflow hope that's ok. (Didn't get a lot of views there, so maybe more lucky here?) Happy to sync both threads back and forth.
I am in a situation where Rust makes me add a HRTB for a generic type that is used as argument in a trait object. But this HRTB makes nested closures not work.
Here's the trait I'm going to use to make a trait object Box<dyn OpTrait>
:
trait OpTrait {}
struct Op<T>(T);
impl<T> OpTrait for Op<T> {}
Here's the struct with the trait objects:
#[derive(Clone)]
struct Succ<'a, T>(T, &'a RefCell<Option<Box<dyn OpTrait>>>);
impl<'a, T: Clone> Succ<'a, T>
where
for<'c> T: 'c,
{
fn trace(&self) -> Self {
let b = Box::new(Op(self.0.clone()));
self.1.borrow_mut().insert(b);
Succ(self.0.clone(), self.1)
}
}
#[derive(Debug, Clone)]
struct Zero;
And here's the function to put it all together:
fn nest<T: Clone, F>(f: F, t: &T) -> T
where
for<'a> F: Fn(&Succ<'a, T>) -> Succ<'a, T>,
{
let trace = RefCell::new(None);
let nested = Succ(t.clone(), &trace);
let result = f(&nested);
result.0
}
I can use this like:
let input = Zero;
let result0 = nest(|n| n.trace(), &input);
which works.
But actually nesting the nest
call stops working:
let result = nest(|n| nest(|nn| nn.trace(), n), &input);
--> src/main.rs:46:37
|
46 | let result = nest(|n| nest(|nn| nn.trace(), n), &input);
| - ^^^^^^^^^^
| | |
| | `n` escapes the closure body here
| | argument requires that `'1` must outlive `'static`
| `n` is a reference that is only valid in the closure body
| has type `&Succ<'1, Zero>`
Note:
Rust makes me add for<'c> T: 'c
in the impl
for Succ
- something to do with the trait object, I'm not exactly sure. This HRTB causes the problem with nested closures - without it in play, nested closures work fine:
// ok
let result2 = nest(|n| nest(|nn| nn.clone(), n), &input);
Playground: Rust Playground
EDIT: There's something with the 'a lifetime of the reference in Succ.
When I update that struct to remove the reference (and use Rc to support Clone):
#[derive(Clone)]
struct Succ<T>(T, Rc<dyn OpTrait>);
That works fine with the nesting, despite needing one more HRTB for T
on nest
.