Skip to content

Commit 2467c2f

Browse files
authored
Merge pull request #73049 from ktoso/wip-codable-dont-addl-always-implicitly
2 parents 2a9a780 + efd8cbf commit 2467c2f

File tree

3 files changed

+270
-0
lines changed

3 files changed

+270
-0
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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-codesign %t/a.out
5+
// RUN: %target-run %t/a.out | %FileCheck %s --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+
// UNSUPPORTED: OS=windows-msvc
16+
17+
import Distributed
18+
19+
extension UInt8: CustomSerializationProtocol {
20+
public func toBytes() throws -> [UInt8] {
21+
[self]
22+
}
23+
public static func fromBytes(_ bytes: [UInt8]) throws -> Self {
24+
bytes.first!
25+
}
26+
}
27+
28+
distributed actor Tester {
29+
typealias ActorSystem = FakeCustomSerializationRoundtripActorSystem
30+
31+
distributed func echo(param: UInt8) -> UInt8 {
32+
param
33+
}
34+
}
35+
36+
// ==== ------------------------------------------------------------------------
37+
38+
func test() async throws {
39+
let system = FakeCustomSerializationRoundtripActorSystem()
40+
41+
let local = Tester(actorSystem: system)
42+
let ref = try Tester.resolve(id: local.id, using: system)
43+
44+
let reply = try await ref.echo(param: 2)
45+
// CHECK: >> remoteCall: on:main.Tester, target:main.Tester.echo(param:), invocation:FakeCustomSerializationInvocationEncoder(genericSubs: [], arguments: [2], returnType: Optional(Swift.UInt8), errorType: nil), throwing:Swift.Never, returning:Swift.UInt8
46+
47+
// CHECK: << remoteCall return: 2
48+
print("reply: \(reply)")
49+
// CHECK: reply: 2
50+
}
51+
52+
@main struct Main {
53+
static func main() async {
54+
try! await test()
55+
}
56+
}
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
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-codesign %t/a.out
5+
// RUN: %target-run %t/a.out | %FileCheck %s --color
6+
7+
// REQUIRES: executable_test
8+
// REQUIRES: concurrency
9+
// REQUIRES: distributed
10+
11+
// We're using Foundation for the JSON Encoder, could be done without but good enough
12+
// REQUIRES: objc_interop
13+
14+
15+
// rdar://76038845
16+
// UNSUPPORTED: use_os_stdlib
17+
// UNSUPPORTED: back_deployment_runtime
18+
19+
import Foundation
20+
import Distributed
21+
22+
final class LocalActorSystem : DistributedActorSystem {
23+
typealias ActorID = LocalTestingActorID
24+
typealias ResultHandler = LocalTestingInvocationResultHandler
25+
typealias InvocationEncoder = LocalTestingInvocationEncoder
26+
typealias InvocationDecoder = LocalTestingInvocationDecoder
27+
typealias SerializationRequirement = any Codable
28+
29+
func makeInvocationEncoder() -> InvocationEncoder { LocalTestingDistributedActorSystem().makeInvocationEncoder() }
30+
31+
func resolve<Act>(id: ActorID, as actorType: Act.Type) throws -> Act? where Act: DistributedActor {
32+
nil
33+
}
34+
35+
func actorReady<Act>(_ actor: Act) where Act: DistributedActor, Act.ID == ActorID {
36+
}
37+
38+
func resignID(_ id: ActorID) {}
39+
40+
func assignID<Act>(_ actorType: Act.Type) -> ActorID
41+
where Act: DistributedActor {
42+
.init(id: "42")
43+
}
44+
45+
func remoteCall<Act, Err, Res>(on actor: Act,
46+
target: RemoteCallTarget,
47+
invocation: inout InvocationEncoder,
48+
throwing: Err.Type,
49+
returning: Res.Type) async throws -> Res
50+
where Act: DistributedActor,
51+
Act.ID == ActorID,
52+
Err: Error,
53+
Res: Codable {
54+
let decoder = JSONDecoder()
55+
return try! decoder.decode(Res.self, from: await fetchData())
56+
}
57+
58+
func remoteCallVoid<Act, Err>(on actor: Act,
59+
target: RemoteCallTarget,
60+
invocation: inout InvocationEncoder,
61+
throwing errorType: Err.Type) async throws
62+
where Act: DistributedActor,
63+
Act.ID == ActorID,
64+
Err: Error {
65+
fatalError("not implemented: \(#function)")
66+
}
67+
68+
func fetchData() async -> Data {
69+
"42".data(using: .ascii)!
70+
}
71+
}
72+
73+
distributed actor NotCodableDA<ActorSystem>
74+
where ActorSystem: DistributedActorSystem<any Codable> {
75+
76+
init(actorSystem: ActorSystem) async {
77+
self.actorSystem = actorSystem
78+
79+
print(try! await self.request())
80+
}
81+
82+
func request() async throws -> Int {
83+
let target = RemoteCallTarget("test.request")
84+
var encoder = actorSystem.makeInvocationEncoder()
85+
return try await actorSystem.remoteCall(on: self,
86+
target: target,
87+
invocation: &encoder,
88+
throwing: Error.self,
89+
returning: Int.self)
90+
}
91+
}
92+
93+
distributed actor CodableDA<ActorSystem>: Codable
94+
where ActorSystem: DistributedActorSystem<any Codable>,
95+
ActorSystem.ActorID: Codable {
96+
97+
init(actorSystem: ActorSystem) async {
98+
self.actorSystem = actorSystem
99+
100+
print(try! await self.request())
101+
}
102+
103+
func request() async throws -> Int {
104+
let target = RemoteCallTarget("test.request")
105+
var encoder = actorSystem.makeInvocationEncoder()
106+
return try await actorSystem.remoteCall(on: self,
107+
target: target,
108+
invocation: &encoder,
109+
throwing: Error.self,
110+
returning: Int.self)
111+
}
112+
}
113+
114+
distributed actor CodableIDDA<ActorSystem>
115+
where ActorSystem: DistributedActorSystem<any Codable>,
116+
ActorSystem.ActorID: Codable {
117+
118+
init(actorSystem: ActorSystem) async {
119+
self.actorSystem = actorSystem
120+
121+
print(try! await self.request())
122+
}
123+
124+
func request() async throws -> Int {
125+
let target = RemoteCallTarget("test.request")
126+
var encoder = actorSystem.makeInvocationEncoder()
127+
return try await actorSystem.remoteCall(on: self,
128+
target: target,
129+
invocation: &encoder,
130+
throwing: Error.self,
131+
returning: Int.self)
132+
}
133+
}
134+
135+
@main struct Main {
136+
static func main() async throws {
137+
if #available(SwiftStdlib 5.9, *) {
138+
let system = LocalActorSystem()
139+
let ncda = await NotCodableDA(actorSystem: system)
140+
let cidda = await CodableIDDA(actorSystem: system)
141+
let cda = await CodableDA(actorSystem: system)
142+
143+
try await ncda.whenLocal {
144+
let got = try await $0.request()
145+
146+
// CHECK: got = 42
147+
print("got = \(got)")
148+
}
149+
150+
try await cidda.whenLocal {
151+
let got = try await $0.request()
152+
153+
// CHECK: got = 42
154+
print("got = \(got)")
155+
}
156+
157+
let _: any (DistributedActor & Codable) = cda
158+
try await cda.whenLocal {
159+
let got = try await $0.request()
160+
161+
// CHECK: got = 42
162+
print("got = \(got)")
163+
}
164+
165+
// CHECK: OK
166+
print("OK")
167+
}
168+
}
169+
}

test/Distributed/distributed_actor_implicit_codable.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,48 @@ func take<A: Codable>(actor: A) {}
1717
func test(actorSystem: FakeActorSystem) {
1818
take(actor: DA(actorSystem: actorSystem)) // ok
1919
}
20+
21+
func takeCodable<A: Codable>(actor: A) {}
22+
23+
func test_DA(actorSystem: FakeActorSystem) {
24+
takeCodable(actor: DA(actorSystem: actorSystem)) // ok
25+
}
26+
27+
// ==== Generic actors
28+
29+
distributed actor DAG<ActorSystem>
30+
where ActorSystem: DistributedActorSystem<any Codable> {
31+
}
32+
func test_DAG(actorSystem: FakeActorSystem) {
33+
takeCodable(actor: DAG<FakeActorSystem>(actorSystem: actorSystem)) // ok
34+
}
35+
36+
distributed actor DAG_ID<ActorSystem>
37+
where ActorSystem: DistributedActorSystem<any Codable>,
38+
ID: Codable { // expected-error{{cannot find type 'ID' in scope}}
39+
}
40+
func test_DAG_ID(actorSystem: FakeActorSystem) {
41+
takeCodable(actor: DAG_ID<FakeActorSystem>(actorSystem: actorSystem)) // ok
42+
}
43+
44+
distributed actor DAG_ActorSystem_ActorID<ActorSystem>
45+
where ActorSystem: DistributedActorSystem<any Codable>,
46+
ActorSystem.ActorID: Codable {
47+
}
48+
func test_DAG_ActorSystem_ActorID(actorSystem: FakeActorSystem) {
49+
takeCodable(actor: DAG_ActorSystem_ActorID<FakeActorSystem>(actorSystem: actorSystem)) // ok
50+
}
51+
52+
// ==== Not codable cases
53+
54+
protocol SerializableButNotCodable {}
55+
56+
distributed actor DAG_ActorSystem_ActorID_Custom<ActorSystem>
57+
where ActorSystem: DistributedActorSystem<any SerializableButNotCodable> {
58+
// expected-note@-2{{requirement specified as 'ActorSystem.SerializationRequirement' == 'any SerializableButNotCodable'}}
59+
}
60+
61+
func test_DAG_ActorSystem_ActorID_Custom(actorSystem: FakeActorSystem) {
62+
takeCodable(actor: DAG_ActorSystem_ActorID_Custom<FakeActorSystem>(actorSystem: actorSystem))
63+
// expected-error@-1{{'DAG_ActorSystem_ActorID_Custom' requires the types 'any FakeActorSystem.SerializationRequirement' (aka 'any Decodable & Encodable') and 'any SerializableButNotCodable' be equivalent}}
64+
}

0 commit comments

Comments
 (0)