Skip to content

Commit bacc5bf

Browse files
committed
[Distributed] make witness be the distributed thunk
1 parent 0dae896 commit bacc5bf

8 files changed

+244
-9
lines changed

lib/SIL/IR/SILDeclRef.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,6 +1052,8 @@ bool SILDeclRef::requiresNewVTableEntry() const {
10521052
return true;
10531053
if (!hasDecl())
10541054
return false;
1055+
// if (isDistributedThunk())
1056+
// return false;
10551057
if (isBackDeploymentThunk())
10561058
return false;
10571059
auto fnDecl = dyn_cast<AbstractFunctionDecl>(getDecl());

lib/SILGen/SILGenPoly.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4442,12 +4442,14 @@ void SILGenFunction::emitProtocolWitness(
44424442
// If the witness is isolated to a distributed actor, but the requirement is
44434443
// not, go through the distributed thunk.
44444444
if (witness.hasDecl() &&
4445-
getActorIsolation(witness.getDecl()).isDistributedActor() &&
4446-
requirement.hasDecl() &&
4447-
!getActorIsolation(requirement.getDecl()).isDistributedActor()) {
4448-
witness = SILDeclRef(
4449-
cast<AbstractFunctionDecl>(witness.getDecl())->getDistributedThunk())
4450-
.asDistributed();
4445+
getActorIsolation(witness.getDecl()).isDistributedActor()) {
4446+
if ((requirement.hasDecl() && !getActorIsolation(requirement.getDecl()).isDistributedActor()) ||
4447+
(requirement.hasDecl() && isa<FuncDecl>(requirement.getDecl()) && witness.getFuncDecl()->isDistributed())) {
4448+
fprintf(stderr, "[%s:%d] (%s) witness thunk\n", __FILE__, __LINE__, __FUNCTION__);
4449+
auto thunk = cast<AbstractFunctionDecl>(witness.getDecl())->getDistributedThunk();
4450+
thunk->dump();
4451+
witness = SILDeclRef(thunk) .asDistributed();
4452+
}
44514453
} else if (enterIsolation) {
44524454
// If we are supposed to enter the actor, do so now by hopping to the
44534455
// actor.

lib/Sema/CodeSynthesisDistributedActor.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -648,8 +648,13 @@ static FuncDecl *createDistributedThunkFunction(FuncDecl *func) {
648648
auto &C = func->getASTContext();
649649
auto DC = func->getDeclContext();
650650

651-
auto systemTy = getConcreteReplacementForProtocolActorSystemType(func);
652-
assert(systemTy &&
651+
// NOTE: So we don't need a thunk in the protocol, we should call the underlying
652+
// thing instead, which MUST have a thunk, since it must be a distributed func as well...
653+
if (dyn_cast<ProtocolDecl>(DC)) {
654+
return nullptr;
655+
}
656+
657+
assert(getConcreteReplacementForProtocolActorSystemType(func) &&
653658
"Thunk synthesis must have concrete actor system type available");
654659

655660
DeclName thunkName = func->getName();

lib/Sema/TypeCheckDistributed.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,11 @@ bool CheckDistributedFunctionRequest::evaluate(
503503
serializationRequirements = getDistributedSerializationRequirementProtocols(
504504
getDistributedActorSystemType(actor)->getAnyNominal(),
505505
C.getProtocol(KnownProtocolKind::DistributedActorSystem));
506+
} else if (auto proto = dyn_cast<ProtocolDecl>(DC)) {
507+
// FIXME: if it has a n AS defined, we can do checks based on that, otherwise, don't
508+
return false;
506509
} else {
510+
func->dump();
507511
llvm_unreachable("Cannot handle types other than extensions and actor "
508512
"declarations in distributed function checking.");
509513
}

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1401,9 +1401,25 @@ bool WitnessChecker::findBestWitness(
14011401
attempt = static_cast<Attempt>(attempt + 1)) {
14021402
SmallVector<ValueDecl *, 4> witnesses;
14031403
switch (attempt) {
1404-
case Regular:
1404+
case Regular: {
14051405
witnesses = lookupValueWitnesses(requirement, ignoringNames);
1406+
1407+
// ValueDecl* thunk = nullptr;
1408+
// for (auto witness : witnesses) {
1409+
// if (auto func = dyn_cast<FuncDecl>(witness)) {
1410+
// if (func->isDistributed()) {
1411+
// thunk = func->getDistributedThunk();
1412+
// fprintf(stderr, "[%s:%d] (%s) ALSO CONSIDER THUNK!!!\n", __FILE__, __LINE__, __FUNCTION__);
1413+
// }
1414+
// }
1415+
// }
1416+
// if (thunk) {
1417+
// witnesses.clear();
1418+
// witnesses.push_back(thunk);
1419+
// }
1420+
14061421
break;
1422+
}
14071423
case OperatorsFromOverlay: {
14081424
// If we have a Clang declaration, the matching operator might be in the
14091425
// overlay for that module.
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
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 -module-name main -Xfrontend -disable-availability-checking -j2 -parse-as-library -I %t %s %S/../Inputs/FakeDistributedActorSystems.swift -o %t/a.out
4+
// RUN: %target-run %t/a.out | %FileCheck %s --color --dump-input=always
5+
6+
// REQUIRES: executable_test
7+
// REQUIRES: concurrency
8+
// REQUIRES: distributed
9+
10+
// rdar://76038845
11+
// UNSUPPORTED: use_os_stdlib
12+
// UNSUPPORTED: back_deployment_runtime
13+
14+
// FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574
15+
// UNSUPPORTED: OS=windows-msvc
16+
17+
import Distributed
18+
import FakeDistributedActorSystems
19+
20+
21+
typealias DefaultDistributedActorSystem = FakeRoundtripActorSystem
22+
23+
protocol DistributedWorker: DistributedActor where ActorSystem == DefaultDistributedActorSystem {
24+
associatedtype WorkItem: Sendable & Codable
25+
associatedtype WorkResult: Sendable & Codable
26+
27+
distributed func submit(work: WorkItem) async throws -> WorkResult
28+
29+
func sync(work: WorkItem) -> WorkResult
30+
}
31+
32+
distributed actor TheWorker: DistributedWorker {
33+
typealias ActorSystem = DefaultDistributedActorSystem
34+
typealias WorkItem = String
35+
typealias WorkResult = String
36+
37+
distributed func submit(work: WorkItem) async throws -> WorkResult {
38+
"\(Self.self) echo: \(work)"
39+
}
40+
41+
func sync(work: WorkItem) -> WorkResult {
42+
return "SYNC: \(work)"
43+
}
44+
}
45+
46+
func test() async throws {
47+
let system = DefaultDistributedActorSystem()
48+
49+
let w = TheWorker(actorSystem: system)
50+
let remoteW = try! TheWorker.resolve(id: w.id, using: system)
51+
print("remoteW is remote: \(__isRemoteActor(remoteW))")
52+
// CHECK: remoteW is remote: true
53+
54+
// direct calls work ok:
55+
let replyDirect = try await remoteW.submit(work: "Direct")
56+
print("reply direct: \(replyDirect)")
57+
// CHECK: >> remoteCall: on:main.TheWorker, target:main.TheWorker.submit(work:), invocation:FakeInvocationEncoder(genericSubs: [], arguments: ["Direct"], returnType: Optional(Swift.String), errorType: Optional(Swift.Error)), throwing:Swift.Error, returning:Swift.String
58+
// CHECK: reply direct: TheWorker echo: Direct
59+
60+
print("==== ---------------------------------------------------")
61+
62+
func callWorker<W: DistributedWorker>(w: W) async throws -> String where W.WorkItem == String, W.WorkResult == String {
63+
try await w.submit(work: "Hello")
64+
}
65+
let reply = try await callWorker(w: remoteW)
66+
67+
print("reply: \(reply)")
68+
// CHECK: >> remoteCall: on:main.TheWorker, target:main.TheWorker.submit(work:), invocation:FakeInvocationEncoder(genericSubs: [], arguments: ["Hello"], returnType: Optional(Swift.String), errorType: Optional(Swift.Error)), throwing:Swift.Error, returning:Swift.String
69+
// CHECK: << remoteCall return: TheWorker echo: Hello
70+
// CHECK: reply: TheWorker echo: Hello
71+
72+
// ----------
73+
let replySyncRemote = await remoteW.whenLocal { __secretlyKnownToBeLocal in
74+
__secretlyKnownToBeLocal.sync(work: "test")
75+
}
76+
print("reply sync (remote): \(replySyncRemote)")
77+
// CHECK: reply sync (remote): nil
78+
79+
let replySyncLocal = await w.whenLocal { __secretlyKnownToBeLocal in
80+
__secretlyKnownToBeLocal.sync(work: "test")
81+
}
82+
print("reply sync (local): \(replySyncLocal)")
83+
// CHECK: reply sync (local): Optional("SYNC: test")
84+
}
85+
86+
@main struct Main {
87+
static func main() async {
88+
try! await test()
89+
}
90+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
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 -module-name main -Xfrontend -disable-availability-checking -j2 -parse-as-library -I %t %s %S/../Inputs/FakeDistributedActorSystems.swift -o %t/a.out
4+
// RUN: %target-run %t/a.out | %FileCheck %s --color --dump-input=always
5+
6+
// REQUIRES: executable_test
7+
// REQUIRES: concurrency
8+
// REQUIRES: distributed
9+
10+
// rdar://76038845
11+
// UNSUPPORTED: use_os_stdlib
12+
// UNSUPPORTED: back_deployment_runtime
13+
14+
// FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574
15+
// UNSUPPORTED: OS=windows-msvc
16+
17+
import Distributed
18+
import FakeDistributedActorSystems
19+
20+
21+
typealias DefaultDistributedActorSystem = FakeRoundtripActorSystem
22+
23+
protocol DistributedWorker: DistributedActor where ActorSystem == DefaultDistributedActorSystem {
24+
associatedtype WorkItem: Sendable & Codable
25+
associatedtype WorkResult: Sendable & Codable
26+
27+
distributed func submit(work: WorkItem) async throws -> WorkResult
28+
}
29+
30+
distributed actor TheWorker: DistributedWorker {
31+
typealias ActorSystem = DefaultDistributedActorSystem
32+
typealias WorkItem = String
33+
typealias WorkResult = String
34+
35+
distributed func submit(work: WorkItem) -> WorkResult {
36+
"\(Self.self) echo: \(work)"
37+
}
38+
}
39+
40+
func test() async throws {
41+
let system = DefaultDistributedActorSystem()
42+
43+
let w = TheWorker(actorSystem: system)
44+
let remoteW = try! TheWorker.resolve(id: w.id, using: system)
45+
print("remoteW is remote: \(__isRemoteActor(remoteW))")
46+
// CHECK: remoteW is remote: true
47+
48+
// direct calls work ok:
49+
let replyDirect = try await remoteW.submit(work: "Direct")
50+
print("reply direct: \(replyDirect)")
51+
// CHECK: >> remoteCall: on:main.TheWorker, target:main.TheWorker.submit(work:), invocation:FakeInvocationEncoder(genericSubs: [], arguments: ["Direct"], returnType: Optional(Swift.String), errorType: nil), throwing:Swift.Never, returning:Swift.String
52+
// CHECK: reply direct: TheWorker echo: Direct
53+
54+
print("==== ---------------------------------------------------")
55+
56+
func callWorker<W: DistributedWorker>(w: W) async throws -> String where W.WorkItem == String, W.WorkResult == String {
57+
try await w.submit(work: "Hello")
58+
}
59+
let reply = try await callWorker(w: remoteW)
60+
print("reply: \(reply)")
61+
// CHECK: >> remoteCall: on:main.TheWorker, target:main.TheWorker.submit(work:), invocation:FakeInvocationEncoder(genericSubs: [], arguments: ["Hello"], returnType: Optional(Swift.String), errorType: nil), throwing:Swift.Never, returning:Swift.String
62+
// CHECK: << remoteCall return: TheWorker echo: Hello
63+
// CHECK: reply: TheWorker echo: Hello
64+
}
65+
66+
@main struct Main {
67+
static func main() async {
68+
try! await test()
69+
}
70+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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-swift-frontend -typecheck -verify -disable-availability-checking -I %t 2>&1 %s
4+
// REQUIRES: concurrency
5+
// REQUIRES: distributed
6+
7+
import Distributed
8+
import FakeDistributedActorSystems
9+
10+
@available(SwiftStdlib 5.5, *)
11+
typealias DefaultDistributedActorSystem = FakeActorSystem
12+
13+
import Distributed
14+
15+
protocol DistributedWorker: DistributedActor {
16+
associatedtype WorkItem: Sendable & Codable
17+
associatedtype WorkResult: Sendable & Codable
18+
19+
distributed func submit(work: WorkItem) async throws -> WorkResult
20+
}
21+
22+
distributed actor TheWorker: DistributedWorker {
23+
typealias ActorSystem = FakeActorSystem
24+
typealias WorkItem = String
25+
typealias WorkResult = String
26+
27+
distributed func submit(work: WorkItem) async throws -> WorkResult {
28+
work
29+
}
30+
}
31+
32+
distributed actor WorkerPool<Worker: DistributedWorker> {
33+
typealias ActorSystem = FakeActorSystem
34+
typealias WorkItem = Worker.WorkItem
35+
typealias WorkResult = Worker.WorkResult
36+
37+
func submit(work: WorkItem) async throws -> WorkResult {
38+
let worker = try await self.selectWorker()
39+
return try await worker.submit(work: work)
40+
// return try await TheWorker(actorSystem: actorSystem).submit(work: "X")
41+
}
42+
43+
func selectWorker() async throws -> Worker {
44+
fatalError()
45+
}
46+
}

0 commit comments

Comments
 (0)