Skip to content

[6.2][silgen] Teach SILGen how to emit a forced dynamic member ref given nonisolated(nonsending) casts. #82082

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

Draft
wants to merge 1 commit into
base: release/6.2
Choose a base branch
from
Draft
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
35 changes: 34 additions & 1 deletion lib/SILGen/SILGenApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1718,6 +1718,37 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
return false;
}

static bool addsNonIsolatedNonSendingToAsyncFn(FunctionConversionExpr *fce) {
CanType oldTy = fce->getSubExpr()->getType()->getCanonicalType();
CanType newTy = fce->getType()->getCanonicalType();

if (auto oldFnTy = dyn_cast<AnyFunctionType>(oldTy)) {
if (auto newFnTy = dyn_cast<AnyFunctionType>(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) {
Expand All @@ -1738,6 +1769,8 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
if (auto funcConv = dyn_cast<FunctionConversionExpr>(nextSubExpr)) {
if (addsGlobalActorToAsyncFn(funcConv))
nextSubExpr = funcConv->getSubExpr();
else if (addsNonIsolatedNonSendingToAsyncFn(funcConv))
nextSubExpr = funcConv->getSubExpr();
}

if (auto bind = dyn_cast<BindOptionalExpr>(nextSubExpr)) {
Expand Down Expand Up @@ -1775,7 +1808,7 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {

auto openExistential = dyn_cast<OpenExistentialExpr>(arg);
if (openExistential)
arg = openExistential->getSubExpr();
arg = ignoreParensAndImpConversions(openExistential->getSubExpr());

auto dynamicMemberRef = dyn_cast<DynamicMemberRefExpr>(arg);
if (!dynamicMemberRef)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<NSObject>
Expand Down
28 changes: 28 additions & 0 deletions test/SILGen/objc_async.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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<NSDate>, @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)
}