Skip to content

Commit 776cf6e

Browse files
committed
[concurrency] Add support in SILGen/SIL for emitting and calling implicit leading parameters for CallerInheritingIsolation isolation.
This does not change region isolation yet to recognize these as effectively nonisolated.
1 parent d7054a5 commit 776cf6e

File tree

7 files changed

+299
-19
lines changed

7 files changed

+299
-19
lines changed

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,6 +1546,7 @@ class DestructureInputs {
15461546
TypeConverter &TC;
15471547
const Conventions &Convs;
15481548
const ForeignInfo &Foreign;
1549+
std::optional<ActorIsolation> IsolationInfo;
15491550
struct ForeignSelfInfo {
15501551
AbstractionPattern OrigSelfParam;
15511552
AnyFunctionType::CanParam SubstSelfParam;
@@ -1558,9 +1559,10 @@ class DestructureInputs {
15581559
public:
15591560
DestructureInputs(TypeExpansionContext expansion, TypeConverter &TC,
15601561
const Conventions &conventions, const ForeignInfo &foreign,
1562+
std::optional<ActorIsolation> isolationInfo,
15611563
SmallVectorImpl<SILParameterInfo> &inputs)
15621564
: expansion(expansion), TC(TC), Convs(conventions), Foreign(foreign),
1563-
Inputs(inputs) {}
1565+
IsolationInfo(isolationInfo), Inputs(inputs) {}
15641566

15651567
void destructure(AbstractionPattern origType,
15661568
CanAnyFunctionType::CanParamArrayRef params,
@@ -1622,6 +1624,23 @@ class DestructureInputs {
16221624
};
16231625
}
16241626

1627+
// If we are an async function that is unspecified or nonisolated, insert an
1628+
// isolated parameter if NonIsolatedAsyncInheritsIsolationFromContext is
1629+
// enabled.
1630+
if (TC.Context.LangOpts.hasFeature(
1631+
Feature::NonIsolatedAsyncInheritsIsolationFromContext) &&
1632+
IsolationInfo &&
1633+
IsolationInfo->getKind() == ActorIsolation::CallerIsolationInheriting &&
1634+
extInfoBuilder.isAsync()) {
1635+
auto actorProtocol = TC.Context.getProtocol(KnownProtocolKind::Actor);
1636+
auto actorType =
1637+
ExistentialType::get(actorProtocol->getDeclaredInterfaceType());
1638+
addParameter(CanType(actorType).wrapInOptionalType(),
1639+
ParameterConvention::Direct_Guaranteed,
1640+
ParameterTypeFlags().withIsolated(true),
1641+
true /*implicit leading parameter*/);
1642+
}
1643+
16251644
// Add any foreign parameters that are positioned at the start
16261645
// of the sequence. visit() will add foreign parameters that are
16271646
// positioned after any parameters it adds.
@@ -2453,8 +2472,17 @@ static CanSILFunctionType getSILFunctionType(
24532472
// Destructure the input tuple type.
24542473
SmallVector<SILParameterInfo, 8> inputs;
24552474
{
2475+
std::optional<ActorIsolation> actorIsolation;
2476+
if (constant) {
2477+
if (constant->kind == SILDeclRef::Kind::Deallocator) {
2478+
actorIsolation = ActorIsolation::forNonisolated(false);
2479+
} else {
2480+
actorIsolation =
2481+
getActorIsolationOfContext(constant->getInnermostDeclContext());
2482+
}
2483+
}
24562484
DestructureInputs destructurer(expansionContext, TC, conventions,
2457-
foreignInfo, inputs);
2485+
foreignInfo, actorIsolation, inputs);
24582486
destructurer.destructure(origType, substFnInterfaceType.getParams(),
24592487
extInfoBuilder, unimplementable);
24602488
}
@@ -2542,8 +2570,9 @@ static CanSILFunctionType getSILFunctionTypeForInitAccessor(
25422570
{
25432571
bool unimplementable = false;
25442572
ForeignInfo foreignInfo;
2573+
std::optional<ActorIsolation> actorIsolation; // For now always null.
25452574
DestructureInputs destructurer(context, TC, conventions, foreignInfo,
2546-
inputs);
2575+
actorIsolation, inputs);
25472576
destructurer.destructure(
25482577
origType, substAccessorType.getParams(),
25492578
extInfoBuilder.withRepresentation(SILFunctionTypeRepresentation::Thin),

lib/SILGen/SILGenApply.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4783,6 +4783,8 @@ struct ParamLowering {
47834783
return ClaimedParamsRef(result, (unsigned)-1);
47844784
}
47854785

4786+
void claimImplicitParameters() { Params = Params.drop_front(); }
4787+
47864788
ArrayRef<SILParameterInfo>
47874789
claimCaptureParams(ArrayRef<ManagedValue> captures) {
47884790
auto firstCapture = Params.size() - captures.size();
@@ -5445,6 +5447,18 @@ ApplyOptions CallEmission::emitArgumentsForNormalApply(
54455447
options |= ApplyFlags::DoesNotAwait;
54465448
}
54475449

5450+
// Before we do anything, claim the implicit parameters. This prevents us
5451+
// from attempting to handle the implicit parameters when we emit explicit
5452+
// parameters.
5453+
//
5454+
// NOTE: The actual work needs to be done /after/ we emit the normal
5455+
// parameters since we are going to reverse the order.
5456+
if (auto isolated = substFnType->maybeGetIsolatedParameter();
5457+
isolated && isolated->hasOption(SILParameterInfo::ImplicitLeading)) {
5458+
assert(SGF.ExpectedExecutor.isNecessary());
5459+
paramLowering.claimImplicitParameters();
5460+
}
5461+
54485462
// Collect the captures, if any.
54495463
if (callee.hasCaptures()) {
54505464
(void)paramLowering.claimCaptureParams(callee.getCaptures());
@@ -5476,6 +5490,18 @@ ApplyOptions CallEmission::emitArgumentsForNormalApply(
54765490
args.back(), delayedArgs, siteForeignError);
54775491
}
54785492

5493+
// Now, actually handle the implicit parameters.
5494+
if (auto isolated = substFnType->maybeGetIsolatedParameter();
5495+
isolated && isolated->hasOption(SILParameterInfo::ImplicitLeading)) {
5496+
auto executor =
5497+
ManagedValue::forBorrowedObjectRValue(SGF.ExpectedExecutor.getEager());
5498+
args.push_back({});
5499+
// NOTE: Even though this calls emitActorInstanceIsolation, this also
5500+
// handles glboal actor isolated cases.
5501+
args.back().push_back(SGF.emitActorInstanceIsolation(
5502+
callSite->Loc, executor, executor.getType().getASTType()));
5503+
}
5504+
54795505
uncurriedLoc = callSite->Loc;
54805506

54815507
// Emit any delayed arguments: formal accesses to inout arguments, etc.

lib/SILGen/SILGenConcurrency.cpp

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -46,23 +46,48 @@ static void setExpectedExecutorForLocalVar(SILGenFunction &SGF,
4646
SGF.ExpectedExecutor.set(SGF.emitLoadActorExecutor(loc, actorInstance));
4747
}
4848

49-
static void setExpectedExecutorForParameterIsolation(SILGenFunction &SGF,
50-
ActorIsolation actorIsolation) {
49+
static void
50+
setExpectedExecutorForParameterIsolation(SILGenFunction &SGF,
51+
ActorIsolation actorIsolation) {
5152
auto loc = RegularLocation::getAutoGeneratedLocation(SGF.F.getLocation());
52-
ManagedValue actorArg;
53-
if (actorIsolation.isActorInstanceForSelfParameter()) {
54-
ManagedValue selfMV;
55-
auto selfArg = SGF.F.getSelfArgument();
56-
if (selfArg->getOwnershipKind() == OwnershipKind::Guaranteed) {
57-
selfMV = ManagedValue::forBorrowedRValue(selfArg);
58-
} else {
59-
selfMV = ManagedValue::forUnmanagedOwnedValue(selfArg);
53+
54+
if (actorIsolation.isActorInstanceIsolated()) {
55+
if (actorIsolation.isActorInstanceForSelfParameter()) {
56+
ManagedValue selfMV;
57+
auto selfArg = SGF.F.getSelfArgument();
58+
if (selfArg->getOwnershipKind() == OwnershipKind::Guaranteed) {
59+
selfMV = ManagedValue::forBorrowedRValue(selfArg);
60+
} else {
61+
selfMV = ManagedValue::forUnmanagedOwnedValue(selfArg);
62+
}
63+
SGF.ExpectedExecutor.set(SGF.emitLoadActorExecutor(loc, selfMV));
64+
return;
65+
}
66+
67+
// See if our actorIsolation actually has an actor instance associated with
68+
// it.
69+
if (auto param = actorIsolation.getActorInstance()) {
70+
return setExpectedExecutorForLocalVar(SGF, param);
71+
}
72+
}
73+
74+
// If we have caller isolation inheriting... just grab from our isolated
75+
// argument.
76+
if (actorIsolation.getKind() == ActorIsolation::CallerIsolationInheriting) {
77+
if (auto *isolatedArg = SGF.F.maybeGetIsolatedArgument()) {
78+
ManagedValue isolatedMV;
79+
if (isolatedArg->getOwnershipKind() == OwnershipKind::Guaranteed) {
80+
isolatedMV = ManagedValue::forBorrowedRValue(isolatedArg);
81+
} else {
82+
isolatedMV = ManagedValue::forUnmanagedOwnedValue(isolatedArg);
83+
}
84+
85+
SGF.ExpectedExecutor.set(SGF.emitLoadActorExecutor(loc, isolatedMV));
86+
return;
6087
}
61-
SGF.ExpectedExecutor.set(SGF.emitLoadActorExecutor(loc, selfMV));
62-
} else {
63-
auto param = actorIsolation.getActorInstance();
64-
setExpectedExecutorForLocalVar(SGF, param);
6588
}
89+
90+
llvm_unreachable("Unhandled case?!");
6691
}
6792

6893
void SILGenFunction::emitExpectedExecutorProlog() {
@@ -139,7 +164,6 @@ void SILGenFunction::emitExpectedExecutorProlog() {
139164
switch (actorIsolation.getKind()) {
140165
case ActorIsolation::Unspecified:
141166
case ActorIsolation::Nonisolated:
142-
case ActorIsolation::CallerIsolationInheriting:
143167
case ActorIsolation::NonisolatedUnsafe:
144168
break;
145169

@@ -163,6 +187,11 @@ void SILGenFunction::emitExpectedExecutorProlog() {
163187
break;
164188
}
165189

190+
case ActorIsolation::CallerIsolationInheriting:
191+
assert(F.isAsync());
192+
setExpectedExecutorForParameterIsolation(*this, actorIsolation);
193+
break;
194+
166195
case ActorIsolation::GlobalActor:
167196
if (F.isAsync() || wantDataRaceChecks) {
168197
setExpectedExecutorForGlobalActor(*this, actorIsolation.getGlobalActor());

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5611,6 +5611,15 @@ InferredActorIsolation ActorIsolationRequest::evaluate(
56115611
checkClassGlobalActorIsolation(classDecl, *isolationFromAttr);
56125612
}
56135613

5614+
if (ctx.LangOpts.hasFeature(
5615+
Feature::NonIsolatedAsyncInheritsIsolationFromContext)) {
5616+
if (auto *func = dyn_cast<AbstractFunctionDecl>(value);
5617+
func && func->hasAsync() && isolationFromAttr->isNonisolated() &&
5618+
func->getModuleContext() == ctx.MainModule) {
5619+
return {ActorIsolation::forCallerIsolationInheriting(), {}};
5620+
}
5621+
}
5622+
56145623
return {*isolationFromAttr,
56155624
IsolationSource(/*source*/ nullptr, IsolationSource::Explicit)};
56165625
}
@@ -5627,6 +5636,16 @@ InferredActorIsolation ActorIsolationRequest::evaluate(
56275636
defaultIsolation = ActorIsolation::forMainActor(ctx);
56285637
}
56295638

5639+
// If we have an async function... by default we inherit isolation.
5640+
if (ctx.LangOpts.hasFeature(
5641+
Feature::NonIsolatedAsyncInheritsIsolationFromContext)) {
5642+
if (auto *func = dyn_cast<AbstractFunctionDecl>(value);
5643+
func && func->hasAsync() &&
5644+
func->getModuleContext() == ctx.MainModule) {
5645+
defaultIsolation = ActorIsolation::forCallerIsolationInheriting();
5646+
}
5647+
}
5648+
56305649
if (auto func = dyn_cast<AbstractFunctionDecl>(value)) {
56315650
// A @Sendable function is assumed to be actor-independent.
56325651
if (func->isSendable()) {

lib/Serialization/ModuleFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5858
/// describe what change you made. The content of this comment isn't important;
5959
/// it just ensures a conflict if two people change the module format.
6060
/// Don't worry about adhering to the 80-column limit for this line.
61-
const uint16_t SWIFTMODULE_VERSION_MINOR = 908; // debug scopes and source locs
61+
const uint16_t SWIFTMODULE_VERSION_MINOR = 909; // caller inheriting isolation
6262

6363
/// A standard hash seed used for all string hashes in a serialized module.
6464
///
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %target-typecheck-verify-swift -swift-version 6 -enable-experimental-feature NonIsolatedAsyncInheritsIsolationFromContext -parse-as-library
2+
3+
class NonSendable {} // expected-note {{}}
4+
5+
@MainActor var global = NonSendable()
6+
7+
@MainActor
8+
struct MainActorIsolatedStruct {
9+
init() {}
10+
11+
func syncMethod() {}
12+
func asyncMethod() {}
13+
}
14+
15+
struct NonisolatedStruct {
16+
// Validate we can still not access global state.
17+
func asyncMethod() async {
18+
let _ = await global // expected-error {{non-sendable type 'NonSendable' of var 'global' cannot exit main actor-isolated context}}
19+
20+
let x = await MainActorIsolatedStruct()
21+
await x.syncMethod()
22+
await x.asyncMethod()
23+
}
24+
}

0 commit comments

Comments
 (0)