Making a "Drop First Argument" Function using Variadic Generics

Hey there,

I just triggered a compiler error (I think): "INTERNAL ERROR: feautre not implemented: reabstraction of pack values". Here's my minimal example to reproduce this:

func dropFirstArg<First, each Others>(_ closure: @escaping ((repeat each Others)) async throws -> Void) -> ((First, repeat each Others)) async throws -> Void {
    fatalError() // trying to implement this gives more unintelligible errors 
}

Is there any workaround to accomplish what I'm trying to do? In my concrete case, all I want is to drop the initial Substring output of a Regex<(Substring, repeat each ActualArgsThatICareAbout)> such that this compiles:

public struct Match<Args> {
    
    public let regex : Regex<Args>
    public let onRecognize : (Args) async throws -> Void
    
    public init<each Arg>(_ regex: Regex<(Substring, repeat each Arg)>,
                          onRecognize: @escaping ((repeat each Arg)) async throws -> Void) where Args == (Substring, repeat each Arg) {
        self.regex = regex
        self.onRecognize = dropFirstArg(onRecognize)
    }
    
}

Other approaches I considered: putting a regex and onRecognize requirement directly into a protocol so I can actually make onRecognize a func rather than a closure; problem with that approach is that associatedtypes can't be variadic generic, so I'd be stuck with a tuple which don't look quite so nice in funcs.

Update: I think the second part of the code is actually significant in producing the mentioned error. When I removed the constructor of Match, everything was fine, so dropFirstArg itself is not the issue... maybe I can get this to work still??

I'm basically doing it manually again - the very thing that we were supposed to avoid with the shiny new variadic generics :frowning: There's apparently still a lot left to be desired

public protocol Matcher {
    var regexText : String {get}
    func match(_ arg: String) throws -> Any?
    func invoke(with arg: Any) async throws
}

public extension Cucumber {
    
    static func match(_ regex: Regex<Substring>, onRecognize: @escaping () async throws -> Void) -> some Matcher {
        Match0(regex: regex, onRecognize: onRecognize)
    }
    
    static func match<Arg0>(_ regex: Regex<(Substring, Arg0)>, onRecognize: @escaping (Arg0) async throws -> Void) -> some Matcher {
        Match1(regex: regex, onRecognize: onRecognize)
    }
    
    static func match<Arg0, Arg1>(_ regex: Regex<(Substring, Arg0, Arg1)>, onRecognize: @escaping (Arg0, Arg1) async throws -> Void) -> some Matcher {
        Match2(regex: regex, onRecognize: onRecognize)
    }
    
    static func match<Arg0, Arg1, Arg2>(_ regex: Regex<(Substring, Arg0, Arg1, Arg2)>, onRecognize: @escaping (Arg0, Arg1, Arg2) async throws -> Void) -> some Matcher {
        Match3(regex: regex, onRecognize: onRecognize)
    }
    
}

struct Match0 : Matcher {
    
    var regexText: String {
        "\(regex)"
    }
    
    let regex : Regex<Substring>
    let onRecognize : () async throws -> Void
    
    func match(_ arg: String) throws -> Any? {
        try regex.wholeMatch(in: arg)?.output
    }
    
    func invoke(with arg: Any) async throws {
        try await onRecognize()
    }
    
}

struct Match1<Arg0> : Matcher {
    
    var regexText: String {
        "\(regex)"
    }
    
    let regex : Regex<(Substring, Arg0)>
    let onRecognize : (Arg0) async throws -> Void
    
    func match(_ arg: String) throws -> Any? {
        try regex.wholeMatch(in: arg)?.output
    }
    
    func invoke(with arg: Any) async throws {
        let (_, arg0) = arg as! (Substring, Arg0)
        try await onRecognize(arg0)
    }
    
}

struct Match2<Arg0, Arg1> : Matcher {
    
    var regexText: String {
        "\(regex)"
    }
    
    let regex : Regex<(Substring, Arg0, Arg1)>
    let onRecognize : (Arg0, Arg1) async throws -> Void
    
    func match(_ arg: String) throws -> Any? {
        try regex.wholeMatch(in: arg)?.output
    }
    
    func invoke(with arg: Any) async throws {
        let (_, arg0, arg1) = arg as! (Substring, Arg0, Arg1)
        try await onRecognize(arg0, arg1)
    }
    
}

struct Match3<Arg0, Arg1, Arg2> : Matcher {
    
    var regexText: String {
        "\(regex)"
    }
    
    let regex : Regex<(Substring, Arg0, Arg1, Arg2)>
    let onRecognize : (Arg0, Arg1, Arg2) async throws -> Void
    
    func match(_ arg: String) throws -> Any? {
        try regex.wholeMatch(in: arg)?.output
    }
    
    func invoke(with arg: Any) async throws {
        let (_, arg0, arg1, arg2) = arg as! (Substring, Arg0, Arg1, Arg2)
        try await onRecognize(arg0, arg1, arg2)
    }
    
}