Weird behavior in MainActor

When I mark a protocol with async functions with @MainActor and it's conformance does not specify it's functions are async, it is not executing on main thread. I don't know if this is a bug or not.

For example, given the following protocol and implementation:

@MainActor
protocol MyMainActorProtocol {
    func doStuff() async
}

struct MyMainActorStruct: MyMainActorProtocol {
    nonisolated init() {}
    func doStuff()  {
        print(">>> \(Thread.isMainThread)")
    }
}

When I execute this code:

  Task {
            let dependency: MyMainActorProtocol = MyMainActorStruct()
            print(">>> \(Thread.isMainThread)")
            await dependency.doStuff()
        }

both print statements run in a background thread.

But with the following adjustments of either


@MainActor
protocol MyMainActorProtocol {
    func doStuff()
}

struct MyMainActorStruct: MyMainActorProtocol {
    nonisolated init() {}
    func doStuff()  {
        print(">>> \(Thread.isMainThread)")
    }
}

or

@MainActor
protocol MyMainActorProtocol {
    func doStuff() async
}

struct MyMainActorStruct: MyMainActorProtocol {
    nonisolated init() {}
    func doStuff() async  {
        print(">>> \(Thread.isMainThread)")
    }
}

I get the correct result, where the body of the function inside the struct runs in the main thread.

Is this expected behavior? What is the explanation behind it.

4 Likes

Sadly I can confirm this is unexpected behavior and likely a bug in witness resolution.

Would you mind filing this as an issue: GitHub - apple/swift: The Swift Programming Language?

Thanks for the reply, I filed a bug there (MainActor isolation is broken by conforming to an async protocol ยท Issue #68487 ยท apple/swift ยท GitHub)

3 Likes

Thank you!