#![feature(fn_traits)]
#![feature(unboxed_closures)]
// I'm keeping this example to FnOnce because it's easiest to implement.
// (doing Fn would require a bunch more boilerplate)
struct Funk;
impl FnOnce<((),)> for Funk {
type Output = ();
extern "rust-call"
fn call_once(self, arg: ((),)) -> () { arg.0 }
}
impl FnOnce<(u8,)> for Funk {
type Output = bool;
extern "rust-call"
fn call_once(self, arg: (u8,)) -> bool { arg.0 % 2 == 0 }
}
trait Constructed { type Data; }
impl Constructed for () { type Data = (); }
impl Constructed for bool { type Data = u8; }
fn fn_with_a<A: Constructed, F: FnOnce(A::Data) -> A>(f: F) -> usize {
::std::mem::size_of::<A>()
}
In this case, fn_with_a(Funk) has two possible implementations; but it is still possible to disambiguate between them:
fn main() {
// error[E0284]: type annotations required: cannot resolve `<_ as Constructed>::Data == _`
println!("{:?}", fn_with_a(Funk));
// okay
println!("{:?}", fn_with_a::<(),_>(Funk)); // prints 0
println!("{:?}", fn_with_a::<bool,_>(Funk)); // prints 1
}
In your trait example, the parameter is on the impl. Those parameters however play no role in distinguishing bewteen trait impls; the full path of a trait method is
<MyType<A,B> as MyTrait<F,G>>::my_method::<X,Y>()
End result: Your original impl, if it were allowed, would create two conflicting implementations for <Funk as Dummy>.