Skip to content

Commit 26eaf75

Browse files
authored
Merge pull request #80004 from xedin/se-0463-enablement
[Frontend] SE-0463: Enable `SendableCompletionHandlers` feature by default
2 parents 418bd22 + 4ce370d commit 26eaf75

8 files changed

+69
-45
lines changed

include/swift/Basic/Features.def

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ LANGUAGE_FEATURE(BuiltinEmplaceTypedThrows, 0, "Builtin.emplace typed throws")
253253
SUPPRESSIBLE_LANGUAGE_FEATURE(MemorySafetyAttributes, 458, "@unsafe attribute")
254254
LANGUAGE_FEATURE(ValueGenerics, 452, "Value generics feature (integer generics)")
255255
LANGUAGE_FEATURE(RawIdentifiers, 451, "Raw identifiers")
256+
LANGUAGE_FEATURE(SendableCompletionHandlers, 463, "Objective-C completion handler parameters are imported as @Sendable")
256257

257258
// Swift 6
258259
UPCOMING_FEATURE(ConciseMagicFile, 274, 6)
@@ -343,10 +344,6 @@ EXPERIMENTAL_FEATURE(ForwardModeDifferentiation, false)
343344
/// conformances.
344345
EXPERIMENTAL_FEATURE(AdditiveArithmeticDerivedConformances, false)
345346

346-
/// Whether Objective-C completion handler parameters are imported as
347-
/// @Sendable.
348-
EXPERIMENTAL_FEATURE(SendableCompletionHandlers, false)
349-
350347
/// Enables opaque type erasure without also enabling implict dynamic
351348
EXPERIMENTAL_FEATURE(OpaqueTypeErasure, true)
352349

lib/Sema/TypeCheckDeclObjC.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3889,12 +3889,27 @@ class ObjCImplementationChecker {
38893889
diagnoseVTableUse(cand);
38903890
return;
38913891

3892-
case MatchOutcome::WrongSendability:
3892+
case MatchOutcome::WrongSendability: {
3893+
auto concurrencyLevel = req->getASTContext().LangOpts.StrictConcurrencyLevel;
3894+
3895+
DiagnosticBehavior behavior;
3896+
switch (concurrencyLevel) {
3897+
case StrictConcurrency::Complete:
3898+
behavior = DiagnosticBehavior::Warning;
3899+
break;
3900+
3901+
case StrictConcurrency::Targeted:
3902+
case StrictConcurrency::Minimal:
3903+
behavior = DiagnosticBehavior::Ignore;
3904+
break;
3905+
}
3906+
38933907
diagnose(cand, diag::objc_implementation_sendability_mismatch, cand,
38943908
getMemberType(cand), getMemberType(req))
3895-
.limitBehaviorWithPreconcurrency(DiagnosticBehavior::Warning,
3909+
.limitBehaviorWithPreconcurrency(behavior,
38963910
/*preconcurrency*/ true);
38973911
return;
3912+
}
38983913

38993914
case MatchOutcome::WrongImplicitObjCName:
39003915
case MatchOutcome::WrongExplicitObjCName: {

test/Concurrency/sendable_objc_attr_in_type_context_swift5.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,7 @@ class TestConformanceWithoutStripping : InnerSendableTypes {
172172
@objc public required init(callback: @escaping () -> Void) {}
173173
// expected-error@-1 {{initializer 'init(callback:)' should not be 'required' to match initializer declared by the header}}
174174

175-
@objc func compute(completionHandler: @escaping () -> Void) {}
176-
// expected-warning@-1 {{sendability of function types in instance method 'compute(completionHandler:)' of type '(@escaping () -> Void) -> ()' does not match type '(@escaping @Sendable () -> Void) -> Void' declared by the header}}
175+
@objc func compute(completionHandler: @escaping () -> Void) {} // Ok (no warnings with minimal checking)
177176
}
178177

179178
// Methods deliberately has no `@Sendable` to make sure that

test/Concurrency/sendable_objc_attr_in_type_context_swift5_strict.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ void doSomethingConcurrently(__attribute__((noescape)) void SWIFT_SENDABLE (^blo
6565
-(void) testWithCallback:(NSString *)name handler:(MAIN_ACTOR void (^)(NSDictionary<NSString *, SWIFT_SENDABLE id> *, NSError * _Nullable))handler;
6666
@end
6767

68+
@interface SwiftImpl : NSObject
69+
-(id)initWithCallback: (void (^ SWIFT_SENDABLE)(void)) callback;
70+
-(void)computeWithCompletionHandler: (void (^)(void)) handler;
71+
@end
72+
6873
#pragma clang assume_nonnull end
6974

7075
//--- main.swift
@@ -153,3 +158,11 @@ class TestConformanceWithoutStripping : InnerSendableTypes {
153158
func test(withCallback name: String, handler: @escaping @MainActor ([String : any Sendable], (any Error)?) -> Void) { // Ok
154159
}
155160
}
161+
162+
@objc @implementation extension SwiftImpl {
163+
@objc public required init(callback: @escaping () -> Void) {}
164+
// expected-error@-1 {{initializer 'init(callback:)' should not be 'required' to match initializer declared by the header}}
165+
166+
@objc func compute(completionHandler: @escaping () -> Void) {}
167+
// expected-warning@-1 {{sendability of function types in instance method 'compute(completionHandler:)' of type '(@escaping () -> Void) -> ()' does not match type '(@escaping @Sendable () -> Void) -> Void' declared by the header}}
168+
}

test/SILGen/objc_async.swift

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ func testSlowServer(slowServer: SlowServer) async throws {
1010
// CHECK: [[RESUME_BUF:%.*]] = alloc_stack $Int
1111
// CHECK: [[STRINGINIT:%.*]] = function_ref @$sSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF :
1212
// CHECK: [[ARG:%.*]] = apply [[STRINGINIT]]
13-
// CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (NSString, @convention(block) (Int) -> (), SlowServer) -> ()
13+
// CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (NSString, @convention(block) @Sendable (Int) -> (), SlowServer) -> ()
1414
// CHECK: [[CONT:%.*]] = get_async_continuation_addr Int, [[RESUME_BUF]]
1515
// CHECK: [[WRAPPED:%.*]] = struct $UnsafeContinuation<Int, Never> ([[CONT]] : $Builtin.RawUnsafeContinuation)
1616
// CHECK: [[BLOCK_STORAGE:%.*]] = alloc_stack $@block_storage Any
1717
// CHECK: [[CONT_SLOT:%.*]] = project_block_storage [[BLOCK_STORAGE]]
1818
// CHECK: [[CONT_SLOT_ADDR:%.*]] = init_existential_addr [[CONT_SLOT]]
1919
// CHECK: store [[WRAPPED]] to [trivial] [[CONT_SLOT_ADDR]]
20-
// CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[INT_COMPLETION_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, Int) -> ()
20+
// CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[INT_COMPLETION_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, Int) -> ()
2121
// CHECK: [[BLOCK:%.*]] = init_block_storage_header [[BLOCK_STORAGE]] {{.*}}, invoke [[BLOCK_IMPL]]
2222
// CHECK: apply [[METHOD]]([[ARG]], [[BLOCK]], %0)
2323
// CHECK: [[COPY:%.*]] = copy_value [[ARG]]
@@ -33,14 +33,14 @@ func testSlowServer(slowServer: SlowServer) async throws {
3333
let _: Int = await slowServer.doSomethingSlowNullably("mail")
3434

3535
// CHECK: [[RESUME_BUF:%.*]] = alloc_stack $String
36-
// CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (@convention(block) (Optional<NSString>, Optional<NSError>) -> (), SlowServer) -> ()
36+
// CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (@convention(block) @Sendable (Optional<NSString>, Optional<NSError>) -> (), SlowServer) -> ()
3737
// CHECK: [[CONT:%.*]] = get_async_continuation_addr [throws] String, [[RESUME_BUF]]
3838
// CHECK: [[WRAPPED:%.*]] = struct $UnsafeContinuation<String, any Error> ([[CONT]] : $Builtin.RawUnsafeContinuation)
3939
// CHECK: [[BLOCK_STORAGE:%.*]] = alloc_stack $@block_storage Any
4040
// CHECK: [[CONT_SLOT:%.*]] = project_block_storage [[BLOCK_STORAGE]]
4141
// CHECK: [[CONT_SLOT_ADDR:%.*]] = init_existential_addr [[CONT_SLOT]]
4242
// CHECK: store [[WRAPPED]] to [trivial] [[CONT_SLOT_ADDR]]
43-
// CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[STRING_COMPLETION_THROW_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, Optional<NSString>, Optional<NSError>) -> ()
43+
// CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[STRING_COMPLETION_THROW_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, Optional<NSString>, Optional<NSError>) -> ()
4444
// CHECK: [[BLOCK:%.*]] = init_block_storage_header [[BLOCK_STORAGE]] {{.*}}, invoke [[BLOCK_IMPL]]
4545
// CHECK: apply [[METHOD]]([[BLOCK]], %0)
4646
// CHECK: await_async_continuation [[CONT]] {{.*}}, resume [[RESUME:bb[0-9]+]], error [[ERROR:bb[0-9]+]]
@@ -50,18 +50,18 @@ func testSlowServer(slowServer: SlowServer) async throws {
5050
// CHECK: dealloc_stack [[RESUME_BUF]]
5151
let _: String = try await slowServer.findAnswer()
5252

53-
// CHECK: objc_method {{.*}} $@convention(objc_method) (NSString, @convention(block) () -> (), SlowServer) -> ()
54-
// CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[VOID_COMPLETION_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any) -> ()
53+
// CHECK: objc_method {{.*}} $@convention(objc_method) (NSString, @convention(block) @Sendable () -> (), SlowServer) -> ()
54+
// CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[VOID_COMPLETION_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any) -> ()
5555
await slowServer.serverRestart("somewhere")
5656

57-
// CHECK: function_ref @[[STRING_NONZERO_FLAG_THROW_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, {{.*}}Bool, Optional<NSString>, Optional<NSError>) -> ()
57+
// CHECK: function_ref @[[STRING_NONZERO_FLAG_THROW_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, {{.*}}Bool, Optional<NSString>, Optional<NSError>) -> ()
5858
let _: String = try await slowServer.doSomethingFlaggy()
59-
// CHECK: function_ref @[[STRING_ZERO_FLAG_THROW_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, Optional<NSString>, {{.*}}Bool, Optional<NSError>) -> ()
59+
// CHECK: function_ref @[[STRING_ZERO_FLAG_THROW_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, Optional<NSString>, {{.*}}Bool, Optional<NSError>) -> ()
6060
let _: String = try await slowServer.doSomethingZeroFlaggy()
61-
// CHECK: function_ref @[[STRING_STRING_ZERO_FLAG_THROW_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, {{.*}}Bool, Optional<NSString>, Optional<NSError>, Optional<NSString>) -> ()
61+
// CHECK: function_ref @[[STRING_STRING_ZERO_FLAG_THROW_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, {{.*}}Bool, Optional<NSString>, Optional<NSError>, Optional<NSString>) -> ()
6262
let _: (String, String) = try await slowServer.doSomethingMultiResultFlaggy()
6363

64-
// CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[NSSTRING_INT_THROW_COMPLETION_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, Optional<NSString>, Int, Optional<NSError>) -> ()
64+
// CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[NSSTRING_INT_THROW_COMPLETION_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, Optional<NSString>, Int, Optional<NSError>) -> ()
6565
let (_, _): (String, Int) = try await slowServer.findMultipleAnswers()
6666

6767
let (_, _): (Bool, Bool) = try await slowServer.findDifferentlyFlavoredBooleans()
@@ -189,14 +189,14 @@ func testSlowServerFromMain(slowServer: SlowServer) async throws {
189189
// CHECK: [[RESUME_BUF:%.*]] = alloc_stack $Int
190190
// CHECK: [[STRINGINIT:%.*]] = function_ref @$sSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF :
191191
// CHECK: [[ARG:%.*]] = apply [[STRINGINIT]]
192-
// CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (NSString, @convention(block) (Int) -> (), SlowServer) -> ()
192+
// CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (NSString, @convention(block) @Sendable (Int) -> (), SlowServer) -> ()
193193
// CHECK: [[CONT:%.*]] = get_async_continuation_addr Int, [[RESUME_BUF]]
194194
// CHECK: [[WRAPPED:%.*]] = struct $UnsafeContinuation<Int, Never> ([[CONT]] : $Builtin.RawUnsafeContinuation)
195195
// CHECK: [[BLOCK_STORAGE:%.*]] = alloc_stack $@block_storage Any
196196
// CHECK: [[CONT_SLOT:%.*]] = project_block_storage [[BLOCK_STORAGE]]
197197
// CHECK: [[CONT_SLOT_ANY:%.*]] = init_existential_addr [[CONT_SLOT]]
198198
// CHECK: store [[WRAPPED]] to [trivial] [[CONT_SLOT_ANY]]
199-
// CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[INT_COMPLETION_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, Int) -> ()
199+
// CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[INT_COMPLETION_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, Int) -> ()
200200
// CHECK: [[BLOCK:%.*]] = init_block_storage_header [[BLOCK_STORAGE]] {{.*}}, invoke [[BLOCK_IMPL]]
201201
// CHECK: apply [[METHOD]]([[ARG]], [[BLOCK]], %0)
202202
// CHECK: [[COPY:%.*]] = copy_value [[ARG]]
@@ -223,10 +223,10 @@ func testThrowingMethodFromMain(slowServer: SlowServer) async -> String {
223223
// CHECK: [[PROJECTED:%.*]] = project_block_storage [[STORE_ALLOC]] : $*@block_storage
224224
// CHECK: [[PROJECTED_ANY:%.*]] = init_existential_addr [[PROJECTED]]
225225
// CHECK: store [[CONT]] to [trivial] [[PROJECTED_ANY]]
226-
// CHECK: [[INVOKER:%.*]] = function_ref @$sSo8NSStringCSgSo7NSErrorCSgIeyByy_SSTz_
226+
// CHECK: [[INVOKER:%.*]] = function_ref @$sSo8NSStringCSgSo7NSErrorCSgIeyBhyy_SSTz_
227227
// CHECK: [[BLOCK:%.*]] = init_block_storage_header [[STORE_ALLOC]] {{.*}}, invoke [[INVOKER]]
228228
// CHECK: [[OPTIONAL_BLK:%.*]] = enum {{.*}}, #Optional.some!enumelt, [[BLOCK]]
229-
// CHECK: apply [[METH]]([[STRING_ARG]], [[OPTIONAL_BLK]], {{%.*}}) : $@convention(objc_method) (NSString, Optional<@convention(block) (Optional<NSString>, Optional<NSError>) -> ()>, SlowServer) -> ()
229+
// CHECK: apply [[METH]]([[STRING_ARG]], [[OPTIONAL_BLK]], {{%.*}}) : $@convention(objc_method) (NSString, Optional<@convention(block) @Sendable (Optional<NSString>, Optional<NSError>) -> ()>, SlowServer) -> ()
230230
// CHECK: [[STRING_ARG_COPY:%.*]] = copy_value [[STRING_ARG]] : $NSString
231231
// CHECK: dealloc_stack [[STORE_ALLOC]] : $*@block_storage Any
232232
// CHECK: destroy_value [[STRING_ARG]] : $NSString

0 commit comments

Comments
 (0)