Skip to content

Commit 6ca5ace

Browse files
committed
[Distributed] Harden detecting adhoc req methods, don't crash when missing protocol decls
This issue manifested in crashing when in Xcode one would do the Archive workflow, and we would be missing the Distributed module types and proceed to run into a nullpointer when faced with code like this: ``` public class TestViewModel { public init() {} public func onReturn() { print("on return executed!") } } ``` where the name matched one of the ad hoc requirements, but we'd get null for the protocol lookup since this does not import the distributed module. resolves rdar://148327936
1 parent a1cdd33 commit 6ca5ace

File tree

2 files changed

+101
-3
lines changed

2 files changed

+101
-3
lines changed

lib/AST/DistributedDecl.cpp

+19-3
Original file line numberDiff line numberDiff line change
@@ -488,8 +488,10 @@ bool AbstractFunctionDecl::isDistributedActorSystemRemoteCall(bool isVoidReturn)
488488
}
489489

490490
// === Must be declared in a 'DistributedActorSystem' conforming type
491-
ProtocolDecl *systemProto =
492-
C.getDistributedActorSystemDecl();
491+
ProtocolDecl *systemProto = C.getDistributedActorSystemDecl();
492+
if (!systemProto) {
493+
return false;
494+
}
493495

494496
auto systemNominal = DC->getSelfNominalTypeDecl();
495497
auto distSystemConformance = lookupConformance(
@@ -794,6 +796,9 @@ AbstractFunctionDecl::isDistributedTargetInvocationEncoderRecordArgument() const
794796
// === Must be declared in a 'DistributedTargetInvocationEncoder' conforming type
795797
ProtocolDecl *encoderProto =
796798
C.getProtocol(KnownProtocolKind::DistributedTargetInvocationEncoder);
799+
if (!encoderProto) {
800+
return false;
801+
}
797802

798803
auto encoderNominal = getDeclContext()->getSelfNominalTypeDecl();
799804
auto protocolConformance = lookupConformance(
@@ -925,6 +930,9 @@ AbstractFunctionDecl::isDistributedTargetInvocationEncoderRecordReturnType() con
925930
// === Must be declared in a 'DistributedTargetInvocationEncoder' conforming type
926931
ProtocolDecl *encoderProto =
927932
C.getProtocol(KnownProtocolKind::DistributedTargetInvocationEncoder);
933+
if (!encoderProto) {
934+
return false;
935+
}
928936

929937
auto encoderNominal = getDeclContext()->getSelfNominalTypeDecl();
930938
auto protocolConformance = lookupConformance(
@@ -1051,6 +1059,9 @@ AbstractFunctionDecl::isDistributedTargetInvocationEncoderRecordErrorType() cons
10511059
// === Must be declared in a 'DistributedTargetInvocationEncoder' conforming type
10521060
ProtocolDecl *encoderProto =
10531061
C.getProtocol(KnownProtocolKind::DistributedTargetInvocationEncoder);
1062+
if (!encoderProto) {
1063+
return false;
1064+
}
10541065

10551066
auto encoderNominal = getDeclContext()->getSelfNominalTypeDecl();
10561067
auto protocolConformance = lookupConformance(
@@ -1158,7 +1169,9 @@ AbstractFunctionDecl::isDistributedTargetInvocationDecoderDecodeNextArgument() c
11581169
// === Must be declared in a 'DistributedTargetInvocationEncoder' conforming type
11591170
ProtocolDecl *decoderProto =
11601171
C.getProtocol(KnownProtocolKind::DistributedTargetInvocationDecoder);
1161-
1172+
if (!decoderProto) {
1173+
return false;
1174+
}
11621175
auto decoderNominal = getDeclContext()->getSelfNominalTypeDecl();
11631176
auto protocolConformance = lookupConformance(
11641177
decoderNominal->getDeclaredInterfaceType(), decoderProto);
@@ -1251,6 +1264,9 @@ AbstractFunctionDecl::isDistributedTargetInvocationResultHandlerOnReturn() const
12511264
// === Must be declared in a 'DistributedTargetInvocationEncoder' conforming type
12521265
ProtocolDecl *decoderProto =
12531266
C.getProtocol(KnownProtocolKind::DistributedTargetInvocationResultHandler);
1267+
if (!decoderProto) {
1268+
return false;
1269+
}
12541270

12551271
auto decoderNominal = getDeclContext()->getSelfNominalTypeDecl();
12561272
auto protocolConformance = lookupConformance(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -target %target-swift-5.7-abi-triple %S/Inputs/FakeDistributedActorSystems.swift
3+
// RUN: %target-swift-frontend -typecheck -verify -target %target-swift-5.7-abi-triple -I %t 2>&1 %s
4+
5+
// UNSUPPORTED: back_deploy_concurrency
6+
// REQUIRES: concurrency
7+
// REQUIRES: distributed
8+
9+
import Distributed
10+
import FakeDistributedActorSystems
11+
12+
distributed actor Philosopher {
13+
typealias ActorSystem = FakeActorSystem
14+
15+
let philosophy: String
16+
17+
init(system: FakeActorSystem) {
18+
philosophy = "Epistemology"
19+
}
20+
21+
distributed func hi1() -> String { "Hi!" }
22+
// distributed func hi2() -> String { "Hi!" }
23+
// distributed func hi3() -> String { "Hi!" }
24+
// distributed func hi4() -> String { "Hi!" }
25+
// distributed func hi5() -> String { "Hi!" }
26+
// distributed func hi6() -> String { "Hi!" }
27+
// distributed func hi7() -> String { "Hi!" }
28+
// distributed func hi8() -> String { "Hi!" }
29+
// distributed func hi9() -> String { "Hi!" }
30+
31+
func test(other: Philosopher) async throws {
32+
// self --------------------------------------------------------------------
33+
async let alet = self.hi1() // none
34+
_ = await alet // Ok - `self.hi()` isn't throwing
35+
36+
// Task {
37+
// _ = self.hi1() // none
38+
// }
39+
//
40+
// Task.detached {
41+
// _ = await self.hi2() // async
42+
// }
43+
}
44+
45+
// // other -------------------------------------------------------------------
46+
//
47+
// async let otherLet = other.hi3() // hi = async throws because of `other`
48+
// _ = try await otherLet
49+
//
50+
// Task {
51+
// _ = try await other.hi4() // hi = async throws
52+
// }
53+
//
54+
// Task.detached {
55+
// _ = try await other.hi5() // hi = async throws
56+
// }
57+
//
58+
// // known to be local -------------------------------------------------------
59+
//
60+
// // FIXME(distributed): relies on the "secretly known to be local" hack in typechecking
61+
// let _: String? = await other.whenLocal { __secretlyKnownToBeLocal in
62+
// // we're able to get state of what would otherwise be distributed-isolated:
63+
// __secretlyKnownToBeLocal.philosophy
64+
// }
65+
// }
66+
//
67+
// static func test(iso: isolated Philosopher) async throws {
68+
// _ = iso.h6() // we're "in the actor" already, since isolated
69+
//
70+
// // isolated parameter ------------------------------------------------------
71+
// async let otherLet = iso.hi7() // async
72+
// _ = await otherLet
73+
//
74+
// Task {
75+
// _ = await iso.hi8() // none
76+
// }
77+
//
78+
// Task.detached {
79+
// _ = await iso.hi9() // async
80+
// }
81+
// }
82+
}

0 commit comments

Comments
 (0)