Skip to content

Commit 141ffc2

Browse files
committed
Model isolated parameters in ActorIsolation.
A function can be actor instance-isolated to one of its parameters. Make sure that this is reflected in ActorIsolation, so such a function doesn't get a different actor isolation.
1 parent cf337a7 commit 141ffc2

File tree

6 files changed

+103
-35
lines changed

6 files changed

+103
-35
lines changed

include/swift/AST/ActorIsolation.h

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,17 @@ class ActorIsolation {
7474
Type globalActor;
7575
void *pointer;
7676
};
77-
uint8_t kind : 3;
78-
uint8_t isolatedByPreconcurrency : 1;
77+
unsigned kind : 3;
78+
unsigned isolatedByPreconcurrency : 1;
79+
unsigned parameterIndex : 28;
7980

80-
ActorIsolation(Kind kind, NominalTypeDecl *actor)
81-
: actor(actor), kind(kind), isolatedByPreconcurrency(false) { }
81+
ActorIsolation(Kind kind, NominalTypeDecl *actor, unsigned parameterIndex)
82+
: actor(actor), kind(kind), isolatedByPreconcurrency(false),
83+
parameterIndex(parameterIndex) { }
8284

8385
ActorIsolation(Kind kind, Type globalActor)
84-
: globalActor(globalActor), kind(kind), isolatedByPreconcurrency(false) { }
86+
: globalActor(globalActor), kind(kind), isolatedByPreconcurrency(false),
87+
parameterIndex(0) { }
8588

8689
public:
8790
static ActorIsolation forUnspecified() {
@@ -92,8 +95,13 @@ class ActorIsolation {
9295
return ActorIsolation(Independent, nullptr);
9396
}
9497

95-
static ActorIsolation forActorInstance(NominalTypeDecl *actor) {
96-
return ActorIsolation(ActorInstance, actor);
98+
static ActorIsolation forActorInstanceSelf(NominalTypeDecl *actor) {
99+
return ActorIsolation(ActorInstance, actor, 0);
100+
}
101+
102+
static ActorIsolation forActorInstanceParameter(NominalTypeDecl *actor,
103+
unsigned parameterIndex) {
104+
return ActorIsolation(ActorInstance, actor, parameterIndex + 1);
97105
}
98106

99107
static ActorIsolation forGlobalActor(Type globalActor, bool unsafe) {
@@ -109,6 +117,14 @@ class ActorIsolation {
109117

110118
bool isIndependent() const { return kind == Independent; }
111119

120+
/// Retrieve the parameter to which actor-instance isolation applies.
121+
///
122+
/// Parameter 0 is `self`.
123+
unsigned getActorInstanceParameter() const {
124+
assert(getKind() == ActorInstance);
125+
return parameterIndex;
126+
}
127+
112128
bool isActorIsolated() const {
113129
switch (getKind()) {
114130
case ActorInstance:
@@ -169,7 +185,7 @@ class ActorIsolation {
169185
return true;
170186

171187
case ActorInstance:
172-
return lhs.actor == rhs.actor;
188+
return lhs.actor == rhs.actor && lhs.parameterIndex == rhs.parameterIndex;
173189

174190
case GlobalActor:
175191
case GlobalActorUnsafe:
@@ -183,7 +199,9 @@ class ActorIsolation {
183199
}
184200

185201
friend llvm::hash_code hash_value(const ActorIsolation &state) {
186-
return llvm::hash_combine(state.kind, state.pointer);
202+
return llvm::hash_combine(
203+
state.kind, state.pointer, state.isolatedByPreconcurrency,
204+
state.parameterIndex);
187205
}
188206
};
189207

lib/AST/Decl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9232,7 +9232,8 @@ ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {
92329232
auto actor = selfDecl->getType()->getReferenceStorageReferent()
92339233
->getAnyActor();
92349234
assert(actor && "Bad closure actor isolation?");
9235-
return ActorIsolation::forActorInstance(actor)
9235+
// FIXME: This could be a parameter... or a capture... hmmm.
9236+
return ActorIsolation::forActorInstanceSelf(actor)
92369237
.withPreconcurrency(isolation.preconcurrency());
92379238
}
92389239
}

lib/SILGen/SILGenPoly.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4438,6 +4438,7 @@ void SILGenFunction::emitProtocolWitness(
44384438

44394439
// For an instance actor, get the actor 'self'.
44404440
if (*enterIsolation == ActorIsolation::ActorInstance) {
4441+
assert(enterIsolation->getActorInstanceParameter() == 0 && "Not self?");
44414442
auto actorSelfVal = origParams.back();
44424443

44434444
if (actorSelfVal.getType().isAddress()) {

lib/SILGen/SILGenProlog.cpp

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -670,16 +670,6 @@ void SILGenFunction::emitProlog(CaptureInfo captureInfo,
670670
switch (actorIsolation.getKind()) {
671671
case ActorIsolation::Unspecified:
672672
case ActorIsolation::Independent:
673-
// If this is an async function that has an isolated parameter, hop
674-
// to it.
675-
if (F.isAsync()) {
676-
for (auto param : *funcDecl->getParameters()) {
677-
if (param->isIsolated()) {
678-
loadExpectedExecutorForLocalVar(param);
679-
break;
680-
}
681-
}
682-
}
683673
break;
684674

685675
case ActorIsolation::ActorInstance: {
@@ -693,10 +683,19 @@ void SILGenFunction::emitProlog(CaptureInfo captureInfo,
693683
.getIsolatedParamCapture()) {
694684
loadExpectedExecutorForLocalVar(isolatedParam);
695685
} else {
696-
assert(selfParam && "no self parameter for ActorInstance isolation");
697686
auto loc = RegularLocation::getAutoGeneratedLocation(F.getLocation());
698-
ManagedValue selfArg = ManagedValue::forUnmanaged(F.getSelfArgument());
699-
ExpectedExecutor = emitLoadActorExecutor(loc, selfArg);
687+
ManagedValue actorArg;
688+
if (actorIsolation.getActorInstanceParameter() == 0) {
689+
assert(selfParam && "no self parameter for ActorInstance isolation");
690+
auto selfArg = ManagedValue::forUnmanaged(F.getSelfArgument());
691+
ExpectedExecutor = emitLoadActorExecutor(loc, selfArg);
692+
} else {
693+
unsigned isolatedParamIdx =
694+
actorIsolation.getActorInstanceParameter() - 1;
695+
auto param = funcDecl->getParameters()->get(isolatedParamIdx);
696+
assert(param->isIsolated());
697+
loadExpectedExecutorForLocalVar(param);
698+
}
700699
}
701700
}
702701
break;

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ bool swift::usesFlowSensitiveIsolation(AbstractFunctionDecl const *fn) {
136136
return true;
137137

138138
// construct an isolation corresponding to the type.
139-
auto actorTypeIso = ActorIsolation::forActorInstance(nominal);
139+
auto actorTypeIso = ActorIsolation::forActorInstanceSelf(nominal);
140140

141141
return requiresFlowIsolation(actorTypeIso, cast<ConstructorDecl>(fn));
142142
}
@@ -2521,7 +2521,6 @@ namespace {
25212521
return false;
25222522

25232523
// Check for isolated parameters.
2524-
Optional<unsigned> isolatedParamIdx;
25252524
for (unsigned paramIdx : range(fnType->getNumParams())) {
25262525
// We only care about isolated parameters.
25272526
if (!fnType->getParams()[paramIdx].isIsolated())
@@ -2545,8 +2544,8 @@ namespace {
25452544
KnownProtocolKind::Actor);
25462545
}
25472546

2548-
unsatisfiedIsolation = ActorIsolation::forActorInstance(nominal);
2549-
isolatedParamIdx = paramIdx;
2547+
unsatisfiedIsolation =
2548+
ActorIsolation::forActorInstanceParameter(nominal, paramIdx);
25502549
break;
25512550
}
25522551

@@ -2595,7 +2594,8 @@ namespace {
25952594

25962595
case ActorIsolation::ActorInstance:
25972596
apply->setImplicitlyAsync(
2598-
ImplicitActorHopTarget::forIsolatedParameter(*isolatedParamIdx));
2597+
ImplicitActorHopTarget::forIsolatedParameter(
2598+
unsatisfiedIsolation->getActorInstanceParameter() - 1));
25992599
break;
26002600

26012601
case ActorIsolation::Unspecified:
@@ -2847,8 +2847,12 @@ namespace {
28472847
if (partialApply && result.isolation.isGlobalActor())
28482848
return false;
28492849

2850-
// A call to a global-actor-isolated function is diagnosed elsewhere.
2851-
if (!partialApply && result.isolation.isGlobalActor() &&
2850+
// A call to a global-actor-isolated function, or a function with an
2851+
// isolated parameter, is diagnosed elsewhere.
2852+
if (!partialApply &&
2853+
(result.isolation.isGlobalActor() ||
2854+
(result.isolation == ActorIsolation::ActorInstance &&
2855+
result.isolation.getActorInstanceParameter() > 0)) &&
28522856
isa<AbstractFunctionDecl>(decl))
28532857
return false;
28542858

@@ -3654,14 +3658,45 @@ static OverrideIsolationResult validOverrideIsolation(
36543658
}
36553659
}
36563660

3661+
/// Retrieve the index of the first isolated parameter of the given
3662+
/// declaration, if there is one.
3663+
static Optional<unsigned> getIsolatedParamIndex(ValueDecl *value) {
3664+
auto params = getParameterList(value);
3665+
if (!params)
3666+
return None;
3667+
3668+
for (unsigned paramIdx : range(params->size())) {
3669+
auto param = params->get(paramIdx);
3670+
if (param->isIsolated())
3671+
return paramIdx;
3672+
}
3673+
3674+
return None;
3675+
}
3676+
36573677
ActorIsolation ActorIsolationRequest::evaluate(
36583678
Evaluator &evaluator, ValueDecl *value) const {
36593679
// If this declaration has actor-isolated "self", it's isolated to that
36603680
// actor.
36613681
if (evaluateOrDefault(evaluator, HasIsolatedSelfRequest{value}, false)) {
36623682
auto actor = value->getDeclContext()->getSelfNominalTypeDecl();
36633683
assert(actor && "could not find the actor that 'self' is isolated to");
3664-
return ActorIsolation::forActorInstance(actor);
3684+
return ActorIsolation::forActorInstanceSelf(actor);
3685+
}
3686+
3687+
// If this declaration has an isolated parameter, it's isolated to that
3688+
// parameter.
3689+
if (auto paramIdx = getIsolatedParamIndex(value)) {
3690+
// FIXME: This doesn't allow us to find an Actor or DistributedActor
3691+
// bound on the parameter type effectively.
3692+
auto param = getParameterList(value)->get(*paramIdx);
3693+
Type paramType = param->getInterfaceType();
3694+
if (paramType->isTypeParameter()) {
3695+
paramType = param->getDeclContext()->mapTypeIntoContext(paramType);
3696+
}
3697+
3698+
if (auto actor = paramType->getAnyActor())
3699+
return ActorIsolation::forActorInstanceParameter(actor, *paramIdx);
36653700
}
36663701

36673702
auto isolationFromAttr = getIsolationFromAttributes(value);
@@ -3947,6 +3982,10 @@ bool HasIsolatedSelfRequest::evaluate(
39473982
value = accessor->getStorage();
39483983
}
39493984

3985+
// If there is an isolated parameter, then "self" is not isolated.
3986+
if (getIsolatedParamIndex(value))
3987+
return false;
3988+
39503989
// Check whether this member can be isolated to an actor at all.
39513990
auto memberIsolation = getMemberIsolationPropagation(value);
39523991
if (!memberIsolation)
@@ -4950,7 +4989,7 @@ static ActorIsolation getActorIsolationForReference(
49504989
// as needing to enter the actor.
49514990
if (auto nominal = ctor->getDeclContext()->getSelfNominalTypeDecl()) {
49524991
if (nominal->isAnyActor())
4953-
return ActorIsolation::forActorInstance(nominal);
4992+
return ActorIsolation::forActorInstanceSelf(nominal);
49544993
}
49554994

49564995
// Fall through to treat initializers like any other declaration.
@@ -4966,7 +5005,7 @@ static ActorIsolation getActorIsolationForReference(
49665005
declIsolation.isIndependent()) {
49675006
if (auto nominal = var->getDeclContext()->getSelfNominalTypeDecl()) {
49685007
if (nominal->isAnyActor())
4969-
return ActorIsolation::forActorInstance(nominal);
5008+
return ActorIsolation::forActorInstanceSelf(nominal);
49705009

49715010
auto nominalIsolation = getActorIsolation(nominal);
49725011
if (nominalIsolation.isGlobalActor())
@@ -5137,7 +5176,8 @@ ActorReferenceResult ActorReferenceResult::forReference(
51375176

51385177
// The declaration we are accessing is actor-isolated. First, check whether
51395178
// we are on the same actor already.
5140-
if (actorInstance && declIsolation == ActorIsolation::ActorInstance) {
5179+
if (actorInstance && declIsolation == ActorIsolation::ActorInstance &&
5180+
declIsolation.getActorInstanceParameter() == 0) {
51415181
// If this instance is isolated, we're in the same concurrency domain.
51425182
if (actorInstance->isIsolated())
51435183
return forSameConcurrencyDomain(declIsolation);

test/Concurrency/isolated_parameters.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func testIsolatedParamCalls(a: isolated A, b: A) {
4141
globalFunc(b)
4242

4343
globalFuncIsolated(a)
44-
globalFuncIsolated(b) // expected-error{{call to actor-isolated global function 'globalFuncIsolated' in a synchronous nonisolated context}}
44+
globalFuncIsolated(b) // expected-error{{call to actor-isolated global function 'globalFuncIsolated' in a synchronous actor-isolated context}}
4545
}
4646

4747
@available(SwiftStdlib 5.1, *)
@@ -63,6 +63,7 @@ typealias MyFn = (isolated: Int) -> Void // expected-error {{function types cann
6363
typealias MyFnFixed = (_: isolated MyActor) -> Void
6464

6565
func standalone(_: isolated MyActor) {}
66+
6667
func check() {
6768
let _: MyFnFixed = standalone
6869
let _: MyFnFixed = { (_: isolated MyActor) in () }
@@ -148,6 +149,14 @@ func testExistentialIsolated(a: isolated P2, b: P2) async {
148149
// "isolated" parameters of closures make the closure itself isolated.
149150
extension TestActor {
150151
func isolatedMethod() { }
152+
// expected-note@-1{{calls to instance method 'isolatedMethod()' from outside of its actor context are implicitly asynchronous}}
153+
154+
func isolatedToParameter(_ other: isolated TestActor) {
155+
isolatedMethod()
156+
// expected-error@-1{{actor-isolated instance method 'isolatedMethod()' can not be referenced on a non-isolated actor instance}}
157+
158+
other.isolatedMethod()
159+
}
151160
}
152161

153162
@available(SwiftStdlib 5.1, *)

0 commit comments

Comments
 (0)