I want a trait requiring that a named type can interact with the implementing type (or associated type):
trait ExternalBound
where
Named: SomeOp<Self>, // or `SomeOp<Self::Associated>`
{}
This constrains any actual implementation, such that if SomeOp<Self> isn't implemented, the trait can't be implemented:
// impl SomeOp<Target> for Named {} // Causes compilation error if commented out.
impl ExternalBound for Target {}
But, that doesn't seem to carry forward to actual usages, where the where Named: SomeOp<Self> clause appears to need to be duplicated.
// Causes a compilation error for lack of `where Named: SomeOp<T>`
fn should_be_constrained<T: ExternalBound>(_value: T) {}
But the compilation error has a cryptic note that there may be a better way:
"help: consider introducing a where clause, but there might be an alternative better way to express this requirement"
Is there some way I'm missing to make the trait self-contained such that the basic generic T: ExternalBound is all that is required?
This is a long-standing unfortunate limitation in the compiler: only bounds that have exactly Self on the left — that is, where Self: SomeOtherTrait — are implied.
Oh neat, that had a somewhat recent post which appears to solve it; move the external type into an "unused" internal associated type to carry the bound (so Self::_Named goes on the left):
struct Named;
struct Target;
trait SomeOp<Rhs: ?Sized> {}
trait GivesBoundType {
type Gives;
type _Named: SomeOp<Self::Gives>;
}
impl SomeOp<Target> for Named {}
impl GivesBoundType for Target {
type Gives = Self;
type _Named = Named;
}
fn uses<T: GivesBoundType>(_value: T) {}