File: objc_async_conformance.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (118 lines) | stat: -rw-r--r-- 4,409 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -I %S/Inputs/custom-modules -disable-availability-checking  %s -verify

// REQUIRES: objc_interop
// REQUIRES: concurrency
import Foundation
import ObjCConcurrency

// Conform via async method
class C1: ConcurrentProtocol {
  func askUser(toSolvePuzzle puzzle: String) async throws -> String { "" }

  func askUser(toJumpThroughHoop hoop: String) async -> String { "hello" }
}

// try to conform to an objc protocol that has both a sync and async requirement
// that has the same name, and both requirements are optional.
class C2 : NSObject, OptionalObserver {}
extension C2 {
  func hello(_ session: NSObject) -> Bool { true }
}

// a version of C2 that requires both sync and async methods (differing only by
// completion handler) in ObjC.
class C3 : NSObject, RequiredObserver {}
extension C3 {
  func hello() -> Bool { true }
  func hello() async -> Bool { true }
}

// the only way to conform to 'RequiredObserver' in Swift is to not use 'async'
class C4 : NSObject, RequiredObserver {}
extension C4 {
  func hello() -> Bool { true }
  func hello(_ completion : @escaping (Bool) -> Void) -> Void { completion(true) }
}

protocol Club : ObjCClub {}

class ConformsToSync : NSObject, Club {
  func activate( completion: @escaping ( Error? ) -> Void ) { }
}

///////
// selector conflicts

// attempting to satisfy the ObjC async requirement in two ways simultaneously
// is problematic due to a clash in selector names on this ObjC-compatible type
class SelectorConflict : NSObject, RequiredObserverOnlyCompletion {
  func hello() async -> Bool { true } // expected-note {{method 'hello()' declared here}}

  // expected-error@+1 {{method 'hello' with Objective-C selector 'hello:' conflicts with method 'hello()' with the same Objective-C selector}}
  func hello(_ completion : @escaping (Bool) -> Void) -> Void { completion(true) }
}

// making either one of the two methods nonobjc fixes it:
class SelectorOK1 : NSObject, RequiredObserverOnlyCompletion {
  @nonobjc func hello() async -> Bool { true }
  func hello(_ completion : @escaping (Bool) -> Void) -> Void { completion(true) }
}

class SelectorOK2 : NSObject, RequiredObserverOnlyCompletion {
  func hello() async -> Bool { true }
  @nonobjc func hello(_ completion : @escaping (Bool) -> Void) -> Void { completion(true) }
}

// can declare an @objc protocol with both selectors...
@objc protocol SelectorBothAsyncProto {
  @objc(helloWithCompletion:)
  func hello() async -> Bool

  @available(*, renamed: "hello()")
  @objc(helloWithCompletion:)
  func hello(completion: @escaping (Bool) -> Void)
}

// and conform by implementing either one...
class SelectorBothAsync1: NSObject, SelectorBothAsyncProto {
  func hello() async -> Bool { true }
}
class SelectorBothAsync2: NSObject, SelectorBothAsyncProto {
  func hello(completion: @escaping (Bool) -> Void) { completion(true) }
}

// but not without declaring the async alternative.
@objc protocol BadSelectorBothAsyncProto {
  @objc(helloWithCompletion:)
  func hello() async -> Bool // expected-note {{method 'hello()' declared here}}

  @objc(helloWithCompletion:)
  func hello(completion: @escaping (Bool) -> Void) // expected-warning {{method 'hello(completion:)' with Objective-C selector 'helloWithCompletion:' conflicts with method 'hello()' with the same Objective-C selector; this is an error in the Swift 6 language mode}}
}

// additional coverage for situation like C4, where the method names don't
// clash on the ObjC side, but they do on Swift side, BUT their ObjC selectors
// differ, so it's OK.
class Rock : NSObject, Rollable {
  func roll(completionHandler: @escaping () -> Void) { completionHandler() }
  func roll() { roll(completionHandler: {}) }
}

// additional coverage for a situation where only an argument label differs, excluding the completion handler.
final class Moon : LabellyProtocol {
  func myMethod(_ value: Int, foo: Int) {}
  func myMethod(_ value: Int, newFoo foo: Int, completion: @escaping (Error?) -> Void) {}
}

// Crash involving actor isolation checking.
class C5 {
  @MainActor @objc var allOperations: [String] = []
}

class C6: C5, ServiceProvider {
  @MainActor func allOperations() async -> [String] { [] }
}

extension ImplementsLoadable: @retroactive Loadable {
  public func loadStuff(withOtherIdentifier otherIdentifier: Int, reply: @escaping () -> Void) {}
}