Skip to content

Commit 2bd4c8c

Browse files
committed
At the SIL level, allow synchronous functions to be nonisolated(nonsending).
1 parent 6f376c2 commit 2bd4c8c

File tree

5 files changed

+65
-14
lines changed

5 files changed

+65
-14
lines changed

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,6 +1262,11 @@ class Conventions {
12621262

12631263
ConventionsKind getKind() const { return kind; }
12641264

1265+
bool hasCallerIsolationParameter() const {
1266+
return kind == ConventionsKind::Default ||
1267+
kind == ConventionsKind::Deallocator;
1268+
}
1269+
12651270
virtual ParameterConvention
12661271
getIndirectParameter(unsigned index,
12671272
const AbstractionPattern &type,
@@ -1706,14 +1711,10 @@ class DestructureInputs {
17061711
};
17071712
}
17081713

1709-
// If we are an async function that is unspecified or nonisolated, insert an
1710-
// isolated parameter if NonisolatedNonsendingByDefault is enabled.
1711-
//
1712-
// NOTE: The parameter is not inserted for async functions imported
1713-
// from ObjC because they are handled in a special way that doesn't
1714-
// require it.
1714+
// If the function has nonisolated(nonsending) isolation, insert the
1715+
// implicit isolation parameter.
17151716
if (IsolationInfo && IsolationInfo->isCallerIsolationInheriting() &&
1716-
extInfoBuilder.isAsync() && !Foreign.async) {
1717+
Convs.hasCallerIsolationParameter()) {
17171718
auto actorProtocol = TC.Context.getProtocol(KnownProtocolKind::Actor);
17181719
auto actorType =
17191720
ExistentialType::get(actorProtocol->getDeclaredInterfaceType());

lib/SILGen/SILGenConcurrency.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ void SILGenFunction::emitExpectedExecutorProlog() {
190190
}
191191

192192
case ActorIsolation::CallerIsolationInheriting:
193-
assert(F.isAsync());
193+
assert(F.isAsync() || F.isDefer());
194194
setExpectedExecutorForParameterIsolation(*this, actorIsolation);
195195
break;
196196

@@ -255,7 +255,7 @@ void SILGenFunction::emitExpectedExecutorProlog() {
255255
RegularLocation::getDebugOnlyLocation(F.getLocation(), getModule()),
256256
executor,
257257
/*mandatory*/ false);
258-
} else {
258+
} else if (wantDataRaceChecks) {
259259
// For a synchronous function, check that we're on the same executor.
260260
// Note: if we "know" that the code is completely Sendable-safe, this
261261
// is unnecessary. The type checker will need to make this determination.

lib/SILGen/SILGenExpr.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2871,12 +2871,22 @@ SILGenFunction::emitApplyOfDefaultArgGenerator(SILLocation loc,
28712871
ResultPlanBuilder::computeResultPlan(*this, calleeTypeInfo, loc, C);
28722872
ArgumentScope argScope(*this, loc);
28732873

2874-
SmallVector<ManagedValue, 4> captures;
2874+
SmallVector<ManagedValue, 4> args;
2875+
2876+
// Add the implicit leading isolation argument for a
2877+
// nonisolated(nonsending) default argument generator.
2878+
if (fnType->maybeGetIsolatedParameter()) {
2879+
auto executor = emitExpectedExecutor(loc);
2880+
args.push_back(emitActorInstanceIsolation(
2881+
loc, executor, executor.getType().getASTType()));
2882+
}
2883+
2884+
// If there are captures, those come at the end.
28752885
emitCaptures(loc, generator, CaptureEmission::ImmediateApplication,
2876-
captures);
2886+
args);
28772887

28782888
return emitApply(std::move(resultPtr), std::move(argScope), loc, fnRef, subs,
2879-
captures, calleeTypeInfo, ApplyOptions(), C, std::nullopt);
2889+
args, calleeTypeInfo, ApplyOptions(), C, std::nullopt);
28802890
}
28812891

28822892
RValue SILGenFunction::emitApplyOfStoredPropertyInitializer(

test/SILGen/isolated_default_arguments.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ func main_actor_int_pair() -> (Int, Int) {
2828
return (0,0)
2929
}
3030

31+
func make_int(isolated isolation: (any Actor)? = #isolation) -> Int {
32+
return 0
33+
}
34+
3135
// This test breaks because the intermediate argument is `nil`, which
3236
// we treat as non-isolated.
3337
@MainActor
@@ -121,3 +125,39 @@ func tupleIsolatedDefaultArg(x: (Int,Int) = main_actor_int_pair(),
121125
func testTupleIsolatedDefaultArg() async {
122126
await tupleIsolatedDefaultArg(y: 0)
123127
}
128+
129+
// When a function is caller-isolated, its default argument generators
130+
// should probably also be caller-isolated and forward their isolation
131+
// properly when #isolation is used. Currently, however, that's not what
132+
// we're doing, so test for the current behavior.
133+
134+
nonisolated(nonsending)
135+
func callerIsolatedDefaultArg(x: Int = make_int()) async {}
136+
137+
@MainActor
138+
func useCallerIsolatedDefaultArg() async {
139+
await callerIsolatedDefaultArg()
140+
}
141+
142+
// Check that the default argument generator isn't caller-isolated.
143+
// CHECK-LABEL: // default argument 0 of test.callerIsolatedDefaultArg
144+
// CHECK-NEXT: // Isolation: unspecified
145+
// CHECK-NEXT: sil hidden [ossa] @$s4test24callerIsolatedDefaultArg1xySi_tYaFfA_ :
146+
// CHECK: bb0:
147+
// Check that we provide a nil isolation for #isolation
148+
// CHECK-NEXT: [[NIL_ISOLATION:%.*]] = enum $Optional<any Actor>, #Optional.none
149+
// CHECK-NEXT: // function_ref test.make_int
150+
// CHECK-NEXT: [[FN:%.*]] = function_ref @$s4test8make_int8isolatedSiScA_pSg_tF :
151+
// CHECK-NEXT: [[RESULT:%.*]] = apply [[FN]]([[NIL_ISOLATION]])
152+
// CHECK-NEXT: return [[RESULT]]
153+
154+
// Check that we pass the right isolation to the generator.
155+
// CHECK-LABEL: sil hidden [ossa] @$s4test27useCallerIsolatedDefaultArgyyYaF :
156+
// Get the main actor reference.
157+
// CHECK: [[GET_MAIN_ACTOR:%.*]] = function_ref @$sScM6sharedScMvgZ :
158+
// CHECK-NEXT: [[T0:%.*]] = apply [[GET_MAIN_ACTOR]](
159+
// CHECK-NEXT: [[MAIN_ACTOR:%.*]] = begin_borrow [[T0]]
160+
// Call the accessor.
161+
// CHECK: // function_ref default argument 0 of
162+
// CHECK-NEXT: [[GEN:%.*]] = function_ref @$s4test24callerIsolatedDefaultArg1xySi_tYaFfA_ :
163+
// CHECK-NEXT: [[ARG:%.*]] = apply [[GEN]]()

test/SILGen/objc_async_from_swift.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ func testAutoclosureInStaticMethod() {
466466
//
467467
// Get standard.
468468
// CHECK: [[METATYPE:%.*]] = metatype $@objc_metatype SlowServer.Type
469-
// CHECK: [[GET_STANDARD_FUNC:%.*]] = objc_method %1 : $@objc_metatype SlowServer.Type, #SlowServer.standard!getter.foreign : (SlowServer.Type) -> () -> SlowServer, $@convention(objc_method) (@objc_metatype SlowServer.Type) -> @autoreleased SlowServer
469+
// CHECK: [[GET_STANDARD_FUNC:%.*]] = objc_method [[METATYPE]] : $@objc_metatype SlowServer.Type, #SlowServer.standard!getter.foreign : (SlowServer.Type) -> () -> SlowServer, $@convention(objc_method) (@objc_metatype SlowServer.Type) -> @autoreleased SlowServer
470470
// CHECK: [[STANDARD:%.*]] = apply [[GET_STANDARD_FUNC]]([[METATYPE]])
471471
//
472472
// Then grab value.
@@ -592,7 +592,7 @@ func testAutoclosureInStaticMethod() {
592592
//
593593
// Get standard.
594594
// CHECK: [[METATYPE:%.*]] = metatype $@objc_metatype SlowServer.Type
595-
// CHECK: [[GET_STANDARD_FUNC:%.*]] = objc_method %1 : $@objc_metatype SlowServer.Type, #SlowServer.standard!getter.foreign : (SlowServer.Type) -> () -> SlowServer, $@convention(objc_method) (@objc_metatype SlowServer.Type) -> @autoreleased SlowServer
595+
// CHECK: [[GET_STANDARD_FUNC:%.*]] = objc_method [[METATYPE]] : $@objc_metatype SlowServer.Type, #SlowServer.standard!getter.foreign : (SlowServer.Type) -> () -> SlowServer, $@convention(objc_method) (@objc_metatype SlowServer.Type) -> @autoreleased SlowServer
596596
// CHECK: [[STANDARD:%.*]] = apply [[GET_STANDARD_FUNC]]([[METATYPE]])
597597
//
598598
// Then grab value.

0 commit comments

Comments
 (0)