Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-15150] Async overloading in protocol implementation fails #57476

Closed
swift-ci opened this issue Sep 3, 2021 · 8 comments
Closed

[SR-15150] Async overloading in protocol implementation fails #57476

swift-ci opened this issue Sep 3, 2021 · 8 comments

Comments

@swift-ci
Copy link
Collaborator

@swift-ci swift-ci commented Sep 3, 2021

Previous ID SR-15150
Radar rdar://FB9595388
Original Reporter Nekitosss (JIRA User)
Type Bug
Status Resolved
Resolution Done

Attachment: Download

Environment

swift-driver version: 1.26.9 Apple Swift version 5.5 (swiftlang-1300.0.29.102 clang-1300.0.28.1)

Target: x86_64-apple-macosx12.0

MacOS: 12.0 Beta (21A5506j)

Additional Detail from JIRA
Votes 4
Component/s Compiler
Labels Bug
Assignee None
Priority Medium

md5: 8395967ad9ff21d97cd2235d2936f952

Issue Description:

Amendment apple/swift-evolution#1392 is incomplete.

Compilation fails, when class with both async and async method versions trying to satisfy protocol requirement with both sync and async methods or just async method implementation.

protocol TestProtocol {
    func read() // Compilation also fails if TestProtocol contains only async version
    func read() async
}

// Note: everything compiles and resolves correctly in call side when TestClass does not implement TestProtocol 
class TestClass: TestProtocol {
    func read() {}
    func read() async {}
}

Throws several issues:

  • error: type 'TestClass' does not conform to protocol 'TestProtocol'

  • note: multiple matching functions named 'read()' with type '() async -> ()'

@typesanitizer
Copy link

@typesanitizer typesanitizer commented Sep 3, 2021

@swift-ci create

@groue
Copy link

@groue groue commented Oct 11, 2021

Hello, I'm the main contributor to the GRDB.swift library, and I wrote the SE-0296 amendment that was later accepted, precisely in order to provide a great async experience to GRDB users, and all authors of libraries that provide both sync and async apis.

I'm concerned the spirit of the amendment was not fully implemented.

A workaround is to add a @_disfavoredOverload attribute on the sync overload. Yet this attribute is underscored, and thus not supposed to be used.

Please let us know if further information is required.

@groue
Copy link

@groue groue commented Oct 12, 2021

I have new information. The code below has the compiler chose the wrong sync overloads in async contexts (as shown by comments). It only happens for generic functions (non-generic functions are correctly handled). Please compare the non-generic function f(), correctly handled, to the generic function g(), which is not:

protocol P {
    func f()
    func g<T>(_ type: T.Type)
}

extension P {
    func f() async { print("P.f (async)") }
    func g<T>(_ type: T.Type) async { print("P.g (async)") }
}

struct S: P {
    func f() { print("S.f") }
    func g<T>(_ type: T.Type) { print("S.g") }
}

// ===

func sync_generic_f<T: P>(_ t: T) {
    t.f()
}

func async_generic_f<T: P>(_ t: T) async {
    await t.f()
}

func sync_f(_ s: S) {
    s.f()
}

func async_f(_ s: S) async {
    await s.f()
}

// ===

func sync_generic_g<T: P>(_ t: T) {
    t.g(Int.self)
}

func async_generic_g<T: P>(_ t: T) async {
    // SE-0296 failure, because compiler warning:
    // No 'async' operations occur within 'await' expression
    await t.g(Int.self)
}

func sync_g(_ s: S) {
    s.g(Int.self)
}

func async_g(_ s: S) async {
    // SE-0296 failure, because compiler warning:
    // No 'async' operations occur within 'await' expression
    await s.g(Int.self)
}

@main
struct App {
    /// Prints:
    ///
    ///     S.f         // OK
    ///     S.f         // OK
    ///     S.g         // OK
    ///     S.g         // OK
    ///     P.f (async) // OK
    ///     P.f (async) // OK
    ///     S.g         // WRONG
    ///     S.g         // WRONG
    ///     P.f (async) // OK
    ///     S.g         // WRONG
    static func main() async {
        func sync() {
            sync_f(S())
            sync_generic_f(S())
            sync_g(S())
            sync_generic_g(S())
        }
        
        sync()
        await async_f(S())
        await async_generic_f(S())
        await async_g(S())
        await async_generic_g(S())
        
        await S().f()
        // SE-0296 failure, because compiler warning:
        // No 'async' operations occur within 'await' expression
        await S().g(Int.self)
    }
}

@groue
Copy link

@groue groue commented Oct 12, 2021

@DougGregor, do you think you have enough information in order to spot where is the wrong compiler behavior, or do you need more information?

@DougGregor
Copy link
Member

@DougGregor DougGregor commented Nov 15, 2021

@groue
Copy link

@groue groue commented Dec 14, 2021

This issue is flagged as RESOLVED, but the problem is still present in Xcode Version 13.2 (13C90):

The compiler keeps on warning with "No 'async' operations occur within 'await' expression" unless the sync version is flagged @_disfavoredOverload.

@DougGregor
Copy link
Member

@DougGregor DougGregor commented Dec 14, 2021

It didn't make it into Swift 5.5.2; it'll appear in Swift 5.6, in the Spring.

@groue
Copy link

@groue groue commented Dec 14, 2021

Thank you Doug 🙂

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants