I have a cut-down example below, and playground here.
It seems that without the closure, rustc does something not quite right with one of the lifetimes:
|
46 | let result0 = nest(Succ::trace, &input);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected trait `for<'a> Fn<(&'a Succ<'a, '_, Zero>,)>`
found trait `Fn<(&Succ<'_, '_, Zero>,)>`
note: the lifetime requirement is introduced here
use std::{
cell::RefCell,
fmt::Debug,
};
trait OpTrait {}
struct Op<T>(T);
impl<T> OpTrait for Op<T> {}
#[derive(Clone)]
struct Succ<'a, 't, T: 't>(T, &'a RefCell<Option<Box<dyn OpTrait + 't>>>);
impl<'a, 't, T: Clone + 't> Succ<'a, 't, T>
{
fn trace(&self) -> Self {
// what this does is unimportant
let b = Box::new(Op(self.0.clone()));
let _r = self.1.borrow_mut().insert(b);
Succ(self.0.clone(), self.1)
}
}
#[derive(Debug, Clone)]
struct Zero;
fn nest<'t, T: Clone + 't, F>(f: F, t: &T) -> T
where
for<'a> F: Fn(&'a Succ<'a, 't, T>) -> Succ<'a, 't, T>,
{
let trace = RefCell::new(None);
let nested = Succ(t.clone(), &trace);
let result = f(&nested);
result.0
}
fn main() {
let input = Zero;
// ok - but redundant closure
let result1 = nest(|n| n.trace(), &input);
dbg!(result1);
// boom
let result0 = nest(Succ::trace, &input);
dbg!(result0);
}
This doesn't block me - happy to keep the closures and add an allow
, but it kinda piqued my interest. I can't figure out what is going wrong here or why a closure does work.
Cheers!