Skip to content

Commit 9ffb303

Browse files
authored
Merge pull request #84495 from xedin/dar-157663660-6.2
[6.2][Concurrency] Prevent some extraneous function conversion sendability checking
2 parents 711b9df + a886c5f commit 9ffb303

File tree

4 files changed

+74
-34
lines changed

4 files changed

+74
-34
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 42 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2683,7 +2683,8 @@ namespace {
26832683

26842684
/// Some function conversions synthesized by the constraint solver may not
26852685
/// be correct AND the solver doesn't know, so we must emit a diagnostic.
2686-
void checkFunctionConversion(Expr *funcConv, Type fromType, Type toType) {
2686+
void checkFunctionConversion(ImplicitConversionExpr *funcConv,
2687+
Type fromType, Type toType) {
26872688
auto diagnoseNonSendableParametersAndResult =
26882689
[&](FunctionType *fnType,
26892690
std::optional<unsigned> warnUntilSwiftMode = std::nullopt) {
@@ -2788,6 +2789,18 @@ namespace {
27882789
if (!fromFnType->isAsync())
27892790
break;
27902791

2792+
// Applying `nonisolated(nonsending)` to an interface type
2793+
// of a declaration.
2794+
if (auto *declRef =
2795+
dyn_cast<DeclRefExpr>(funcConv->getSubExpr())) {
2796+
auto *decl = declRef->getDecl();
2797+
if (auto *nonisolatedAttr =
2798+
decl->getAttrs().getAttribute<NonisolatedAttr>()) {
2799+
if (nonisolatedAttr->isNonSending())
2800+
return;
2801+
}
2802+
}
2803+
27912804
// @concurrent -> nonisolated(nonsending)
27922805
// crosses an isolation boundary.
27932806
LLVM_FALLTHROUGH;
@@ -2797,16 +2810,13 @@ namespace {
27972810
diagnoseNonSendableParametersAndResult(toFnType);
27982811
break;
27992812

2800-
case FunctionTypeIsolation::Kind::Parameter:
2801-
llvm_unreachable("invalid conversion");
2802-
2813+
// @Sendable nonisolated(nonsending) -> nonisolated(nonsending)
2814+
// doesn't require Sendable checking.
28032815
case FunctionTypeIsolation::Kind::NonIsolatedCaller:
2804-
// Non isolated caller is always async. This can only occur if we
2805-
// are converting from an `@Sendable` representation to something
2806-
// else. So we need to just check that we diagnose non sendable
2807-
// parameters and results.
2808-
diagnoseNonSendableParametersAndResult(toFnType);
28092816
break;
2817+
2818+
case FunctionTypeIsolation::Kind::Parameter:
2819+
llvm_unreachable("invalid conversion");
28102820
}
28112821
break;
28122822
}
@@ -3477,19 +3487,6 @@ namespace {
34773487
}
34783488
}
34793489

3480-
// The constraint solver may not have chosen legal casts.
3481-
if (auto funcConv = dyn_cast<FunctionConversionExpr>(expr)) {
3482-
checkFunctionConversion(funcConv,
3483-
funcConv->getSubExpr()->getType(),
3484-
funcConv->getType());
3485-
}
3486-
3487-
if (auto *isolationErasure = dyn_cast<ActorIsolationErasureExpr>(expr)) {
3488-
checkFunctionConversion(isolationErasure,
3489-
isolationErasure->getSubExpr()->getType(),
3490-
isolationErasure->getType());
3491-
}
3492-
34933490
if (auto *defaultArg = dyn_cast<DefaultArgumentExpr>(expr)) {
34943491
checkDefaultArgument(defaultArg);
34953492
}
@@ -3581,6 +3578,19 @@ namespace {
35813578
}
35823579
}
35833580

3581+
// The constraint solver may not have chosen legal casts.
3582+
if (auto funcConv = dyn_cast<FunctionConversionExpr>(expr)) {
3583+
checkFunctionConversion(funcConv,
3584+
funcConv->getSubExpr()->getType(),
3585+
funcConv->getType());
3586+
}
3587+
3588+
if (auto *isolationErasure = dyn_cast<ActorIsolationErasureExpr>(expr)) {
3589+
checkFunctionConversion(isolationErasure,
3590+
isolationErasure->getSubExpr()->getType(),
3591+
isolationErasure->getType());
3592+
}
3593+
35843594
return Action::Continue(expr);
35853595
}
35863596

@@ -5007,16 +5017,6 @@ ActorIsolation ActorIsolationChecker::determineClosureIsolation(
50075017
return ActorIsolation::forActorInstanceCapture(param);
50085018
}
50095019

5010-
// If we have a closure that acts as an isolation inference boundary, then
5011-
// we return that it is non-isolated.
5012-
//
5013-
// NOTE: Since we already checked for global actor isolated things, we
5014-
// know that all Sendable closures must be nonisolated. That is why it is
5015-
// safe to rely on this path to handle Sendable closures.
5016-
if (isIsolationInferenceBoundaryClosure(closure,
5017-
/*canInheritActorContext=*/true))
5018-
return ActorIsolation::forNonisolated(/*unsafe=*/false);
5019-
50205020
// A non-Sendable closure gets its isolation from its context.
50215021
auto parentIsolation = getActorIsolationOfContext(
50225022
closure->getParent(), getClosureActorIsolation);
@@ -5048,6 +5048,16 @@ ActorIsolation ActorIsolationChecker::determineClosureIsolation(
50485048
}
50495049
}
50505050

5051+
// If we have a closure that acts as an isolation inference boundary, then
5052+
// we return that it is non-isolated.
5053+
//
5054+
// NOTE: Since we already checked for global actor isolated things, we
5055+
// know that all Sendable closures must be nonisolated. That is why it is
5056+
// safe to rely on this path to handle Sendable closures.
5057+
if (isIsolationInferenceBoundaryClosure(closure,
5058+
/*canInheritActorContext=*/true))
5059+
return ActorIsolation::forNonisolated(/*unsafe=*/false);
5060+
50515061
return normalIsolation;
50525062
}();
50535063

test/Concurrency/actor_inout_isolation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ if #available(SwiftStdlib 5.1, *) {
220220
let _ = Task.detached { await { (_ foo: inout Int) async in foo += 1 }(&number) }
221221
// expected-error @-1 {{actor-isolated var 'number' cannot be passed 'inout' to 'async' function call}}
222222
// expected-minimal-error @-2 {{global actor 'MyGlobalActor'-isolated var 'number' can not be used 'inout' from a nonisolated context}}
223-
// expected-complete-tns-error @-3 {{main actor-isolated var 'number' can not be used 'inout' from a nonisolated context}}
223+
// expected-complete-tns-warning @-3 {{main actor-isolated var 'number' can not be used 'inout' from a nonisolated context}}
224224
}
225225

226226
// attempt to pass global state owned by the global actor to another async function

test/Concurrency/attr_execution/conversions_silgen.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,3 +613,33 @@ func testConvertToThrowing(isolation: isolated (any Actor)? = #isolation) async
613613
observe()
614614
}
615615
}
616+
617+
func testSendableClosureNonisolatedNonSendingInference() {
618+
// CHECK-LABEL: sil private [ossa] @$s21attr_execution_silgen49testSendableClosureNonisolatedNonSendingInferenceyyFySiYaYbYCcfU_ : $@convention(thin) @Sendable @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>, Int) -> ()
619+
// CHECK: bb0([[EXECUTOR:%.*]] : @guaranteed $Optional<any Actor>, %1 : $Int):
620+
// CHECK: hop_to_executor [[EXECUTOR]]
621+
// CHECK: // end sil function '$s21attr_execution_silgen49testSendableClosureNonisolatedNonSendingInferenceyyFySiYaYbYCcfU_'
622+
let _: nonisolated(nonsending) @Sendable (Int) async -> Void = { _ in }
623+
624+
// CHECK-LABEL: sil private [ossa] @$s21attr_execution_silgen49testSendableClosureNonisolatedNonSendingInferenceyyFyS2SYaKYCcYaYbYCcfU0_ : $@convention(thin) @Sendable @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>, @guaranteed @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>, @guaranteed String) -> (@owned String, @error any Error)) -> @error any Error
625+
// CHECK: bb0([[EXECUTOR:%.*]] : @guaranteed $Optional<any Actor>, %1 : @guaranteed $@async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>, @guaranteed String) -> (@owned String, @error any Error)):
626+
// CHECK: hop_to_executor [[EXECUTOR]]
627+
// CHECK: // end sil function '$s21attr_execution_silgen49testSendableClosureNonisolatedNonSendingInferenceyyFyS2SYaKYCcYaYbYCcfU0_'
628+
let _: nonisolated(nonsending) @Sendable (
629+
nonisolated(nonsending) @escaping (String) async throws -> String
630+
) async throws -> Void = { _ in }
631+
}
632+
633+
// CHECK-LABEL: sil hidden [ossa] @$s21attr_execution_silgen014testSendableToE35ConversionWithNonisilatedNonsendingyyF : $@convention(thin) () -> ()
634+
// CHECK: [[TEST_REF:%.*]] = function_ref @$s21attr_execution_silgen014testSendableToE35ConversionWithNonisilatedNonsendingyyF0D0L_7closureyS2SYaKYCc_tYaYbKF : $@convention(thin) @Sendable @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>, @guaranteed @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>, @guaranteed String) -> (@owned String, @error any Error)) -> @error any Error
635+
// CHECK: // end sil function '$s21attr_execution_silgen014testSendableToE35ConversionWithNonisilatedNonsendingyyF'
636+
func testSendableToSendableConversionWithNonisilatedNonsending() {
637+
@Sendable nonisolated(nonsending) func test(
638+
closure: nonisolated(nonsending) @escaping (String) async throws -> String
639+
) async throws {
640+
}
641+
642+
let _: nonisolated(nonsending) @Sendable (
643+
nonisolated(nonsending) @escaping (String) async throws -> String
644+
) async throws -> Void = test
645+
}

test/Concurrency/sendable_checking_captures_swift5.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,5 +92,5 @@ do {
9292

9393
let c: Class
9494
test(c)
95-
// expected-complete-warning@-1:8 {{implicit capture of 'c' requires that 'Class' conforms to 'Sendable'; this is an error in the Swift 6 language mode}}
95+
// expected-complete-warning@-1:8 {{implicit capture of 'c' requires that 'Class' conforms to 'Sendable'}}
9696
}

0 commit comments

Comments
 (0)