My guess is that you're getting &&str in the iterator (if you used &ID), and the outer & is not static but borrowed temporarily. The fix for that is to dereference it or add .copied() to the iterator.
I can't explain it fully, but it has something to do with type inference for closures with higher ranked lifetimes.
although the type of the Stream::Item is a single type &'static str, for some reason when a reference type is involved (even if the reference has a lifetime of 'static), the type checker want the closure to have higher ranked lifetimes. if you replace the closure with a named function, it compiles:
a usual workaround for similar inference error is to use an explicit annotated coersion site to wrap the closure, but unfortunately in this case, the return type of the closure is an unnamable future, it is impossible to annotate, unless you want to box the returned future of the closure:
fn funnel<F>(f: F) -> F
where
F: FnMut(&str) -> Pin<Box<dyn Future<Output = Result<(), ()>> + Send + '_>>,
{
f
}
stream::iter(ID)
.map(funnel(|id| {
async move {
match id {
"foo" => Ok(()),
"bar" => Ok(()),
_ => unreachable!(),
}
}
.boxed()
}))
.buffer_unordered(2)
.try_collect::<()>()
.await?;
If the named function accepts a &'static str, it still fails.
It’s definitely something to do with the trait solver being weird about references as inputs… replace the input with some struct Foo(&’static str) (and add ID.map(Foo), id.0 where appropriate) so it shouldn’t be a trait bound issue.
I’m suspicious of some where Self: Sized bounds…. I recall those being inexplicably weird when higher-order closures are involved.
funny enough, if you create a wrapper type, then the type checker will not demand a closure with higher ranked trait bounds, because the wrapper type doesn't have a lifetime:
interesting, I just read through the linked issue where it is mentioned that Send actually triggers the error. if I remove the Send bound in the original example code, it indeed compiles: