Open rylev opened 2 years ago
The code cannot compile because, from different points of view, the function is doing either of the following 2 things
ReturnTypeOf(flatten) = Chain<Once, FlatMap<BTreeMapValue, flatten>>
. Note that flatten
appears on both sides, and you would get an infinitely nested type if you try to deduce the return typeLeaf
return type for the leaf, then the function is returning a different type for each recursion level, which a single impl Trait
cannot capture. If the leaf level returns a Leaf
type, then the next level would return a Chain<Once, FlatMap<BTreeMapValue, BTreeMap -> Leaf>>
type, and then the next following level would be Chain<Once, FlatMap<BTreeMapValue, BTreeMap -> Chain<Once, FlatMap<BTreeMapValue, BTreeMap -> Leaf>>>>
, and so on. This is also what the error message is about:
hidden type (of the current recursion level) is differed from previous (the previous recursion level)
One way to work around this is to introduce a type-erasing dynamic dispatch somewhere in the recursion, so the return type becomes finite. For example:
struct Tree<'a> {
nested: std::collections::BTreeMap<&'a str, Tree<'a>>,
}
impl<'a> Tree<'a> {
fn flatten(&self) -> impl Iterator<Item = &Tree<'a>> {
Box::new(std::iter::once(self).chain(self.nested.values().flat_map(|tree| tree.flatten())))
as Box<dyn Iterator<Item = &Tree<'a>>>
}
}
The error message indeed looks confusing on a recursive function. Maybe some special case error message and advises could be better for recursive function.
Given the following code: [link]
The current output on stable is:
and on nightly:
Ideally this code should compile, but if it cannot be made to compile than the compiler error should use lesson compiler jargon (e.g., "opaque type").