Skip to content

Commit 2b1290d

Browse files
committed
[Distributed] Accessor must be available cross module in resilient mode
This is an important fix for libraries using @resolvable in resilient libraries. Without the fix we're missing an accessor and this will fail some remote calls which make use of remote calls on resolvable protocols. This would manifest as missing accessor error thrown by the executeDistributedTarget function. resolves rdar://148224780
1 parent 562d7dc commit 2b1290d

File tree

3 files changed

+265
-8
lines changed

3 files changed

+265
-8
lines changed

lib/IRGen/GenMeta.cpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,15 +1071,13 @@ namespace {
10711071
SILDeclRef func(entry.getFunction());
10721072

10731073
/// Distributed thunks don't need resilience.
1074-
if (func.isDistributedThunk()) {
1075-
continue;
1074+
if (!func.isDistributedThunk()) {
1075+
auto *descriptor =
1076+
B.getAddrOfCurrentPosition(
1077+
IGM.ProtocolRequirementStructTy);
1078+
IGM.defineMethodDescriptor(func, Proto, descriptor,
1079+
IGM.ProtocolRequirementStructTy);
10761080
}
1077-
1078-
auto *descriptor =
1079-
B.getAddrOfCurrentPosition(
1080-
IGM.ProtocolRequirementStructTy);
1081-
IGM.defineMethodDescriptor(func, Proto, descriptor,
1082-
IGM.ProtocolRequirementStructTy);
10831081
}
10841082
}
10851083

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -target %target-swift-6.0-abi-triple %S/../Inputs/FakeDistributedActorSystems.swift -plugin-path %swift-plugin-dir
3+
// RUN: %target-build-swift -module-name ActorsFramework -target %target-swift-6.0-abi-triple -j2 -parse-as-library -I %t %s %S/../Inputs/FakeDistributedActorSystems.swift -plugin-path %swift-plugin-dir -o %t/a.out
4+
// RUN: %target-codesign %t/a.out
5+
// RUN: %env-SWIFT_DUMP_ACCESSIBLE_FUNCTIONS=true %target-run %t/a.out 2>&1 | %FileCheck %s --color --dump-input=always
6+
7+
// REQUIRES: executable_test
8+
// REQUIRES: concurrency
9+
// REQUIRES: distributed
10+
11+
// rdar://76038845
12+
// UNSUPPORTED: use_os_stdlib
13+
// UNSUPPORTED: back_deployment_runtime
14+
15+
// FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574
16+
// UNSUPPORTED: OS=windows-msvc
17+
18+
import Distributed
19+
import FakeDistributedActorSystems
20+
21+
// ==== Known actor system -----------------------------------------------------
22+
23+
public struct Response: Codable, Sendable {
24+
let resp: Int
25+
public init(resp: Int) {
26+
self.resp = resp
27+
}
28+
}
29+
30+
public struct Provider: Codable, Sendable {
31+
let r1: Int
32+
public init(r1: Int) {
33+
self.r1 = r1
34+
}
35+
}
36+
37+
@Resolvable
38+
public protocol DistributedNotificationService: DistributedActor
39+
where ActorSystem == FakeRoundtripActorSystem {
40+
distributed func getArray(a1: [Int], a2: String?) async throws -> [Response]
41+
}
42+
43+
distributed actor DistributedNotificationServiceImpl: DistributedNotificationService {
44+
typealias ActorSystem = FakeRoundtripActorSystem
45+
46+
distributed func getArray(a1: [Int], a2: String?) async throws -> [Response] {
47+
[] // mock impl is enough
48+
}
49+
}
50+
51+
// ==== ------------------------------------------------------------------------
52+
53+
@main struct Main {
54+
static func main() async throws {
55+
let roundtripSystem = FakeRoundtripActorSystem()
56+
57+
let real: any DistributedNotificationService = DistributedNotificationServiceImpl(
58+
actorSystem: roundtripSystem)
59+
60+
let proxy: any DistributedNotificationService =
61+
try $DistributedNotificationService.resolve(id: real.id, using: roundtripSystem)
62+
_ = try await proxy.getArray(a1: [], a2: "")
63+
64+
// CHECK: ==== Accessible Function Records ====
65+
66+
// CHECK: Record name: $s15ActorsFramework30DistributedNotificationServicePAA0C001_C9ActorStubRzrlE8getArray2a12a2SayAA8ResponseVGSaySiG_SSSgtYaKFTE
67+
// CHECK: Demangled: distributed thunk (extension in ActorsFramework):ActorsFramework.DistributedNotificationService< where A: Distributed._DistributedActorStub>.getArray(a1: Swift.Array<Swift.Int>, a2: Swift.Optional<Swift.String>) async throws -> Swift.Array<ActorsFramework.Response>
68+
// CHECK: Function Ptr: [[PTR:0x.*]]
69+
// CHECK: Flags.IsDistributed: 1
70+
71+
// CHECK: Record name: $s15ActorsFramework34DistributedNotificationServiceImplC8getArray2a12a2SayAA8ResponseVGSaySiG_SSSgtYaKFTE
72+
// CHECK: Demangled: distributed thunk ActorsFramework.DistributedNotificationServiceImpl.getArray(a1: Swift.Array<Swift.Int>, a2: Swift.Optional<Swift.String>) async throws -> Swift.Array<ActorsFramework.Response>
73+
// CHECK: Function Ptr: [[PTR:0x.*]]
74+
// CHECK: Flags.IsDistributed: 1
75+
76+
// CHECK: Record name: $s15ActorsFramework31$DistributedNotificationServiceC8getArray2a12a2SayAA8ResponseVGSaySiG_SSSgtYaKFTE
77+
// CHECK: Demangled: distributed thunk ActorsFramework.$DistributedNotificationService.getArray(a1: Swift.Array<Swift.Int>, a2: Swift.Optional<Swift.String>) async throws -> Swift.Array<ActorsFramework.Response>
78+
// CHECK: Function Ptr: [[PTR:0x.*]]
79+
// CHECK: Flags.IsDistributed: 1
80+
81+
// CHECK: Record count: 3
82+
// CHECK: ==== End of Accessible Function Records ====
83+
}
84+
}
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
// RUN: %empty-directory(%t/src)
2+
// RUN: split-file %s %t/src
3+
4+
/// Build the fake actor systems lib
5+
// RUN: %target-build-swift \
6+
// RUN: -target %target-swift-6.0-abi-triple \
7+
// RUN: -parse-as-library -emit-library \
8+
// RUN: -emit-module-path %t/FakeDistributedActorSystems.swiftmodule \
9+
// RUN: -module-name FakeDistributedActorSystems \
10+
// RUN: %S/../Inputs/FakeDistributedActorSystems.swift \
11+
// RUN: -enable-library-evolution \
12+
// RUN: -Xfrontend -validate-tbd-against-ir=none \
13+
// RUN: -o %t/%target-library-name(FakeDistributedActorSystems)
14+
15+
/// Build the Lib
16+
// RUN: %target-build-swift \
17+
// RUN: -target %target-swift-6.0-abi-triple \
18+
// RUN: -parse-as-library -emit-library \
19+
// RUN: -emit-module-path %t/ResilientAPILib.swiftmodule \
20+
// RUN: -module-name ResilientAPILib \
21+
// RUN: -I %t \
22+
// RUN: -L %t \
23+
// RUN: -plugin-path %swift-plugin-dir \
24+
// RUN: %t/src/ResilientAPILib.swift \
25+
// RUN: -lFakeDistributedActorSystems \
26+
// RUN: -Xfrontend -validate-tbd-against-ir=none \
27+
// RUN: -enable-library-evolution \
28+
// RUN: -o %t/%target-library-name(ResilientAPILib)
29+
30+
/// Build the ActorLib
31+
// RUN: %target-build-swift \
32+
// RUN: -target %target-swift-6.0-abi-triple \
33+
// RUN: -parse-as-library -emit-library \
34+
// RUN: -emit-module-path %t/ResilientImplLib.swiftmodule \
35+
// RUN: -module-name ResilientImplLib \
36+
// RUN: -I %t \
37+
// RUN: -L %t \
38+
// RUN: %t/src/ResilientImplLib.swift \
39+
// RUN: -lFakeDistributedActorSystems \
40+
// RUN: -lResilientAPILib \
41+
// RUN: -enable-library-evolution \
42+
// RUN: -Xfrontend -validate-tbd-against-ir=none \
43+
// RUN: -o %t/%target-library-name(ResilientImplLib)
44+
45+
/// Build the client
46+
// RUN: %target-build-swift \
47+
// RUN: -target %target-swift-6.0-abi-triple \
48+
// RUN: -parse-as-library \
49+
// RUN: -lFakeDistributedActorSystems \
50+
// RUN: -lResilientAPILib \
51+
// RUN: -lResilientImplLib \
52+
// RUN: -module-name main \
53+
// RUN: -I %t \
54+
// RUN: -L %t \
55+
// RUN: %s \
56+
// RUN: -Xfrontend -validate-tbd-against-ir=none \
57+
// RUN: -enable-library-evolution \
58+
// RUN: -o %t/a.out
59+
60+
// Sign the main binary and all libraries
61+
// RUN: %target-codesign %t/a.out
62+
// RUN: %target-codesign %t/%target-library-name(FakeDistributedActorSystems)
63+
// RUN: %target-codesign %t/%target-library-name(ResilientAPILib)
64+
// RUN: %target-codesign %t/%target-library-name(ResilientImplLib)
65+
66+
// Run and verify output
67+
// RUN: %env-SWIFT_DUMP_ACCESSIBLE_FUNCTIONS=true %target-run %t/a.out \
68+
// RUN: %t/%target-library-name(FakeDistributedActorSystems) \
69+
// RUN: %t/%target-library-name(ResilientAPILib) \
70+
// RUN: %t/%target-library-name(ResilientImplLib) \
71+
// RUN: 2>&1 \
72+
// RUN: | %FileCheck %s --color --dump-input=always
73+
74+
// REQUIRES: executable_test
75+
// REQUIRES: concurrency
76+
// REQUIRES: distributed
77+
78+
// Locating the built libraries failed on Linux (construction of test case),
79+
// but we primarily care about macOS in this test
80+
// UNSUPPORTED: OS=linux-gnu
81+
82+
// UNSUPPORTED: use_os_stdlib
83+
// UNSUPPORTED: back_deployment_runtime
84+
// UNSUPPORTED: remote_run || device_run
85+
86+
87+
// FIXME: Also reproduces the following issue rdar://128284016
88+
//<unknown>:0: error: symbol '$s15ResilientAPILib30ServiceProtocolP8getArray2a12a2SayAA8ResponseVGSaySiG_SSSgtYaKFTj' (dispatch thunk of ResilientAPILib.ServiceProtocol.getArray(a1: Swift.Array<Swift.Int>, a2: Swift.Optional<Swift.String>) async throws -> Swift.Array<ResilientAPILib.Response>) is in generated IR file, but not in TBD file
89+
90+
//<unknown>:0: error: symbol '$s15ResilientAPILib30ServiceProtocolP8getArray2a12a2SayAA8ResponseVGSaySiG_SSSgtYaKFTjTu' (async function pointer to dispatch thunk of ResilientAPILib.ServiceProtocol.getArray(a1: Swift.Array<Swift.Int>, a2: Swift.Optional<Swift.String>) async throws -> Swift.Array<ResilientAPILib.Response>) is in generated IR file, but not in TBD file
91+
92+
//--- ResilientAPILib.swift
93+
94+
import Distributed
95+
import FakeDistributedActorSystems
96+
97+
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
98+
public struct Response: Codable {}
99+
100+
@Resolvable
101+
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
102+
public protocol ServiceProtocol: DistributedActor where ActorSystem == FakeRoundtripActorSystem {
103+
distributed func getArray(a1: [Int], a2: String?) -> [Response]
104+
}
105+
106+
//--- ResilientImplLib.swift
107+
108+
import ResilientAPILib
109+
110+
import Distributed
111+
import FakeDistributedActorSystems
112+
113+
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
114+
public distributed actor ServiceImpl: ServiceProtocol {
115+
public typealias ActorSystem = FakeRoundtripActorSystem
116+
117+
public distributed func getArray(a1: [Int], a2: String?) -> [Response] {
118+
[]
119+
}
120+
}
121+
122+
//--- Main.swift
123+
124+
import ResilientAPILib
125+
import ResilientImplLib
126+
127+
import Distributed
128+
import FakeDistributedActorSystems
129+
130+
@main
131+
struct Main {
132+
static func main() async throws {
133+
if #available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) {
134+
let system = FakeRoundtripActorSystem()
135+
136+
let real: any ServiceProtocol = ServiceImpl(actorSystem: system)
137+
138+
let proxy: any ServiceProtocol =
139+
try $ServiceProtocol.resolve(id: real.id, using: system)
140+
141+
// just in order to see if we crash and trigger the accessible funcs printout
142+
_ = try await proxy.getArray(a1: [], a2: "")
143+
144+
// === We expect records for accessible functions from other modules as well,
145+
// and especially we want to see records for the `$` macro generated stubs,
146+
// including
147+
148+
// CHECK: ==== Accessible Function Records ====
149+
// CHECK: Record name: $s16ResilientImplLib07ServiceB0C8getArray2a12a2Say0A6APILib8ResponseVGSaySiG_SSSgtYaKFTE
150+
// CHECK: Demangled: distributed thunk ResilientImplLib.ServiceImpl.getArray(a1: Swift.Array<Swift.Int>, a2: Swift.Optional<Swift.String>) async throws -> Swift.Array<ResilientAPILib.Response>
151+
152+
// CHECK: Record name: $s15ResilientAPILib15ServiceProtocolPAA11Distributed01_E9ActorStubRzrlE8getArray2a12a2SayAA8ResponseVGSaySiG_SSSgtYaKFTE
153+
// CHECK: Demangled: distributed thunk (extension in ResilientAPILib):ResilientAPILib.ServiceProtocol< where A: Distributed._DistributedActorStub>.getArray(a1: Swift.Array<Swift.Int>, a2: Swift.Optional<Swift.String>) async throws -> Swift.Array<ResilientAPILib.Response>
154+
155+
// CHECK: Record name: $s15ResilientAPILib16$ServiceProtocolC8getArray2a12a2SayAA8ResponseVGSaySiG_SSSgtYaKFTE
156+
// CHECK: Demangled: distributed thunk ResilientAPILib.$ServiceProtocol.getArray(a1: Swift.Array<Swift.Int>, a2: Swift.Optional<Swift.String>) async throws -> Swift.Array<ResilientAPILib.Response>
157+
158+
// CHECK: Record name: $s4main15ServiceProtocolPAA11Distributed01_D9ActorStubRzrlE8getArray2a12a2SayAA8ResponseVGSaySiG_SSSgtYaKFTE
159+
// CHECK: Demangled: distributed thunk (extension in main):main.ServiceProtocol< where A: Distributed._DistributedActorStub>.getArray(a1: Swift.Array<Swift.Int>, a2: Swift.Optional<Swift.String>) async throws -> Swift.Array<main.Response>
160+
161+
// CHECK: Record name: $s4main11ServiceImplC8getArray2a12a2SayAA8ResponseVGSaySiG_SSSgtYaKFTE
162+
// CHECK: Demangled: distributed thunk main.ServiceImpl.getArray(a1: Swift.Array<Swift.Int>, a2: Swift.Optional<Swift.String>) async throws -> Swift.Array<main.Response>
163+
164+
// CHECK: Record name: $s4main16$ServiceProtocolC8getArray2a12a2SayAA8ResponseVGSaySiG_SSSgtYaKFTE
165+
// CHECK: Demangled: distributed thunk main.$ServiceProtocol.getArray(a1: Swift.Array<Swift.Int>, a2: Swift.Optional<Swift.String>) async throws -> Swift.Array<main.Response>
166+
167+
// We expect these to be the exact records we get, no other ones:
168+
// CHECK: Record count: 6
169+
170+
// CHECK: ==== End of Accessible Function Records ====
171+
172+
print("DONE") // CHECK: DONE
173+
}
174+
}
175+
}

0 commit comments

Comments
 (0)