Type inferencer probably could figure this case out (associated types)
trait Async {
type Value;
type Error;
}
enum Result<T, E> {
Ok(T),
Err(E),
}
impl<T, E> Result<T, E> {
fn reduce<F, U>(self, init: U::Value, action: F) -> U::Value
where F: Fn(U::Value, T) -> U,
U: Async<Error=E> {
unimplemented!();
}
}
impl Async for i32 {
type Value = i32;
type Error = ();
}
pub fn main() {
let res: Result<&'static str, ()> = Result::Ok("hello");
let val: i32 = 123;
res.reduce(val, |val /* i32 */, curr| val);
// Compiles if annotated ^^
}
cc @nikomatsakis
This requires two features which have not been implemented yet: #19476 and #21939 - and I'm not certain on the interaction between the two.
Eduard-Mihai Burtescu at 2015-03-26 06:53:11
Carl, I think you could workaround this limitation by introducing another type parameter:
impl<T, E> Result<T, E> { fn reduce<F, U, X>(self, init: X, action: F) -> U::Value where F: Fn(X, T) -> U, U: Async<Error=E, Value=X> { unimplemented!(); } }Indeed this works in play.
I'm actually not sure why it's not working today. I think what should be happening is that when we try to normalize
$U::Value, where$Uis the variable we created forU, we wind up with a type variable$1and the side-constraint that$U: Async<Value=$1>. Clearly$1will get unified withi32and then$Ushould (through the return value) be unified with$1. This seems like enough to figure out everything that is needed. But you do get an error, so presumably something goes wrong at an earlier point in the process, I'm not quite sure what.Niko Matsakis at 2015-03-26 17:14:18
Oh, my bad, I didn't realize
U::Valuewas being fedi32from passingvalinto the call.Eduard-Mihai Burtescu at 2015-03-26 19:06:09
Triage: this still reproduces today.
Steve Klabnik at 2016-11-15 20:21:03
Triage: no change
Steve Klabnik at 2018-09-24 15:57:46
Triage: no change
Maayan Hanin at 2022-03-22 10:41:25