Skip to content

Commit 629ac65

Browse files
committed
[Distributed] better test for SIL lifetime with AddressOnly types
1 parent 7ecfc82 commit 629ac65

File tree

2 files changed

+155
-1
lines changed

2 files changed

+155
-1
lines changed

test/Distributed/Inputs/FakeDistributedActorSystems.swift

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,36 @@ public struct ActorAddress: Hashable, Sendable, Codable {
3434
}
3535
}
3636

37+
/// This type is same as ActorAddress however for purposes of SIL tests we make it not-loadable.
38+
///
39+
/// By adding the `Any` we don't know the full size of the struct making the type in SIL `$*ActorAddress`
40+
/// when we try to store or pass it around, which triggers `isAddressOnly` guarded paths which we need to test.
41+
public struct NotLoadableActorAddress: Hashable, Sendable, Codable {
42+
public let address: String
43+
public let any: Sendable = "" // DO NOT REMOVE, this makes this struct address-only which is crucial for testing.
44+
45+
public init(parse address: String) {
46+
self.address = address
47+
}
48+
49+
public init(from decoder: Decoder) throws {
50+
let container = try decoder.singleValueContainer()
51+
self.address = try container.decode(String.self)
52+
}
53+
54+
public func encode(to encoder: Encoder) throws {
55+
var container = encoder.singleValueContainer()
56+
try container.encode(self.address)
57+
}
58+
59+
public func hash(into hasher: inout Swift.Hasher) {
60+
}
61+
62+
public static func ==(lhs: NotLoadableActorAddress, rhs: NotLoadableActorAddress) -> Bool {
63+
lhs.address == rhs.address
64+
}
65+
}
66+
3767
// ==== Noop Transport ---------------------------------------------------------
3868

3969
@available(SwiftStdlib 5.7, *)
@@ -109,9 +139,81 @@ public struct FakeActorSystem: DistributedActorSystem, CustomStringConvertible {
109139
}
110140
}
111141

142+
@available(SwiftStdlib 5.7, *)
143+
public struct FakeNotLoadableAddressActorSystem: DistributedActorSystem, CustomStringConvertible {
144+
public typealias ActorID = NotLoadableActorAddress
145+
public typealias InvocationDecoder = FakeInvocationDecoder
146+
public typealias InvocationEncoder = FakeInvocationEncoder
147+
public typealias SerializationRequirement = Codable
148+
public typealias ResultHandler = FakeRoundtripResultHandler
149+
150+
// just so that the struct does not become "trivial"
151+
let someValue: String = ""
152+
let someValue2: String = ""
153+
let someValue3: String = ""
154+
let someValue4: String = ""
155+
156+
public init() {
157+
print("Initialized new FakeActorSystem")
158+
}
159+
160+
public func resolve<Act>(id: ActorID, as actorType: Act.Type) throws -> Act?
161+
where Act: DistributedActor,
162+
Act.ID == ActorID {
163+
nil
164+
}
165+
166+
public func assignID<Act>(_ actorType: Act.Type) -> ActorID
167+
where Act: DistributedActor,
168+
Act.ID == ActorID {
169+
NotLoadableActorAddress(parse: "xxx")
170+
}
171+
172+
public func actorReady<Act>(_ actor: Act)
173+
where Act: DistributedActor,
174+
Act.ID == ActorID {
175+
}
176+
177+
public func resignID(_ id: ActorID) {
178+
}
179+
180+
public func makeInvocationEncoder() -> InvocationEncoder {
181+
.init()
182+
}
183+
184+
public func remoteCall<Act, Err, Res>(
185+
on actor: Act,
186+
target: RemoteCallTarget,
187+
invocation invocationEncoder: inout InvocationEncoder,
188+
throwing: Err.Type,
189+
returning: Res.Type
190+
) async throws -> Res
191+
where Act: DistributedActor,
192+
Act.ID == ActorID,
193+
Err: Error,
194+
Res: SerializationRequirement {
195+
throw ExecuteDistributedTargetError(message: "\(#function) not implemented.")
196+
}
197+
198+
public func remoteCallVoid<Act, Err>(
199+
on actor: Act,
200+
target: RemoteCallTarget,
201+
invocation invocationEncoder: inout InvocationEncoder,
202+
throwing: Err.Type
203+
) async throws
204+
where Act: DistributedActor,
205+
Act.ID == ActorID,
206+
Err: Error {
207+
throw ExecuteDistributedTargetError(message: "\(#function) not implemented.")
208+
}
209+
210+
public nonisolated var description: Swift.String {
211+
"\(Self.self)()"
212+
}
213+
}
214+
112215
// ==== Fake Roundtrip Transport -----------------------------------------------
113216

114-
// TODO(distributed): not thread safe...
115217
@available(SwiftStdlib 5.7, *)
116218
public final class FakeRoundtripActorSystem: DistributedActorSystem, @unchecked Sendable {
117219
public typealias ActorID = ActorAddress
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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 -verify -emit-sil -module-name main -disable-availability-checking -parse-as-library -I %t %s %S/../Inputs/FakeDistributedActorSystems.swift | %FileCheck %s
4+
5+
// REQUIRES: concurrency
6+
// REQUIRES: distributed
7+
8+
// rdar://76038845
9+
// UNSUPPORTED: use_os_stdlib
10+
// UNSUPPORTED: back_deployment_runtime
11+
12+
// FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574
13+
// UNSUPPORTED: OS=windows-msvc
14+
15+
import Distributed
16+
import FakeDistributedActorSystems
17+
18+
/// This type uses a non loadable (size not known at compile time) ID which forces the actor's init SILGen
19+
/// to make use of the isAddressOnly handling of the ID assignments.
20+
///
21+
/// This test covers rdar://104583893 / https://github.com/apple/swift/issues/62898
22+
/// And used to fail with:
23+
/// SIL memory lifetime failure in @$s18DistributedCluster0B16EventStreamActorC11actorSystemAcA0bG0C_tcfc: memory is initialized, but shouldn't be
24+
typealias DefaultDistributedActorSystem = FakeNotLoadableAddressActorSystem
25+
26+
distributed actor Greeter {
27+
28+
init(actorSystem: ActorSystem) {
29+
self.actorSystem = actorSystem
30+
}
31+
32+
distributed func echo(name: String) -> String {
33+
return "Echo: \(name)"
34+
}
35+
}
36+
37+
// CHECK: sil hidden @$s4main7GreeterC7resolve2id5usingAcA23NotLoadableActorAddressV_AA04FakefgiH6SystemVtKFZ : $@convention(method) (@in_guaranteed NotLoadableActorAddress, @guaranteed FakeNotLoadableAddressActorSystem, @thick Greeter.Type) -> (@owned Greeter, @error any Error) {
38+
// CHECK: bb0([[ADDRESS_ARG:%[0-9]+]] : $*NotLoadableActorAddress, [[SYSTEM_ARG:%[0-9]+]] : $FakeNotLoadableAddressActorSystem, [[TYPE_ARG:%[0-9]+]] : $@thick Greeter.Type):
39+
// CHECK: [[TYPE:%[0-9]+]] = metatype $@thick Greeter.Type
40+
41+
// CHECK: // makeProxyBB
42+
// CHECK: [[INSTANCE:%[0-9]+]] = builtin "initializeDistributedRemoteActor"([[TYPE]] : $@thick Greeter.Type) : $Greeter
43+
// CHECK: [[ID_PROPERTY:%[0-9]+]] = ref_element_addr [[INSTANCE]] : $Greeter, #Greeter.id
44+
// Note specifically that we don't [take] in the below copy_addr:
45+
// CHECK: copy_addr [[ADDRESS_ARG]] to [init] [[ID_PROPERTY]] : $*NotLoadableActorAddress
46+
47+
func test() async throws {
48+
let system = DefaultDistributedActorSystem()
49+
50+
let local = Greeter(actorSystem: system)
51+
_ = try await local.echo(name: "Caplin")
52+
}

0 commit comments

Comments
 (0)