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 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
// 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) {}
}
class ImplementsDictionaryLoader1: DictionaryLoader {
func loadDictionary(completionHandler: @escaping ([String: NSNumber]?) -> Void) {}
}
// expected-error@+2 {{type 'ImplementsDictionaryLoader2' does not conform to protocol 'DictionaryLoader'}}
// expected-note@+1 {{add stubs for conformance}}
class ImplementsDictionaryLoader2: DictionaryLoader {
func loadDictionary(completionHandler: @escaping ([String: Any]?) -> Void) {} // expected-note {{candidate has non-matching type '(@escaping ([String : Any]?) -> Void) -> ()'}}
}
// expected-error@+2 {{type 'ImplementsDictionaryLoader3' does not conform to protocol 'DictionaryLoader'}}
// expected-note@+1 {{add stubs for conformance}}
class ImplementsDictionaryLoader3: DictionaryLoader {
func loadDictionary(completionHandler: @escaping ([String: NSNumber?]?) -> Void) {} // expected-note {{candidate has non-matching type '(@escaping ([String : NSNumber?]?) -> Void) -> ()'}}
}
// expected-error@+2 {{type 'ImplementsDictionaryLoader4' does not conform to protocol 'DictionaryLoader'}}
// expected-note@+1 {{add stubs for conformance}}
class ImplementsDictionaryLoader4: DictionaryLoader {
func loadDictionary(completionHandler: @escaping ([String: Int]?) -> Void) {} // expected-note {{candidate has non-matching type '(@escaping ([String : Int]?) -> Void) -> ()'}}
}
class ImplementsFloatLoader: FloatLoader {
public func loadFloat(completionHandler: @escaping (Float) -> Void) {}
}
class ImplementsFloatLoader2: FloatLoader {
public func loadFloat(withCompletionHandler completionHandler: @escaping (Float) -> Void) {}
// expected-warning@-1 {{instance method 'loadFloat(withCompletionHandler:)' nearly matches optional requirement 'loadFloat(completionHandler:)' of protocol 'FloatLoader'}}
// expected-note@-2 {{rename to 'loadFloat(completionHandler:)' to satisfy this requirement}}
// expected-note@-3 {{move 'loadFloat(withCompletionHandler:)' to an extension to silence this warning}}
}
|