swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.19k stars 10.32k forks source link

Swift 6 treats function references as being referenced outside of isolated context regardless of context #74807

Open dfed opened 1 month ago

dfed commented 1 month ago

Description

With the Swift 6 compiler mode turned on, it is not possible to reference a @MainActor-bound instance method's function reference. Doing so results in a Call to main actor-isolated instance method '<functionName>' in a synchronous nonisolated context. error, even when the reference is made in a @MainActor-bound method.

Reproduction

@MainActor
final class MainActorTest {
    func function() {}

    func referenceFunction() {
        let functionReference: (MainActorTest) -> @MainActor () -> () = MainActorTest.function // Error: Call to main actor-isolated instance method 'function()' in a synchronous nonisolated context.
        _ = functionReference(self)
    }
}

Note that the line:

let functionReference: (MainActorTest) -> @MainActor () -> () = MainActorTest.function

can also read as:

let functionReference = MainActorTest.function

And result in the same error.

Expected behavior

The above code compiles without issue.

Environment

swift-driver version: 1.110 Apple Swift version 6.0 (swiftlang-6.0.0.4.52 clang-1600.0.21.1.3) Target: arm64-apple-macosx14.0

Additional information

No response

jamieQ commented 1 month ago

of possible relevance for triage & investigation: if you make function in the above example async, the error appears to go away

dfed commented 3 weeks ago

Solid insight @jamieQ!

Riffing on that, making the functionReference itself async gets things compiling. The following code compiles:

@MainActor
final class MainActorTest {
    func function() {}

    func referenceFunction() {
        let functionReference: (MainActorTest) -> @MainActor () async -> () = MainActorTest.function
        _ = functionReference(self)
    }
}
dfed commented 3 weeks ago

Worth noting that the workaround above only works if the function reference is assigned locally. If the function reference is a parameter to a method this workaround does not work.