Repository: JelteF/derive_more (Rust)

Issue:
IntoIterator for generic type includes unnecessary trait bounds
I'm trying to derive `IntoIterator` for a custom struct that wraps over [Bevy](http://bevyengine.org)'s `Query` type, among other things:

```rust
#[derive(SystemParam, Deref, DerefMut, IntoIterator)]
pub struct AnimationControlsQuery<'w, 's, K, F = ()>
    where K: Copy + Eq + Hash + Send + Sync + TypeUuid + 'static,
          F: WorldQuery + ReadOnlyWorldQuery + 'static
{
    #[deref]
    #[deref_mut]
    #[into_iterator(ref, ref_mut)]
    query: Query<'w, 's, AnimationControls<K>, F>,
    animation_assets: Res<'w, Assets<Animation>>,
    animation_set_assets: Res<'w, Assets<AnimationSet<K>>>,
}
```

with the intended usage being roughly:

```rust
fn update_enemy_animations(
    mut animation_controls: AnimationsControlsQuery<EnemyAnimation, With<Enemy>>,
) {
    for mut anim_ctls in &mut animation_controls {
        // do something with anim_ctls which is of type &mut AnimationControls<EnemyAnimation>
    }
}
```

However, as per `cargo expand`, this generates the `IntoIterator` impls for `&'a AnimationControlsQuery<'w, 's, K, F>` and `&'a mut AnimationControlsQuery<'w, 's, K, F>` that have the following trait bounds:

```rust
impl<'w, 's, '__deriveMoreLifetime, K, F> ::core::iter::IntoIterator
    for &'__deriveMoreLifetime AnimationControlsQuery<'w, 's, K, F>
    where
        &'__deriveMoreLifetime K: ::core::iter::IntoIterator,
        &'__deriveMoreLifetime F: ::core::iter::IntoIterator,
        K: Copy + Eq + Hash + Send + Sync + TypeUuid + 'static,
        F: WorldQuery + ReadOnlyWorldQuery + 'static,
    {
        // omitted for brevity
    }
// and analogously for the mut version
```

The extra bounds on `K` and `F` are unnecessary and incorrect, rendering the impls unusable. Neither of those generic parameters are intended to be iterators/iterables themselves, and they aren't even used inside the generated `into_iter` for anything other than for specifying the exact `Query<...>` type and its `into_iter` method to delegate to:

```rust
        #[inline]
        fn into_iter(self) -> Self::IntoIter {
            <&'__deriveMoreLifetime Query<
                'w,
                's,
                AnimationControls<K>,
                F,
            > as ::core::iter::IntoIterator>::into_iter(&self.query)
        }
// similarly for the ::Item and ::IntoIter associated types
```

Thus I think those bounds should be removed by default, and perhaps an `#[into_iterator]` attribute param could be introduced for the use cases that do need them (similar to Serde's `#[serde(bound = "T: MyTrait")]`).


Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 16795055..694012e0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -72,6 +72,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
 - Fix `Error` derive not working with `const` generics.
 - Support trait objects for source in Error, e.g.
   `Box<dyn Error + Send + 'static>`
+- Fix bounds on derived `IntoIterator` impls for generic structs.
+  ([#284](https://github.com/JelteF/derive_more/pull/284))
 
 ## 0.99.10 - 2020-09-11
 
diff --git a/impl/src/into_iterator.rs b/impl/src/into_iterator.rs
index f10dbf7a..243e8346 100644
--- a/impl/src/into_iterator.rs
+++ b/impl/src/into_iterator.rs
@@ -1,5 +1,5 @@
 use crate::utils::{
-    add_extra_generic_param, add_extra_ty_param_bound_ref, SingleFieldData, State,
+    add_extra_generic_param, add_extra_where_clauses, SingleFieldData, State,
 };
 use proc_macro2::TokenStream;
 use quote::{quote, ToTokens};
@@ -26,16 +26,19 @@ pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStre
         let reference_with_lifetime = ref_type.reference_with_lifetime();
 
         let generics_impl;
-        let generics =
-            add_extra_ty_param_bound_ref(&input.generics, trait_path, ref_type);
-        let (_, ty_generics, where_clause) = generics.split_for_impl();
         let (impl_generics, _, _) = if ref_type.is_ref() {
-            generics_impl = add_extra_generic_param(&generics, lifetime.clone());
+            generics_impl = add_extra_generic_param(&input.generics, lifetime.clone());
             generics_impl.split_for_impl()
         } else {
-            generics.split_for_impl()
+            input.generics.split_for_impl()
         };
-        // let generics = add_extra_ty_param_bound(&input.generics, trait_path);
+
+        let generics = add_extra_where_clauses(
+            &input.generics,
+            quote! { where #reference_with_lifetime #field_type: #trait_path },
+        );
+        let (_, ty_generics, where_clause) = generics.split_for_impl();
+
         let casted_trait = &quote! {
             <#reference_with_lifetime #field_type as #trait_path>
         };
diff --git a/impl/src/utils.rs b/impl/src/utils.rs
index 95c3f915..cd970e28 100644
--- a/impl/src/utils.rs
+++ b/impl/src/utils.rs
@@ -159,27 +159,6 @@ pub fn add_extra_ty_param_bound<'a>(
     generics
 }
 
-pub fn add_extra_ty_param_bound_ref<'a>(
-    generics: &'a Generics,
-    bound: &'a TokenStream,
-    ref_type: RefType,
-) -> Generics {
-    match ref_type {
-        RefType::No => add_extra_ty_param_bound(generics, bound),
-        _ => {
-            let generics = generics.clone();
-            let idents = generics.type_params().map(|x| &x.ident);
-            let ref_with_lifetime = ref_type.reference_with_lifetime();
-            add_extra_where_clauses(
-                &generics,
-                quote! {
-                    where #(#ref_with_lifetime #idents: #bound),*
-                },
-            )
-        }
-    }
-}
-
 pub fn add_extra_generic_param(
     generics: &Generics,
     generic_param: TokenStream,


Test patch:
diff --git a/tests/into_iterator.rs b/tests/into_iterator.rs
index 7f9d6a36..6458ec12 100644
--- a/tests/into_iterator.rs
+++ b/tests/into_iterator.rs
@@ -2,23 +2,52 @@
 #![allow(dead_code, unused_imports)]
 
 #[cfg(not(feature = "std"))]
+#[macro_use]
 extern crate alloc;
 
 #[cfg(not(feature = "std"))]
 use alloc::vec::Vec;
+use core::fmt::Debug;
 
 use derive_more::IntoIterator;
 
+#[track_caller]
+fn assert_iter<T: PartialEq + Debug, I: IntoIterator<Item = T>>(iter: I, vals: &[T]) {
+    assert_eq!(iter.into_iter().collect::<Vec<_>>(), vals);
+}
+
 #[derive(IntoIterator)]
 #[into_iterator(owned, ref, ref_mut)]
 struct MyVec(Vec<i32>);
 
+#[test]
+fn tuple_single() {
+    let mut vals = vec![1, 2, 3];
+    let mut iter = MyVec(vals.clone());
+
+    assert_iter(&mut iter, &vals.iter_mut().collect::<Vec<_>>());
+    assert_iter(&iter, &vals.iter().collect::<Vec<_>>());
+    assert_iter(iter, &vals);
+}
+
 #[derive(IntoIterator)]
 #[into_iterator(owned, ref, ref_mut)]
 struct Numbers {
     numbers: Vec<i32>,
 }
 
+#[test]
+fn named_single() {
+    let mut vals = vec![1, 2, 3];
+    let mut iter = Numbers {
+        numbers: vals.clone(),
+    };
+
+    assert_iter(&mut iter, &vals.iter_mut().collect::<Vec<_>>());
+    assert_iter(&iter, &vals.iter().collect::<Vec<_>>());
+    assert_iter(iter, &vals);
+}
+
 #[derive(IntoIterator)]
 struct Numbers2 {
     #[into_iterator(owned, ref, ref_mut)]
@@ -27,6 +56,19 @@ struct Numbers2 {
     useless2: bool,
 }
 
+fn named_many() {
+    let mut vals = vec![1, 2, 3];
+    let mut iter = Numbers2 {
+        numbers: vals.clone(),
+        useless: true,
+        useless2: true,
+    };
+
+    assert_iter(&mut iter, &vals.iter_mut().collect::<Vec<_>>());
+    assert_iter(&iter, &vals.iter().collect::<Vec<_>>());
+    assert_iter(iter, &vals);
+}
+
 #[derive(IntoIterator)]
 struct Numbers3 {
     #[into_iterator(ref, ref_mut)]
@@ -45,3 +87,87 @@ impl ::core::iter::IntoIterator for Numbers3 {
         <Vec<i32> as ::core::iter::IntoIterator>::into_iter(self.numbers)
     }
 }
+
+#[derive(IntoIterator)]
+struct Generic1<T> {
+    #[into_iterator(owned, ref, ref_mut)]
+    items: Vec<T>,
+}
+
+#[test]
+fn generic() {
+    let mut vals = vec![1, 2, 3];
+    let mut iter = Generic1 {
+        items: vals.clone(),
+    };
+
+    assert_iter(&mut iter, &vals.iter_mut().collect::<Vec<_>>());
+    assert_iter(&iter, &vals.iter().collect::<Vec<_>>());
+    assert_iter(iter, &vals);
+}
+
+#[derive(IntoIterator)]
+struct Generic2<'a, T, U: Send>
+where
+    T: Send,
+{
+    #[into_iterator(owned, ref, ref_mut)]
+    items: Vec<T>,
+    useless: &'a U,
+}
+
+#[test]
+fn generic_bounds() {
+    let mut vals = vec![1, 2, 3];
+    let useless = false;
+    let mut iter = Generic2 {
+        items: vals.clone(),
+        useless: &useless,
+    };
+
+    assert_iter(&mut iter, &vals.iter_mut().collect::<Vec<_>>());
+    assert_iter(&iter, &vals.iter().collect::<Vec<_>>());
+    assert_iter(iter, &vals);
+}
+
+#[derive(IntoIterator)]
+struct Generic3<'a, 'b, T> {
+    #[into_iterator(owned)]
+    items: &'a mut Vec<&'b mut T>,
+}
+
+#[test]
+fn generic_refs() {
+    let mut numbers = vec![1, 2, 3];
+    let mut numbers2 = numbers.clone();
+
+    let mut number_refs = numbers.iter_mut().collect::<Vec<_>>();
+    let mut number_refs2 = numbers2.iter_mut().collect::<Vec<_>>();
+
+    assert_iter(
+        Generic3 {
+            items: &mut number_refs,
+        },
+        &number_refs2.iter_mut().collect::<Vec<_>>(),
+    )
+}
+
+#[derive(IntoIterator)]
+struct Generic4<T> {
+    #[into_iterator]
+    items: Vec<T>,
+    useless: bool,
+}
+
+#[test]
+fn generic_owned() {
+    let numbers = vec![1, 2, 3];
+
+    assert_iter(
+        Generic4 {
+            items: numbers.clone(),
+            useless: true,
+        },
+        &numbers,
+    );
+}