I ran into some strange behavior with the trait solver while trying to implement codegen for my Rust library. I have the following trait and struct definitions in my library:
trait HasKind {
type Kind;
}
trait HasView<V> {
type View;
}
pub trait HasLength {}
struct Node;
struct Signal;
impl HasView<Node> for Signal {
type View = Node;
}
struct Input;
impl HasKind for Input {
type Kind = Signal;
}
The input to my codegen is something like this:
#[derive(Interface)]
struct Interface
{
a: Input
}
I then generate a struct like this and attempt to implement the HasLength
trait on it if all of its fields implement HasLength
:
#[automatically_derived]
struct InterfaceView<V>
where
Input: HasKind<Kind: HasView<V>>,
{
a: <<Input as HasKind>::Kind as HasView<V>>::View,
}
// DOESN'T COMPILE
impl<V> HasLength for InterfaceView<V> where Input: HasKind<Kind: HasView<V, View: HasKind>> {}
This doesn't compile with the following error:
error[E0277]: the trait bound `Signal: HasView<V>` is not satisfied
--> src/lib.rs:39:1
|
39 | impl<V> HasLength for InterfaceView<V> where Input: HasKind<Kind: HasView<V, View: HasLength>> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasView<V>` is not implemented for `Signal`
|
help: consider extending the `where` clause, but there might be an alternative better way to express this requirement
|
39 | impl<V> HasLength for InterfaceView<V> where Input: HasKind<Kind: HasView<V, View: HasLength>>, Signal: HasView<V> {}
Strangely, I can get it to compile just by removing the HasLength
bound, even though it has nothing to do with HasView<V>
being implemented on Signal
:
// DOES COMPILE
impl<V> HasLength for InterfaceView<V> where Input: HasKind<Kind: HasView<V>> {}
To actually get the HasLength
bound to be asserted (which is needed for my codegen), I have to create a new trait which has the exact same trait bounds:
// DOES COMPILE
trait HasViewWithKind<V>: HasKind<Kind: HasView<V, View = <Self as HasViewWithKind<V>>::View>> {
type View: HasLength;
}
impl<V> HasLength for InterfaceView<V> where Input: HasViewWithKind<V> {}
This achieves what I want, but I am curious why my original attempt does not compile. It seems like the trait solver is unable to understand the implications of the trait bounds on associated types. Is this a issue with the compiler, or is this expected?