Yes, this does not really feel intuitive. After a bit of research however, it seems that it is a somewhat-intentional restriction of the type checker that was reported as soon as 2015.
Indeed, the #107699 Rust issue that was opened fairly recently describes exactly the situation encountered here, only with the function being replaced by a trait instead, but that does not change anything regarding the constraints check. It is linked to the old #20671. #103387 seems to be another duplicate of it, where this comment makes a good summary of the opened issues. See also this other SO question on the matter.
Generally speaking, the situation occurs because the trait bound is not added on Self
, but rather on &'a Self
, and by current design only bounds on Self
are propagated to use sites ("elaborated" in rustc terminology) and may be implied there. For example:
trait SuperTrait {}
trait SubTrait: SuperTrait {}
fn f<T: SubTrait>() {}
compiles just fine, but this:
trait OtherTrait {}
trait SuperTrait { type A; }
trait SubTrait: SuperTrait where Self::A: OtherTrait {}
fn f<T: SubTrait>() {}
does not, on the following error:
error[E0277]: the trait bound `<T as SuperTrait>::A: OtherTrait` is not satisfied
--> src/lib.rs:4:9
|
4 | fn f<T: SubTrait>() {}
| ^^^^^^^^ the trait `OtherTrait` is not implemented for `<T as SuperTrait>::A`
|
note: required by a bound in `SubTrait`
--> src/lib.rs:3:43
|
3 | trait SubTrait: SuperTrait where Self::A: OtherTrait {}
| ^^^^^^^^^^ required by this bound in `SubTrait`
help: consider further restricting the associated type
|
4 | fn f<T: SubTrait>() where <T as SuperTrait>::A: OtherTrait {}
| ++++++++++++++++++++++++++++++++++++++
that is very similar to what is obtained when compiling the example provided. Adding the suggested where
bound does also solve the error.
Also note that the situation is not HRTB-specific since simply bubbling up the lifetime in:
trait PtrTrait {}
trait RegTrait<'a>: 'a
where
&'a Self: PtrTrait,
{}
fn bar<'a, T>()
where
T: RegTrait<'a>,
// &'a T: PtrTrait,
{}
also exhibits the same behavior.
Regarding a workaround, supposing a no-HRTB scenario, I think the above can be transformed to:
trait PtrTrait {}
trait Intermediary {
type Type: PtrTrait;
}
trait RegTrait<'a>: Intermediary<Type = &'a Self> + 'a {}
fn bar<'a, T: RegTrait<'a>>() {}
and is accepted by the compiler, although it might be too convoluted to be usable in your concrete case at this point.