What's going on with this bizarre recursive type error in Rust?











up vote
5
down vote

favorite












I have an iterable struct called Join:



use std::iter::Peekable;

#[derive(Debug)]
pub struct Join<T, S> {
container: T,
separator: S,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum JoinItem<T, S> {
Element(T),
Separator(S),
}

pub struct JoinIter<Iter: Iterator, Sep> {
iter: Peekable<Iter>,
sep: Sep,
next_sep: bool,
}

impl<Iter: Iterator, Sep> JoinIter<Iter, Sep> {
fn new(iter: Iter, sep: Sep) -> Self {
JoinIter {
iter: iter.peekable(),
sep,
next_sep: false,
}
}
}

impl<I: Iterator, S: Clone> Iterator for JoinIter<I, S> {
type Item = JoinItem<I::Item, S>;

/// Advance to the next item in the Join. This will either be the next
/// element in the underlying iterator, or a clone of the separator.
fn next(&mut self) -> Option<Self::Item> {
let sep = &self.sep;
let next_sep = &mut self.next_sep;

if *next_sep {
self.iter.peek().map(|_| {
*next_sep = false;
JoinItem::Separator(sep.clone())
})
} else {
self.iter.next().map(|element| {
*next_sep = true;
JoinItem::Element(element)
})
}
}
}


A reference to Join implements IntoIterator:



impl<'a, T, S> IntoIterator for &'a Join<T, S>
where
&'a T: IntoIterator,
{
type IntoIter = JoinIter<<&'a T as IntoIterator>::IntoIter, &'a S>;
type Item = JoinItem<<&'a T as IntoIterator>::Item, &'a S>;

fn into_iter(self) -> Self::IntoIter {
JoinIter::new(self.container.into_iter(), &self.separator)
}
}


This compiles and passes usage tests.



I also have an iter method defined on my Join struct:



impl<T, S> Join<T, S>
where
for<'a> &'a T: IntoIterator,
{
pub fn iter(&self) -> JoinIter<<&T as IntoIterator>::IntoIter, &S> {
self.into_iter()
}
}


This compiles fine, but when I actually try to use it:



fn main() {
// Create a join struct
let join = Join {
container: vec![1, 2, 3],
separator: ", ",
};

// This works fine
let mut good_ref_iter = (&join).into_iter();
assert_eq!(good_ref_iter.next(), Some(JoinItem::Element(&1)));
assert_eq!(good_ref_iter.next(), Some(JoinItem::Separator(&", ")));
assert_eq!(good_ref_iter.next(), Some(JoinItem::Element(&2)));
assert_eq!(good_ref_iter.next(), Some(JoinItem::Separator(&", ")));
assert_eq!(good_ref_iter.next(), Some(JoinItem::Element(&3)));
assert_eq!(good_ref_iter.next(), None);

// This line fails to compile; comment out this section and it all works
let bad_ref_iter = join.iter();
assert_eq!(bad_ref_iter.next(), Some(JoinItem::Element(&1)));
assert_eq!(bad_ref_iter.next(), Some(JoinItem::Separator(&", ")));
assert_eq!(bad_ref_iter.next(), Some(JoinItem::Element(&2)));
assert_eq!(bad_ref_iter.next(), Some(JoinItem::Separator(&", ")));
assert_eq!(bad_ref_iter.next(), Some(JoinItem::Element(&3)));
assert_eq!(bad_ref_iter.next(), None);
}


I get some kind of weird type recursion error:



error[E0275]: overflow evaluating the requirement `&_: std::marker::Sized`
--> src/join.rs:288:29
|
96 | let mut iter = join.iter();
| ^^^^
|
= help: consider adding a `#![recursion_limit="128"]` attribute to your crate
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&_`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&join::Join<_, _>`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&join::Join<join::Join<_, _>, _>`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&join::Join<join::Join<join::Join<_, _>, _>, _>`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&join::Join<join::Join<join::Join<join::Join<_, _>, _>, _>, _>`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&join::Join<join::Join<join::Join<join::Join<join::Join<_, _>, _>, _>, _>, _>`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&join::Join<join::Join<join::Join<join::Join<join::Join<join::Join<_, _>, _>, _>, _>, _>, _>`
...


(I redacted about 100 more lines of recursive type error in the ...)



As best I can tell, it appears to be attempting to proactively evaluate whether &Join<_, _> implements IntoIterator, which requires checking if &Join<Join<_, _>, _> fulfills IntoIterator, and so on forever. What I can't figure out is why it thinks it has to do this, since my actual type is fully qualified as Join<Vec<{integer}, &'static str>. Some things I've tried:





  • Moving the trait bound off of the impl header and into the iter function, like so:



    fn iter(&'a self) -> JoinIter<<&'a T as IntoIterator>::IntoIter, &'a S>
    where &'a T: IntoIterator


    This has the same result.




  • Replacing self.into_iter() with the underlying expression, JoinIter::new(self.container.into_iter(), self.separator), in the hopes that maybe it's struggling to differentiate self.into_iter() from (&self).into_iter(). I've tried all of the following patterns:




    • fn iter(&self) -> ... { self.into_iter() }

    • fn iter(&self) -> ... { (&self).into_iter() }

    • fn iter(&self) -> ... { JoinIter::new(self.container.into_iter(), &self.separator) }

    • fn iter(&self) -> ... { JoinIter::new((&self.container).into_iter(), &self.separator) }



  • Speaking of which, replacing the call to self.iter() with (&self).into_iter() fixes the problem, but replacing it with (&self).iter() does not.


Why does (&join).into_iter() work, but join.iter() does not, even though iter() simply calls self.into_iter() under the hood?



This complete example, with identical code, is also available in the Rust Playground





For more context about Join, see my older Stack Overflow question and my actual source code.










share|improve this question




















  • 1




    @Lucretiel I've reduced the playground example to a fraction of its size. Note that removing the empty impl block makes the error go away. This gives some clues why it is occurring, but I don't really have an explanation yet. Also note that the line triggering the error now is let _ = join;.
    – Sven Marnach
    Nov 21 at 21:10












  • @SvenMarnach that microexample has the same error as my code, but doesn't reproduce my specific issue. In my code, IntoIterator DOES work fine; it's the fn iter() (which literally just calls into_iter()) that inexplicably breaks
    – Lucretiel
    Nov 21 at 23:23















up vote
5
down vote

favorite












I have an iterable struct called Join:



use std::iter::Peekable;

#[derive(Debug)]
pub struct Join<T, S> {
container: T,
separator: S,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum JoinItem<T, S> {
Element(T),
Separator(S),
}

pub struct JoinIter<Iter: Iterator, Sep> {
iter: Peekable<Iter>,
sep: Sep,
next_sep: bool,
}

impl<Iter: Iterator, Sep> JoinIter<Iter, Sep> {
fn new(iter: Iter, sep: Sep) -> Self {
JoinIter {
iter: iter.peekable(),
sep,
next_sep: false,
}
}
}

impl<I: Iterator, S: Clone> Iterator for JoinIter<I, S> {
type Item = JoinItem<I::Item, S>;

/// Advance to the next item in the Join. This will either be the next
/// element in the underlying iterator, or a clone of the separator.
fn next(&mut self) -> Option<Self::Item> {
let sep = &self.sep;
let next_sep = &mut self.next_sep;

if *next_sep {
self.iter.peek().map(|_| {
*next_sep = false;
JoinItem::Separator(sep.clone())
})
} else {
self.iter.next().map(|element| {
*next_sep = true;
JoinItem::Element(element)
})
}
}
}


A reference to Join implements IntoIterator:



impl<'a, T, S> IntoIterator for &'a Join<T, S>
where
&'a T: IntoIterator,
{
type IntoIter = JoinIter<<&'a T as IntoIterator>::IntoIter, &'a S>;
type Item = JoinItem<<&'a T as IntoIterator>::Item, &'a S>;

fn into_iter(self) -> Self::IntoIter {
JoinIter::new(self.container.into_iter(), &self.separator)
}
}


This compiles and passes usage tests.



I also have an iter method defined on my Join struct:



impl<T, S> Join<T, S>
where
for<'a> &'a T: IntoIterator,
{
pub fn iter(&self) -> JoinIter<<&T as IntoIterator>::IntoIter, &S> {
self.into_iter()
}
}


This compiles fine, but when I actually try to use it:



fn main() {
// Create a join struct
let join = Join {
container: vec![1, 2, 3],
separator: ", ",
};

// This works fine
let mut good_ref_iter = (&join).into_iter();
assert_eq!(good_ref_iter.next(), Some(JoinItem::Element(&1)));
assert_eq!(good_ref_iter.next(), Some(JoinItem::Separator(&", ")));
assert_eq!(good_ref_iter.next(), Some(JoinItem::Element(&2)));
assert_eq!(good_ref_iter.next(), Some(JoinItem::Separator(&", ")));
assert_eq!(good_ref_iter.next(), Some(JoinItem::Element(&3)));
assert_eq!(good_ref_iter.next(), None);

// This line fails to compile; comment out this section and it all works
let bad_ref_iter = join.iter();
assert_eq!(bad_ref_iter.next(), Some(JoinItem::Element(&1)));
assert_eq!(bad_ref_iter.next(), Some(JoinItem::Separator(&", ")));
assert_eq!(bad_ref_iter.next(), Some(JoinItem::Element(&2)));
assert_eq!(bad_ref_iter.next(), Some(JoinItem::Separator(&", ")));
assert_eq!(bad_ref_iter.next(), Some(JoinItem::Element(&3)));
assert_eq!(bad_ref_iter.next(), None);
}


I get some kind of weird type recursion error:



error[E0275]: overflow evaluating the requirement `&_: std::marker::Sized`
--> src/join.rs:288:29
|
96 | let mut iter = join.iter();
| ^^^^
|
= help: consider adding a `#![recursion_limit="128"]` attribute to your crate
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&_`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&join::Join<_, _>`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&join::Join<join::Join<_, _>, _>`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&join::Join<join::Join<join::Join<_, _>, _>, _>`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&join::Join<join::Join<join::Join<join::Join<_, _>, _>, _>, _>`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&join::Join<join::Join<join::Join<join::Join<join::Join<_, _>, _>, _>, _>, _>`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&join::Join<join::Join<join::Join<join::Join<join::Join<join::Join<_, _>, _>, _>, _>, _>, _>`
...


(I redacted about 100 more lines of recursive type error in the ...)



As best I can tell, it appears to be attempting to proactively evaluate whether &Join<_, _> implements IntoIterator, which requires checking if &Join<Join<_, _>, _> fulfills IntoIterator, and so on forever. What I can't figure out is why it thinks it has to do this, since my actual type is fully qualified as Join<Vec<{integer}, &'static str>. Some things I've tried:





  • Moving the trait bound off of the impl header and into the iter function, like so:



    fn iter(&'a self) -> JoinIter<<&'a T as IntoIterator>::IntoIter, &'a S>
    where &'a T: IntoIterator


    This has the same result.




  • Replacing self.into_iter() with the underlying expression, JoinIter::new(self.container.into_iter(), self.separator), in the hopes that maybe it's struggling to differentiate self.into_iter() from (&self).into_iter(). I've tried all of the following patterns:




    • fn iter(&self) -> ... { self.into_iter() }

    • fn iter(&self) -> ... { (&self).into_iter() }

    • fn iter(&self) -> ... { JoinIter::new(self.container.into_iter(), &self.separator) }

    • fn iter(&self) -> ... { JoinIter::new((&self.container).into_iter(), &self.separator) }



  • Speaking of which, replacing the call to self.iter() with (&self).into_iter() fixes the problem, but replacing it with (&self).iter() does not.


Why does (&join).into_iter() work, but join.iter() does not, even though iter() simply calls self.into_iter() under the hood?



This complete example, with identical code, is also available in the Rust Playground





For more context about Join, see my older Stack Overflow question and my actual source code.










share|improve this question




















  • 1




    @Lucretiel I've reduced the playground example to a fraction of its size. Note that removing the empty impl block makes the error go away. This gives some clues why it is occurring, but I don't really have an explanation yet. Also note that the line triggering the error now is let _ = join;.
    – Sven Marnach
    Nov 21 at 21:10












  • @SvenMarnach that microexample has the same error as my code, but doesn't reproduce my specific issue. In my code, IntoIterator DOES work fine; it's the fn iter() (which literally just calls into_iter()) that inexplicably breaks
    – Lucretiel
    Nov 21 at 23:23













up vote
5
down vote

favorite









up vote
5
down vote

favorite











I have an iterable struct called Join:



use std::iter::Peekable;

#[derive(Debug)]
pub struct Join<T, S> {
container: T,
separator: S,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum JoinItem<T, S> {
Element(T),
Separator(S),
}

pub struct JoinIter<Iter: Iterator, Sep> {
iter: Peekable<Iter>,
sep: Sep,
next_sep: bool,
}

impl<Iter: Iterator, Sep> JoinIter<Iter, Sep> {
fn new(iter: Iter, sep: Sep) -> Self {
JoinIter {
iter: iter.peekable(),
sep,
next_sep: false,
}
}
}

impl<I: Iterator, S: Clone> Iterator for JoinIter<I, S> {
type Item = JoinItem<I::Item, S>;

/// Advance to the next item in the Join. This will either be the next
/// element in the underlying iterator, or a clone of the separator.
fn next(&mut self) -> Option<Self::Item> {
let sep = &self.sep;
let next_sep = &mut self.next_sep;

if *next_sep {
self.iter.peek().map(|_| {
*next_sep = false;
JoinItem::Separator(sep.clone())
})
} else {
self.iter.next().map(|element| {
*next_sep = true;
JoinItem::Element(element)
})
}
}
}


A reference to Join implements IntoIterator:



impl<'a, T, S> IntoIterator for &'a Join<T, S>
where
&'a T: IntoIterator,
{
type IntoIter = JoinIter<<&'a T as IntoIterator>::IntoIter, &'a S>;
type Item = JoinItem<<&'a T as IntoIterator>::Item, &'a S>;

fn into_iter(self) -> Self::IntoIter {
JoinIter::new(self.container.into_iter(), &self.separator)
}
}


This compiles and passes usage tests.



I also have an iter method defined on my Join struct:



impl<T, S> Join<T, S>
where
for<'a> &'a T: IntoIterator,
{
pub fn iter(&self) -> JoinIter<<&T as IntoIterator>::IntoIter, &S> {
self.into_iter()
}
}


This compiles fine, but when I actually try to use it:



fn main() {
// Create a join struct
let join = Join {
container: vec![1, 2, 3],
separator: ", ",
};

// This works fine
let mut good_ref_iter = (&join).into_iter();
assert_eq!(good_ref_iter.next(), Some(JoinItem::Element(&1)));
assert_eq!(good_ref_iter.next(), Some(JoinItem::Separator(&", ")));
assert_eq!(good_ref_iter.next(), Some(JoinItem::Element(&2)));
assert_eq!(good_ref_iter.next(), Some(JoinItem::Separator(&", ")));
assert_eq!(good_ref_iter.next(), Some(JoinItem::Element(&3)));
assert_eq!(good_ref_iter.next(), None);

// This line fails to compile; comment out this section and it all works
let bad_ref_iter = join.iter();
assert_eq!(bad_ref_iter.next(), Some(JoinItem::Element(&1)));
assert_eq!(bad_ref_iter.next(), Some(JoinItem::Separator(&", ")));
assert_eq!(bad_ref_iter.next(), Some(JoinItem::Element(&2)));
assert_eq!(bad_ref_iter.next(), Some(JoinItem::Separator(&", ")));
assert_eq!(bad_ref_iter.next(), Some(JoinItem::Element(&3)));
assert_eq!(bad_ref_iter.next(), None);
}


I get some kind of weird type recursion error:



error[E0275]: overflow evaluating the requirement `&_: std::marker::Sized`
--> src/join.rs:288:29
|
96 | let mut iter = join.iter();
| ^^^^
|
= help: consider adding a `#![recursion_limit="128"]` attribute to your crate
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&_`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&join::Join<_, _>`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&join::Join<join::Join<_, _>, _>`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&join::Join<join::Join<join::Join<_, _>, _>, _>`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&join::Join<join::Join<join::Join<join::Join<_, _>, _>, _>, _>`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&join::Join<join::Join<join::Join<join::Join<join::Join<_, _>, _>, _>, _>, _>`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&join::Join<join::Join<join::Join<join::Join<join::Join<join::Join<_, _>, _>, _>, _>, _>, _>`
...


(I redacted about 100 more lines of recursive type error in the ...)



As best I can tell, it appears to be attempting to proactively evaluate whether &Join<_, _> implements IntoIterator, which requires checking if &Join<Join<_, _>, _> fulfills IntoIterator, and so on forever. What I can't figure out is why it thinks it has to do this, since my actual type is fully qualified as Join<Vec<{integer}, &'static str>. Some things I've tried:





  • Moving the trait bound off of the impl header and into the iter function, like so:



    fn iter(&'a self) -> JoinIter<<&'a T as IntoIterator>::IntoIter, &'a S>
    where &'a T: IntoIterator


    This has the same result.




  • Replacing self.into_iter() with the underlying expression, JoinIter::new(self.container.into_iter(), self.separator), in the hopes that maybe it's struggling to differentiate self.into_iter() from (&self).into_iter(). I've tried all of the following patterns:




    • fn iter(&self) -> ... { self.into_iter() }

    • fn iter(&self) -> ... { (&self).into_iter() }

    • fn iter(&self) -> ... { JoinIter::new(self.container.into_iter(), &self.separator) }

    • fn iter(&self) -> ... { JoinIter::new((&self.container).into_iter(), &self.separator) }



  • Speaking of which, replacing the call to self.iter() with (&self).into_iter() fixes the problem, but replacing it with (&self).iter() does not.


Why does (&join).into_iter() work, but join.iter() does not, even though iter() simply calls self.into_iter() under the hood?



This complete example, with identical code, is also available in the Rust Playground





For more context about Join, see my older Stack Overflow question and my actual source code.










share|improve this question















I have an iterable struct called Join:



use std::iter::Peekable;

#[derive(Debug)]
pub struct Join<T, S> {
container: T,
separator: S,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum JoinItem<T, S> {
Element(T),
Separator(S),
}

pub struct JoinIter<Iter: Iterator, Sep> {
iter: Peekable<Iter>,
sep: Sep,
next_sep: bool,
}

impl<Iter: Iterator, Sep> JoinIter<Iter, Sep> {
fn new(iter: Iter, sep: Sep) -> Self {
JoinIter {
iter: iter.peekable(),
sep,
next_sep: false,
}
}
}

impl<I: Iterator, S: Clone> Iterator for JoinIter<I, S> {
type Item = JoinItem<I::Item, S>;

/// Advance to the next item in the Join. This will either be the next
/// element in the underlying iterator, or a clone of the separator.
fn next(&mut self) -> Option<Self::Item> {
let sep = &self.sep;
let next_sep = &mut self.next_sep;

if *next_sep {
self.iter.peek().map(|_| {
*next_sep = false;
JoinItem::Separator(sep.clone())
})
} else {
self.iter.next().map(|element| {
*next_sep = true;
JoinItem::Element(element)
})
}
}
}


A reference to Join implements IntoIterator:



impl<'a, T, S> IntoIterator for &'a Join<T, S>
where
&'a T: IntoIterator,
{
type IntoIter = JoinIter<<&'a T as IntoIterator>::IntoIter, &'a S>;
type Item = JoinItem<<&'a T as IntoIterator>::Item, &'a S>;

fn into_iter(self) -> Self::IntoIter {
JoinIter::new(self.container.into_iter(), &self.separator)
}
}


This compiles and passes usage tests.



I also have an iter method defined on my Join struct:



impl<T, S> Join<T, S>
where
for<'a> &'a T: IntoIterator,
{
pub fn iter(&self) -> JoinIter<<&T as IntoIterator>::IntoIter, &S> {
self.into_iter()
}
}


This compiles fine, but when I actually try to use it:



fn main() {
// Create a join struct
let join = Join {
container: vec![1, 2, 3],
separator: ", ",
};

// This works fine
let mut good_ref_iter = (&join).into_iter();
assert_eq!(good_ref_iter.next(), Some(JoinItem::Element(&1)));
assert_eq!(good_ref_iter.next(), Some(JoinItem::Separator(&", ")));
assert_eq!(good_ref_iter.next(), Some(JoinItem::Element(&2)));
assert_eq!(good_ref_iter.next(), Some(JoinItem::Separator(&", ")));
assert_eq!(good_ref_iter.next(), Some(JoinItem::Element(&3)));
assert_eq!(good_ref_iter.next(), None);

// This line fails to compile; comment out this section and it all works
let bad_ref_iter = join.iter();
assert_eq!(bad_ref_iter.next(), Some(JoinItem::Element(&1)));
assert_eq!(bad_ref_iter.next(), Some(JoinItem::Separator(&", ")));
assert_eq!(bad_ref_iter.next(), Some(JoinItem::Element(&2)));
assert_eq!(bad_ref_iter.next(), Some(JoinItem::Separator(&", ")));
assert_eq!(bad_ref_iter.next(), Some(JoinItem::Element(&3)));
assert_eq!(bad_ref_iter.next(), None);
}


I get some kind of weird type recursion error:



error[E0275]: overflow evaluating the requirement `&_: std::marker::Sized`
--> src/join.rs:288:29
|
96 | let mut iter = join.iter();
| ^^^^
|
= help: consider adding a `#![recursion_limit="128"]` attribute to your crate
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&_`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&join::Join<_, _>`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&join::Join<join::Join<_, _>, _>`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&join::Join<join::Join<join::Join<_, _>, _>, _>`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&join::Join<join::Join<join::Join<join::Join<_, _>, _>, _>, _>`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&join::Join<join::Join<join::Join<join::Join<join::Join<_, _>, _>, _>, _>, _>`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&join::Join<join::Join<join::Join<join::Join<join::Join<join::Join<_, _>, _>, _>, _>, _>, _>`
...


(I redacted about 100 more lines of recursive type error in the ...)



As best I can tell, it appears to be attempting to proactively evaluate whether &Join<_, _> implements IntoIterator, which requires checking if &Join<Join<_, _>, _> fulfills IntoIterator, and so on forever. What I can't figure out is why it thinks it has to do this, since my actual type is fully qualified as Join<Vec<{integer}, &'static str>. Some things I've tried:





  • Moving the trait bound off of the impl header and into the iter function, like so:



    fn iter(&'a self) -> JoinIter<<&'a T as IntoIterator>::IntoIter, &'a S>
    where &'a T: IntoIterator


    This has the same result.




  • Replacing self.into_iter() with the underlying expression, JoinIter::new(self.container.into_iter(), self.separator), in the hopes that maybe it's struggling to differentiate self.into_iter() from (&self).into_iter(). I've tried all of the following patterns:




    • fn iter(&self) -> ... { self.into_iter() }

    • fn iter(&self) -> ... { (&self).into_iter() }

    • fn iter(&self) -> ... { JoinIter::new(self.container.into_iter(), &self.separator) }

    • fn iter(&self) -> ... { JoinIter::new((&self.container).into_iter(), &self.separator) }



  • Speaking of which, replacing the call to self.iter() with (&self).into_iter() fixes the problem, but replacing it with (&self).iter() does not.


Why does (&join).into_iter() work, but join.iter() does not, even though iter() simply calls self.into_iter() under the hood?



This complete example, with identical code, is also available in the Rust Playground





For more context about Join, see my older Stack Overflow question and my actual source code.







types reference rust type-inference






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 22 at 21:11









Shepmaster

145k11279413




145k11279413










asked Nov 21 at 4:31









Lucretiel

793823




793823








  • 1




    @Lucretiel I've reduced the playground example to a fraction of its size. Note that removing the empty impl block makes the error go away. This gives some clues why it is occurring, but I don't really have an explanation yet. Also note that the line triggering the error now is let _ = join;.
    – Sven Marnach
    Nov 21 at 21:10












  • @SvenMarnach that microexample has the same error as my code, but doesn't reproduce my specific issue. In my code, IntoIterator DOES work fine; it's the fn iter() (which literally just calls into_iter()) that inexplicably breaks
    – Lucretiel
    Nov 21 at 23:23














  • 1




    @Lucretiel I've reduced the playground example to a fraction of its size. Note that removing the empty impl block makes the error go away. This gives some clues why it is occurring, but I don't really have an explanation yet. Also note that the line triggering the error now is let _ = join;.
    – Sven Marnach
    Nov 21 at 21:10












  • @SvenMarnach that microexample has the same error as my code, but doesn't reproduce my specific issue. In my code, IntoIterator DOES work fine; it's the fn iter() (which literally just calls into_iter()) that inexplicably breaks
    – Lucretiel
    Nov 21 at 23:23








1




1




@Lucretiel I've reduced the playground example to a fraction of its size. Note that removing the empty impl block makes the error go away. This gives some clues why it is occurring, but I don't really have an explanation yet. Also note that the line triggering the error now is let _ = join;.
– Sven Marnach
Nov 21 at 21:10






@Lucretiel I've reduced the playground example to a fraction of its size. Note that removing the empty impl block makes the error go away. This gives some clues why it is occurring, but I don't really have an explanation yet. Also note that the line triggering the error now is let _ = join;.
– Sven Marnach
Nov 21 at 21:10














@SvenMarnach that microexample has the same error as my code, but doesn't reproduce my specific issue. In my code, IntoIterator DOES work fine; it's the fn iter() (which literally just calls into_iter()) that inexplicably breaks
– Lucretiel
Nov 21 at 23:23




@SvenMarnach that microexample has the same error as my code, but doesn't reproduce my specific issue. In my code, IntoIterator DOES work fine; it's the fn iter() (which literally just calls into_iter()) that inexplicably breaks
– Lucretiel
Nov 21 at 23:23












1 Answer
1






active

oldest

votes

















up vote
2
down vote













It seems that the compiler is not able to resolve the trait requirement needed by iter() return type JoinIter<<&T as IntoIterator>::IntoIter, &S>.



I've received an hint for this from rustc --explain E0275 error explanation:




This error occurs when there was a recursive trait requirement that overflowed
before it could be evaluated. Often this means that there is unbounded
recursion in resolving some type bounds.




I don't know the details of the inference process of rust, I imagine the following is happening.



Take this signature:



fn iter(&self) -> JoinIter<<&T as IntoIterator>::IntoIter, &S>


The compiler try to infer the return type from:



JoinIter<<&T as IntoIterator>::IntoIter, &S>


but <&T as IntoIterator>::IntoIter is inferred from the &'a Join impl:



impl<'a, T, S> IntoIterator for &'a Join<T, S>
where &'a T: IntoIterator
{
type IntoIter = JoinIter<<&'a T as IntoIterator>::IntoIter, &'a S>;
type Item = JoinItem<<&'a T as IntoIterator>::Item, &'a S>;

fn into_iter(self) -> Self::IntoIter {
JoinIter::new(self.container.into_iter(), &self.separator)
}
}


and IntoIter is again a JoinIter<<&'a T as IntoIterator>::IntoIter, &'a S> that has an IntoIter and so and so ad infinitum.



A way to make it compile it is to help the compiler with a turbofish:



let mut bad_ref_iter = Join::<Vec<i32>, &str>::iter(&join);


instead of:



let bad_ref_iter = join.iter();


Update



The line:



type IntoIter = JoinIter<<&'a T as IntoIterator>::IntoIter, &'a S>;    


generate a recursion because Rust checks that traits are valid when they are defined rather than when they are used.



See this post for some more details and pointers to the progress of work
of lazy normalization, which may solve this problem.






share|improve this answer



















  • 1




    I still don't have any clue where the infinite recursion is coming from. Why does <&T as IntoIterator>::IntoIter need to be "inferred"? My understanding is the T and S are inferred from the type of join, but once T is known, <&T as IntoIterator>::IntoIter is a complete type that does not require any inference. The work-around is nice, but the source of the problem remains a complete mystery to me.
    – Sven Marnach
    Nov 22 at 18:02










  • Could be that the recursion happens before T and S are inferred from join? Look at this
    – attdona
    Nov 23 at 6:41










  • cross-posted here
    – attdona
    Nov 23 at 7:24











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53405287%2fwhats-going-on-with-this-bizarre-recursive-type-error-in-rust%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
2
down vote













It seems that the compiler is not able to resolve the trait requirement needed by iter() return type JoinIter<<&T as IntoIterator>::IntoIter, &S>.



I've received an hint for this from rustc --explain E0275 error explanation:




This error occurs when there was a recursive trait requirement that overflowed
before it could be evaluated. Often this means that there is unbounded
recursion in resolving some type bounds.




I don't know the details of the inference process of rust, I imagine the following is happening.



Take this signature:



fn iter(&self) -> JoinIter<<&T as IntoIterator>::IntoIter, &S>


The compiler try to infer the return type from:



JoinIter<<&T as IntoIterator>::IntoIter, &S>


but <&T as IntoIterator>::IntoIter is inferred from the &'a Join impl:



impl<'a, T, S> IntoIterator for &'a Join<T, S>
where &'a T: IntoIterator
{
type IntoIter = JoinIter<<&'a T as IntoIterator>::IntoIter, &'a S>;
type Item = JoinItem<<&'a T as IntoIterator>::Item, &'a S>;

fn into_iter(self) -> Self::IntoIter {
JoinIter::new(self.container.into_iter(), &self.separator)
}
}


and IntoIter is again a JoinIter<<&'a T as IntoIterator>::IntoIter, &'a S> that has an IntoIter and so and so ad infinitum.



A way to make it compile it is to help the compiler with a turbofish:



let mut bad_ref_iter = Join::<Vec<i32>, &str>::iter(&join);


instead of:



let bad_ref_iter = join.iter();


Update



The line:



type IntoIter = JoinIter<<&'a T as IntoIterator>::IntoIter, &'a S>;    


generate a recursion because Rust checks that traits are valid when they are defined rather than when they are used.



See this post for some more details and pointers to the progress of work
of lazy normalization, which may solve this problem.






share|improve this answer



















  • 1




    I still don't have any clue where the infinite recursion is coming from. Why does <&T as IntoIterator>::IntoIter need to be "inferred"? My understanding is the T and S are inferred from the type of join, but once T is known, <&T as IntoIterator>::IntoIter is a complete type that does not require any inference. The work-around is nice, but the source of the problem remains a complete mystery to me.
    – Sven Marnach
    Nov 22 at 18:02










  • Could be that the recursion happens before T and S are inferred from join? Look at this
    – attdona
    Nov 23 at 6:41










  • cross-posted here
    – attdona
    Nov 23 at 7:24















up vote
2
down vote













It seems that the compiler is not able to resolve the trait requirement needed by iter() return type JoinIter<<&T as IntoIterator>::IntoIter, &S>.



I've received an hint for this from rustc --explain E0275 error explanation:




This error occurs when there was a recursive trait requirement that overflowed
before it could be evaluated. Often this means that there is unbounded
recursion in resolving some type bounds.




I don't know the details of the inference process of rust, I imagine the following is happening.



Take this signature:



fn iter(&self) -> JoinIter<<&T as IntoIterator>::IntoIter, &S>


The compiler try to infer the return type from:



JoinIter<<&T as IntoIterator>::IntoIter, &S>


but <&T as IntoIterator>::IntoIter is inferred from the &'a Join impl:



impl<'a, T, S> IntoIterator for &'a Join<T, S>
where &'a T: IntoIterator
{
type IntoIter = JoinIter<<&'a T as IntoIterator>::IntoIter, &'a S>;
type Item = JoinItem<<&'a T as IntoIterator>::Item, &'a S>;

fn into_iter(self) -> Self::IntoIter {
JoinIter::new(self.container.into_iter(), &self.separator)
}
}


and IntoIter is again a JoinIter<<&'a T as IntoIterator>::IntoIter, &'a S> that has an IntoIter and so and so ad infinitum.



A way to make it compile it is to help the compiler with a turbofish:



let mut bad_ref_iter = Join::<Vec<i32>, &str>::iter(&join);


instead of:



let bad_ref_iter = join.iter();


Update



The line:



type IntoIter = JoinIter<<&'a T as IntoIterator>::IntoIter, &'a S>;    


generate a recursion because Rust checks that traits are valid when they are defined rather than when they are used.



See this post for some more details and pointers to the progress of work
of lazy normalization, which may solve this problem.






share|improve this answer



















  • 1




    I still don't have any clue where the infinite recursion is coming from. Why does <&T as IntoIterator>::IntoIter need to be "inferred"? My understanding is the T and S are inferred from the type of join, but once T is known, <&T as IntoIterator>::IntoIter is a complete type that does not require any inference. The work-around is nice, but the source of the problem remains a complete mystery to me.
    – Sven Marnach
    Nov 22 at 18:02










  • Could be that the recursion happens before T and S are inferred from join? Look at this
    – attdona
    Nov 23 at 6:41










  • cross-posted here
    – attdona
    Nov 23 at 7:24













up vote
2
down vote










up vote
2
down vote









It seems that the compiler is not able to resolve the trait requirement needed by iter() return type JoinIter<<&T as IntoIterator>::IntoIter, &S>.



I've received an hint for this from rustc --explain E0275 error explanation:




This error occurs when there was a recursive trait requirement that overflowed
before it could be evaluated. Often this means that there is unbounded
recursion in resolving some type bounds.




I don't know the details of the inference process of rust, I imagine the following is happening.



Take this signature:



fn iter(&self) -> JoinIter<<&T as IntoIterator>::IntoIter, &S>


The compiler try to infer the return type from:



JoinIter<<&T as IntoIterator>::IntoIter, &S>


but <&T as IntoIterator>::IntoIter is inferred from the &'a Join impl:



impl<'a, T, S> IntoIterator for &'a Join<T, S>
where &'a T: IntoIterator
{
type IntoIter = JoinIter<<&'a T as IntoIterator>::IntoIter, &'a S>;
type Item = JoinItem<<&'a T as IntoIterator>::Item, &'a S>;

fn into_iter(self) -> Self::IntoIter {
JoinIter::new(self.container.into_iter(), &self.separator)
}
}


and IntoIter is again a JoinIter<<&'a T as IntoIterator>::IntoIter, &'a S> that has an IntoIter and so and so ad infinitum.



A way to make it compile it is to help the compiler with a turbofish:



let mut bad_ref_iter = Join::<Vec<i32>, &str>::iter(&join);


instead of:



let bad_ref_iter = join.iter();


Update



The line:



type IntoIter = JoinIter<<&'a T as IntoIterator>::IntoIter, &'a S>;    


generate a recursion because Rust checks that traits are valid when they are defined rather than when they are used.



See this post for some more details and pointers to the progress of work
of lazy normalization, which may solve this problem.






share|improve this answer














It seems that the compiler is not able to resolve the trait requirement needed by iter() return type JoinIter<<&T as IntoIterator>::IntoIter, &S>.



I've received an hint for this from rustc --explain E0275 error explanation:




This error occurs when there was a recursive trait requirement that overflowed
before it could be evaluated. Often this means that there is unbounded
recursion in resolving some type bounds.




I don't know the details of the inference process of rust, I imagine the following is happening.



Take this signature:



fn iter(&self) -> JoinIter<<&T as IntoIterator>::IntoIter, &S>


The compiler try to infer the return type from:



JoinIter<<&T as IntoIterator>::IntoIter, &S>


but <&T as IntoIterator>::IntoIter is inferred from the &'a Join impl:



impl<'a, T, S> IntoIterator for &'a Join<T, S>
where &'a T: IntoIterator
{
type IntoIter = JoinIter<<&'a T as IntoIterator>::IntoIter, &'a S>;
type Item = JoinItem<<&'a T as IntoIterator>::Item, &'a S>;

fn into_iter(self) -> Self::IntoIter {
JoinIter::new(self.container.into_iter(), &self.separator)
}
}


and IntoIter is again a JoinIter<<&'a T as IntoIterator>::IntoIter, &'a S> that has an IntoIter and so and so ad infinitum.



A way to make it compile it is to help the compiler with a turbofish:



let mut bad_ref_iter = Join::<Vec<i32>, &str>::iter(&join);


instead of:



let bad_ref_iter = join.iter();


Update



The line:



type IntoIter = JoinIter<<&'a T as IntoIterator>::IntoIter, &'a S>;    


generate a recursion because Rust checks that traits are valid when they are defined rather than when they are used.



See this post for some more details and pointers to the progress of work
of lazy normalization, which may solve this problem.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 24 at 17:51

























answered Nov 22 at 13:37









attdona

2,93411120




2,93411120








  • 1




    I still don't have any clue where the infinite recursion is coming from. Why does <&T as IntoIterator>::IntoIter need to be "inferred"? My understanding is the T and S are inferred from the type of join, but once T is known, <&T as IntoIterator>::IntoIter is a complete type that does not require any inference. The work-around is nice, but the source of the problem remains a complete mystery to me.
    – Sven Marnach
    Nov 22 at 18:02










  • Could be that the recursion happens before T and S are inferred from join? Look at this
    – attdona
    Nov 23 at 6:41










  • cross-posted here
    – attdona
    Nov 23 at 7:24














  • 1




    I still don't have any clue where the infinite recursion is coming from. Why does <&T as IntoIterator>::IntoIter need to be "inferred"? My understanding is the T and S are inferred from the type of join, but once T is known, <&T as IntoIterator>::IntoIter is a complete type that does not require any inference. The work-around is nice, but the source of the problem remains a complete mystery to me.
    – Sven Marnach
    Nov 22 at 18:02










  • Could be that the recursion happens before T and S are inferred from join? Look at this
    – attdona
    Nov 23 at 6:41










  • cross-posted here
    – attdona
    Nov 23 at 7:24








1




1




I still don't have any clue where the infinite recursion is coming from. Why does <&T as IntoIterator>::IntoIter need to be "inferred"? My understanding is the T and S are inferred from the type of join, but once T is known, <&T as IntoIterator>::IntoIter is a complete type that does not require any inference. The work-around is nice, but the source of the problem remains a complete mystery to me.
– Sven Marnach
Nov 22 at 18:02




I still don't have any clue where the infinite recursion is coming from. Why does <&T as IntoIterator>::IntoIter need to be "inferred"? My understanding is the T and S are inferred from the type of join, but once T is known, <&T as IntoIterator>::IntoIter is a complete type that does not require any inference. The work-around is nice, but the source of the problem remains a complete mystery to me.
– Sven Marnach
Nov 22 at 18:02












Could be that the recursion happens before T and S are inferred from join? Look at this
– attdona
Nov 23 at 6:41




Could be that the recursion happens before T and S are inferred from join? Look at this
– attdona
Nov 23 at 6:41












cross-posted here
– attdona
Nov 23 at 7:24




cross-posted here
– attdona
Nov 23 at 7:24


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53405287%2fwhats-going-on-with-this-bizarre-recursive-type-error-in-rust%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

What visual should I use to simply compare current year value vs last year in Power BI desktop

How to ignore python UserWarning in pytest?

Alexandru Averescu