Emulating generic associated types

I've tried to emulate GAT by using an intermediate builder trait like this:

trait Foo: Sized {
    type AssocBuilder: BuildAssoc<'static, Foo = Self>; // removing the bound allows this to be compiled
    
    fn build_assoc<'a>(&'a self) -> <Self::AssocBuilder as BuildAssoc<'a>>::Assoc
    where
        Self::AssocBuilder: BuildAssoc<'a, Foo = Self>
    {
        <Self::AssocBuilder as BuildAssoc<'a>>::build_assoc(self)
    }
}

trait BuildAssoc<'a> {
    type Foo: Foo;
    type Assoc: 'a;
    
    fn build_assoc(foo: &'a Self::Foo) -> Self::Assoc;
}

I've required a trait bound for Foo::AssocBuilder to improve ergonomics in case the trait is used for global Foos (common use case), but this fails to compile with:

error[E0284]: type annotations needed
 --> src/lib.rs:4:5
  |
4 | /     fn build_assoc<'a>(&'a self) -> <Self::AssocBuilder as BuildAssoc<'a>>::Assoc
5 | |     where
6 | |         Self::AssocBuilder: BuildAssoc<'a, Foo = Self>
7 | |     {
8 | |         <Self::AssocBuilder as BuildAssoc<'a>>::build_assoc(self)
9 | |     }
  | |_____^ cannot infer type for associated type `<Self as Foo>::AssocBuilder`
  |
  = note: cannot resolve `<<Self as Foo>::AssocBuilder as BuildAssoc<'a>>::Assoc == _`

When I remove the trait bound for Foo::AssocBuilder the code compiles, but I don't understand why the type can supposedly not be inferred otherwise, since I very explicitly state all involved types and lifetimes.

For higher-kinded drop the where and use;
type AssocBuilder: for<'a> BuildAssoc<'a, Foo = Self>;

Thanks, this is extremely useful and simplifies things significantly!

I still wonder why my original code fails to compile, to me it appears to be only valid bounds and the compiler error is at least misleading.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.