diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index 623540eb163c9..2ac048ed841c0 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -1718,6 +1718,37 @@ class SILGenApply : public Lowering::ExprVisitor { return false; } + static bool addsNonIsolatedNonSendingToAsyncFn(FunctionConversionExpr *fce) { + CanType oldTy = fce->getSubExpr()->getType()->getCanonicalType(); + CanType newTy = fce->getType()->getCanonicalType(); + + if (auto oldFnTy = dyn_cast(oldTy)) { + if (auto newFnTy = dyn_cast(newTy)) { + // old type and new type MUST both be async + if (!oldFnTy->hasEffect(EffectKind::Async) || + !newFnTy->hasEffect(EffectKind::Async)) + return false; + + // old type MUST NOT have nonisolated(nonsending). + if (oldFnTy->getIsolation().isNonIsolatedCaller()) + return false; + + // new type MUST nonisolated(nonsending) + if (!newFnTy->getIsolation().isNonIsolatedCaller()) + return false; + + // See if setting isolation of old type to nonisolated(nonsending) + // yields the new type. + auto addedNonIsolatedNonSending = oldFnTy->getExtInfo().withIsolation( + FunctionTypeIsolation::forNonIsolatedCaller()); + + return oldFnTy->withExtInfo(addedNonIsolatedNonSending) == newFnTy; + } + } + + return false; + } + /// Ignore parentheses and implicit conversions. static Expr *ignoreParensAndImpConversions(Expr *expr) { while (true) { @@ -1738,6 +1769,8 @@ class SILGenApply : public Lowering::ExprVisitor { if (auto funcConv = dyn_cast(nextSubExpr)) { if (addsGlobalActorToAsyncFn(funcConv)) nextSubExpr = funcConv->getSubExpr(); + else if (addsNonIsolatedNonSendingToAsyncFn(funcConv)) + nextSubExpr = funcConv->getSubExpr(); } if (auto bind = dyn_cast(nextSubExpr)) { @@ -1775,7 +1808,7 @@ class SILGenApply : public Lowering::ExprVisitor { auto openExistential = dyn_cast(arg); if (openExistential) - arg = openExistential->getSubExpr(); + arg = ignoreParensAndImpConversions(openExistential->getSubExpr()); auto dynamicMemberRef = dyn_cast(arg); if (!dynamicMemberRef) diff --git a/test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h b/test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h index 6d3436589a36c..589d1b07185c7 100644 --- a/test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h +++ b/test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h @@ -133,6 +133,9 @@ typedef void (^NonsendableCompletionHandler)(NSString * _Nullable, NSString * _N (void (^)(NSString *__nullable value, NSError *__nullable error))completionHandler MAIN_ACTOR; + +- (void)startAt:(__nullable NSDate *)value + completion:(void (^_Nonnull)(void))completion; @end @protocol RefrigeratorDelegate diff --git a/test/SILGen/objc_async.swift b/test/SILGen/objc_async.swift index ab9b2af44fb53..bf6eb7a038823 100644 --- a/test/SILGen/objc_async.swift +++ b/test/SILGen/objc_async.swift @@ -360,3 +360,31 @@ extension SlowServer: @retroactive FailableFloatLoader { // CHECK-NEXT: [[ZERO_FLOAT:%.*]] = builtin "zeroInitializer"() : $Float // CHECK-NEXT: [[BORROWED_SOME_NSERROR:%.*]] = begin_borrow [[SOME_NSERROR]] : // CHECK-NEXT: apply [[BORROWED_BLOCK]]([[ZERO_FLOAT]], [[BORROWED_SOME_NSERROR]]) + +// CHECK-LABEL: sil hidden [ossa] @$s10objc_async13testAnyObjectyySo10SlowServerCYaF : $@convention(thin) @async (@guaranteed SlowServer) -> () { +// CHECK: bb0([[SLOWSERVER:%.*]] : @guaranteed $SlowServer): +// CHECK: [[SLOWSERVER_C:%.*]] = copy_value [[SLOWSERVER]] +// CHECK: [[SLOWSERVER_ANYOBJECT:%.*]] = init_existential_ref [[SLOWSERVER_C]] +// CHECK: [[SLOWSERVER_ANYOBJECT_M:%.*]] = move_value [lexical] [var_decl] [[SLOWSERVER_ANYOBJECT]] +// CHECK: debug_value [[SLOWSERVER_ANYOBJECT_M]] : $AnyObject, let, name "anyObjectSlowServer" +// CHECK: [[SLOWSERVER_ANYOBJECT_M_B:%.*]] = begin_borrow [[SLOWSERVER_ANYOBJECT_M]] +// CHECK: [[SLOWSERVER_ANYOBJECT_M_B_O:%.*]] = open_existential_ref [[SLOWSERVER_ANYOBJECT_M_B]] +// CHECK: [[SLOWSERVER_ANYOBJECT_M_B_O_C:%.*]] = copy_value [[SLOWSERVER_ANYOBJECT_M_B_O]] +// CHECK: [[METHOD:%.*]] = objc_method [[SLOWSERVER_ANYOBJECT_M_B_O_C]] : $@opened("{{.*}}", AnyObject) Self, #SlowServer.start!foreign : (SlowServer) -> (NSDate?) async -> (), $@convention(objc_method) (Optional, @convention(block) @Sendable () -> (), @opened("{{.*}}", AnyObject) Self) -> () +// CHECK: [[CONT:%.*]] = get_async_continuation_addr () +// CHECK: [[UNSAFE_CONT:%.*]] = struct $UnsafeContinuation<(), Never> ([[CONT]] : $Builtin.RawUnsafeContinuation) +// CHECK: [[BLOCK:%.*]] = alloc_stack $@block_storage Any +// CHECK: [[BLOCK_PROJECT:%.*]] = project_block_storage [[BLOCK]] +// CHECK: [[BLOCK_PROJECT_EX:%.*]] = init_existential_addr [[BLOCK_PROJECT]] +// CHECK: store [[UNSAFE_CONT]] to [trivial] [[BLOCK_PROJECT_EX]] +// CHECK: merge_isolation_region [[BLOCK]] : $*@block_storage Any, +// CHECK: [[CONT_HANDLER:%.*]] = function_ref @$sIeyBh_ytTz_ : $@convention(c) @Sendable (@inout_aliasable @block_storage Any) -> () +// CHECK: [[INIT_BLOCK_STORAGE_HEADER:%.*]] = init_block_storage_header [[BLOCK]] : $*@block_storage Any, invoke [[CONT_HANDLER]] +// CHECK: merge_isolation_region [[SLOWSERVER_ANYOBJECT_M_B_O_C]] : $@opened("{{.*}}", AnyObject) Self, [[BLOCK]] +// CHECK: apply [[METHOD]]({{%.*}}, [[INIT_BLOCK_STORAGE_HEADER]], [[SLOWSERVER_ANYOBJECT_M_B_O_C]]) +// CHECK: await_async_continuation [[CONT]] : $Builtin.RawUnsafeContinuation, resume bb1 +// CHECK: } // end sil function '$s10objc_async13testAnyObjectyySo10SlowServerCYaF' +func testAnyObject(_ slowServer: SlowServer) async { + let anyObjectSlowServer: AnyObject = slowServer + await anyObjectSlowServer.start(at: nil) +}