iosswiftparameter-pack

Swift 5.9: Parameter Packs getting Pack reference 'each V' can only appear in pack expansion


Hi Im trying to use the new variadic generic feature of swift 5.9.

So I have a code that Im trying to refactor it:

func resolve<T>() -> T {
// Resolve method
}
    func autoResolve<T>(_ initializer: () -> T) -> T { initializer() }
    func autoResolve<T, A>(_ initializer: (A) -> T) -> T { initializer(resolve()) }
    func autoResolve<T, A, B>(_ initializer: (A, B) -> T) -> T { initializer(resolve(), resolve()) }
    func autoResolve<T, A, B, C>(_ initializer: (A, B, C) -> T) -> T { initializer(resolve(), resolve(), resolve()) }
    func autoResolve<T, A, B, C, D>(_ initializer: (A, B, C, D) -> T) -> T { initializer(resolve(), resolve(), resolve(), resolve()) }
    func autoResolve<T, A, B, C, D, E>(_ initializer: (A, B, C, D, E) -> T) -> T { initializer(resolve(), resolve(), resolve(), resolve(), resolve()) }

To

func autoResolve<T, each V>(_ initializer: (repeat each V) -> T) -> T { initializer(repeat each resolve()) }

But Im getting this error Pack reference 'each V' can only appear in pack expansion

Where is the problem?


Solution

  • The following code compiles and works. The secret here is that you need to give type evidence. The packed generic type A must be mentioned somewhere in the repeat expression. If you don't do that, it's simply not going to work. But if you experiment a bit you'll find it's quite flexible.

    protocol Resolver {
      func resolve<T>() -> T
    }
    
    func auto<T, each A>(_ initializer: @escaping (repeat each A) -> T) -> (any Resolver) -> T {
      return { r in
        initializer(repeat r.resolve() as (each A))
      }
    }
    
    struct Foo {
      let x: Int
      let y: Int
    }
    
    let fooResolver = auto(Foo.init)
    

    This is the pattern that I used in my own DI framework to replace the many overloads I have for auto.