Skip to content

Commit a11c96a

Browse files
committed
[Executors] Ensure we treat DA older than 5.9 always as DefaultActor
1 parent 219a137 commit a11c96a

11 files changed

+178
-0
lines changed

include/swift/AST/ASTContext.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -891,6 +891,9 @@ class ASTContext final {
891891
/// Get the back-deployed availability for concurrency.
892892
AvailabilityContext getBackDeployedConcurrencyAvailability();
893893

894+
/// The the availability since when distributed actors are able to have custom executors.
895+
AvailabilityContext getConcurrencyDistributedActorWithCustomExecutorAvailability();
896+
894897
/// Get the runtime availability of support for differentiation.
895898
AvailabilityContext getDifferentiationAvailability();
896899

@@ -934,6 +937,14 @@ class ASTContext final {
934937
/// compiler for the target platform.
935938
AvailabilityContext getSwift57Availability();
936939

940+
/// Get the runtime availability of features introduced in the Swift 5.8
941+
/// compiler for the target platform.
942+
AvailabilityContext getSwift58Availability();
943+
944+
/// Get the runtime availability of features introduced in the Swift 5.9
945+
/// compiler for the target platform.
946+
AvailabilityContext getSwift59Availability();
947+
937948
// Note: Update this function if you add a new getSwiftXYAvailability above.
938949
/// Get the runtime availability for a particular version of Swift (5.0+).
939950
AvailabilityContext

include/swift/AST/Availability.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,11 @@ class AvailabilityContext {
329329
bool isAvailableAsSPI() const {
330330
return SPI && *SPI;
331331
}
332+
333+
/// Returns a representation of this range as a string for debugging purposes.
334+
std::string getAsString() const {
335+
return "AvailabilityContext(" + OSVersion.getAsString() + (isAvailableAsSPI() ? ", spi" : "") + ")";
336+
}
332337
};
333338

334339

lib/AST/Availability.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,10 @@ AvailabilityContext ASTContext::getBackDeployedConcurrencyAvailability() {
483483
return getSwift51Availability();
484484
}
485485

486+
AvailabilityContext ASTContext::getConcurrencyDistributedActorWithCustomExecutorAvailability() {
487+
return getSwift59Availability();
488+
}
489+
486490
AvailabilityContext ASTContext::getDifferentiationAvailability() {
487491
return getSwiftFutureAvailability();
488492
}
@@ -636,6 +640,28 @@ AvailabilityContext ASTContext::getSwift57Availability() {
636640
}
637641
}
638642

643+
AvailabilityContext ASTContext::getSwift58Availability() {
644+
auto target = LangOpts.Target;
645+
646+
if (target.isMacOSX()) {
647+
return AvailabilityContext(
648+
VersionRange::allGTE(llvm::VersionTuple(13, 3, 0)));
649+
} else if (target.isiOS()) {
650+
return AvailabilityContext(
651+
VersionRange::allGTE(llvm::VersionTuple(16, 4, 0)));
652+
} else if (target.isWatchOS()) {
653+
return AvailabilityContext(
654+
VersionRange::allGTE(llvm::VersionTuple(9, 4, 0)));
655+
} else {
656+
return AvailabilityContext::alwaysAvailable();
657+
}
658+
}
659+
660+
AvailabilityContext ASTContext::getSwift59Availability() {
661+
// TODO: Update Availability impl when Swift 5.9 is released
662+
return getSwiftFutureAvailability();
663+
}
664+
639665
AvailabilityContext ASTContext::getSwiftFutureAvailability() {
640666
auto target = LangOpts.Target;
641667

@@ -665,6 +691,8 @@ ASTContext::getSwift5PlusAvailability(llvm::VersionTuple swiftVersion) {
665691
case 5: return getSwift55Availability();
666692
case 6: return getSwift56Availability();
667693
case 7: return getSwift57Availability();
694+
case 8: return getSwift58Availability();
695+
case 9: return getSwift59Availability();
668696
default: break;
669697
}
670698
}

lib/SILOptimizer/Mandatory/LowerHopToActor.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,9 @@ SILValue LowerHopToActor::emitGetExecutor(SILBuilderWithScope &B,
185185
// If the actor type is a default actor, go ahead and devirtualize here.
186186
auto module = F->getModule().getSwiftModule();
187187
SILValue unmarkedExecutor;
188+
189+
// Determine if the actor is a "default actor" in which case we'll build a default
190+
// actor executor ref inline, rather than calling out to the user-provided executor function.
188191
if (isDefaultActorType(actorType, module, F->getResilienceExpansion())) {
189192
auto builtinName = ctx.getIdentifier(
190193
getBuiltinName(BuiltinValueKind::BuildDefaultActorExecutorRef));

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,27 @@ bool IsDefaultActorRequest::evaluate(
182182
if (!classDecl->isActor())
183183
return false;
184184

185+
// Distributed actors were not able to have custom executors until Swift 5.9,
186+
// so in order to avoid wrongly treating a resilient distributed actor from another
187+
// module as not-default we need to handle this case explicitly.
188+
if (classDecl->isDistributedActor()) {
189+
ASTContext &ctx = classDecl->getASTContext();
190+
auto customExecutorAvailability =
191+
ctx.getConcurrencyDistributedActorWithCustomExecutorAvailability();
192+
193+
auto actorAvailability = TypeChecker::overApproximateAvailabilityAtLocation(
194+
classDecl->getStartLoc(),
195+
classDecl);
196+
197+
if (!actorAvailability.isContainedIn(customExecutorAvailability)) {
198+
// Any 'distributed actor' declared with availability lower than the
199+
// introduction of custom executors for distributed actors, must be treated as default actor,
200+
// even if it were to declared the unowned executor property, as older compilers
201+
// do not have the the logic to handle that case.
202+
return true;
203+
}
204+
}
205+
185206
// If the class is resilient from the perspective of the module
186207
// module, it's not a default actor.
187208
if (classDecl->isForeign() || classDecl->isResilient(M, expansion))

test/Distributed/Runtime/distributed_actor_assume_executor.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ func check(actor: MainDistributedFriend) {
3939
checkAssumeMainActor(actor: actor)
4040
}
4141

42+
@available(SwiftStdlib 5.9, *)
4243
distributed actor MainDistributedFriend {
4344
nonisolated var localUnownedExecutor: UnownedSerialExecutor? {
4445
print("get unowned executor")
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/../Inputs/FakeDistributedActorSystems.swift
3+
// RUN: %target-build-swift -Xfrontend -disable-availability-checking -parse-as-library -I %t %s %S/../Inputs/FakeDistributedActorSystems.swift -o %t/a.out
4+
// RUN: %target-codesign %t/a.out
5+
// RUN: %target-run %t/a.out
6+
7+
// REQUIRES: executable_test
8+
// REQUIRES: concurrency
9+
// REQUIRES: distributed
10+
// REQUIRES: concurrency_runtime
11+
// UNSUPPORTED: back_deployment_runtime
12+
13+
// UNSUPPORTED: back_deploy_concurrency
14+
// UNSUPPORTED: use_os_stdlib
15+
// UNSUPPORTED: freestanding
16+
17+
import StdlibUnittest
18+
import Distributed
19+
import FakeDistributedActorSystems
20+
21+
@available(SwiftStdlib 5.7, *)
22+
typealias DefaultDistributedActorSystem = LocalTestingDistributedActorSystem
23+
24+
@available(SwiftStdlib 5.7, *)
25+
distributed actor FiveSevenActor_NothingExecutor {
26+
// @available(SwiftStdlib 5.9, *) // because of `localUnownedExecutor`
27+
nonisolated var localUnownedExecutor: UnownedSerialExecutor? {
28+
print("get unowned executor")
29+
return MainActor.sharedUnownedExecutor
30+
}
31+
32+
distributed func test(x: Int) async throws {
33+
print("executed: \(#function)")
34+
defer {
35+
print("done executed: \(#function)")
36+
}
37+
assumeOnMainActorExecutor {
38+
// ignore
39+
}
40+
}
41+
}
42+
43+
@available(SwiftStdlib 5.9, *)
44+
distributed actor FiveNineActor_NothingExecutor {
45+
// @available(SwiftStdlib 5.9, *) // because of `localUnownedExecutor`
46+
nonisolated var localUnownedExecutor: UnownedSerialExecutor? {
47+
print("get unowned executor")
48+
return MainActor.sharedUnownedExecutor
49+
}
50+
51+
distributed func test(x: Int) async throws {
52+
print("executed: \(#function)")
53+
defer {
54+
print("done executed: \(#function)")
55+
}
56+
assumeOnMainActorExecutor {
57+
// ignore
58+
}
59+
}
60+
}
61+
62+
@available(SwiftStdlib 5.7, *)
63+
distributed actor FiveSevenActor_FiveNineExecutor {
64+
@available(SwiftStdlib 5.9, *)
65+
nonisolated var localUnownedExecutor: UnownedSerialExecutor? {
66+
print("get unowned executor")
67+
return MainActor.sharedUnownedExecutor
68+
}
69+
70+
distributed func test(x: Int) async throws {
71+
print("executed: \(#function)")
72+
defer {
73+
print("done executed: \(#function)")
74+
}
75+
assumeOnMainActorExecutor {
76+
// ignore
77+
}
78+
}
79+
}
80+
81+
@main struct Main {
82+
static func main() async {
83+
if #available(SwiftStdlib 5.9, *) {
84+
let tests = TestSuite("DistributedActorExecutorAvailability")
85+
86+
let system = LocalTestingDistributedActorSystem()
87+
88+
tests.test("5.7 actor, no availability executor property => no custom executor") {
89+
expectCrashLater(withMessage: "Fatal error: Incorrect actor executor assumption; Expected 'MainActor' executor.")
90+
try! await FiveSevenActor_NothingExecutor(actorSystem: system).test(x: 42)
91+
}
92+
93+
tests.test("5.9 actor, no availability executor property => custom executor") {
94+
try! await FiveNineActor_NothingExecutor(actorSystem: system).test(x: 42)
95+
}
96+
97+
tests.test("5.7 actor, 5.9 executor property => no custom executor") {
98+
expectCrashLater(withMessage: "Fatal error: Incorrect actor executor assumption; Expected 'MainActor' executor.")
99+
try! await FiveSevenActor_FiveNineExecutor(actorSystem: system).test(x: 42)
100+
}
101+
102+
await runAllTestsAsync()
103+
}
104+
}
105+
}

test/Distributed/Runtime/distributed_actor_custom_executor_basic.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import FakeDistributedActorSystems
2121

2222
typealias DefaultDistributedActorSystem = FakeRoundtripActorSystem
2323

24+
@available(SwiftStdlib 5.9, *) // because conforming to the protocol... that has this field in 5.9?
2425
distributed actor Worker {
2526
nonisolated var localUnownedExecutor: UnownedSerialExecutor? {
2627
print("get unowned executor")

test/Distributed/Runtime/distributed_actor_custom_executor_from_id.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import FakeDistributedActorSystems
2121

2222
typealias DefaultDistributedActorSystem = FakeRoundtripActorSystem
2323

24+
@available(SwiftStdlib 5.9, *)
2425
distributed actor Worker {
2526
nonisolated var localUnownedExecutor: UnownedSerialExecutor? {
2627
print("get unowned 'local' executor via ID")

test/Distributed/SIL/distributed_actor_initialize_nondefault.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ typealias DefaultDistributedActorSystem = FakeRoundtripActorSystem
1313

1414
// ==== ----------------------------------------------------------------------------------------------------------------
1515

16+
@available(SwiftStdlib 5.9, *)
1617
distributed actor MyDistActor {
1718
nonisolated var localUnownedExecutor: UnownedSerialExecutor? {
1819
return MainActor.sharedUnownedExecutor

utils/availability-macros.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ SwiftStdlib 5.6:macOS 12.3, iOS 15.4, watchOS 8.5, tvOS 15.4
3434
SwiftStdlib 5.7:macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0
3535
SwiftStdlib 5.8:macOS 13.3, iOS 16.4, watchOS 9.4, tvOS 16.4
3636
SwiftStdlib 5.9:macOS 9999, iOS 9999, watchOS 9999, tvOS 9999
37+
# TODO: Also update ASTContext::getSwift59Availability when 5.9 is released
3738

3839
# Local Variables:
3940
# mode: conf-unix

0 commit comments

Comments
 (0)