Skip to content

Commit 88bb1e2

Browse files
authored
Merge pull request #36600 from DougGregor/actor-independent-closures
2 parents 687b4c8 + d7b2887 commit 88bb1e2

File tree

6 files changed

+37
-66
lines changed

6 files changed

+37
-66
lines changed

lib/Sema/TypeCheckAttr.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5614,6 +5614,10 @@ class ClosureAttributeChecker
56145614
// Nothing else to check.
56155615
}
56165616

5617+
void visitActorIndependentAttr(ActorIndependentAttr *attr) {
5618+
// Nothing else to check.
5619+
}
5620+
56175621
void visitCustomAttr(CustomAttr *attr) {
56185622
// Check whether this custom attribute is the global actor attribute.
56195623
auto globalActorAttr = evaluateOrDefault(

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 17 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,69 +1544,21 @@ namespace {
15441544
}
15451545

15461546
/// Get the actor isolation of the innermost relevant context.
1547-
ActorIsolation getInnermostIsolatedContext(const DeclContext *constDC) {
1548-
// Retrieve the actor isolation for a declaration somewhere in our
1549-
// declaration context chain and map it into our own context so that
1550-
// the types can be compared.
1551-
auto getActorIsolation = [constDC](ValueDecl *value) {
1552-
switch (auto isolation = swift::getActorIsolation(value)) {
1553-
case ActorIsolation::ActorInstance:
1554-
case ActorIsolation::Independent:
1555-
case ActorIsolation::IndependentUnsafe:
1556-
case ActorIsolation::Unspecified:
1557-
return isolation;
1558-
1559-
case ActorIsolation::GlobalActor:
1560-
case ActorIsolation::GlobalActorUnsafe:
1561-
return ActorIsolation::forGlobalActor(
1562-
constDC->mapTypeIntoContext(isolation.getGlobalActor()),
1563-
isolation == ActorIsolation::GlobalActorUnsafe);
1564-
}
1565-
};
1566-
1567-
auto dc = const_cast<DeclContext *>(constDC);
1568-
while (!dc->isModuleScopeContext()) {
1569-
if (auto closure = dyn_cast<AbstractClosureExpr>(dc)) {
1570-
// If this closure has specific isolation, use it.
1571-
auto closureIsolation = getActorIsolationOfContext(dc);
1572-
if (closureIsolation != ActorIsolation::Independent)
1573-
return closureIsolation;
1574-
1575-
// Look through non-escaping closures.
1576-
if (auto type = closure->getType()) {
1577-
if (auto fnType = type->getAs<AnyFunctionType>()) {
1578-
if (fnType->isNoEscape()) {
1579-
dc = closure->getParent();
1580-
continue;
1581-
}
1582-
}
1583-
}
1584-
}
1585-
1586-
// Functions have actor isolation defined on them.
1587-
if (auto func = dyn_cast<AbstractFunctionDecl>(dc))
1588-
return getActorIsolation(func);
1589-
1590-
// Subscripts have actor isolation defined on them.
1591-
if (auto subscript = dyn_cast<SubscriptDecl>(dc))
1592-
return getActorIsolation(subscript);
1593-
1594-
// Pattern binding declarations have actor isolation defined on their
1595-
// properties, if any.
1596-
if (auto init = dyn_cast<PatternBindingInitializer>(dc)) {
1597-
auto var = init->getBinding()->getAnchoringVarDecl(
1598-
init->getBindingIndex());
1599-
if (var)
1600-
return getActorIsolation(var);
1601-
1602-
return ActorIsolation::forUnspecified();
1603-
}
1547+
ActorIsolation getInnermostIsolatedContext(DeclContext *dc) {
1548+
// Retrieve the actor isolation of the context.
1549+
switch (auto isolation = getActorIsolationOfContext(dc)) {
1550+
case ActorIsolation::ActorInstance:
1551+
case ActorIsolation::Independent:
1552+
case ActorIsolation::IndependentUnsafe:
1553+
case ActorIsolation::Unspecified:
1554+
return isolation;
16041555

1605-
return ActorIsolation::forUnspecified();
1556+
case ActorIsolation::GlobalActor:
1557+
case ActorIsolation::GlobalActorUnsafe:
1558+
return ActorIsolation::forGlobalActor(
1559+
dc->mapTypeIntoContext(isolation.getGlobalActor()),
1560+
isolation == ActorIsolation::GlobalActorUnsafe);
16061561
}
1607-
1608-
// At module scope, actor independence with safety is assumed.
1609-
return ActorIsolation::forIndependent(ActorIndependentKind::Safe);
16101562
}
16111563

16121564
bool isInAsynchronousContext() const {
@@ -1718,7 +1670,7 @@ namespace {
17181670
bool isCrossActor,
17191671
Expr *context) {
17201672
ValueDecl *value = valueRef.getDecl();
1721-
auto declContext = getDeclContext();
1673+
auto declContext = const_cast<DeclContext *>(getDeclContext());
17221674

17231675
// Check whether we are within the same isolation context, in which
17241676
// case there is nothing further to check,
@@ -2243,6 +2195,9 @@ namespace {
22432195
AbstractClosureExpr *closure) {
22442196
// If the closure specifies a global actor, use it.
22452197
if (auto explicitClosure = dyn_cast<ClosureExpr>(closure)) {
2198+
if (explicitClosure->getAttrs().hasAttribute<ActorIndependentAttr>())
2199+
return ClosureActorIsolation::forIndependent();
2200+
22462201
if (Type globalActorType = resolveGlobalActorType(explicitClosure))
22472202
return ClosureActorIsolation::forGlobalActor(globalActorType);
22482203
}

test/Concurrency/actor_inout_isolation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ struct MyGlobalActor {
196196
// expected-note@-3{{mutation of this var is only permitted within the actor}}
197197

198198
// expected-error@+2{{actor-isolated var 'number' cannot be passed 'inout' to 'async' function call}}
199-
// expected-error@+1{{var 'number' isolated to global actor 'MyGlobalActor' can not be used 'inout' from this context}}
199+
// expected-error@+1{{var 'number' isolated to global actor 'MyGlobalActor' can not be used 'inout' from a non-isolated context}}
200200
let _ = Task.runDetached { await { (_ foo: inout Int) async in foo += 1 }(&number) }
201201

202202
// attempt to pass global state owned by the global actor to another async function

test/Concurrency/closure_isolation.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ struct SomeGlobalActor {
4545

4646
func someAsyncFunc() async { }
4747

48+
@SomeGlobalActor func getGlobal7() -> Int { 7 }
49+
4850
// CHECK-LABEL: someGlobalActorFunc
4951
@SomeGlobalActor func someGlobalActorFunc() async {
5052
// CHECK: acceptAsyncClosure
@@ -66,5 +68,4 @@ func someAsyncFunc() async { }
6668
// CHECK: closure_expr
6769
// CHECK-NOT:actor-isolated
6870
acceptEscapingAsyncClosure { () async in print("hello") }
69-
7071
}

test/Concurrency/global_actor_from_ordinary_context.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,12 @@ func callGlobalActor() {
6161

6262
func fromClosure() {
6363
{ () -> Void in
64-
// expected-error@+1 {{global function 'syncGlobActorFn()' isolated to global actor 'SomeGlobalActor' can not be referenced from this context}}
64+
// expected-error@+1 {{global function 'syncGlobActorFn()' isolated to global actor 'SomeGlobalActor' can not be referenced from a non-isolated context}}
6565
let x = syncGlobActorFn
6666
x()
6767
}()
6868

69-
// expected-error@+1 {{global function 'syncGlobActorFn()' isolated to global actor 'SomeGlobalActor' can not be referenced from this synchronous context}}
69+
// expected-error@+1 {{global function 'syncGlobActorFn()' isolated to global actor 'SomeGlobalActor' can not be referenced from a non-isolated synchronous context}}
7070
let _ = { syncGlobActorFn() }()
7171
}
7272

test/Concurrency/global_actor_inference.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,3 +426,14 @@ struct HasWrapperOnUnsafeActor {
426426
synced = 17
427427
}
428428
}
429+
430+
// ----------------------------------------------------------------------
431+
// Actor-independent closures
432+
// ----------------------------------------------------------------------
433+
@SomeGlobalActor func getGlobal7() -> Int { 7 } // expected-note{{calls to global function 'getGlobal7()' from outside of its actor context are implicitly asynchronous}}
434+
func acceptClosure<T>(_: () -> T) { }
435+
436+
@SomeGlobalActor func someGlobalActorFunc() async {
437+
acceptClosure { getGlobal7() } // okay
438+
acceptClosure { @actorIndependent in getGlobal7() } // expected-error{{global function 'getGlobal7()' isolated to global actor 'SomeGlobalActor' can not be referenced from a non-isolated synchronous context}}
439+
}

0 commit comments

Comments
 (0)