Skip to content

Commit 48f4d7b

Browse files
committed
[Concurrency] NonisolatedNonsendingByDefault: Extend nonisolated(nonsending) to withoutActuallyEscaping
`withoutActuallyEscaping` is type-checked in a special way which means that we need to explicitly inject `nonisolated(nonsending)` isolation when forming a reference to this builtin.
1 parent 2e8f74f commit 48f4d7b

File tree

3 files changed

+64
-0
lines changed

3 files changed

+64
-0
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3527,6 +3527,28 @@ namespace {
35273527
if (auto isolationExpr = dyn_cast<CurrentContextIsolationExpr>(expr))
35283528
recordCurrentContextIsolation(isolationExpr);
35293529

3530+
// `withoutActuallyEscaping` parameter types are set to be
3531+
// `nonisolated(nonsending)` when the `NonisolatedNonsendingByDefault`
3532+
// feature is enabled, which means that we need to make the argument
3533+
// as `nonisolated(nonsending)` if it's a closure. This cannot be done
3534+
// sooner because we need to make sure that closure is definitely
3535+
// nonisolated and due to how AST is structured we cannot do this in
3536+
// `determineClosureIsolation`.
3537+
if (ctx.LangOpts.hasFeature(Feature::NonisolatedNonsendingByDefault)) {
3538+
if (auto *MTEE = dyn_cast<MakeTemporarilyEscapableExpr>(expr)) {
3539+
if (auto *call = dyn_cast<CallExpr>(MTEE->getSubExpr())) {
3540+
if (auto *closure = dyn_cast<ClosureExpr>(call->getFn())) {
3541+
if (auto closureTy = closure->getType()->getAs<FunctionType>()) {
3542+
if (closureTy->isAsync() &&
3543+
closure->getActorIsolation().isNonisolated())
3544+
closure->setActorIsolation(
3545+
ActorIsolation::forCallerIsolationInheriting());
3546+
}
3547+
}
3548+
}
3549+
}
3550+
}
3551+
35303552
return Action::Continue(expr);
35313553
}
35323554

lib/Sema/TypeOfReference.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2427,9 +2427,17 @@ static DeclReferenceType getTypeOfReferenceWithSpecialTypeCheckingSemantics(
24272427
CS.getConstraintLocator(locator, ConstraintLocator::ThrownErrorType),
24282428
0, preparedOverload);
24292429
FunctionType::Param arg(escapeClosure);
2430+
2431+
auto bodyParamIsolation = FunctionTypeIsolation::forNonIsolated();
2432+
if (CS.getASTContext().LangOpts.hasFeature(
2433+
Feature::NonisolatedNonsendingByDefault)) {
2434+
bodyParamIsolation = FunctionTypeIsolation::forNonIsolatedCaller();
2435+
}
2436+
24302437
auto bodyClosure = FunctionType::get(arg, result,
24312438
FunctionType::ExtInfoBuilder()
24322439
.withNoEscape(true)
2440+
.withIsolation(bodyParamIsolation)
24332441
.withAsync(true)
24342442
.withThrows(true, thrownError)
24352443
.build());
@@ -2438,9 +2446,16 @@ static DeclReferenceType getTypeOfReferenceWithSpecialTypeCheckingSemantics(
24382446
FunctionType::Param(bodyClosure, CS.getASTContext().getIdentifier("do")),
24392447
};
24402448

2449+
auto withoutEscapingIsolation = FunctionTypeIsolation::forNonIsolated();
2450+
if (CS.getASTContext().LangOpts.hasFeature(
2451+
Feature::NonisolatedNonsendingByDefault)) {
2452+
withoutEscapingIsolation = FunctionTypeIsolation::forNonIsolatedCaller();
2453+
}
2454+
24412455
auto refType = FunctionType::get(args, result,
24422456
FunctionType::ExtInfoBuilder()
24432457
.withNoEscape(false)
2458+
.withIsolation(withoutEscapingIsolation)
24442459
.withAsync(true)
24452460
.withThrows(true, thrownError)
24462461
.build());

test/Concurrency/attr_execution/attr_execution.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,30 @@ func testClosure() {
8080
takesClosure {
8181
}
8282
}
83+
84+
func testWithoutActuallyEscaping(_ f: () async -> ()) async {
85+
// CHECK-LABEL: // closure #1 in testWithoutActuallyEscaping(_:)
86+
// CHECK-NEXT: // Isolation: caller_isolation_inheriting
87+
await withoutActuallyEscaping(f) {
88+
await $0()
89+
}
90+
91+
// CHECK-LABEL: // closure #2 in testWithoutActuallyEscaping(_:)
92+
// CHECK-NEXT: // Isolation: global_actor. type: MainActor
93+
await withoutActuallyEscaping(f) { @MainActor in
94+
await $0()
95+
}
96+
97+
actor Test {
98+
// CHECK-LABEL: // closure #1 in testActorIsolatedCapture() in Test #1 in testWithoutActuallyEscaping(_:)
99+
// CHECK-NEXT: // Isolation: actor_instance. name: 'self'
100+
func testActorIsolatedCapture() async {
101+
await withoutActuallyEscaping(compute) {
102+
_ = self
103+
await $0()
104+
}
105+
}
106+
107+
func compute() async {}
108+
}
109+
}

0 commit comments

Comments
 (0)