I ran into the limitations of that closure hack about a year ago when trying to write a macro which could be used like this:
zip_with!(
(frac, radii, self.sorted.as_ref(), self.hints.as_mut())
|x, r, set, hints| {
hints.start = update_lower_hint(hints.start, &set.keys, x - r);
hints.end = update_upper_hint(hints.end, &set.keys, x + r);
});
The trouble is that eta expansion pretty much destroys the order-based type checker if you do it anywhere except directly as a function parameter:
// works just fine
expr.map(|((x, y), z)| x.stuff);
// ERROR: the type of x must be known
expr.map(|((x, y), z)| (|x, y, z| x.stuff)(x, y, z));
of course, the latter is what my macro actually expanded into. To work around this, I created a helper type which allowed the user's closure to appear directly as an argument. Basically, the macro was changed to expand into:
obj.map(|((x, y), z)| $crate::FlippedCall((x, y, z)).on(|x, y, z| x.stuff)); // ok
tl;dr: In a macro where $f:expr
, thou shalt not write $f($args)
.