Associated type bound with HRTBs says type doesn't implement trait

I'm trying to use HRTBs to express that a value passed to a function implements a trait for any reference to the value. The actual use case is on a trait impl, but it's simpler to demonstrate with functions.

It looks almost exactly like #56556, but that issue has been closed, and at least some of the examples on the issue no longer fail.

I can't decide if this is just an edge case that fix didn't cover, or if this is one of those situations where the lifetimes in the type are causing issues and I am just not seeing where.

Playground

pub trait Trait {}

impl<'a, T> Trait for &'a T where T: Trait {}

impl<'a> Trait for &'a str {}

fn check_hrtb<T>(_: T)
where
    for<'a> &'a T: IntoIterator,
    for<'a> <&'a T as IntoIterator>::Item: Trait,
{
}

fn check<'a, T>(_: T)
where
    T: 'a,
    &'a T: IntoIterator,
    <&'a T as IntoIterator>::Item: Trait,
{
}

fn main() {
    check(["hi"]); // Works
    check_hrtb(["hi"]); // Fails with error below
}

Output:

error[E0277]: the trait bound `for<'a> <&'a _ as IntoIterator>::Item: Trait` is not satisfied
  --> src/main.rs:24:16
   |
24 |     check_hrtb(["hi"]);
   |     ---------- ^^^^^^ the trait `for<'a> Trait` is not implemented for `<&'a _ as IntoIterator>::Item`
   |     |
   |     required by a bound introduced by this call
   |
   = help: the following other types implement trait `Trait`:
             &'a T
             &'a str
note: required by a bound in `check_hrtb`
  --> src/main.rs:10:44
   |
7  | fn check_hrtb<T>(_: T)
   |    ---------- required by a bound in this
...
10 |     for<'a> <&'a T as IntoIterator>::Item: Trait,
   |                                            ^^^^^ required by this bound in `check_hrtb`

The provided example is actually an inference issue. So... maybe #89196? I didn't dig into the comments there to be sure.

To be more clear:

-    check_hrtb(["hi"]);
+    check_hrtb::<[&str; 1]>(["hi"]);
1 Like

Oh interesting, thank you!

I had a follow-up thought that maybe this is because your concrete implementation was for &str when the bounds on the check need &&str (i.e. they have to go through the blanket &-lifting implementation). But implementing on &&str (or str) directly doesn't help, so I guess that's not it.

The complier should handle this case IMO, since all I did is supply the type of the parameter (minus a lifetime even). Your use-case is a bit different from the minimum examples in that issue, so maybe file a new issue or ask in the issue if they think it's the same problem.

I opened #101099

1 Like

If you want to keep the ergonomics, you can move your higher-ranked function/method bounds onto a trait of their own. The compiler seems to do better when handles inference first and then checks HRTB, versus trying to infer underneath a HRTB. Unfortunately it requires a lot of boiler-plate for patterns like these.

Here it is on stable. And your link was to Nightly, so if you're ok using GATs, here's a version that does that.

I discovered the actual problem I was having was totally unrelated, and this issue was purely from how I attempted to reduce the original issue for the question.

I was doing something like

impl<Values, Value> Something
where
    for<'a> &'a Values: IntoIterator<Item = Value>,
    Value: Trait,
{
}

Which now I can obviously see didn't work because Value has to be the same for any 'a. Not sure why I didn't see that immediately.

The solution was to just get rid of Value and suffer the fully qualified associated type syntax (for<'a> <<&'a Values as IntoIterator>::Item as Pair>::First), but I was experimenting on a function and not the impl which is when I hit the issue that this thread ended up being about. When I just tried it on the impl it worked fine.

That workaround is interesting though. I'm sure it will come in handy at some point, thank you for sharing it!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.