mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
When overriding a method or witnessing a requirement that comes from Objective-C and has no actor annotation, allow the overriding method or witness to specify a global actor (any global actor, but probably almost always the main actor) without triggering the actor-isolation errors one would normally get if both entities were written in Swift. This opens up a hole in actor-isolation checking, because nothing guarantees that code won't call these methods through the superclass or protocol from the wrong actor. On the other hand, it's a very convenient hole, because it allows us to state when we "know" that an Objective-C framework will only call a method on (e.g.) the main actor, and make that known to Swift to be enforced everywhere else in Swift. If this is a good idea, it's plausible to introduce runtime assertions of some form to tell the user when such an annotation is wrong.
74 lines
2.3 KiB
Swift
74 lines
2.3 KiB
Swift
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -I %S/Inputs/custom-modules -enable-experimental-concurrency %s -verify -verify-ignore-unknown
|
|
|
|
// REQUIRES: objc_interop
|
|
// REQUIRES: concurrency
|
|
import Foundation
|
|
import ObjectiveC
|
|
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" }
|
|
}
|
|
|
|
// Conform via completion-handler method
|
|
class C2: ConcurrentProtocol {
|
|
func askUser(toSolvePuzzle puzzle: String, completionHandler: ((String?, Error?) -> Void)?) {
|
|
completionHandler?("hello", nil)
|
|
}
|
|
|
|
func askUser(toJumpThroughHoop hoop: String, completionHandler: ((String) -> Void)?) {
|
|
completionHandler?("hello")
|
|
}
|
|
}
|
|
|
|
// Conform via both; this is an error
|
|
class C3: ConcurrentProtocol {
|
|
// expected-note@+1{{method 'askUser(toSolvePuzzle:)' declared here}}
|
|
func askUser(toSolvePuzzle puzzle: String) async throws -> String { "" }
|
|
|
|
// expected-error@+1{{'askUser(toSolvePuzzle:completionHandler:)' with Objective-C selector 'askUserToSolvePuzzle:completionHandler:' conflicts with method 'askUser(toSolvePuzzle:)' with the same Objective-C selector}}
|
|
func askUser(toSolvePuzzle puzzle: String, completionHandler: ((String?, Error?) -> Void)?) {
|
|
completionHandler?("hello", nil)
|
|
}
|
|
}
|
|
|
|
// Conform but forget to supply either. Also an error.
|
|
// FIXME: Suppress one of the notes?
|
|
class C4: ConcurrentProtocol { // expected-error{{type 'C4' does not conform to protocol 'ConcurrentProtocol'}}
|
|
}
|
|
|
|
class C5 {
|
|
}
|
|
|
|
extension C5: ConcurrentProtocol {
|
|
func askUser(toSolvePuzzle puzzle: String, completionHandler: ((String?, Error?) -> Void)?) {
|
|
completionHandler?("hello", nil)
|
|
}
|
|
|
|
func askUser(toJumpThroughHoop hoop: String, completionHandler: ((String) -> Void)?) {
|
|
completionHandler?("hello")
|
|
}
|
|
}
|
|
|
|
// Global actors.
|
|
actor class SomeActor { }
|
|
|
|
@globalActor
|
|
struct SomeGlobalActor {
|
|
static let shared = SomeActor()
|
|
}
|
|
|
|
class C6: ConcurrentProtocol {
|
|
@SomeGlobalActor
|
|
func askUser(toSolvePuzzle puzzle: String) async throws -> String { "" }
|
|
|
|
func askUser(toJumpThroughHoop hoop: String) async -> String { "hello" }
|
|
}
|
|
|
|
class C7: NSObject {
|
|
@SomeGlobalActor override var description: String { "on an actor" }
|
|
}
|