Skip to content

Commit 8e6d721

Browse files
committed
[Distributed] Further witness checking cleanup and tests
1 parent 911b42f commit 8e6d721

File tree

2 files changed

+28
-17
lines changed

2 files changed

+28
-17
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3031,12 +3031,12 @@ bool ConformanceChecker::checkActorIsolation(
30313031
if (isDistributed) {
30323032
// Check if the protocol where the requirement originates from
30333033
// is a distributed actor constrained one.
3034-
auto proto = dyn_cast<ProtocolDecl>(requirement->getDeclContext());
3035-
if (proto && proto->isDistributedActor()) {
3034+
if (cast<ProtocolDecl>(requirement->getDeclContext())->isDistributedActor()) {
30363035
// The requirement was declared in a DistributedActor constrained proto.
30373036
//
3038-
// This means casting up to this `P` won't "strip off" the "distributed-ness"
3039-
// of the type, and all call-sites will be checking distributed isolation.
3037+
// This means casting up to this `P` won't "strip off" the
3038+
// "distributed-ness" of the type, and all call-sites will be checking
3039+
// distributed isolation.
30403040
//
30413041
// This means that we can actually allow these specific requirements,
30423042
// to be witnessed without the distributed keyword (!), but they won't be
@@ -3052,8 +3052,7 @@ bool ConformanceChecker::checkActorIsolation(
30523052

30533053
// If the requirement is distributed, we still need to require it on the witness though.
30543054
// We DO allow a non-distributed requirement to be witnessed here though!
3055-
if (isDistributedDecl(requirement) &&
3056-
!isDistributedDecl(witness))
3055+
if (isDistributedDecl(requirement) && !isDistributedDecl(witness))
30573056
missingOptions |= MissingFlags::WitnessDistributed;
30583057
} else {
30593058
// The protocol requirement comes from a normal (non-distributed actor)
@@ -3062,12 +3061,12 @@ bool ConformanceChecker::checkActorIsolation(
30623061

30633062
// If we're coming from a non-distributed requirement,
30643063
// then the requirement must be 'throws' to accommodate failure.
3065-
if (!isDistributedDecl(requirement) && !isThrowsDecl(requirement))
3064+
if (!isThrowsDecl(requirement))
30663065
missingOptions |= MissingFlags::RequirementThrows;
30673066

3068-
// If the requirement is distributed, we require a distributed witness
3069-
if (!isDistributedDecl(witness) &&
3070-
(isDistributedDecl(requirement) || !missingOptions))
3067+
// If the witness is distributed, it is able to witness a requirement
3068+
// only if the requirement is `async throws`.
3069+
if (!isDistributedDecl(witness) && !missingOptions)
30713070
missingOptions |= MissingFlags::WitnessDistributed;
30723071
}
30733072
}

test/Distributed/distributed_protocol_isolation.swift

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,9 @@ protocol StrictlyLocal {
100100

101101
func localThrows() throws
102102
// expected-note@-1 2{{mark the protocol requirement 'localThrows()' 'async' to allow actor-isolated conformances}}{{22-22=async }}
103-
104-
// TODO: localAsync
103+
104+
func localAsync() async
105+
// expected-note@-1 2{{mark the protocol requirement 'localAsync()' 'throws' to allow actor-isolated conformances}}
105106
}
106107

107108
distributed actor Nope1_StrictlyLocal: StrictlyLocal {
@@ -111,24 +112,29 @@ distributed actor Nope1_StrictlyLocal: StrictlyLocal {
111112
func localThrows() throws {}
112113
// expected-error@-1{{distributed actor-isolated instance method 'localThrows()' cannot be used to satisfy nonisolated protocol requirement}}
113114
// expected-note@-2{{add 'nonisolated' to 'localThrows()' to make this instance method not isolated to the actor}}
115+
func localAsync() async {}
116+
// expected-error@-1{{distributed actor-isolated instance method 'localAsync()' cannot be used to satisfy nonisolated protocol requirement}}
117+
// expected-note@-2{{add 'nonisolated' to 'localAsync()' to make this instance method not isolated to the actor}}
114118
}
115119
distributed actor Nope2_StrictlyLocal: StrictlyLocal {
116120
distributed func local() {}
117121
// expected-error@-1{{actor-isolated distributed instance method 'local()' cannot be used to satisfy nonisolated protocol requirement}}
118122
distributed func localThrows() throws {}
119123
// expected-error@-1{{actor-isolated distributed instance method 'localThrows()' cannot be used to satisfy nonisolated protocol requirement}}
124+
distributed func localAsync() async {}
125+
// expected-error@-1{{actor-isolated distributed instance method 'localAsync()' cannot be used to satisfy nonisolated protocol requirement}}
120126
}
121127
distributed actor OK_StrictlyLocal: StrictlyLocal {
122128
nonisolated func local() {}
123129
nonisolated func localThrows() throws {}
130+
nonisolated func localAsync() async {}
124131
}
125132

126133
protocol Server {
127-
func send<Message: Codable>(message: Message) async throws -> String
134+
func send<Message: Codable & Sendable>(message: Message) async throws -> String
128135
}
129136
actor MyServer : Server {
130-
// expected-note@+1{{consider making generic parameter 'Message' conform to the 'Sendable' protocol}} {{29-29=, Sendable}}
131-
func send<Message: Codable>(message: Message) throws -> String { "" } // expected-warning{{non-sendable type 'Message' in parameter of actor-isolated instance method 'send(message:)' satisfying protocol requirement cannot cross actor boundary}}
137+
func send<Message: Codable & Sendable>(message: Message) throws -> String { "" } // OK
132138
}
133139

134140
protocol AsyncThrowsAll {
@@ -140,9 +146,15 @@ actor LocalOK_AsyncThrowsAll: AsyncThrowsAll {
140146
func maybe(param: String, int: Int) async throws -> Int { 1111 }
141147
}
142148

143-
actor LocalOK_Implicitly_AsyncThrowsAll: AsyncThrowsAll {
149+
actor LocalOK_ImplicitlyThrows_AsyncThrowsAll: AsyncThrowsAll {
150+
func maybe(param: String, int: Int) async -> Int { 1111 }
151+
}
152+
actor LocalOK_ImplicitlyAsync_AsyncThrowsAll: AsyncThrowsAll {
144153
func maybe(param: String, int: Int) throws -> Int { 1111 }
145154
}
155+
actor LocalOK_ImplicitlyThrowsAsync_AsyncThrowsAll: AsyncThrowsAll {
156+
func maybe(param: String, int: Int) -> Int { 1111 }
157+
}
146158

147159
distributed actor Nope1_AsyncThrowsAll: AsyncThrowsAll {
148160
func maybe(param: String, int: Int) async throws -> Int { 111 }
@@ -226,7 +238,7 @@ func test_watchingDA_erased(da: DA_TerminationWatchingDA) async throws {
226238
// expected-warning@-2{{no calls to throwing functions occur within 'try' expression}}
227239

228240
let __secretlyKnownToBeLocal = wda
229-
await __secretlyKnownToBeLocal.terminated(da: "local calls are okey!") // OK // OK // FIXME(#59356): (the __secretlyKnown is a hack, but the whenLocal crashes now on pending isolation getting with generic actors for closures)
241+
await __secretlyKnownToBeLocal.terminated(da: "local calls are okey!") // OK // FIXME(#59356): (the __secretlyKnown is a hack, but the whenLocal crashes now on pending isolation getting with generic actors for closures)
230242
// FIXME: pending fix of closure isolation checking with actors #59356
231243
// await wda.whenLocal { __secretlyKnownToBeLocal in
232244
// await __secretlyKnownToBeLocal.terminated(da: "local calls are okey!") // OK

0 commit comments

Comments
 (0)