A combination of defer-statement and closure may cause crash

Here is the code causing crash:

import Foundation

let KEY = "key"
func doHeavyWork() {
    print("Enter doHeavyWork")
    defer { print("Leave doHeavyWork") }

    defer {
        let callback: () -> () = {
            let existed = dict.keys.contains(KEY)
            print("In callback: \(existed)")
        }
        callback()
    }
    let dict: [String: Int] = [
        KEY: 0
    ]
    print("Do something")
}

doHeavyWork()

Thread.sleep(forTimeInterval: 3)

The version of swift is:

swift-driver version: 1.90.11.1 Apple Swift version 5.10 (swiftlang-5.10.0.13 clang-1500.3.9.4)
Target: arm64-apple-macosx14.0

If I move the declaration of dict to be earlier than the second defer-statement, it doesn't crash.

According to some try-and-error, I believe the crash is due to:

  1. the variable, dict, is destroyed first
  2. then the closure, callback, is called and it access the variable, dict

However, it's promised that the closure can access variables even if the scope is no longer existed.

I believe it is a syntax bug since the following codes got compile error
error: use of local variable 'dict' before its declaration

    defer {
            let existed = dict.keys.contains(KEY)
            print("In callback: \(existed)")
    }
    let dict: [String: Int] = [
        KEY: 0
    ]

and

    let callback: () -> () = {
        let existed = dict.keys.contains(KEY)
        print("In callback: \(existed)")
    }
    let dict: [String: Int] = [
        KEY: 0
    ]
    callback()

But it doesn't cause a compile error when using defer+closure.

2 Likes