Swift 5.7 thinks a closure is escaping even though it's not

Consider the following code:

func test(v: inout [Int]) {
    let closure = {
        v += [1]
    }
    closure()
}
var a = [0]
test(v: &a)

It won't compile, the error is: "escaping closure captures 'inout' parameter 'v'". But why, though? Is closure actually escapes anywhere? Is it how it's supposed to be, or it's a compiler bug?

My swiftc is 5.7, swiftc --version is swift-driver version: 1.62.1 Apple Swift version 5.7 (swiftlang-5.7.0.123.7 clang-1400.0.29.50).

1 Like

it is considered escaping because you have bound it to a variable (closure). if you execute it immediately, it should be considered non-escaping:

return {
    v += [1]
}()
4 Likes

Thank you @taylorswift . Yes, it seems I didn't quite understand what an "escaping" closure means precisely in Swift, because the docs are a bit muddy on that (they didn't list this rule at all). Thanks.

2 Likes

it’s oral tradition

3 Likes

The analysis whether a closure is escaping is not very sophisticated currently, and doesn't look past the immediate context of where the closure literal appears. When you pass the closure as an immediate argument to a method call that takes a nonescaping parameter, or you immediately apply the closure literal, then we can determine it's nonescaping. In pretty much any other case, we assume it may escape.

10 Likes