Hi,
Over the past few days, I have been looking into getting my apps work in Swift 6 language mode. This went mostly great! However, one of my apps was crashing in Swift 6 lanaguage mode, while it runs fine in Swift 5 language mode. After doing some digging, I found the culprit. In the AppKit SDK shipping with Xcode 16, NSDocument is marked as @MainActor. However, some of its functions can be called from another thread, such as the autosavesInPlace, which was causing problems in my case. This function is not marked as nonisolated, so it will incorrectly inherit the MainActor from NSDocument (FB13874012). In Swift 6 language mode, the code will correctly crash. In Swift 5 language mode, it won't, even though it is called from another thread. My question is, why is that? I would expect the code to crash in both cases.
@MainActor
class FileDocument: NSDocument {
...
// Incorrect
override class var autosavesInPlace: Bool {
true
}
// |
// |
// v
// Correct
override nonisolated class var autosavesInPlace: Bool {
true
}
}
Stack trace:
* thread #5, queue = 'com.apple.root.default-qos', stop reason = EXC_BREAKPOINT (code=1, subcode=0x1004f8a5c)
* frame #0: 0x00000001004f8a5c libdispatch.dylib`_dispatch_assert_queue_fail + 120
frame #1: 0x00000001004f89e4 libdispatch.dylib`dispatch_assert_queue + 196
frame #2: 0x0000000275bd293c libswift_Concurrency.dylib`swift_task_isCurrentExecutorImpl(swift::SerialExecutorRef) + 280
frame #3: 0x0000000275b78588 libswift_Concurrency.dylib`Swift._checkExpectedExecutor(_filenameStart: Builtin.RawPointer, _filenameLength: Builtin.Word, _filenameIsASCII: Builtin.Int1, _line: Builtin.Word, _executor: Builtin.Executor) -> () + 60
frame #4: 0x0000000108922788 MyApp.debug.dylib`@objc static FileDocument.autosavesInPlace.getter at <compiler-generated>:0
frame #5: 0x00000001a2f7d780 AppKit`-[NSDocument(NSDocument_Versioning) _preserveContentsIfNecessaryAfterWriting:toURL:forSaveOperation:version:error:] + 92
frame #6: 0x00000001a2fe6d1c AppKit`__85-[NSDocument(NSDocumentSaving) _saveToURL:ofType:forSaveOperation:completionHandler:]_block_invoke_2.398 + 116
frame #7: 0x00000001004f4bd4 libdispatch.dylib`_dispatch_call_block_and_release + 32
frame #8: 0x00000001004f6914 libdispatch.dylib`_dispatch_client_callout + 20
frame #9: 0x00000001004f9878 libdispatch.dylib`_dispatch_queue_override_invoke + 1076
frame #10: 0x000000010050e9f8 libdispatch.dylib`_dispatch_root_queue_drain + 404
frame #11: 0x000000010050f604 libdispatch.dylib`_dispatch_worker_thread2 + 188
frame #12: 0x00000001005910c4 libsystem_pthread.dylib`_pthread_wqthread + 228