Skip to content

Commit 0897962

Browse files
authored
Merge pull request #80373 from xedin/rdar-146101172-narrow
[SILOptimizer] Prevent devirtualization of call to distributed witnes…
2 parents 918756f + 585b687 commit 0897962

File tree

2 files changed

+157
-0
lines changed

2 files changed

+157
-0
lines changed

lib/SILOptimizer/Utils/Devirtualize.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,24 @@ bool swift::canDevirtualizeClassMethod(FullApplySite applySite, ClassDecl *cd,
809809
return false;
810810
}
811811

812+
// A narrow fix for https://github.com/swiftlang/swift/issues/79318
813+
// to make sure that uses of distributed requirement witnesses are
814+
// not devirtualized because that results in a loss of the ad-hoc
815+
// requirement infomation in the re-created substitution map.
816+
//
817+
// We have a similar check in `canSpecializeFunction` which presents
818+
// specialization for exactly the same reason.
819+
//
820+
// TODO: A better way to fix this would be to record the ad-hoc conformance
821+
// requirement in `RequirementEnvironment` and adjust IRGen to handle it.
822+
if (f->hasLocation()) {
823+
if (auto *funcDecl =
824+
dyn_cast_or_null<FuncDecl>(f->getLocation().getAsDeclContext())) {
825+
if (funcDecl->isDistributedWitnessWithAdHocSerializationRequirement())
826+
return false;
827+
}
828+
}
829+
812830
return true;
813831
}
814832

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-ir -swift-version 6 -O -I %t %s
3+
// RUN: %target-swift-frontend -emit-sil -swift-version 6 -O -I %t %s | %FileCheck %s
4+
5+
// REQUIRES: concurrency
6+
// REQUIRES: distributed
7+
8+
// REQUIRES: OS=macosx || OS=ios
9+
10+
import Distributed
11+
12+
// NOTE: None of the ad-hoc protocol requirement implementations
13+
14+
public protocol Transferable: Sendable {}
15+
16+
// NOT final on purpose
17+
public class TheSpecificResultHandlerWhichIsANonFinalClass: DistributedTargetInvocationResultHandler {
18+
public typealias SerializationRequirement = Transferable
19+
20+
public func onReturn<Success>(value: Success) async throws where Success: Transferable {
21+
}
22+
23+
public func onReturnVoid() async throws {
24+
fatalError()
25+
}
26+
27+
public func onThrow<Err>(error: Err) async throws where Err : Error {
28+
fatalError()
29+
}
30+
}
31+
32+
// NOT final on purpose
33+
public class FakeInvocationDecoder: DistributedTargetInvocationDecoder {
34+
public typealias SerializationRequirement = Transferable
35+
36+
public func decodeGenericSubstitutions() throws -> [Any.Type] {
37+
[]
38+
}
39+
40+
public func decodeNextArgument<Argument: SerializationRequirement>() throws -> Argument {
41+
fatalError()
42+
}
43+
44+
public func decodeErrorType() throws -> Any.Type? {
45+
nil
46+
}
47+
48+
public func decodeReturnType() throws -> Any.Type? {
49+
nil
50+
}
51+
}
52+
53+
// NOT final on purpose
54+
public class FakeInvocationEncoder : DistributedTargetInvocationEncoder {
55+
public typealias SerializationRequirement = Transferable
56+
57+
public func recordArgument<Value: SerializationRequirement>(
58+
_ argument: RemoteCallArgument<Value>) throws {
59+
}
60+
61+
public func recordGenericSubstitution<T>(_ type: T.Type) throws {
62+
}
63+
64+
public func recordErrorType<E: Error>(_ type: E.Type) throws {
65+
}
66+
67+
public func recordReturnType<R: SerializationRequirement>(_ type: R.Type) throws {
68+
}
69+
70+
public func doneRecording() throws {
71+
}
72+
}
73+
74+
// NOT final on purpose
75+
public class NotFinalActorSystemForAdHocRequirementTest: DistributedActorSystem, @unchecked Sendable {
76+
public typealias ActorID = String
77+
public typealias InvocationEncoder = FakeInvocationEncoder
78+
public typealias InvocationDecoder = FakeInvocationDecoder
79+
public typealias SerializationRequirement = Transferable
80+
public typealias ResultHandler = TheSpecificResultHandlerWhichIsANonFinalClass
81+
82+
public init() {}
83+
84+
public func resolve<Act>(id: ActorID, as actorType: Act.Type)
85+
throws -> Act? where Act: DistributedActor {
86+
fatalError()
87+
}
88+
89+
public func assignID<Act>(_ actorType: Act.Type) -> ActorID
90+
where Act: DistributedActor {
91+
fatalError()
92+
}
93+
94+
public func actorReady<Act>(_ actor: Act) where Act: DistributedActor, Act.ID == ActorID {
95+
fatalError()
96+
}
97+
98+
public func resignID(_ id: ActorID) {
99+
fatalError()
100+
}
101+
102+
public func makeInvocationEncoder() -> InvocationEncoder {
103+
fatalError()
104+
}
105+
106+
public func remoteCall<Act, Err, Res>(
107+
on actor: Act,
108+
target: RemoteCallTarget,
109+
invocation: inout InvocationEncoder,
110+
throwing errorType: Err.Type,
111+
returning returnType: Res.Type
112+
) async throws -> Res
113+
where Act: DistributedActor,
114+
Act.ID == ActorID,
115+
Err: Error,
116+
Res: SerializationRequirement {
117+
fatalError()
118+
}
119+
120+
public func remoteCallVoid<Act, Err>(
121+
on actor: Act,
122+
target: RemoteCallTarget,
123+
invocation: inout InvocationEncoder,
124+
throwing errorType: Err.Type
125+
) async throws
126+
where Act: DistributedActor,
127+
Act.ID == ActorID,
128+
Err: Error {
129+
fatalError()
130+
}
131+
}
132+
133+
// FIXME: This call should be devirtualized but it cannot be done at the moment due to issues with ad-hoc serialization requirement.
134+
135+
// CHECK-LABEL: sil shared [transparent] [thunk] @$s52distributed_actor_adhoc_requirements_optimized_build42NotFinalActorSystemForAdHocRequirementTestC11Distributed0piJ0AadEP10remoteCall2on6target10invocation8throwing9returningqd_1_qd___AD06RemoteR6TargetV17InvocationEncoderQzzqd_0_mqd_1_mtYaKAD0pI0Rd__s5ErrorRd_0_2IDQyd__0I2IDRtzr1_lFTW
136+
// CHECK: bb0(%0 : $*τ_0_2, %1 : $τ_0_0, %2 : $*RemoteCallTarget, %3 : $*FakeInvocationEncoder, %4 : $@thick τ_0_1.Type, %5 : $@thick τ_0_2.Type, %6 : $*NotFinalActorSystemForAdHocRequirementTest):
137+
// CHECK-NEXT: [[DIST_IMPL:%.*]] = load %6
138+
// CHECK-NEXT: [[REMOTE_CALL_WITNESS:%.*]] = class_method [[DIST_IMPL]], #NotFinalActorSystemForAdHocRequirementTest.remoteCall
139+
// CHECK-NEXT: try_apply [[REMOTE_CALL_WITNESS]]<τ_0_0, τ_0_1, τ_0_2>(%0, %1, %2, %3, %4, %5, [[DIST_IMPL]])

0 commit comments

Comments
 (0)