I've been updating a library to use Rust's new associated types. The library offers a Node
trait for constructing a DSP graph. Below is a simplified version of the trait that produces the same error I'm running into in my library.
use std::default::Default;
use std::num::Float;
trait Node {
type Output: Default + Float;
fn inputs<N>(&mut self) -> Vec<&mut N>
where
N: Node<Output = <Self as Node>::Output>;
fn output_requested(&mut self, output: &mut <Self as Node>::Output) {
for input in self.inputs().into_iter() {
let mut working: <Self as Node>::Output = Default::default();
input.output_requested(&mut working);
// ^~~~~ ERROR
*output = *output + working;
}
}
}
fn main() {}
Here's the error message
<anon>:15:19: 15:49 error: the type of this value must be known in this context
<anon>:15 input.output_requested(&mut working);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Playpen link - http://is.gd/xm0wvS
Considering that self.inputs()
returns N
where N: Node<Output = <Self as Node>::Output>
, I'm under the impression rustc should have enough type information about input
to satisfy the call to the output_requested
method?
Any help greatly appreciated!
First of all: given an object x
implementing Node
, x.inputs()
takes a generic parameter N
and returns Vec<&mut N>
.
Now let’s write out a more explicitly typed version of what’s happening in output_requested
.
(Incidentally, with the fancy new IntoIterator
basis of the for
loop, the .into_iter()
is no longer necessary.)
fn output_requested(&mut self, output: &mut <Self as Node>::Output) {
let inputs: Vec<&mut N> = self.inputs();
for input in inputs { // input: &mut N
let mut working: <Self as Node>::Output = Default::default();
input.output_requested(&mut working);
*output = *output + working;
}
}
Well, then; what can we figure about this type N
? Can we resolve it?
It came from self.inputs()
, introducing the constraint that it implements Node<Output = <Self as Node>::Output>
;
On the object, you called the method self.output_requested(&mut <Self as Node>::Output)
, which only confirms the previous point.
So all we know about this N
is that it implements Node
with the same Output
as our type. But that could be two completely different types, like this:
impl Node for A {
type Output = Out;
…
}
impl Node for B {
type Output = Out;
…
}
Thus you can see that it is not possible to determine what N
is; it can always be Self
, but there may be other possibilities as well, and so it cannot be resolved statically and is forbidden.