Weird trait bound issue between traits

So I just ran into this:

trait Foo
where
    u16: From<Self::Id>,
{
    type Id;
}

trait Bar<T>
where
    u16: From<T>,
{
}

fn test<F, B>()
where
    F: Foo,
    B: Bar<F::Id>,
{
}

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `u16: From<<F as Foo>::Id>` is not satisfied
  --> src/lib.rs:16:8
   |
16 |     F: Foo,
   |        ^^^ the trait `From<<F as Foo>::Id>` is not implemented for `u16`
   |
note: required by a bound in `Foo`
  --> src/lib.rs:3:10
   |
1  | trait Foo
   |       --- required by a bound in this trait
2  | where
3  |     u16: From<Self::Id>,
   |          ^^^^^^^^^^^^^^ required by this bound in `Foo`
help: consider extending the `where` clause, but there might be an alternative better way to express this requirement
   |
17 |     B: Bar<F::Id>, u16: From<<F as Foo>::Id>
   |                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~

For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` (lib) due to 1 previous error

What's going on here? The trait is implemented by

trait Foo
where
    u16: From<Self::Id>,

isn't it?

Only certain bounds of traits are implied elsewhere. Bounds on the implementing type and on associated types, mainly. u16 isn't either of those, so you need to restate the bound elsewhere:

fn test<F, B>()
where
    F: Foo,
    B: Bar<F::Id>,
    u16: From<F::Id>, // <-- new
{
}

Alternatively, you may be able to rephrase the bound as something you can put on the associated type:

trait Foo {
    type Id: Into<u16>;
}

// It wasn't clear to me why you needed the bound here,
// so I just removed it
trait Bar<T> {
}

fn test<F, B>()
where
    F: Foo,
    B: Bar<F::Id>,
{
}

Or not have the bound at all and only state it in places it's needed, like on a particular function (if possible).

3 Likes

Thanks. Then I'll need to bite the bullet and add the u16: from<F::Id> bound everywhere.
Due to the nature of my code, requiring Into is unfortunately insufficient, since I need the other direction as well.

Here's another roundabout workaround.

trait BaseFoo {
    type U16: From<Self::Id>;
    type Id;
}

trait Foo: BaseFoo<U16 = u16> {}

impl<T: ?Sized + BaseFoo<U16 = u16>> Foo for T {}

// ...
1 Like

Strike my last reply. I actually managed to refactor the code to using Into<u16>

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.