Hi everyone, I'm new to Rust, but I don't understand why PhantomData helps the following code compile. However, when I directly impl F, even though I've already set a constraint for P, it doesn't compile successfully?
pub struct PhantomSystem<F, P>(F, PhantomData<P>);
pub trait TSystemParam
{
fn new() -> Self;
}
//impl<F, P> TSystem for F // ❌ ERROR
impl<F, P> TSystem for PhantomSystem<F, P> // ✅ OK !?
where
F: Fn(P),
P: TSystemParam + 'static,
{
fn run(self) { (self.0)(P::new()); }
//fn run(self) { (self)(P::new()); }
}
P has to appear in the trait or the implementing type, or be determined by the trait and the implementing type by way of an associated type equality bound. That way the implementation including all the generics can be determined by qualified paths such as
<PhantomSystem<F, P> as TSystem>::...
I.e. by the trait and implementing type alone.
In contrast with
// P is ... ?
<F as TSystem>::...
More details can be found in this RFC.
P.S. You had it right the first time: post textual code blocks, not images. Edit: Thanks 
you have not.
F : Fn(P) does not set a constraint for P, because the type system cannot deduce which P to choose solely from F and TSyStem.
suppose u32 :TSystemParam + 'static and u16::TSystemParam + 'static
and F : Fn(u32) + Fn(u16).
then the compiler cannot tell what P is, i.e. P is unconstrained.
P: TSystemParam + 'static
But I already have the P type constraint here, right? Surely the compiler should read that information when I implement it for F?
you have a bound on P but it doesn't constrain it because there are can be multiple valid candidate for P for one impl.
P is constrained only if there is only one valid P per impl.
i invite you to reread what i said above in detail, especially the example with u32 and u16