Open ahoppen opened 3 months ago
Compiling the following in Swift 6 mode produces an error. As far as I can tell, we don’t actually send anything since nothing is asynchronous.
class DocumentManager { func fileHasInMemoryModifications() -> Bool { true } } class CheckedIndex { func fileHasInMemoryModifications() -> Bool { true } func unitTests() {} } actor Foo { let documentManager: DocumentManager = DocumentManager() private func test(index: CheckedIndex?) async { _ = [1, 2].filter { _ in if let index { return index.fileHasInMemoryModifications() } else { return documentManager.fileHasInMemoryModifications() } } index?.unitTests() } }
Error:
/tmp/a.swift:15:14: error: sending 'index' risks causing data races 13 | private func tests2(index: CheckedIndex?) async { 14 | _ = [1, 2].filter { _ in 15 | if let index { | |- error: sending 'index' risks causing data races | `- note: 'self'-isolated 'index' is captured by a actor-isolated closure. actor-isolated uses in closure may race against later nonisolated uses 16 | return index.fileHasInMemoryModifications() 17 | } else { : 20 | } 21 | 22 | index?.unitTests() | `- note: access can happen concurrently 23 | } 24 | }
A workaround appears to be to put the access to documentManager inside a local function
func documentManagerHasInMemoryModifications() -> Bool { return documentManager.fileHasInMemoryModifications() } _ = [1, 2].filter { _ in if let index { return index.fileHasInMemoryModifications() } else { return documentManagerHasInMemoryModifications() } } index?.unitTests()
rdar://130112205
Looking at this a little bit. One thing that is interesting is that in the erroring example, we consider the closure to be actor isolated and the one that doesn't error is not considered actor isolated.
Compiling the following in Swift 6 mode produces an error. As far as I can tell, we don’t actually send anything since nothing is asynchronous.
Error:
A workaround appears to be to put the access to documentManager inside a local function
rdar://130112205