Skip to content

Putting @concurrent before actor methods has no effect #85727

@rayx

Description

@rayx

Description

While doing experiments, I find putting @concurrent before actor methods has no effect. For example, in the following code I expected runInGlobalExecutor() should run in different isolation than that of test(), but I couldn't observe the behavior I expected.

actor A {
    @concurrent func runInGlobalExecutor() async {
    }

    func test() {
        Task {
            await runInGlobalExecutor()
        }
    }
}

There wasn't an obvious way to confirm my suspicion. One approach I tried at first was to print thread id in test() and runInGlobalExecutor() separately and expected they should be different. But this approach didn't produce meaningful reasult, because in Swift concurrency an available thread is used dynamically to run code in different isolation. For example, in the following example @concurrent works correctly but printing thread id in test() and runInGlobalExecutor2() may still gives the same result (I observed it).

@concurrent func runInGlobalExecutor2() async {
}

actor A {
    func test() {
        Task {
            await runInGlobalExecutor2()
        }
    }
}

Fortunately I thought of an approach to prove runInGlobalExecutor() and runInGlobalExecutor2() have different behaviors. See this example:

class NS {}

@concurrent func runInGlobalExecutor2(_ x: NS) async {
}

actor A {
    @concurrent func runInGlobalExecutor(_ x: NS) async {
    }

    func test() async {
        let x = NS()
        Task {
            await runInGlobalExecutor(x) // Not OK
            await runInGlobalExecutor2(x) // OK
        }
    }
}

Since x is task isolated, it's expected that runInGlobalExecutor2(x) should compile. In my understanding runInGlobalExecutor(x) should work the same and compiles too, but it doesn't.

Reproduction

class NS {}

@concurrent func runInGlobalExecutor2(_ x: NS) async {
}

actor A {
    @concurrent func runInGlobalExecutor(_ x: NS) async {
    }

    func test() async {
        let x = NS()
        Task {
            await runInGlobalExecutor(x) // Not OK
            await runInGlobalExecutor2(x) // OK
        }
    }
}

Expected behavior

runInGlobalExecutor() should work the same as runInGlobalExecutor2()

Environment

x86-64 swiftc nightly on godbolt

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugA deviation from expected or documented behavior. Also: expected but undesirable behavior.triage neededThis issue needs more specific labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions