Skip to content

Commit 334df59

Browse files
Fix IntoIterator derived bounds (#284, #208)
## Synopsis For generic structs, some derived `IntoIterator` bounds are based on the struct's type parameters, rather than the field used in the implementation. ## Solution Require only the type of the field used to be `IntoIterator`. Co-authored-by: Kai Ren <[email protected]>
1 parent df771b4 commit 334df59

File tree

4 files changed

+138
-28
lines changed

4 files changed

+138
-28
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
7272
- Fix `Error` derive not working with `const` generics.
7373
- Support trait objects for source in Error, e.g.
7474
`Box<dyn Error + Send + 'static>`
75+
- Fix bounds on derived `IntoIterator` impls for generic structs.
76+
([#284](https://github.com/JelteF/derive_more/pull/284))
7577

7678
## 0.99.10 - 2020-09-11
7779

impl/src/into_iterator.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::utils::{
2-
add_extra_generic_param, add_extra_ty_param_bound_ref, SingleFieldData, State,
2+
add_extra_generic_param, add_extra_where_clauses, SingleFieldData, State,
33
};
44
use proc_macro2::TokenStream;
55
use quote::{quote, ToTokens};
@@ -26,16 +26,19 @@ pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStre
2626
let reference_with_lifetime = ref_type.reference_with_lifetime();
2727

2828
let generics_impl;
29-
let generics =
30-
add_extra_ty_param_bound_ref(&input.generics, trait_path, ref_type);
31-
let (_, ty_generics, where_clause) = generics.split_for_impl();
3229
let (impl_generics, _, _) = if ref_type.is_ref() {
33-
generics_impl = add_extra_generic_param(&generics, lifetime.clone());
30+
generics_impl = add_extra_generic_param(&input.generics, lifetime.clone());
3431
generics_impl.split_for_impl()
3532
} else {
36-
generics.split_for_impl()
33+
input.generics.split_for_impl()
3734
};
38-
// let generics = add_extra_ty_param_bound(&input.generics, trait_path);
35+
36+
let generics = add_extra_where_clauses(
37+
&input.generics,
38+
quote! { where #reference_with_lifetime #field_type: #trait_path },
39+
);
40+
let (_, ty_generics, where_clause) = generics.split_for_impl();
41+
3942
let casted_trait = &quote! {
4043
<#reference_with_lifetime #field_type as #trait_path>
4144
};

impl/src/utils.rs

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -159,27 +159,6 @@ pub fn add_extra_ty_param_bound<'a>(
159159
generics
160160
}
161161

162-
pub fn add_extra_ty_param_bound_ref<'a>(
163-
generics: &'a Generics,
164-
bound: &'a TokenStream,
165-
ref_type: RefType,
166-
) -> Generics {
167-
match ref_type {
168-
RefType::No => add_extra_ty_param_bound(generics, bound),
169-
_ => {
170-
let generics = generics.clone();
171-
let idents = generics.type_params().map(|x| &x.ident);
172-
let ref_with_lifetime = ref_type.reference_with_lifetime();
173-
add_extra_where_clauses(
174-
&generics,
175-
quote! {
176-
where #(#ref_with_lifetime #idents: #bound),*
177-
},
178-
)
179-
}
180-
}
181-
}
182-
183162
pub fn add_extra_generic_param(
184163
generics: &Generics,
185164
generic_param: TokenStream,

tests/into_iterator.rs

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,52 @@
22
#![allow(dead_code, unused_imports)]
33

44
#[cfg(not(feature = "std"))]
5+
#[macro_use]
56
extern crate alloc;
67

78
#[cfg(not(feature = "std"))]
89
use alloc::vec::Vec;
10+
use core::fmt::Debug;
911

1012
use derive_more::IntoIterator;
1113

14+
#[track_caller]
15+
fn assert_iter<T: PartialEq + Debug, I: IntoIterator<Item = T>>(iter: I, vals: &[T]) {
16+
assert_eq!(iter.into_iter().collect::<Vec<_>>(), vals);
17+
}
18+
1219
#[derive(IntoIterator)]
1320
#[into_iterator(owned, ref, ref_mut)]
1421
struct MyVec(Vec<i32>);
1522

23+
#[test]
24+
fn tuple_single() {
25+
let mut vals = vec![1, 2, 3];
26+
let mut iter = MyVec(vals.clone());
27+
28+
assert_iter(&mut iter, &vals.iter_mut().collect::<Vec<_>>());
29+
assert_iter(&iter, &vals.iter().collect::<Vec<_>>());
30+
assert_iter(iter, &vals);
31+
}
32+
1633
#[derive(IntoIterator)]
1734
#[into_iterator(owned, ref, ref_mut)]
1835
struct Numbers {
1936
numbers: Vec<i32>,
2037
}
2138

39+
#[test]
40+
fn named_single() {
41+
let mut vals = vec![1, 2, 3];
42+
let mut iter = Numbers {
43+
numbers: vals.clone(),
44+
};
45+
46+
assert_iter(&mut iter, &vals.iter_mut().collect::<Vec<_>>());
47+
assert_iter(&iter, &vals.iter().collect::<Vec<_>>());
48+
assert_iter(iter, &vals);
49+
}
50+
2251
#[derive(IntoIterator)]
2352
struct Numbers2 {
2453
#[into_iterator(owned, ref, ref_mut)]
@@ -27,6 +56,19 @@ struct Numbers2 {
2756
useless2: bool,
2857
}
2958

59+
fn named_many() {
60+
let mut vals = vec![1, 2, 3];
61+
let mut iter = Numbers2 {
62+
numbers: vals.clone(),
63+
useless: true,
64+
useless2: true,
65+
};
66+
67+
assert_iter(&mut iter, &vals.iter_mut().collect::<Vec<_>>());
68+
assert_iter(&iter, &vals.iter().collect::<Vec<_>>());
69+
assert_iter(iter, &vals);
70+
}
71+
3072
#[derive(IntoIterator)]
3173
struct Numbers3 {
3274
#[into_iterator(ref, ref_mut)]
@@ -45,3 +87,87 @@ impl ::core::iter::IntoIterator for Numbers3 {
4587
<Vec<i32> as ::core::iter::IntoIterator>::into_iter(self.numbers)
4688
}
4789
}
90+
91+
#[derive(IntoIterator)]
92+
struct Generic1<T> {
93+
#[into_iterator(owned, ref, ref_mut)]
94+
items: Vec<T>,
95+
}
96+
97+
#[test]
98+
fn generic() {
99+
let mut vals = vec![1, 2, 3];
100+
let mut iter = Generic1 {
101+
items: vals.clone(),
102+
};
103+
104+
assert_iter(&mut iter, &vals.iter_mut().collect::<Vec<_>>());
105+
assert_iter(&iter, &vals.iter().collect::<Vec<_>>());
106+
assert_iter(iter, &vals);
107+
}
108+
109+
#[derive(IntoIterator)]
110+
struct Generic2<'a, T, U: Send>
111+
where
112+
T: Send,
113+
{
114+
#[into_iterator(owned, ref, ref_mut)]
115+
items: Vec<T>,
116+
useless: &'a U,
117+
}
118+
119+
#[test]
120+
fn generic_bounds() {
121+
let mut vals = vec![1, 2, 3];
122+
let useless = false;
123+
let mut iter = Generic2 {
124+
items: vals.clone(),
125+
useless: &useless,
126+
};
127+
128+
assert_iter(&mut iter, &vals.iter_mut().collect::<Vec<_>>());
129+
assert_iter(&iter, &vals.iter().collect::<Vec<_>>());
130+
assert_iter(iter, &vals);
131+
}
132+
133+
#[derive(IntoIterator)]
134+
struct Generic3<'a, 'b, T> {
135+
#[into_iterator(owned)]
136+
items: &'a mut Vec<&'b mut T>,
137+
}
138+
139+
#[test]
140+
fn generic_refs() {
141+
let mut numbers = vec![1, 2, 3];
142+
let mut numbers2 = numbers.clone();
143+
144+
let mut number_refs = numbers.iter_mut().collect::<Vec<_>>();
145+
let mut number_refs2 = numbers2.iter_mut().collect::<Vec<_>>();
146+
147+
assert_iter(
148+
Generic3 {
149+
items: &mut number_refs,
150+
},
151+
&number_refs2.iter_mut().collect::<Vec<_>>(),
152+
)
153+
}
154+
155+
#[derive(IntoIterator)]
156+
struct Generic4<T> {
157+
#[into_iterator]
158+
items: Vec<T>,
159+
useless: bool,
160+
}
161+
162+
#[test]
163+
fn generic_owned() {
164+
let numbers = vec![1, 2, 3];
165+
166+
assert_iter(
167+
Generic4 {
168+
items: numbers.clone(),
169+
useless: true,
170+
},
171+
&numbers,
172+
);
173+
}

0 commit comments

Comments
 (0)