Skip to content

Commit ed5fd4e

Browse files
authored
Merge pull request #82673 from xedin/rdar-154695053
[Concurrency] SE-0463: `Sendable` inference on sync and async variant…
2 parents a0c6eca + 30f0fa8 commit ed5fd4e

8 files changed

+116
-61
lines changed

lib/ClangImporter/ImportType.cpp

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2463,6 +2463,15 @@ static bool isParameterContextGlobalActorIsolated(DeclContext *dc,
24632463
return false;
24642464
}
24652465

2466+
static bool isSendableInferenceOnCompletionHandlerParameterAllowed(
2467+
DeclContext *dc, const clang::Decl *parent) {
2468+
auto &C = dc->getASTContext();
2469+
if (!C.LangOpts.hasFeature(Feature::SendableCompletionHandlers))
2470+
return false;
2471+
2472+
return !isParameterContextGlobalActorIsolated(dc, parent);
2473+
}
2474+
24662475
std::optional<ClangImporter::Implementation::ImportParameterTypeResult>
24672476
ClangImporter::Implementation::importParameterType(
24682477
DeclContext *dc, const clang::Decl *parent, const clang::ParmVarDecl *param,
@@ -2493,10 +2502,9 @@ ClangImporter::Implementation::importParameterType(
24932502
bool isConsuming = false;
24942503
bool isParamTypeImplicitlyUnwrapped = false;
24952504

2496-
if (SwiftContext.LangOpts.hasFeature(Feature::SendableCompletionHandlers) &&
2497-
paramIsCompletionHandler) {
2498-
if (!isParameterContextGlobalActorIsolated(dc, parent))
2499-
attrs |= ImportTypeAttr::DefaultsToSendable;
2505+
if (paramIsCompletionHandler &&
2506+
isSendableInferenceOnCompletionHandlerParameterAllowed(dc, parent)) {
2507+
attrs |= ImportTypeAttr::DefaultsToSendable;
25002508
}
25012509

25022510
if (auto optionSetEnum = importer::findOptionSetEnum(paramTy, *this)) {
@@ -3379,11 +3387,19 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType(
33793387
decomposeCompletionHandlerType(swiftParamTy, *asyncInfo)) {
33803388
swiftResultTy = replacedSwiftResultTy;
33813389

3390+
ImportTypeAttrs attrs;
3391+
// This is required because a parameter type of a sync variant and
3392+
// a completion type of an async variant have to match exactly.
3393+
if (isSendableInferenceOnCompletionHandlerParameterAllowed(origDC,
3394+
clangDecl)) {
3395+
attrs |= ImportTypeAttr::DefaultsToSendable;
3396+
}
3397+
33823398
// Import the original completion handler type without adjustments.
33833399
Type origSwiftParamTy =
33843400
importType(paramTy, ImportTypeKind::CompletionHandlerParameter,
33853401
paramAddDiag, allowNSUIntegerAsIntInParam,
3386-
Bridgeability::Full, ImportTypeAttrs(),
3402+
Bridgeability::Full, attrs,
33873403
optionalityOfParam,
33883404
/*resugarNSErrorPointer=*/!paramIsError, std::nullopt)
33893405
.getType();

test/ClangImporter/regionbasedisolation.swift

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ extension ObjCObject {
7474
// CHECK: [[RESULT:%.*]] = alloc_stack $Array<NSObject>
7575

7676
// Our method.
77-
// CHECK: [[METHOD:%.*]] = objc_method [[SELF]], #ObjCObject.loadObjects2!foreign : (ObjCObject) -> () async throws -> [NSObject], $@convention(objc_method) (@convention(block) (Optional<NSArray>, Optional<NSError>) -> (), ObjCObject) -> ()
77+
// CHECK: [[METHOD:%.*]] = objc_method [[SELF]], #ObjCObject.loadObjects2!foreign : (ObjCObject) -> () async throws -> [NSObject], $@convention(objc_method) (@convention(block) @Sendable (Optional<NSArray>, Optional<NSError>) -> (), ObjCObject) -> ()
7878

7979
// Begin setting up the unsafe continuation for our method. Importantly note
8080
// that [[UNSAFE_CONT]] is Sendable, so we lose any connection from the
@@ -103,17 +103,18 @@ extension ObjCObject {
103103
// CHECK: copy_addr [take] [[CHECKED_CONT]] to [init] [[EXISTENTIAL_BLOCK_STORAGE]]
104104
// CHECK: merge_isolation_region [[BLOCK_STORAGE]], [[RESULT]]
105105

106-
// Then create the actual block. NOTE: Since the block is not @Sendable, the block does propagate regions.
106+
// Then create the actual block. NOTE: Since the block is @Sendable, the block
107+
// does not propagate regions.
107108
//
108-
// CHECK: [[COMPLETION_HANDLER_BLOCK:%.*]] = function_ref @$sSo7NSArrayCSgSo7NSErrorCSgIeyByy_SaySo8NSObjectCGTz_ : $@convention(c) (@inout_aliasable @block_storage Any, Optional<NSArray>, Optional<NSError>) -> ()
109+
// CHECK: [[COMPLETION_HANDLER_BLOCK:%.*]] = function_ref @$sSo7NSArrayCSgSo7NSErrorCSgIeyBhyy_SaySo8NSObjectCGTz_ : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, Optional<NSArray>, Optional<NSError>) -> ()
109110
// CHECK: [[COMPLETION_BLOCK:%.*]] = init_block_storage_header [[BLOCK_STORAGE]], invoke [[COMPLETION_HANDLER_BLOCK]]
110111
//
111-
// Since the block is not @Sendable, it does propagate the connection in
112+
// Since the block is @Sendable, it does not propagate the connection in
112113
// between self and the block storage when we just call the method. Thus we
113-
// don't need to perform a merge_isolation_region to communicate that the block
114+
// need to perform a merge_isolation_region to communicate that the block
114115
// storage and self are part of the same region.
115116
//
116-
// CHECK-NOT: merge_isolation_region [[SELF]], [[BLOCK_STORAGE]]
117+
// CHECK: merge_isolation_region [[SELF]], [[BLOCK_STORAGE]]
117118
//
118119
// Then call the method.
119120
// CHECK: apply [[METHOD]]([[COMPLETION_BLOCK]], [[SELF]])

test/SILGen/objc_async.swift

Lines changed: 19 additions & 19 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
@@ -340,10 +340,10 @@ extension SlowServer: @retroactive FailableFloatLoader {
340340
}
341341
// CHECK-LABEL: sil [ossa] @$sSo10SlowServerC10objc_asyncE16loadFloatOrThrowSfyYaKF : $@convention(method) @async (@guaranteed SlowServer) -> (Float, @error any Error)
342342

343-
// CHECK-LABEL: sil private [thunk] [ossa] @$sSo10SlowServerC10objc_asyncE16loadFloatOrThrowSfyYaKFTo : $@convention(objc_method) (@convention(block) (Float, Optional<NSError>) -> (), SlowServer) -> () {
343+
// CHECK-LABEL: sil private [thunk] [ossa] @$sSo10SlowServerC10objc_asyncE16loadFloatOrThrowSfyYaKFTo : $@convention(objc_method) (@convention(block) @Sendable (Float, Optional<NSError>) -> (), SlowServer) -> () {
344344
// CHECK: function_ref @$sSo10SlowServerC10objc_asyncE16loadFloatOrThrowSfyYaKFyyYacfU_To
345345

346-
// CHECK-LABEL: sil shared [thunk] [ossa] @$sSo10SlowServerC10objc_asyncE16loadFloatOrThrowSfyYaKFyyYacfU_To : $@convention(thin) @Sendable @async (@convention(block) (Float, Optional<NSError>) -> (), SlowServer) -> ()
346+
// CHECK-LABEL: sil shared [thunk] [ossa] @$sSo10SlowServerC10objc_asyncE16loadFloatOrThrowSfyYaKFyyYacfU_To : $@convention(thin) @Sendable @async (@convention(block) @Sendable (Float, Optional<NSError>) -> (), SlowServer) -> ()
347347
// CHECK: [[BLOCK:%.*]] = copy_block
348348
// CHECK: [[METHOD:%.*]] = function_ref @$sSo10SlowServerC10objc_asyncE16loadFloatOrThrowSfyYaKF :
349349
// CHECK: try_apply [[METHOD]]({{%.*}}) : {{.*}}, normal bb1, error bb2
@@ -370,17 +370,17 @@ extension SlowServer: @retroactive FailableFloatLoader {
370370
// CHECK: [[SLOWSERVER_ANYOBJECT_M_B:%.*]] = begin_borrow [[SLOWSERVER_ANYOBJECT_M]]
371371
// CHECK: [[SLOWSERVER_ANYOBJECT_M_B_O:%.*]] = open_existential_ref [[SLOWSERVER_ANYOBJECT_M_B]]
372372
// CHECK: [[SLOWSERVER_ANYOBJECT_M_B_O_C:%.*]] = copy_value [[SLOWSERVER_ANYOBJECT_M_B_O]]
373-
// CHECK: [[METHOD:%.*]] = objc_method [[SLOWSERVER_ANYOBJECT_M_B_O_C]] : $@opened("{{.*}}", AnyObject) Self, #SlowServer.start!foreign : (SlowServer) -> (NSDate?) async -> (), $@convention(objc_method) (Optional<NSDate>, @convention(block) () -> (), @opened("{{.*}}", AnyObject) Self) -> ()
373+
// CHECK: [[METHOD:%.*]] = objc_method [[SLOWSERVER_ANYOBJECT_M_B_O_C]] : $@opened("{{.*}}", AnyObject) Self, #SlowServer.start!foreign : (SlowServer) -> (NSDate?) async -> (), $@convention(objc_method) (Optional<NSDate>, @convention(block) @Sendable () -> (), @opened("{{.*}}", AnyObject) Self) -> ()
374374
// CHECK: [[CONT:%.*]] = get_async_continuation_addr ()
375375
// CHECK: [[UNSAFE_CONT:%.*]] = struct $UnsafeContinuation<(), Never> ([[CONT]] : $Builtin.RawUnsafeContinuation)
376376
// CHECK: [[BLOCK:%.*]] = alloc_stack $@block_storage Any
377377
// CHECK: [[BLOCK_PROJECT:%.*]] = project_block_storage [[BLOCK]]
378378
// CHECK: [[BLOCK_PROJECT_EX:%.*]] = init_existential_addr [[BLOCK_PROJECT]]
379379
// CHECK: store [[UNSAFE_CONT]] to [trivial] [[BLOCK_PROJECT_EX]]
380380
// CHECK: merge_isolation_region [[BLOCK]] : $*@block_storage Any,
381-
// CHECK: [[CONT_HANDLER:%.*]] = function_ref @$sIeyB_ytTz_ : $@convention(c) (@inout_aliasable @block_storage Any) -> ()
381+
// CHECK: [[CONT_HANDLER:%.*]] = function_ref @$sIeyBh_ytTz_ : $@convention(c) @Sendable (@inout_aliasable @block_storage Any) -> ()
382382
// CHECK: [[INIT_BLOCK_STORAGE_HEADER:%.*]] = init_block_storage_header [[BLOCK]] : $*@block_storage Any, invoke [[CONT_HANDLER]]
383-
// CHECK-NOT: merge_isolation_region [[SLOWSERVER_ANYOBJECT_M_B_O_C]] : $@opened("{{.*}}", AnyObject) Self, [[BLOCK]]
383+
// CHECK: merge_isolation_region [[SLOWSERVER_ANYOBJECT_M_B_O_C]] : $@opened("{{.*}}", AnyObject) Self, [[BLOCK]]
384384
// CHECK: apply [[METHOD]]({{%.*}}, [[INIT_BLOCK_STORAGE_HEADER]], [[SLOWSERVER_ANYOBJECT_M_B_O_C]])
385385
// CHECK: await_async_continuation [[CONT]] : $Builtin.RawUnsafeContinuation, resume bb1
386386
// CHECK: } // end sil function '$s10objc_async13testAnyObjectyySo10SlowServerCYaF'

0 commit comments

Comments
 (0)