Swift Parameter Packs: Is there a way to spread a tuple into the arguments of a function?

343 views Asked by At

Consider the following code from a dependency injection package:

func register<T, each A>(
  _ type: T.Type = T.self,
  tags: AnyHashable...,
  lifetime: Lifetime = .transient,
  factory: @escaping (any Resolver, repeat each A) throws -> T
) -> Key {
  let thunk = { (r: any Resolver, args: (repeat each A)) throws -> T in
    try factory(r, repeat each args)
  }
  return register(type, tags: Set(tags), lifetime: lifetime, factory: thunk)
}

This fails to compile. The error is:

INTERNAL ERROR: feature not implemented: reabstraction of pack values.

Now, I know why this is happening. Inside of thunk I attempt to do something fancy. We've told it that the type of args is (repeat each A), i.e., a tuple generated from the parameter pack types. But, in the body of thunk I say try factory(r, repeat each args). I was crossing my fingers that Swift 5.9 would be smart enough to "unravel" the tuple it had just created from the parameter pack, but it looks like this (superb) feature has not yet been implemented, if it ever will be. This means I'm forced to use the old style of multiple overloads with different numbers of parameters.

Does anyone know a workaround for this? Is there some clever way to spread a tuple in Swift 5.9?

1

There are 1 answers

7
Serge Vysotsky On BEST ANSWER

Passing all tests after changing function and types signatures:

public typealias SyncFactory<T, each A> = (any Resolver, repeat each A) throws -> T
func register<T, each A>(_ type: T.Type = T.self, tags: AnyHashable..., lifetime: Lifetime = .transient, factory: @escaping (any Resolver, repeat each A) throws -> T) -> Key {
    let factory: SyncFactory<T, repeat each A> = { (r: any Resolver, arg: repeat each A) in
        try factory(r, repeat each arg)
    }
    return register(type, tags: Set(tags), lifetime: lifetime, factory: factory)
}

Here is the pull request with all the changes to SyncFactory APIs.