Skip to content

Commit 370fa50

Browse files
authored
Merge pull request #69093 from ktoso/wip-distributed-effective-label
2 parents 0677cbd + 1d150c8 commit 370fa50

File tree

2 files changed

+238
-4
lines changed

2 files changed

+238
-4
lines changed

stdlib/public/Distributed/DistributedActorSystem.swift

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -790,11 +790,20 @@ public struct RemoteCallArgument<Value> {
790790
/// the user-visible name of this argument.
791791
public let label: String?
792792

793-
/// The effective label of this argument, i.e. if no explicit `label` was set
794-
/// this defaults to the `name`. This reflects the semantics of call sites of
795-
/// function declarations without explicit label definitions in Swift.
793+
/// The effective label of this argument. This reflects the semantics
794+
/// of call sites of function declarations without explicit label
795+
/// definitions in Swift.
796+
///
797+
/// For example, for a method declared like `func hi(a: String)` the effective
798+
/// label is `a` while for a method like `func hi(a b: String)` or
799+
/// `func hi(_ b: String)` the label is the explicitly declared one,
800+
/// so `a` and `_` respectively.
796801
public var effectiveLabel: String {
797-
return label ?? name
802+
if let label {
803+
return label
804+
} else {
805+
return "_"
806+
}
798807
}
799808

800809
/// The internal name of parameter this argument is accessible as in the
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
// RUN: %target-run-simple-swift( -Xfrontend -disable-availability-checking -parse-as-library) | %FileCheck %s
2+
3+
// REQUIRES: executable_test
4+
// REQUIRES: concurrency
5+
// REQUIRES: distributed
6+
7+
// UNSUPPORTED: OS=windows-msvc
8+
9+
import Distributed
10+
11+
@available(SwiftStdlib 5.5, *)
12+
distributed actor ParamsDA {
13+
14+
// CHECK: argument.label: Optional("a")
15+
// CHECK: argument.name: a
16+
// CHECK: argument.effectiveLabel: a
17+
distributed func callMe(a: String) {}
18+
19+
// CHECK: argument.label: Optional("b")
20+
// CHECK: argument.name: c
21+
// CHECK: argument.effectiveLabel: b
22+
distributed func callMe(b c: String) {}
23+
24+
// CHECK: argument.label: nil
25+
// CHECK: argument.name: d
26+
// CHECK: argument.effectiveLabel: _
27+
distributed func callMe(_ d: String) {}
28+
29+
// CHECK: argument.label: nil
30+
// CHECK: argument.name: p0
31+
// CHECK: argument.effectiveLabel: _
32+
distributed func callMe2(_: String) {}
33+
}
34+
35+
@available(SwiftStdlib 5.5, *)
36+
typealias DefaultDistributedActorSystem = FakeActorSystem
37+
38+
@main struct Main {
39+
static func main() async {
40+
let system = FakeActorSystem()
41+
let pda = try! ParamsDA.resolve(id: .init(parse: "x"), using: system)
42+
print("--- (a a)")
43+
try! await pda.callMe(a: "")
44+
print("--- (b c)")
45+
try! await pda.callMe(b: "")
46+
print("--- (_ d)")
47+
try! await pda.callMe(_: "")
48+
print("--- (_)")
49+
try! await pda.callMe2(_: "")
50+
print("OK")
51+
}
52+
}
53+
54+
55+
// ==== Fake Transport ---------------------------------------------------------
56+
struct ActorAddress: Sendable, Hashable, Codable {
57+
let address: String
58+
init(parse address: String) {
59+
self.address = address
60+
}
61+
}
62+
63+
struct FakeActorSystem: DistributedActorSystem {
64+
typealias ActorID = ActorAddress
65+
typealias InvocationDecoder = FakeInvocationDecoder
66+
typealias InvocationEncoder = FakeInvocationEncoder
67+
typealias SerializationRequirement = Codable
68+
typealias ResultHandler = FakeResultHandler
69+
70+
func resolve<Act>(id: ActorID, as actorType: Act.Type)
71+
throws -> Act? where Act: DistributedActor {
72+
return nil
73+
}
74+
75+
func assignID<Act>(_ actorType: Act.Type) -> ActorID
76+
where Act: DistributedActor {
77+
let id = ActorAddress(parse: "xxx")
78+
return id
79+
}
80+
81+
func actorReady<Act>(_ actor: Act)
82+
where Act: DistributedActor,
83+
Act.ID == ActorID {
84+
}
85+
86+
func resignID(_ id: ActorID) {
87+
}
88+
89+
func makeInvocationEncoder() -> InvocationEncoder {
90+
.init()
91+
}
92+
93+
func remoteCall<Act, Err, Res>(
94+
on actor: Act,
95+
target: RemoteCallTarget,
96+
invocation invocationEncoder: inout InvocationEncoder,
97+
throwing: Err.Type,
98+
returning: Res.Type
99+
) async throws -> Res
100+
where Act: DistributedActor,
101+
Act.ID == ActorID,
102+
Err: Error,
103+
Res: SerializationRequirement {
104+
fatalError("INVOKED REMOTE CALL")
105+
}
106+
107+
func remoteCallVoid<Act, Err>(
108+
on actor: Act,
109+
target: RemoteCallTarget,
110+
invocation invocationEncoder: inout InvocationEncoder,
111+
throwing: Err.Type
112+
) async throws
113+
where Act: DistributedActor,
114+
Act.ID == ActorID,
115+
Err: Error {
116+
return // expected; mock out replying
117+
}
118+
}
119+
120+
struct FakeInvocationEncoder: DistributedTargetInvocationEncoder {
121+
typealias SerializationRequirement = Codable
122+
123+
var substitutions: [Any.Type] = []
124+
var arguments: [Any] = []
125+
var returnType: Any.Type? = nil
126+
var errorType: Any.Type? = nil
127+
128+
mutating func recordGenericSubstitution<T>(_ type: T.Type) throws {
129+
substitutions.append(type)
130+
}
131+
mutating func recordArgument<Value: SerializationRequirement>(_ argument: RemoteCallArgument<Value>) throws {
132+
print("argument.label: \(String(describing: argument.label))")
133+
print("argument.name: \(argument.name)")
134+
print("argument.effectiveLabel: \(argument.effectiveLabel)")
135+
arguments.append(argument.value)
136+
}
137+
mutating func recordErrorType<E: Error>(_ type: E.Type) throws {
138+
self.errorType = type
139+
}
140+
mutating func recordReturnType<R: SerializationRequirement>(_ type: R.Type) throws {
141+
self.returnType = type
142+
}
143+
mutating func doneRecording() throws {}
144+
145+
// For testing only
146+
func makeDecoder() -> FakeInvocationDecoder {
147+
return .init(
148+
args: arguments,
149+
substitutions: substitutions,
150+
returnType: returnType,
151+
errorType: errorType
152+
)
153+
}
154+
}
155+
156+
157+
class FakeInvocationDecoder : DistributedTargetInvocationDecoder {
158+
typealias SerializationRequirement = Codable
159+
160+
var arguments: [Any] = []
161+
var substitutions: [Any.Type] = []
162+
var returnType: Any.Type? = nil
163+
var errorType: Any.Type? = nil
164+
165+
init(
166+
args: [Any],
167+
substitutions: [Any.Type] = [],
168+
returnType: Any.Type? = nil,
169+
errorType: Any.Type? = nil
170+
) {
171+
self.arguments = args
172+
self.substitutions = substitutions
173+
self.returnType = returnType
174+
self.errorType = errorType
175+
}
176+
177+
// === Receiving / decoding -------------------------------------------------
178+
func decodeGenericSubstitutions() throws -> [Any.Type] {
179+
return substitutions
180+
}
181+
182+
var argumentIndex: Int = 0
183+
func decodeNextArgument<Argument: SerializationRequirement>() throws -> Argument {
184+
guard argumentIndex < arguments.count else {
185+
fatalError("Attempted to decode more arguments than stored! Index: \(argumentIndex), args: \(arguments)")
186+
}
187+
188+
let anyArgument = arguments[argumentIndex]
189+
guard let argument = anyArgument as? Argument else {
190+
fatalError("Cannot cast argument\(anyArgument) to expected \(Argument.self)")
191+
}
192+
193+
if (argumentIndex == 0 && Argument.self == Int???.self) {
194+
throw ExecuteDistributedTargetError(message: "Failed to decode of Int??? (for a test)")
195+
}
196+
197+
argumentIndex += 1
198+
return argument
199+
}
200+
201+
func decodeErrorType() throws -> Any.Type? {
202+
self.errorType
203+
}
204+
205+
func decodeReturnType() throws -> Any.Type? {
206+
self.returnType
207+
}
208+
}
209+
210+
@available(SwiftStdlib 5.5, *)
211+
struct FakeResultHandler: DistributedTargetInvocationResultHandler {
212+
typealias SerializationRequirement = Codable
213+
214+
func onReturn<Success: SerializationRequirement>(value: Success) async throws {
215+
print("RETURN: \(value)")
216+
}
217+
func onReturnVoid() async throws {
218+
print("RETURN VOID: ()")
219+
}
220+
func onThrow<Err: Error>(error: Err) async throws {
221+
print("ERROR: \(error)")
222+
}
223+
}
224+
225+
// ==== ------------------------------------------------------------------------

0 commit comments

Comments
 (0)