Skip to content

Disable @Sendable inference on imported completion handler parameters. #60112

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/ClangImporter/ImportType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2850,7 +2850,7 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType(
importType(paramTy, importKind, paramAddDiag,
allowNSUIntegerAsIntInParam, Bridgeability::Full,
getImportTypeAttrs(param, /*isParam=*/true,
/*sendableByDefault=*/paramIsCompletionHandler),
/*sendableByDefault=*/false),
optionalityOfParam,
/*resugarNSErrorPointer=*/!paramIsError,
completionHandlerErrorParamIndex);
Expand Down
8 changes: 4 additions & 4 deletions test/Concurrency/objc_async_overload.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,22 @@ func asyncWithAwait() async {
// completion handler's implicit `@Sendable` isn't respected.
extension Delegate {
nonisolated func makeRequest(_ req: Request??, completionHandler: (() -> Void)? = nil) {
// expected-note@-1 {{parameter 'completionHandler' is implicitly non-sendable}}
// expected-DISABLED-note@-1 {{parameter 'completionHandler' is implicitly non-sendable}}
if let req = (req ?? nil) {
makeRequest1(req, completionHandler: completionHandler)
// expected-warning@-1 {{passing non-sendable parameter 'completionHandler' to function expecting a @Sendable closure}}
// expected-DISABLED-warning@-1 {{passing non-sendable parameter 'completionHandler' to function expecting a @Sendable closure}}
}
}
}

@MainActor class C {
func finish() { }
// expected-note@-1 {{calls to instance method 'finish()' from outside of its actor context are implicitly asynchronous}}
// expected-DISABLED-note@-1 {{calls to instance method 'finish()' from outside of its actor context are implicitly asynchronous}}

func handle(_ req: Request, with delegate: Delegate) {
delegate.makeRequest1(req) {
self.finish()
// expected-warning@-1 {{call to main actor-isolated instance method 'finish()' in a synchronous nonisolated context; this is an error in Swift 6}}
// expected-DISABLED-warning@-1 {{call to main actor-isolated instance method 'finish()' in a synchronous nonisolated context; this is an error in Swift 6}}
}
}
}
Expand Down
26 changes: 13 additions & 13 deletions test/IDE/print_clang_objc_async.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import _Concurrency
// CHECK-LABEL: class SlowServer : NSObject, ServiceProvider {

// CHECK: @available(*, renamed: "doSomethingSlow(_:)")
// CHECK-NEXT: func doSomethingSlow(_ operation: String, completionHandler handler: @escaping @Sendable (Int) -> Void)
// CHECK-NEXT: func doSomethingSlow(_ operation: String, completionHandler handler: @escaping (Int) -> Void)
// CHECK-NEXT: @discardableResult
// CHECK-NEXT: func doSomethingSlow(_ operation: String) async -> Int

// CHECK: @available(*, renamed: "doSomethingDangerous(_:)")
// CHECK-NEXT: func doSomethingDangerous(_ operation: String, completionHandler handler: (@Sendable (String?, Error?) -> Void)? = nil)
// CHECK-NEXT: func doSomethingDangerous(_ operation: String, completionHandler handler: ((String?, Error?) -> Void)? = nil)
// CHECK-NEXT: @discardableResult
// CHECK-NEXT: func doSomethingDangerous(_ operation: String) async throws -> String

Expand All @@ -25,37 +25,37 @@ import _Concurrency
// CHECK-NEXT: func doSomethingReckless(_ operation: String) async throws -> String

// CHECK: @available(*, renamed: "checkAvailability()")
// CHECK-NEXT: func checkAvailability(completionHandler: @escaping @Sendable (Bool) -> Void)
// CHECK-NEXT: func checkAvailability(completionHandler: @escaping (Bool) -> Void)
// CHECK-NEXT: @discardableResult
// CHECK-NEXT: func checkAvailability() async -> Bool

// CHECK: @available(*, renamed: "anotherExample()")
// CHECK-NEXT: func anotherExample(completionBlock block: @escaping @Sendable (String) -> Void)
// CHECK-NEXT: func anotherExample(completionBlock block: @escaping (String) -> Void)
// CHECK-NEXT: @discardableResult
// CHECK-NEXT: func anotherExample() async -> String

// CHECK: @available(*, renamed: "finalExample()")
// CHECK-NEXT: func finalExampleWithReply(to block: @escaping @Sendable (String) -> Void)
// CHECK-NEXT: func finalExampleWithReply(to block: @escaping (String) -> Void)
// CHECK-NEXT: @discardableResult
// CHECK-NEXT: func finalExample() async -> String

// CHECK: @available(*, renamed: "replyingOperation(_:)")
// CHECK-NEXT: func replyingOperation(_ operation: String, replyTo block: @escaping @Sendable (String) -> Void)
// CHECK-NEXT: func replyingOperation(_ operation: String, replyTo block: @escaping (String) -> Void)
// CHECK-NEXT: @discardableResult
// CHECK-NEXT: func replyingOperation(_ operation: String) async -> String

// CHECK: @available(*, renamed: "findAnswer()")
// CHECK-NEXT: func findAnswer(completionHandler handler: @escaping @Sendable (String?, Error?) -> Void)
// CHECK-NEXT: func findAnswer(completionHandler handler: @escaping (String?, Error?) -> Void)
// CHECK-NEXT: @discardableResult
// CHECK-NEXT: func findAnswer() async throws -> String

// CHECK: @available(*, renamed: "findAnswerFailingly()")
// CHECK-NEXT: func findAnswerFailingly(completionHandler handler: @escaping @Sendable (String?, Error?) -> Void) throws
// CHECK-NEXT: func findAnswerFailingly(completionHandler handler: @escaping (String?, Error?) -> Void) throws
// CHECK-NEXT: @discardableResult
// CHECK-NEXT: func findAnswerFailingly() async throws -> String

// CHECK: @available(*, renamed: "findQAndA()")
// CHECK-NEXT: func findQAndA(completionHandler handler: @escaping @Sendable (String?, String?, Error?) -> Void)
// CHECK-NEXT: func findQAndA(completionHandler handler: @escaping (String?, String?, Error?) -> Void)
// CHECK-NEXT: @discardableResult
// CHECK-NEXT: func findQAndA() async throws -> (String?, String)

Expand All @@ -65,7 +65,7 @@ import _Concurrency
// CHECK-NEXT: func findQuestionableAnswers() async throws -> (String, String?)

// CHECK: @available(*, renamed: "findAnswerableQuestions()")
// CHECK-NEXT: func findAnswerableQuestions(completionHandler handler: @escaping @Sendable (String?, String?, Error?) -> Void)
// CHECK-NEXT: func findAnswerableQuestions(completionHandler handler: @escaping NonsendableCompletionHandler)
// CHECK-NEXT: @discardableResult
// CHECK-NEXT: func findAnswerableQuestions() async throws -> (String, String?)

Expand All @@ -75,11 +75,11 @@ import _Concurrency
// CHECK-NEXT: func findUnanswerableQuestions() async throws -> (String, String?)

// CHECK: @available(*, renamed: "doSomethingFun(_:)")
// CHECK-NEXT: func doSomethingFun(_ operation: String, then completionHandler: @escaping @Sendable () -> Void)
// CHECK-NEXT: func doSomethingFun(_ operation: String, then completionHandler: @escaping () -> Void)
// CHECK-NEXT: func doSomethingFun(_ operation: String) async

// CHECK: @available(*, renamed: "doSomethingConflicted(_:)")
// CHECK-NEXT: func doSomethingConflicted(_ operation: String, completionHandler handler: @escaping @Sendable (Int) -> Void)
// CHECK-NEXT: func doSomethingConflicted(_ operation: String, completionHandler handler: @escaping (Int) -> Void)
// CHECK-NEXT: @discardableResult
// CHECK-NEXT: func doSomethingConflicted(_ operation: String) async -> Int
// CHECK-NEXT: @discardableResult
Expand All @@ -94,7 +94,7 @@ import _Concurrency
// CHECK-NEXT: func runOnMainThread() async -> String

// CHECK: @available(*, renamed: "asyncImportSame(_:)")
// CHECK-NEXT: func asyncImportSame(_ operation: String, completionHandler handler: @escaping @Sendable (Int) -> Void)
// CHECK-NEXT: func asyncImportSame(_ operation: String, completionHandler handler: @escaping (Int) -> Void)
// CHECK-NEXT: @discardableResult
// CHECK-NEXT: func asyncImportSame(_ operation: String) async -> Int
// CHECK-NEXT: func asyncImportSame(_ operation: String, replyTo handler: @escaping (Int) -> Void)
Expand Down
14 changes: 7 additions & 7 deletions test/IDE/print_clang_objc_effectful_properties.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,27 @@

// CHECK-LABEL: class EffProps : NSObject {
// CHECK: @available(*, renamed: "getter:doggo()")
// CHECK-NEXT: func getDogWithCompletion(_ completionHandler: @escaping @Sendable (NSObject) -> Void)
// CHECK-NEXT: func getDogWithCompletion(_ completionHandler: @escaping (NSObject) -> Void)
// CHECK: var doggo: NSObject { get async }

// CHECK: @available(*, renamed: "getter:catto()")
// CHECK-NEXT: func obtainCat(_ completionHandler: @escaping @Sendable (NSObject?, Error?) -> Void)
// CHECK-NEXT: func obtainCat(_ completionHandler: @escaping (NSObject?, Error?) -> Void)
// CHECK-NEXT: var catto: NSObject? { get async throws }

// CHECK: @available(*, renamed: "getter:available()")
// CHECK-NEXT: func checkAvailability(completionHandler: @escaping @Sendable (Bool) -> Void)
// CHECK-NEXT: func checkAvailability(completionHandler: @escaping (Bool) -> Void)
// CHECK-NEXT: var available: Bool { get async }
// CHECK-NEXT: @available(swift, obsoleted: 3, renamed: "checkAvailability(completionHandler:)")
// CHECK-NEXT: func checkAvailabilityWithCompletionHandler(_ completionHandler: @escaping @Sendable (Bool) -> Void)
// CHECK-NEXT: func checkAvailabilityWithCompletionHandler(_ completionHandler: @escaping (Bool) -> Void)

// CHECK: @available(*, renamed: "getter:touch()")
// CHECK-NEXT: func returnNothing(completion completionHandler: @escaping @Sendable () -> Void)
// CHECK-NEXT: func returnNothing(completion completionHandler: @escaping () -> Void)
// CHECK-NEXT: var touch: Void { get async }
// CHECK-NEXT: @available(swift, obsoleted: 3, renamed: "returnNothing(completion:)")
// CHECK-NEXT: func returnNothingWithCompletion(_ completionHandler: @escaping @Sendable () -> Void)
// CHECK-NEXT: func returnNothingWithCompletion(_ completionHandler: @escaping () -> Void)

// CHECK: @available(*, renamed: "getter:fromNullableHandler()")
// CHECK-NEXT: func nullableHandler(_ completion: (@Sendable (String) -> Void)? = nil)
// CHECK-NEXT: func nullableHandler(_ completion: ((String) -> Void)? = nil)
// CHECK-NEXT: var fromNullableHandler: String { get async }

// CHECK: @available(*, renamed: "getter:mainDogProp()")
Expand Down
2 changes: 1 addition & 1 deletion test/IDE/print_objc_concurrency_interface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import _Concurrency

// rdar://76685011: Make sure we don't print implicit @available in generated interfaces.
// CHECK-NOT: @available
// CHECK: func doSomethingSlow(_ operation: String, completionHandler handler: @escaping @Sendable (Int) -> Void)
// CHECK: func doSomethingSlow(_ operation: String, completionHandler handler: @escaping (Int) -> Void)
// CHECK: func doSomethingSlow(_ operation: String) async -> Int

// NEGATIVE-NOT: @Sendable{{.+}}class
Expand Down
6 changes: 3 additions & 3 deletions test/IDE/print_omit_needless_words.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@
// CHECK-FOUNDATION-NEXT: case binary

// Note: Make sure initialisms work in various places
// CHECK-FOUNDATION: open(_: URL!, completionHandler: (@Sendable (Bool) -> Void)!)
// CHECK-FOUNDATION: open(_: NSGUID!, completionHandler: (@Sendable (Bool) -> Void)!)
// CHECK-FOUNDATION: open(_: URL!, completionHandler: ((Bool) -> Void)!)
// CHECK-FOUNDATION: open(_: NSGUID!, completionHandler: ((Bool) -> Void)!)

// Note: property name stripping property type.
// CHECK-FOUNDATION: var uppercased: String
Expand Down Expand Up @@ -137,7 +137,7 @@
// CHECK-FOUNDATION: func enumerateObjects(options: NSEnumerationOptions = [], using: ((Any?, Int, UnsafeMutablePointer<ObjCBool>?) -> Void)!)

// Note: WithBlock -> body, nullable closures default to nil.
// CHECK-FOUNDATION: func enumerateObjectsRandomly(block: (@Sendable (Any?, Int, UnsafeMutablePointer<ObjCBool>?) -> Void)? = nil)
// CHECK-FOUNDATION: func enumerateObjectsRandomly(block: ((Any?, Int, UnsafeMutablePointer<ObjCBool>?) -> Void)? = nil)

// Note: id<Proto> treated as "Proto".
// CHECK-FOUNDATION: func doSomething(with: NSCopying)
Expand Down
2 changes: 1 addition & 1 deletion test/SourceKit/DocSupport/doc_objc_concurrency.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@
// Especially if the @available was implicitly added to an imported Clang decl
// (rdar://76685011).

// OBJC-DOC: key.fully_annotated_decl: "<decl.function.method.instance><syntaxtype.keyword>func</syntaxtype.keyword> <decl.name>method</decl.name>(<decl.var.parameter><decl.var.parameter.argument_label>withHandler</decl.var.parameter.argument_label> <decl.var.parameter.name>operation</decl.var.parameter.name>: <decl.var.parameter.type><ref.struct usr=\"s:SS\">String</ref.struct>!</decl.var.parameter.type></decl.var.parameter>, <decl.var.parameter><decl.var.parameter.argument_label>completionHandler</decl.var.parameter.argument_label> <decl.var.parameter.name>handler</decl.var.parameter.name>: <decl.var.parameter.type>(<syntaxtype.attribute.builtin><syntaxtype.attribute.name>@Sendable</syntaxtype.attribute.name></syntaxtype.attribute.builtin> (<decl.var.parameter><decl.var.parameter.type><ref.struct usr=\"s:Si\">Int</ref.struct></decl.var.parameter.type></decl.var.parameter>) -&gt; <decl.function.returntype><ref.typealias usr=\"s:s4Voida\">Void</ref.typealias></decl.function.returntype>)!</decl.var.parameter.type></decl.var.parameter>)</decl.function.method.instance>"
// OBJC-DOC: key.fully_annotated_decl: "<decl.function.method.instance><syntaxtype.keyword>func</syntaxtype.keyword> <decl.name>method</decl.name>(<decl.var.parameter><decl.var.parameter.argument_label>withHandler</decl.var.parameter.argument_label> <decl.var.parameter.name>operation</decl.var.parameter.name>: <decl.var.parameter.type><ref.struct usr=\"s:SS\">String</ref.struct>!</decl.var.parameter.type></decl.var.parameter>, <decl.var.parameter><decl.var.parameter.argument_label>completionHandler</decl.var.parameter.argument_label> <decl.var.parameter.name>handler</decl.var.parameter.name>: <decl.var.parameter.type>((<decl.var.parameter><decl.var.parameter.type><ref.struct usr=\"s:Si\">Int</ref.struct></decl.var.parameter.type></decl.var.parameter>) -&gt; <decl.function.returntype><ref.typealias usr=\"s:s4Voida\">Void</ref.typealias></decl.function.returntype>)!</decl.var.parameter.type></decl.var.parameter>)</decl.function.method.instance>"

// OBJC-DOC: key.fully_annotated_decl: "<decl.function.method.instance><syntaxtype.keyword>func</syntaxtype.keyword> <decl.name>method</decl.name>(<decl.var.parameter><decl.var.parameter.argument_label>withHandler</decl.var.parameter.argument_label> <decl.var.parameter.name>operation</decl.var.parameter.name>: <decl.var.parameter.type><ref.struct usr=\"s:SS\">String</ref.struct>!</decl.var.parameter.type></decl.var.parameter>) <syntaxtype.keyword>async</syntaxtype.keyword> -&gt; <decl.function.returntype><ref.struct usr=\"s:Si\">Int</ref.struct></decl.function.returntype></decl.function.method.instance>"
2 changes: 1 addition & 1 deletion test/SourceKit/InterfaceGen/gen_objc_concurrency.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
// But don't print @available if it was implicitly added to an imported Clang decl (rdar://76685011).
// OBJC-GEN-INTERFACE-LABEL: class ClassWithHandlerMethod {
// OBJC-GEN-INTERFACE-NOT: @available
// OBJC-GEN-INTERFACE: func method(withHandler operation: String!, completionHandler handler: (@Sendable (Int) -> Void)!)
// OBJC-GEN-INTERFACE: func method(withHandler operation: String!, completionHandler handler: ((Int) -> Void)!)
// OBJC-GEN-INTERFACE: func method(withHandler operation: String!) async -> Int

// OBJC-GEN-INTERFACE: @MainActor open func mainActorMethod()