Skip to content

Swift compiler does not chose the correct sync/async overload #74459

Open
@groue

Description

@groue

Description

Hello,

SE-0296 contains those paragraphs in its Overloading and overload resolution section:

[...] we propose an overload-resolution rule to select the appropriate function based on the context of the call. Given a call, overload resolution prefers non-async functions within a synchronous context (because such contexts cannot contain a call to an async function). Furthermore, overload resolution prefers async functions within an asynchronous context (because such contexts should avoid stepping out of the asynchronous model into blocking APIs).

This rule is crucially important, because when a library ships an async overload of a sync function, it may well be with the intent of avoiding the grave problems that happen when the cooperative thread pool is blocked by the sync overload. The language must respect the intended design of SE-0296, and the care put by API authors into helping their users write correct programs. See this very interesting forum thread for a longer discussion.

The reason for this issue is that the overload resolution is not correctly implemented, and the compiler mistakenly allows sync calls in asynchronous contexts.

Reproduction

struct Runner {
    func run() { }
    func run() async { }
}

func testSync() {
    // 👍 sync overload chosen
    Runner().run()
}

func testAsync() async {
    // 👍 compiler error: expression is 'async' but is not marked with 'await'
    // Runner().run()
    await Runner().run()
}

func testTask() {
    Task {
        // ❌ sync overload wrongly chosen. No error and no warning.
        Runner().run()
    }
}

Expected behavior

The testTask function does not compile, and the compiler complains with "expression is 'async' but is not marked with 'await'"

Environment

Problem exists in Swift 5.10, and still exists in Xcode 16 beta:

swift-driver version: 1.90.11.1 Apple Swift version 5.10 (swiftlang-5.10.0.13 clang-1500.3.9.4)
Target: arm64-apple-macosx14.0

swift-driver version: 1.109.2 Apple Swift version 6.0 (swiftlang-6.0.0.3.300 clang-1600.0.20.10)
Target: arm64-apple-macosx14.0

Additional information

@_disfavoredOverload does not help. I don't know any workaround that would have the compiler correctly identify the incorrect use of the sync overload in an async context.

Metadata

Metadata

Assignees

No one assigned

    Labels

    concurrencyFeature: umbrella label for concurrency language featuresswift evolution proposal neededFlag → feature: A feature that warrants a Swift evolution proposal

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions