Skip to content

Issue with non-lifetime trait used ion associated type in HRTB context #66817

Closed
@Lucretiel

Description

@Lucretiel

Consider this example (playground):

use std::fmt::{self, Display, Formatter};

// This struct provides a `Display` implementation that iterates over
// &collection, writing each element in sequence.
pub struct Concat<C> {
    collection: C,
}

impl<C> Display for Concat<C>
    where for <'a> &'a C: IntoIterator,
    for <'a> <&'a C as IntoIterator>::Item: Display,
{
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.collection.into_iter().try_for_each(move |element| {
            element.fmt(f)
        })
    }
}

fn main() {
    let collection = vec![1u32, 2, 3, 4, 5, 6];
    let concat = Concat { collection };
    println!("{}", concat);
}

We define a struct, Concat, that provides a Display implementation by immutably iterating over collection and writing each element to f in sequence. This trait implementation depends on the following trait bounds:

for<'a> &'a C: IntoIterator,  // immutable iteration
for<'a> <&'a C as IntoIterator>::Item: Display  // Items are displayable

However, the latter trait bound appears to not be binding correctly, as the example code fails to compile with the following error:

error[E0277]: `<&'a std::vec::Vec<u32> as std::iter::IntoIterator>::Item` doesn't implement `std::fmt::Display`
  --> src/main.rs:23:20
   |
23 |     println!("{}", concat);
   |                    ^^^^^^ `<&'a std::vec::Vec<u32> as std::iter::IntoIterator>::Item` cannot be formatted with the default formatter
   |
   = help: the trait `for<'a> std::fmt::Display` is not implemented for `<&'a std::vec::Vec<u32> as std::iter::IntoIterator>::Item`
   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
   = note: required because of the requirements on the impl of `std::fmt::Display` for `Concat<std::vec::Vec<u32>>`
   = note: required by `std::fmt::Display::fmt`

It's worth noting that the code does compile if you don't include the usage in main. I've tried a lot of variations on this code, but the issue seems to boil down to the fact that Rust seems to consider for<'a> Display different than display.

I posted this issue on stackoverflow, and got a response with the following workaround:

mod private {
    use std::fmt;
    pub trait Display<'a>: fmt::Display {}
    impl<'a, T> Display<'a> for T where T: fmt::Display {}
}

impl<C> fmt::Display for Concat<C>
where
    for<'a> &'a Container: IntoIterator,
    for<'a> <&'a Container as IntoIterator>::Item: private::Display<'a>,
...

In summary, there appears to be an issue with binding an associated type to a trait in an HRTB context.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions