Skip to content

Commit 941fc8d

Browse files
authored
Merge pull request #41685 from DougGregor/isolated-match-may-not-execute-concurrently
2 parents 1ab41bf + 70fa3df commit 941fc8d

File tree

3 files changed

+60
-4
lines changed

3 files changed

+60
-4
lines changed

include/swift/AST/ActorIsolation.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,19 @@ class ActorIsolation {
109109

110110
bool isIndependent() const { return kind == Independent; }
111111

112+
bool isActorIsolated() const {
113+
switch (getKind()) {
114+
case ActorInstance:
115+
case GlobalActor:
116+
case GlobalActorUnsafe:
117+
return true;
118+
119+
case Unspecified:
120+
case Independent:
121+
return false;
122+
}
123+
}
124+
112125
NominalTypeDecl *getActor() const {
113126
assert(getKind() == ActorInstance);
114127
return actor;

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3059,6 +3059,21 @@ namespace {
30593059

30603060
bool ActorIsolationChecker::mayExecuteConcurrentlyWith(
30613061
const DeclContext *useContext, const DeclContext *defContext) {
3062+
// Fast path for when the use and definition contexts are the same.
3063+
if (useContext == defContext)
3064+
return false;
3065+
3066+
// If both contexts are isolated to the same actor, then they will not
3067+
// execute concurrently.
3068+
auto useIsolation = getActorIsolationOfContext(
3069+
const_cast<DeclContext *>(useContext));
3070+
if (useIsolation.isActorIsolated()) {
3071+
auto defIsolation = getActorIsolationOfContext(
3072+
const_cast<DeclContext *>(defContext));
3073+
if (useIsolation == defIsolation)
3074+
return false;
3075+
}
3076+
30623077
// Walk the context chain from the use to the definition.
30633078
while (useContext != defContext) {
30643079
// If we find a concurrent closure... it can be run concurrently.

test/Concurrency/actor_isolation.swift

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,31 +1109,59 @@ actor MyServer : Server {
11091109
// ----------------------------------------------------------------------
11101110
// @_inheritActorContext
11111111
// ----------------------------------------------------------------------
1112+
@available(SwiftStdlib 5.1, *)
11121113
func acceptAsyncSendableClosure<T>(_: @Sendable () async -> T) { }
1114+
@available(SwiftStdlib 5.1, *)
11131115
func acceptAsyncSendableClosureInheriting<T>(@_inheritActorContext _: @Sendable () async -> T) { }
11141116

11151117
@available(SwiftStdlib 5.1, *)
11161118
extension MyActor {
11171119
func testSendableAndInheriting() {
1120+
var counter = 0
1121+
11181122
acceptAsyncSendableClosure {
1119-
synchronous() // expected-error{{expression is 'async' but is not marked with 'await'}}
1123+
_ = synchronous() // expected-error{{expression is 'async' but is not marked with 'await'}}
11201124
// expected-note@-1{{calls to instance method 'synchronous()' from outside of its actor context are implicitly asynchronous}}
1125+
1126+
counter += 1 // expected-error{{mutation of captured var 'counter' in concurrently-executing code}}
11211127
}
11221128

11231129
acceptAsyncSendableClosure {
1124-
await synchronous() // ok
1130+
_ = await synchronous() // ok
1131+
counter += 1 // expected-error{{mutation of captured var 'counter' in concurrently-executing code}}
11251132
}
11261133

11271134
acceptAsyncSendableClosureInheriting {
1128-
synchronous() // okay
1135+
_ = synchronous() // okay
1136+
counter += 1 // okay
11291137
}
11301138

11311139
acceptAsyncSendableClosureInheriting {
1132-
await synchronous() // expected-warning{{no 'async' operations occur within 'await' expression}}
1140+
_ = await synchronous() // expected-warning{{no 'async' operations occur within 'await' expression}}
1141+
counter += 1 // okay
11331142
}
11341143
}
11351144
}
11361145

1146+
@available(SwiftStdlib 5.1, *)
1147+
@SomeGlobalActor
1148+
func testGlobalActorInheritance() {
1149+
var counter = 0
1150+
1151+
acceptAsyncSendableClosure {
1152+
counter += 1 // expected-error{{mutation of captured var 'counter' in concurrently-executing code}}
1153+
}
1154+
1155+
acceptAsyncSendableClosure { @SomeGlobalActor in
1156+
counter += 1 // ok
1157+
}
1158+
1159+
1160+
acceptAsyncSendableClosureInheriting {
1161+
counter += 1 // ok
1162+
}
1163+
}
1164+
11371165
@available(SwiftStdlib 5.1, *)
11381166
@MainActor // expected-note {{'GloballyIsolatedProto' is isolated to global actor 'MainActor' here}}
11391167
protocol GloballyIsolatedProto {

0 commit comments

Comments
 (0)