Why are Parameter Pack Parameters required to be escapable?

The following code does not compile in today’s Swift:

func f(_ fn: @escaping (() -> ()) -> ()) {
    f2(fn)
}

func f2<each T>(_ fn: @escaping (repeat each T) -> ()) {
    
}

There is a fixit, which suggests applying a second @escaping annotation to fn.

I initially thought this was because a program could somehow contrive to acquire a reference to and store an instance of T, causing it to escape. But in writing this post, I tried a plain, non-parameter-pack version, and it works fine.

func f(_ fn: @escaping (() -> ()) -> ()) {
    f3(fn)
}

func f3<T>(_ fn: @escaping (T) -> ()) {
    
}

But before that, I thought to try ~Escapable. I’ve not used ~Escapable before, but it seems like it should help here: the signature func f2<each T>(_ fn: @escaping (repeat each T) -> ()) where repeat each T: ~Escapable should indicate to the compiler that we don’t need to escape anything. But this is explicitly not supported, and produces the error “Each T required to be Escapable but is marked with ~Escapable“.

So I have two questions: first, is this a bug? And second, why does the requirement that parameter pack arguments be escapable exist?

It’s a bug, or really just unimplemented functionality. There’s no inherent reason you can’t have a pack of nonescaping function types. Support for ~Copyable and ~Escaping is similar, but probably requires more plumbling at the SIL level so that you can useful things without copying a pack. I don’t believe @autoclosure works either.

2 Likes