Confused About Error Message: error[E0277]: `&'a TCollection` is not an iterator

Hello,

I was trying to create a generic collection trait and a default implementation with a vector working behind the scenes and it worked out as expected. However, when I added the Organism struct, that makes use of the my Collection trait, I get a bunch of confusing errors popping up. I neither understand the reasoning behind the error message nor do I think, that adding the Iterator trait is what I want. Any help would be much appreciated!

P.S.: I fixed the last error by adding the line I've commented out, again, because that didn't fix the other errors. No idea if that fix was correct or if fixing the other errors also fixes the last error and I don't need to use PhantomData.

#![feature(vec_remove_item)]

struct Organism<'a, TCollection>
where
    TCollection: self::Collection<'a, std::ptr::NonNull<()>>,
{
    mates: std::cell::RefCell<TCollection>,
	// _phantom: std::marker::PhantomData<&'a ()>, // Is this the solution?
    _pin: std::marker::PhantomPinned,
}

trait Collection<'a, Element>
where
    Self: 'a + Default + IntoIterator<Item = Element>,
    &'a Self: IntoIterator<Item = &'a Element>,
    &'a mut Self: IntoIterator<Item = &'a mut Element>,
    Element: 'a + PartialEq,
{
    fn add(&mut self, item: Element);
    fn contains(&self, item: &Element);
    fn remove(&mut self, item: &Element);
}

struct DefaultCollection<Element>(Vec<Element>)
where
    Element: PartialEq;

impl<'a, Element> Collection<'a, Element> for DefaultCollection<Element>
where
    Element: 'a + PartialEq,
{
    #[inline]
    fn add(&mut self, item: Element) {
        self.0.push(item);
    }
	
    #[inline]
    fn contains(&self, item: &Element) {
        self.0.contains(item);
    }

    #[inline]
    fn remove(&mut self, item: &Element) {
        self.0.remove_item(item);
    }
}

impl<Element> Default for DefaultCollection<Element>
where
    Element: PartialEq,
{
    fn default() -> Self {
        Self(Vec::new())
    }
}

impl<Element> IntoIterator for DefaultCollection<Element>
where
    Element: PartialEq, {
    type Item = Element;
    type IntoIter = std::vec::IntoIter<Element>;

    #[inline]
    fn into_iter(self) -> std::vec::IntoIter<Element> {
        self.0.into_iter()
    }
}

impl<'a, Element> IntoIterator for &'a DefaultCollection<Element>
where
    Element: PartialEq, {
    type Item = &'a Element;
    type IntoIter = std::slice::Iter<'a, Element>;

    #[inline]
    fn into_iter(self) -> std::slice::Iter<'a, Element> {
        self.0.iter()
    }
}

impl<'a, Element> IntoIterator for &'a mut DefaultCollection<Element>
where
    Element: PartialEq, {
    type Item = &'a mut Element;
    type IntoIter = std::slice::IterMut<'a, Element>;

    #[inline]
    fn into_iter(self) -> std::slice::IterMut<'a, Element> {
        self.0.iter_mut()
    }
}

fn main() {
	let mut c = DefaultCollection::<usize>::default();
	c.add(1337);
	
	for e in &c {
		println!("{}", e);
	}
	
	c.add(42);
	
	for e in &mut c {
		println!("{}", e);
		*e = 123;
	}
	
	for e in &c {
		println!("{}", e);
	}
	
    println!("Hello, world!");
}

(Playground)

I've reduced the code as much as possible while keeping the error. This should be the minimum needed code to reproduce the error. I hope this makes it easier for whoever takes a look at this.

struct A<'a, T: B<'a, ()>>(std::marker::PhantomData<(T, &'a ())>);

trait B<'a, T: 'a>
where
    Self: 'a,
    &'a Self: IntoIterator<Item = &'a T>,
{
}

fn main() {}

   Compiling playground v0.0.1 (/playground)
error[E0277]: `&'a T` is not an iterator
 --> src/main.rs:1:1
  |
1 |   struct A<'a, T: B<'a, ()>>(std::marker::PhantomData<(T, &'a ())>);
  |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'a T` is not an iterator
2 | 
3 | / trait B<'a, T: 'a>
4 | | where
5 | |     Self: 'a,
6 | |     &'a Self: IntoIterator<Item = &'a T>,
7 | | {
8 | | }
  | |_- required by `B`
  |
  = help: the trait `std::iter::Iterator` is not implemented for `&'a T`
  = note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&'a T`

(Playground)

It's because & (shared borrow) is immutable, and immutable iterators can't exist — without mutation they can't advance to the next element.

Use &mut (exclusive borrow) or an owned value (a struct that contains a reference to the collection internally, but which itself can be mutated).

I didn't specify IntoIterator::IntoIter, which defines the iterator, though. The compiler shouldn't assume I'm trying to return an immutable iterator.

= help: the trait `std::iter::Iterator` is not implemented for `&'a T`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&'a T`

While I still don't understand how to fix the issue, I am starting to understand the error message. The note is generated from this part of trait B:

&'a Self: IntoIterator<Item = &'a T>,

The help is displayed, because IntoIterator is automatically implemented for every Iterator. What the compiler complains about is not the fact, that &'a T doesn't implement Iterator, but IntoIterator!

1 Like

I've found the solution! :smiley:

B implies, that the trait IntoIterator is implemented for Self, &Self and &mut Self. However, when specifying T: B<'a, ()> as a where-clause in struct A, it doesn't "inherit" the where-clauses from trait B, that deal with the borrowed and mutably borrowed version of T, thus they have to be re-specified in A in order to implement the trait for T.

This works:

struct A<'a, T>(std::marker::PhantomData<(T, &'a ())>)
where
    T: B<'a, ()>,
    &'a T: IntoIterator<Item = &'a ()>,
    &'a mut T: IntoIterator<Item = &'a mut ()>;

trait B<'a, T>
where
    Self: 'a + IntoIterator<Item = T>,
    &'a Self: IntoIterator<Item = &'a T>,
    &'a mut Self: IntoIterator<Item = &'a mut T>,
    T: 'a,
{
}

fn main() {}