Skip to content

Commit e382459

Browse files
authored
Merge pull request #35282 from slavapestov/actor-isolation-lazy-init
AST: Fix actor isolation checking for lazy property initializers
2 parents fc05d4a + e8c0e33 commit e382459

File tree

4 files changed

+84
-18
lines changed

4 files changed

+84
-18
lines changed

include/swift/AST/ActorIsolation.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ class ActorIsolation {
152152
/// Determine how the given value declaration is isolated.
153153
ActorIsolation getActorIsolation(ValueDecl *value);
154154

155+
/// Determine how the given declaration context is isolated.
156+
ActorIsolation getActorIsolationOfContext(DeclContext *dc);
157+
155158
void simple_display(llvm::raw_ostream &out, const ActorIsolation &state);
156159

157160
} // end namespace swift

lib/AST/Decl.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7976,6 +7976,25 @@ void ClassDecl::setSuperclass(Type superclass) {
79767976
true);
79777977
}
79787978

7979+
ActorIsolation swift::getActorIsolation(ValueDecl *value) {
7980+
auto &ctx = value->getASTContext();
7981+
return evaluateOrDefault(
7982+
ctx.evaluator, ActorIsolationRequest{value},
7983+
ActorIsolation::forUnspecified());
7984+
}
7985+
7986+
ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {
7987+
if (auto *vd = dyn_cast_or_null<ValueDecl>(dc->getAsDecl()))
7988+
return getActorIsolation(vd);
7989+
7990+
if (auto *init = dyn_cast<PatternBindingInitializer>(dc)) {
7991+
if (auto *var = init->getBinding()->getSingleVar())
7992+
return getActorIsolation(var);
7993+
}
7994+
7995+
return ActorIsolation::forUnspecified();
7996+
}
7997+
79797998
ClangNode Decl::getClangNodeImpl() const {
79807999
assert(Bits.Decl.FromClang);
79818000
void * const *ptr = nullptr;

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -852,8 +852,9 @@ namespace {
852852
}
853853

854854
private:
855-
/// If the expression is a reference to `self`, return the 'self' parameter.
856-
static VarDecl *getSelfReference(Expr *expr) {
855+
/// If the expression is a reference to `self`, return the context of
856+
/// the 'self' parameter.
857+
static DeclContext *getSelfReferenceContext(Expr *expr) {
857858
// Look through identity expressions and implicit conversions.
858859
Expr *prior;
859860
do {
@@ -867,13 +868,25 @@ namespace {
867868

868869
// 'super' references always act on self.
869870
if (auto super = dyn_cast<SuperRefExpr>(expr))
870-
return super->getSelf();
871+
return super->getSelf()->getDeclContext();
871872

872873
// Declaration references to 'self'.
873874
if (auto declRef = dyn_cast<DeclRefExpr>(expr)) {
874-
if (auto var = dyn_cast<VarDecl>(declRef->getDecl()))
875+
if (auto var = dyn_cast<VarDecl>(declRef->getDecl())) {
875876
if (var->isSelfParameter())
876-
return var;
877+
return var->getDeclContext();
878+
879+
// If this is a 'self' capture in a capture list, recurse through
880+
// the capture list entry's initializer to find the original 'self'.
881+
if (var->isSelfParamCapture()) {
882+
for (auto capture : var->getParentCaptureList()->getCaptureList()) {
883+
if (capture.Var == var) {
884+
expr = capture.Init->getInit(0);
885+
return getSelfReferenceContext(expr);
886+
}
887+
}
888+
}
889+
}
877890
}
878891

879892
// Not a self reference.
@@ -1250,8 +1263,8 @@ namespace {
12501263

12511264
case ActorIsolationRestriction::ActorSelf: {
12521265
// Must reference actor-isolated state on 'self'.
1253-
auto selfVar = getSelfReference(base);
1254-
if (!selfVar) {
1266+
auto *selfDC = getSelfReferenceContext(base);
1267+
if (!selfDC) {
12551268
// actor-isolated non-self calls are implicitly async and thus OK.
12561269
if (maybeImplicitAsync && isa<AbstractFunctionDecl>(member)) {
12571270
markNearestCallAsImplicitlyAsync();
@@ -1268,8 +1281,7 @@ namespace {
12681281
}
12691282

12701283
// Check whether the context of 'self' is actor-isolated.
1271-
switch (auto contextIsolation = getActorIsolation(
1272-
cast<ValueDecl>(selfVar->getDeclContext()->getAsDecl()))) {
1284+
switch (auto contextIsolation = getActorIsolationOfContext(selfDC)) {
12731285
case ActorIsolation::ActorInstance:
12741286
// An escaping partial application of something that is part of
12751287
// the actor's isolated state is never permitted.
@@ -1312,8 +1324,7 @@ namespace {
13121324

13131325
// Check whether we are in a context that will not execute concurrently
13141326
// with the context of 'self'.
1315-
if (mayExecuteConcurrentlyWith(
1316-
getDeclContext(), selfVar->getDeclContext())) {
1327+
if (mayExecuteConcurrentlyWith(getDeclContext(), selfDC)) {
13171328
ctx.Diags.diagnose(
13181329
memberLoc, diag::actor_isolated_concurrent_access,
13191330
member->getDescriptiveKind(), member->getName());
@@ -1886,13 +1897,6 @@ ActorIsolation ActorIsolationRequest::evaluate(
18861897
return defaultIsolation;
18871898
}
18881899

1889-
ActorIsolation swift::getActorIsolation(ValueDecl *value) {
1890-
auto &ctx = value->getASTContext();
1891-
return evaluateOrDefault(
1892-
ctx.evaluator, ActorIsolationRequest{value},
1893-
ActorIsolation::forUnspecified());
1894-
}
1895-
18961900
void swift::checkOverrideActorIsolation(ValueDecl *value) {
18971901
if (isa<TypeDecl>(value))
18981902
return;

test/Concurrency/actor_isolation.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,3 +367,43 @@ func checkLocalFunctions() async {
367367

368368
print(k)
369369
}
370+
371+
// ----------------------------------------------------------------------
372+
// Lazy properties with initializers referencing 'self'
373+
// ----------------------------------------------------------------------
374+
375+
actor class LazyActor {
376+
var v: Int = 0
377+
// expected-note@-1 5 {{mutable state is only available within the actor instance}}
378+
379+
let l: Int = 0
380+
381+
lazy var l11: Int = { v }()
382+
lazy var l12: Int = v
383+
lazy var l13: Int = { self.v }()
384+
lazy var l14: Int = self.v
385+
lazy var l15: Int = { [unowned self] in self.v }()
386+
387+
lazy var l21: Int = { l }()
388+
lazy var l22: Int = l
389+
lazy var l23: Int = { self.l }()
390+
lazy var l24: Int = self.l
391+
lazy var l25: Int = { [unowned self] in self.l }()
392+
393+
@actorIndependent lazy var l31: Int = { v }()
394+
// expected-error@-1 {{actor-isolated property 'v' can not be referenced from an '@actorIndependent' context}}
395+
@actorIndependent lazy var l32: Int = v
396+
// expected-error@-1 {{actor-isolated property 'v' can not be referenced from an '@actorIndependent' context}}
397+
@actorIndependent lazy var l33: Int = { self.v }()
398+
// expected-error@-1 {{actor-isolated property 'v' can not be referenced from an '@actorIndependent' context}}
399+
@actorIndependent lazy var l34: Int = self.v
400+
// expected-error@-1 {{actor-isolated property 'v' can not be referenced from an '@actorIndependent' context}}
401+
@actorIndependent lazy var l35: Int = { [unowned self] in self.v }()
402+
// expected-error@-1 {{actor-isolated property 'v' can not be referenced from an '@actorIndependent' context}}
403+
404+
@actorIndependent lazy var l41: Int = { l }()
405+
@actorIndependent lazy var l42: Int = l
406+
@actorIndependent lazy var l43: Int = { self.l }()
407+
@actorIndependent lazy var l44: Int = self.l
408+
@actorIndependent lazy var l45: Int = { [unowned self] in self.l }()
409+
}

0 commit comments

Comments
 (0)