The following code fails with a type error:
Compiling playground v0.0.1 (/playground)
error[E0282]: type annotations needed
--> src/main.rs:41:8
|
41 | &produce_generic(),
| ^^^^^^^^^^^^^^^ cannot infer type of the type parameter `P` declared on the function `produce_generic`
|
help: consider specifying the generic argument
|
41 | &produce_generic::<P>(),
| +++++
For more information about this error, try `rustc --explain E0282`.
error: could not compile `playground` due to previous error
Full link to playground.
Code:
trait Produce {
type Output<A>;
fn produce<A>(a: A) -> Self::Output<A>;
}
struct ProduceUint;
impl Produce for ProduceUint {
type Output<A> = u64;
fn produce<A>(_a: A) -> Self::Output<A> {
0
}
}
struct ProduceString;
impl Produce for ProduceString {
type Output<A> = String;
fn produce<A>(_a: A) -> Self::Output<A> {
"hello".into()
}
}
fn produce_both<A, B>(
produce_uint: &<ProduceUint as Produce>::Output<A>,
produce_string: &<ProduceString as Produce>::Output<A>
) -> (u64, String) {
(*produce_uint, produce_string.clone())
}
struct SomeType;
fn produce_generic<P: Produce>() -> P::Output<SomeType> {
P::produce(SomeType)
}
fn main() {
assert_eq!(produce_both::<SomeType, SomeType>(
&produce_generic(),
&produce_generic()
), (0, "hello".into()))
}
This surprised me because the function signature for produce_both
is very clear about which implementation it is using. Any ideas why inference fails in this scenario and perhaps if there's an alternative way to define the functions to help the compiler infer types?
The compiler cannot infer "in reverse" with associated types. The fact that you're specifying in product_both
the type does not matter - there could be defined another type that is also producing the same type:
struct AnotherProduceUint;
impl Produce for AnotherProduceUint {
type Output<A> = u64;
fn produce<A>(_a: A) -> Self::Output<A> {
123
}
}
And now the compiler cannot decide between ProductUint
and AnotherProductUint
.