Skip to content

Commit bbff064

Browse files
committed
Consistently handle 'self' captures
(cherry picked from commit 3f5ee47)
1 parent e22106a commit bbff064

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
@@ -5162,6 +5162,9 @@ class VarDecl : public AbstractStorageDecl {
51625162
Bits.VarDecl.IsSelfParamCapture = IsSelfParamCapture;
51635163
}
51645164

5165+
/// Check whether this capture of the self param is actor-isolated.
5166+
bool isSelfParamCaptureIsolated() const;
5167+
51655168
/// Determines if this var has an initializer expression that should be
51665169
/// exposed to clients.
51675170
///

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"
@@ -8614,6 +8615,41 @@ void ClassDecl::setSuperclass(Type superclass) {
86148615
true);
86158616
}
86168617

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

86448680
case ClosureActorIsolation::ActorInstance: {
86458681
auto selfDecl = isolation.getActorInstance();
8646-
auto actorClass = selfDecl->getType()->getRValueType()
8682+
auto actorClass = selfDecl->getType()->getReferenceStorageReferent()
86478683
->getClassOrBoundGenericClass();
86488684
// FIXME: Doesn't work properly with generics
86498685
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)