Repository: rust-lang-nursery/futures-rs (rust)

Issue:
join_all() is too picky about lifetimes
Consider the following function:

```rust
fn foo<'a>(bufs: Vec<&'a [u8]>) -> Box<::futures::Future<Item=Vec<usize>, Error=()> + 'static> {
    let iter = bufs.into_iter().map(|b| ::futures::future::ok::<usize, ()>(b.len()));
    Box::new(::futures::future::join_all(iter))
}
```

I expect this to typecheck successfully, but I get an error:

```
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:35:21
   |
35 |     let iter = bufs.into_iter().map(|b| ::futures::future::ok::<usize, ()>(b.len()));
   |                     ^^^^^^^^^
   |
   = note: first, the lifetime cannot outlive the lifetime 'a as defined on unknown free region bounded by scope CodeExtent(212/CallSiteScope { fn_id: NodeId(122), body_id: NodeId(276) })...
note: ...so that types are compatible (expected std::vec::Vec<&[u8]>, found std::vec::Vec<&'a [u8]>)
  --> src/main.rs:35:21
   |
35 |     let iter = bufs.into_iter().map(|b| ::futures::future::ok::<usize, ()>(b.len()));
   |                     ^^^^^^^^^
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `futures::JoinAll<std::iter::Map<std::vec::IntoIter<&[u8]>, [closure@src/main.rs:35:37: 35:84]>>` will meet its required lifetime bounds
  --> src/main.rs:36:5
   |
36 |     Box::new(::futures::future::join_all(iter))
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error
```

The problem seems to be that `JoinAll<I>` is parameterized by the type of the `IntoIterator` that is passed into `join_all()`. In the above case, that type is not `'static`, even though its `Item` is `'static`.

Pull request:
Join all into iter
Rebase of @dwrensha's work from #286.

Fixes #285, and unblocks #662.

Patch:
diff --git a/src/future/join_all.rs b/src/future/join_all.rs
index 398a7a47..e1cddd42 100644
--- a/src/future/join_all.rs
+++ b/src/future/join_all.rs
@@ -19,18 +19,16 @@ enum ElemState<T> where T: Future {
 ///
 /// This future is created with the `join_all` method.
 #[must_use = "futures do nothing unless polled"]
-pub struct JoinAll<I>
-    where I: IntoIterator,
-          I::Item: IntoFuture,
+pub struct JoinAll<Item>
+    where Item: IntoFuture,
 {
-    elems: Vec<ElemState<<I::Item as IntoFuture>::Future>>,
+    elems: Vec<ElemState<<Item as IntoFuture>::Future>>,
 }
 
 impl<I> fmt::Debug for JoinAll<I>
-    where I: IntoIterator,
-          I::Item: IntoFuture,
-          <<I as IntoIterator>::Item as IntoFuture>::Future: fmt::Debug,
-          <<I as IntoIterator>::Item as IntoFuture>::Item: fmt::Debug,
+    where I: IntoFuture,
+          <I as IntoFuture>::Future: fmt::Debug,
+          <I as IntoFuture>::Item: fmt::Debug,
 {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         fmt.debug_struct("JoinAll")
@@ -73,7 +71,7 @@ impl<I> fmt::Debug for JoinAll<I>
 ///     x
 /// });
 /// ```
-pub fn join_all<I>(i: I) -> JoinAll<I>
+pub fn join_all<I>(i: I) -> JoinAll<I::Item>
     where I: IntoIterator,
           I::Item: IntoFuture,
 {
@@ -83,12 +81,11 @@ pub fn join_all<I>(i: I) -> JoinAll<I>
     JoinAll { elems: elems }
 }
 
-impl<I> Future for JoinAll<I>
-    where I: IntoIterator,
-          I::Item: IntoFuture,
+impl<Item> Future for JoinAll<Item>
+    where Item: IntoFuture,
 {
-    type Item = Vec<<I::Item as IntoFuture>::Item>;
-    type Error = <I::Item as IntoFuture>::Error;
+    type Item = Vec<<Item as IntoFuture>::Item>;
+    type Error = <Item as IntoFuture>::Error;
 
 
     fn poll(&mut self) -> Poll<Self::Item, Self::Error> {


Test patch:
diff --git a/tests/all.rs b/tests/all.rs
index bdd67315..7c093b2b 100644
--- a/tests/all.rs
+++ b/tests/all.rs
@@ -251,6 +251,18 @@ fn collect_collects() {
     // TODO: needs more tests
 }
 
+#[test]
+fn join_all_iter_lifetime() {
+    // In futures-rs version 0.1, this function would fail to typecheck due to an overly
+    // conservative type parameterization of `JoinAll`.
+    fn sizes<'a>(bufs: Vec<&'a [u8]>) -> Box<Future<Item=Vec<usize>, Error=()> + 'static> {
+        let iter = bufs.into_iter().map(|b| future::ok::<usize, ()>(b.len()));
+        Box::new(join_all(iter))
+    }
+
+    assert_done(|| sizes(vec![&[1,2,3], &[], &[0]]), Ok(vec![3, 0, 1]));
+}
+
 #[test]
 fn select2() {
     fn d<T, U, E>(r: Result<(T, U), (E, U)>) -> Result<T, E> {