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` +- 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 }; 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, 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>(iter: I, vals: &[T]) { + assert_eq!(iter.into_iter().collect::>(), vals); +} + #[derive(IntoIterator)] #[into_iterator(owned, ref, ref_mut)] struct MyVec(Vec); +#[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::>()); + assert_iter(&iter, &vals.iter().collect::>()); + assert_iter(iter, &vals); +} + #[derive(IntoIterator)] #[into_iterator(owned, ref, ref_mut)] struct Numbers { numbers: Vec, } +#[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::>()); + assert_iter(&iter, &vals.iter().collect::>()); + 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::>()); + assert_iter(&iter, &vals.iter().collect::>()); + assert_iter(iter, &vals); +} + #[derive(IntoIterator)] struct Numbers3 { #[into_iterator(ref, ref_mut)] @@ -45,3 +87,87 @@ impl ::core::iter::IntoIterator for Numbers3 { as ::core::iter::IntoIterator>::into_iter(self.numbers) } } + +#[derive(IntoIterator)] +struct Generic1 { + #[into_iterator(owned, ref, ref_mut)] + items: Vec, +} + +#[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::>()); + assert_iter(&iter, &vals.iter().collect::>()); + assert_iter(iter, &vals); +} + +#[derive(IntoIterator)] +struct Generic2<'a, T, U: Send> +where + T: Send, +{ + #[into_iterator(owned, ref, ref_mut)] + items: Vec, + 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::>()); + assert_iter(&iter, &vals.iter().collect::>()); + 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::>(); + let mut number_refs2 = numbers2.iter_mut().collect::>(); + + assert_iter( + Generic3 { + items: &mut number_refs, + }, + &number_refs2.iter_mut().collect::>(), + ) +} + +#[derive(IntoIterator)] +struct Generic4 { + #[into_iterator] + items: Vec, + useless: bool, +} + +#[test] +fn generic_owned() { + let numbers = vec![1, 2, 3]; + + assert_iter( + Generic4 { + items: numbers.clone(), + useless: true, + }, + &numbers, + ); +}