Skip to content

Commit 3f5ee47

Browse files
committed
Consistently handle 'self' captures
1 parent 13de9d6 commit 3f5ee47

File tree

6 files changed

+91
-26
lines changed

6 files changed

+91
-26
lines changed

include/swift/AST/CaptureInfo.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ namespace swift {
3636
class ValueDecl;
3737
class FuncDecl;
3838
class OpaqueValueExpr;
39-
class ParamDecl;
39+
class VarDecl;
4040

4141
/// CapturedValue includes both the declaration being captured, along with flags
4242
/// that indicate how it is captured.
@@ -220,8 +220,10 @@ class CaptureInfo {
220220
return StorageAndFlags.getPointer()->getOpaqueValue();
221221
}
222222

223-
/// Retrieve the isolated parameter that has been captured, if there is one.
224-
ParamDecl *getIsolatedParamCapture() const;
223+
/// Retrieve the variable corresponding to an isolated parameter that has
224+
/// been captured, if there is one. This might be a capture variable
225+
/// that was initialized with an isolated parameter.
226+
VarDecl *getIsolatedParamCapture() const;
225227

226228
SWIFT_DEBUG_DUMP;
227229
void print(raw_ostream &OS) const;

include/swift/AST/Decl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5135,6 +5135,9 @@ class VarDecl : public AbstractStorageDecl {
51355135
Bits.VarDecl.IsSelfParamCapture = IsSelfParamCapture;
51365136
}
51375137

5138+
/// Check whether this capture of the self param is actor-isolated.
5139+
bool isSelfParamCaptureIsolated() const;
5140+
51385141
/// Determines if this var has an initializer expression that should be
51395142
/// exposed to clients.
51405143
///

lib/AST/CaptureInfo.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ getLocalCaptures(SmallVectorImpl<CapturedValue> &Result) const {
7878
}
7979
}
8080

81-
ParamDecl *CaptureInfo::getIsolatedParamCapture() const {
81+
VarDecl *CaptureInfo::getIsolatedParamCapture() const {
8282
if (!hasLocalCaptures())
8383
return nullptr;
8484

@@ -89,13 +89,18 @@ ParamDecl *CaptureInfo::getIsolatedParamCapture() const {
8989
if (capture.isDynamicSelfMetadata())
9090
continue;
9191

92-
auto param = dyn_cast_or_null<ParamDecl>(capture.getDecl());
93-
if (!param)
94-
continue;
95-
96-
// If we have captured an isolated parameter, return it.
97-
if (param->isIsolated())
98-
return param;
92+
// If we captured an isolated parameter, return it.
93+
if (auto param = dyn_cast_or_null<ParamDecl>(capture.getDecl())) {
94+
// If we have captured an isolated parameter, return it.
95+
if (param->isIsolated())
96+
return param;
97+
}
98+
99+
// If we captured 'self', check whether it is (still) isolated.
100+
if (auto var = dyn_cast_or_null<VarDecl>(capture.getDecl())) {
101+
if (var->isSelfParamCapture() && var->isSelfParamCaptureIsolated())
102+
return var;
103+
}
99104
}
100105

101106
return nullptr;

lib/AST/Decl.cpp

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/AST/ASTContext.h"
2121
#include "swift/AST/ASTWalker.h"
2222
#include "swift/AST/ASTMangler.h"
23+
#include "swift/AST/CaptureInfo.h"
2324
#include "swift/AST/DiagnosticEngine.h"
2425
#include "swift/AST/DiagnosticsSema.h"
2526
#include "swift/AST/ExistentialLayout.h"
@@ -8609,6 +8610,41 @@ void ClassDecl::setSuperclass(Type superclass) {
86098610
true);
86108611
}
86118612

8613+
bool VarDecl::isSelfParamCaptureIsolated() const {
8614+
assert(isSelfParamCapture());
8615+
8616+
// Find the "self" parameter that we captured and determine whether
8617+
// it is potentially isolated.
8618+
for (auto dc = getDeclContext(); dc; dc = dc->getParent()) {
8619+
if (auto func = dyn_cast<AbstractFunctionDecl>(dc)) {
8620+
if (auto selfDecl = func->getImplicitSelfDecl()) {
8621+
return selfDecl->isIsolated();
8622+
}
8623+
8624+
if (auto capture = func->getCaptureInfo().getIsolatedParamCapture())
8625+
return capture->isSelfParameter() || capture->isSelfParamCapture();
8626+
}
8627+
8628+
if (auto closure = dyn_cast<AbstractClosureExpr>(dc)) {
8629+
switch (auto isolation = closure->getActorIsolation()) {
8630+
case ClosureActorIsolation::Independent:
8631+
case ClosureActorIsolation::GlobalActor:
8632+
return false;
8633+
8634+
case ClosureActorIsolation::ActorInstance:
8635+
auto isolatedVar = isolation.getActorInstance();
8636+
return isolatedVar->isSelfParameter() ||
8637+
isolatedVar-isSelfParamCapture();
8638+
}
8639+
}
8640+
8641+
if (dc->isModuleScopeContext() || dc->isTypeContext())
8642+
break;
8643+
}
8644+
8645+
return false;
8646+
}
8647+
86128648
ActorIsolation swift::getActorIsolation(ValueDecl *value) {
86138649
auto &ctx = value->getASTContext();
86148650
return evaluateOrDefault(
@@ -8638,7 +8674,7 @@ ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {
86388674

86398675
case ClosureActorIsolation::ActorInstance: {
86408676
auto selfDecl = isolation.getActorInstance();
8641-
auto actorClass = selfDecl->getType()->getRValueType()
8677+
auto actorClass = selfDecl->getType()->getReferenceStorageReferent()
86428678
->getClassOrBoundGenericClass();
86438679
// FIXME: Doesn't work properly with generics
86448680
assert(actorClass && "Bad closure actor isolation?");

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4328,20 +4328,10 @@ bool swift::isPotentiallyIsolatedActor(
43284328
if (auto param = dyn_cast<ParamDecl>(var))
43294329
return isIsolated(param);
43304330

4331-
if (var->isSelfParamCapture()) {
4332-
// Find the "self" parameter that we captured and determine whether
4333-
// it is potentially isolated.
4334-
for (auto dc = var->getDeclContext(); dc; dc = dc->getParent()) {
4335-
if (auto func = dyn_cast<AbstractFunctionDecl>(dc)) {
4336-
if (auto selfDecl = func->getImplicitSelfDecl()) {
4337-
return selfDecl->isIsolated();
4338-
}
4339-
}
4340-
4341-
if (dc->isModuleScopeContext() || dc->isTypeContext())
4342-
break;
4343-
}
4344-
}
4331+
// If this is a captured 'self', check whether the original 'self' is
4332+
// isolated.
4333+
if (var->isSelfParamCapture())
4334+
return var->isSelfParamCaptureIsolated();
43454335

43464336
return false;
43474337
}

test/Concurrency/actor_isolation.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,35 @@ func f() {
589589
}
590590
}
591591

592+
// ----------------------------------------------------------------------
593+
// Local function isolation restrictions
594+
// ----------------------------------------------------------------------
595+
@available(SwiftStdlib 5.1, *)
596+
actor AnActorWithClosures {
597+
var counter: Int = 0 // expected-note 2 {{mutation of this property is only permitted within the actor}}
598+
func exec() {
599+
acceptEscapingClosure { [unowned self] in
600+
self.counter += 1
601+
602+
acceptEscapingClosure {
603+
self.counter += 1
604+
605+
acceptEscapingClosure { [self] in
606+
self.counter += 1
607+
}
608+
609+
acceptConcurrentClosure { [self] in
610+
self.counter += 1 // expected-error{{actor-isolated property 'counter' can not be mutated from a Sendable closure}}
611+
612+
acceptEscapingClosure {
613+
self.counter += 1 // expected-error{{actor-isolated property 'counter' can not be mutated from a non-isolated context}}
614+
}
615+
}
616+
}
617+
}
618+
}
619+
}
620+
592621
// ----------------------------------------------------------------------
593622
// Local function isolation restrictions
594623
// ----------------------------------------------------------------------

0 commit comments

Comments
 (0)