Let's get straightforward, here's the definition for std::iter::Extend
:
/// code-listing-1
pub trait Extend<A> {
fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = A>;
fn extend_one(&mut self, item: A) { ... }
fn extend_reserve(&mut self, additional: usize) { ... }
}
With this definition, I went to implement it for a custom type as follow:
/// code-listing-2
1 │ struct Foo;
2 │
3 │ impl std::ops::Deref for Foo {
4 │ type Target = str;
5 │ fn deref(&self) -> &Self::Target {
6 │ "foo"
7 │ }
8 │ }
9 │
10 │ impl std::iter::Extend<Foo> for String {
11 │ fn extend<I>(&mut self, iter: I) {
12 │ //iter.into_iter().for_each(|f| self.push_str(&f));
13 │ }
14 │ }
Case 1.
The following code compiles, so it seems that the trait bound T: IntoIterator<Item = A>
from std::iter::Extend::extend
propagates to the impl.
/// code-listing-3
let once = std::iter::once<Foo>(Foo);
let string = String::new();
string.extend(once);
// Error: Foo is not an Iterator
// string.extend(Foo);
Case 2.
Uncommenting line 12
in code-listing-2
caused compilation failure of code-listing-3
. So it seems that the trait bound T: IntoIterator<Item = A>
from std::iter::Extend::extend
does not propagates to the impl, which is contradictive to the observation from case 1
.
error[E0599]: the method `into_iter` exists for type parameter `I`, but its trait bounds were not satisfied
--> test.rs:12:14
|
12 | iter.into_iter().for_each(|f| self.push_str(&f));
| ^^^^^^^^^ method cannot be called on `I` due to unsatisfied trait bounds
Case 3.
Adding the trait bound I: std::iter::IntoIterator
in the method impl:
10 │ impl std::iter::Extend<Foo> for String {
11 │ fn extend<I: std::iter::IntoIterator>(&mut self, iter: I) {
12 │ iter.into_iter().for_each(|f| self.push_str(&f));
13 │ }
14 │ }
the code still fails to compile
error[E0308]: mismatched types
--> test.rs:12:53
|
12 | iter.into_iter().for_each(|f| self.push_str(&f));
| ^^ expected `str`, found associated type
|
= note: expected reference `&str`
found reference `&<I as IntoIterator>::Item`
Seems that the bound on the associated type Item = A
was not inferred, and indeed adding the bound on the associated type make the code compile.
10 │ impl std::iter::Extend<Foo> for String {
11 │ fn extend<I: std::iter::IntoIterator<Item = Foo>>(&mut self, iter: I) {
12 │ iter.into_iter().for_each(|f| self.push_str(&f));
13 │ }
14 │ }
Questions
So my questions are:
- Do bounds on trait method generic type parameter propagate to implementors?
- Do bounds on associated type of trait method generic type parameter propagate to implementors?
- Are the observations from the cases limitations of the current compiler or of deliberate design ?
Thank you for reaching here !
I've googled around for some bit, but did not find something related to my questions. It would be of great help if someone could point me to related documentations. Thank you!