Skip to content

Commit 0ae1203

Browse files
authored
Merge pull request #40197 from ktoso/wip-more-func-restrictions
[Distributed] more restrictions on distributed funcs based on serialization findings
2 parents 0d195d7 + f191730 commit 0ae1203

8 files changed

+104
-37
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4505,25 +4505,34 @@ ERROR(distributed_actor_isolated_method,none,
45054505
"only 'distributed' instance methods can be called on a potentially remote distributed actor",
45064506
())
45074507
ERROR(distributed_actor_func_param_not_codable,none,
4508-
"distributed instance method parameter '%0' of type %1 does not conform to 'Codable'",
4509-
(StringRef, Type))
4508+
"parameter '%0' of type %1 in %2 does not conform to '%3'",
4509+
(StringRef, Type, DescriptiveDeclKind, StringRef))
45104510
ERROR(distributed_actor_func_result_not_codable,none,
4511-
"distributed instance method result type %0 does not conform to 'Codable'",
4512-
(Type))
4511+
"result type %0 of %1 does not conform to '%2'",
4512+
(Type, DescriptiveDeclKind, StringRef))
45134513
ERROR(distributed_actor_remote_func_implemented_manually,none,
4514-
"distributed function's %0 remote counterpart %1 cannot not be implemented manually.",
4514+
"distributed instance method's %0 remote counterpart %1 cannot not be implemented manually.",
45154515
(Identifier, Identifier))
45164516
ERROR(nonisolated_distributed_actor_storage,none,
45174517
"'nonisolated' can not be applied to distributed actor stored properties",
45184518
())
45194519
ERROR(distributed_actor_func_nonisolated, none,
4520-
"function %0 cannot be both 'nonisolated' and 'distributed'",
4520+
"cannot declare method %0 as both 'nonisolated' and 'distributed'",
45214521
(DeclName))
45224522
ERROR(distributed_actor_func_private, none,
45234523
"%0 %1 cannot be 'private'",
45244524
(DescriptiveDeclKind, DeclName))
4525+
ERROR(distributed_actor_func_inout, none,
4526+
"cannot declare 'inout' argument %0 in %1 %2",
4527+
(DeclName, DescriptiveDeclKind, DeclName))
4528+
ERROR(distributed_actor_func_closure, none,
4529+
"%0 %1 cannot declare closure arguments, as they cannot be serialized",
4530+
(DescriptiveDeclKind, DeclName))
4531+
ERROR(distributed_actor_func_variadic, none,
4532+
"cannot declare variadic argument %0 in %1 %2",
4533+
(DeclName, DescriptiveDeclKind, DeclName))
45254534
ERROR(distributed_actor_remote_func_is_not_static,none,
4526-
"remote function %0 must be static.",
4535+
"remote function %0 must be static",
45274536
(DeclName))
45284537
ERROR(distributed_actor_remote_func_is_not_async_throws,none,
45294538
"remote function %0 must be 'async throws'.",
@@ -4654,7 +4663,7 @@ ERROR(distributed_actor_func_static,none,
46544663
"'distributed' method cannot be 'static'",
46554664
())
46564665
ERROR(distributed_actor_func_not_in_distributed_actor,none,
4657-
"'distributed' function can only be declared within 'distributed actor'",
4666+
"'distributed' method can only be declared within 'distributed actor'",
46584667
())
46594668
ERROR(distributed_actor_designated_ctor_must_have_one_transport_param,none,
46604669
"designated distributed actor initializer %0 must accept exactly one "

lib/Sema/TypeCheckDistributed.cpp

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,24 @@ void swift::diagnoseDistributedFunctionInNonDistributedActorProtocol(
6969
}
7070
}
7171

72+
73+
/// Add Fix-It text for the given nominal type to adopt Codable.
74+
///
75+
/// Useful when 'Codable' is the 'SerializationRequirement' and a non-Codable
76+
/// function parameter or return value type is detected.
77+
void swift::addCodableFixIt(
78+
const NominalTypeDecl *nominal, InFlightDiagnostic &diag) {
79+
if (nominal->getInherited().empty()) {
80+
SourceLoc fixItLoc = nominal->getBraces().Start;
81+
diag.fixItInsert(fixItLoc, ": Codable");
82+
} else {
83+
ASTContext &ctx = nominal->getASTContext();
84+
SourceLoc fixItLoc = nominal->getInherited().back().getSourceRange().End;
85+
fixItLoc = Lexer::getLocForEndOfToken(ctx.SourceMgr, fixItLoc);
86+
diag.fixItInsert(fixItLoc, ", Codable");
87+
}
88+
}
89+
7290
// ==== ------------------------------------------------------------------------
7391

7492
bool IsDistributedActorRequest::evaluate(
@@ -119,28 +137,53 @@ bool swift::checkDistributedFunction(FuncDecl *func, bool diagnose) {
119137
auto paramTy = func->mapTypeIntoContext(param->getInterfaceType());
120138
if (TypeChecker::conformsToProtocol(paramTy, encodableType, module).isInvalid() ||
121139
TypeChecker::conformsToProtocol(paramTy, decodableType, module).isInvalid()) {
122-
if (diagnose)
123-
func->diagnose(
140+
if (diagnose) {
141+
auto diag = func->diagnose(
124142
diag::distributed_actor_func_param_not_codable,
125-
param->getArgumentName().str(),
126-
param->getInterfaceType()
127-
);
128-
// TODO: suggest a fixit to add Codable to the type?
143+
param->getArgumentName().str(), param->getInterfaceType(),
144+
func->getDescriptiveKind(), "Codable");
145+
if (auto paramNominalTy = paramTy->getAnyNominal()) {
146+
addCodableFixIt(paramNominalTy, diag);
147+
} // else, no nominal type to suggest the fixit for, e.g. a closure
148+
}
149+
return true;
150+
}
151+
152+
if (param->isInOut()) {
153+
param->diagnose(
154+
diag::distributed_actor_func_inout,
155+
param->getName(),
156+
func->getDescriptiveKind(), func->getName()
157+
).fixItRemove(SourceRange(param->getTypeSourceRangeForDiagnostics().Start,
158+
param->getTypeSourceRangeForDiagnostics().Start.getAdvancedLoc(1)));
159+
// FIXME(distributed): the fixIt should be on param->getSpecifierLoc(), but that Loc is invalid for some reason?
129160
return true;
130161
}
162+
163+
if (param->isVariadic()) {
164+
param->diagnose(
165+
diag::distributed_actor_func_variadic,
166+
param->getName(),
167+
func->getDescriptiveKind(), func->getName()
168+
);
169+
}
131170
}
132171

133172
// --- Result type must be either void or a codable type
134173
auto resultType = func->mapTypeIntoContext(func->getResultInterfaceType());
135174
if (!resultType->isVoid()) {
136175
if (TypeChecker::conformsToProtocol(resultType, decodableType, module).isInvalid() ||
137176
TypeChecker::conformsToProtocol(resultType, encodableType, module).isInvalid()) {
138-
if (diagnose)
139-
func->diagnose(
177+
if (diagnose) {
178+
auto diag = func->diagnose(
140179
diag::distributed_actor_func_result_not_codable,
141-
func->getResultInterfaceType()
180+
func->getResultInterfaceType(), func->getDescriptiveKind(),
181+
"Codable" // Codable is a typealias, easier to diagnose like that
142182
);
143-
// TODO: suggest a fixit to add Codable to the type?
183+
if (auto resultNominalType = resultType->getAnyNominal()) {
184+
addCodableFixIt(resultNominalType, diag);
185+
}
186+
}
144187
return true;
145188
}
146189
}

lib/Sema/TypeCheckDistributed.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ Type getDistributedActorIdentityType(NominalTypeDecl *actor);
5555
void diagnoseDistributedFunctionInNonDistributedActorProtocol(
5656
const ProtocolDecl *proto, InFlightDiagnostic &diag);
5757

58+
/// Emit a FixIt suggesting to add Codable to the nominal type.
59+
void addCodableFixIt(const NominalTypeDecl *nominal, InFlightDiagnostic &diag);
60+
5861
}
5962

6063

test/Distributed/distributed_actor_inference.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,21 @@ distributed enum SomeDistributedActor_3 { } // expected-error{{'distributed' mod
2929

3030
@available(SwiftStdlib 5.6, *)
3131
struct SomeNotActorStruct_2 {
32-
distributed func nopeAsyncThrows() async throws -> Int { 42 } // expected-error{{'distributed' function can only be declared within 'distributed actor'}}
32+
distributed func nopeAsyncThrows() async throws -> Int { 42 } // expected-error{{'distributed' method can only be declared within 'distributed actor'}}
3333
}
3434

3535
@available(SwiftStdlib 5.6, *)
3636
class SomeNotActorClass_3 {
37-
distributed func nopeAsyncThrows() async throws -> Int { 42 } // expected-error{{'distributed' function can only be declared within 'distributed actor'}}
37+
distributed func nopeAsyncThrows() async throws -> Int { 42 } // expected-error{{'distributed' method can only be declared within 'distributed actor'}}
3838
}
3939

4040
@available(SwiftStdlib 5.6, *)
4141
actor SomeNotDistributedActor_4 {
42-
distributed func notInDistActorAsyncThrowing() async throws -> Int { 42 } // expected-error{{'distributed' function can only be declared within 'distributed actor'}}
42+
distributed func notInDistActorAsyncThrowing() async throws -> Int { 42 } // expected-error{{'distributed' method can only be declared within 'distributed actor'}}
4343
}
4444

4545
protocol DP {
46-
distributed func hello() // expected-error{{'distributed' function can only be declared within 'distributed actor'}}
46+
distributed func hello() // expected-error{{'distributed' method can only be declared within 'distributed actor'}}
4747
}
4848

4949
@available(SwiftStdlib 5.6, *)
@@ -58,7 +58,7 @@ protocol DPOK2: DPOK {
5858

5959
@available(SwiftStdlib 5.6, *)
6060
enum SomeNotActorEnum_5 {
61-
distributed func nopeAsyncThrows() async throws -> Int { 42 } // expected-error{{'distributed' function can only be declared within 'distributed actor'}}
61+
distributed func nopeAsyncThrows() async throws -> Int { 42 } // expected-error{{'distributed' method can only be declared within 'distributed actor'}}
6262
}
6363

6464
@available(SwiftStdlib 5.6, *)
@@ -68,9 +68,9 @@ distributed actor SomeDistributedActor_6 {
6868

6969
@available(SwiftStdlib 5.6, *)
7070
distributed actor SomeDistributedActor_7 {
71-
distributed func dont_1() async throws -> Int { 42 } // expected-error{{distributed function's 'dont_1' remote counterpart '_remote_dont_1' cannot not be implemented manually.}}
72-
distributed func dont_2() async throws -> Int { 42 } // expected-error{{distributed function's 'dont_2' remote counterpart '_remote_dont_2' cannot not be implemented manually.}}
73-
distributed func dont_3() async throws -> Int { 42 } // expected-error{{distributed function's 'dont_3' remote counterpart '_remote_dont_3' cannot not be implemented manually.}}
71+
distributed func dont_1() async throws -> Int { 42 } // expected-error{{distributed instance method's 'dont_1' remote counterpart '_remote_dont_1' cannot not be implemented manually.}}
72+
distributed func dont_2() async throws -> Int { 42 } // expected-error{{distributed instance method's 'dont_2' remote counterpart '_remote_dont_2' cannot not be implemented manually.}}
73+
distributed func dont_3() async throws -> Int { 42 } // expected-error{{distributed instance method's 'dont_3' remote counterpart '_remote_dont_3' cannot not be implemented manually.}}
7474
}
7575

7676
@available(SwiftStdlib 5.6, *)

test/Distributed/distributed_actor_is_experimental_enabled_missing_import.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ distributed actor class DAC {}
1515

1616
actor A {
1717
func normal() async {}
18-
distributed func dist() {} // expected-error{{'distributed' function can only be declared within 'distributed actor'}}
19-
distributed func distAsync() async {} // expected-error{{'distributed' function can only be declared within 'distributed actor'}}
18+
distributed func dist() {} // expected-error{{'distributed' method can only be declared within 'distributed actor'}}
19+
distributed func distAsync() async {} // expected-error{{'distributed' method can only be declared within 'distributed actor'}}
2020

2121
distributed var neverOk: String { // expected-error{{'distributed' modifier cannot be applied to this declaration}}
2222
"vars are not allowed to be distributed *ever* anyway"

test/Distributed/distributed_actor_isolation.swift

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ actor LocalActor_1 {
2222
var mutable: String = ""
2323

2424
distributed func nope() {
25-
// expected-error@-1{{'distributed' function can only be declared within 'distributed actor'}}
25+
// expected-error@-1{{'distributed' method can only be declared within 'distributed actor'}}
2626
}
2727
}
2828

@@ -68,21 +68,33 @@ distributed actor DistributedActor_1 {
6868
distributed func distIntString(int: Int, two: String) async throws -> (String) { "\(int) + \(two)" } // ok
6969

7070
distributed func dist(notCodable: NotCodableValue) async throws {
71-
// expected-error@-1 {{distributed instance method parameter 'notCodable' of type 'NotCodableValue' does not conform to 'Codable'}}
71+
// expected-error@-1 {{parameter 'notCodable' of type 'NotCodableValue' in distributed instance method does not conform to 'Codable'}}
7272
}
7373
distributed func distBadReturn(int: Int) async throws -> NotCodableValue {
74-
// expected-error@-1 {{distributed instance method result type 'NotCodableValue' does not conform to 'Codable'}}
74+
// expected-error@-1 {{result type 'NotCodableValue' of distributed instance method does not conform to 'Codable'}}
7575
fatalError()
7676
}
7777

78+
distributed func varargs(int: Int...) {
79+
// expected-error@-1{{cannot declare variadic argument 'int' in distributed instance method 'varargs(int:)'}}
80+
}
81+
82+
distributed func closure(close: () -> String) {
83+
// expected-error@-1{{parameter 'close' of type '() -> String' in distributed instance method does not conform to 'Codable'}}
84+
}
85+
86+
distributed func noInout(inNOut burger: inout String) {
87+
// expected-error@-1{{cannot declare 'inout' argument 'burger' in distributed instance method 'noInout(inNOut:)'}}{{43-49=}}
88+
}
89+
7890
distributed func distReturnGeneric<T: Codable & Sendable>(item: T) async throws -> T { // ok
7991
item
8092
}
8193
distributed func distReturnGenericWhere<T: Sendable>(item: Int) async throws -> T where T: Codable { // ok
8294
fatalError()
8395
}
8496
distributed func distBadReturnGeneric<T: Sendable>(int: Int) async throws -> T {
85-
// expected-error@-1 {{distributed instance method result type 'T' does not conform to 'Codable'}}
97+
// expected-error@-1 {{result type 'T' of distributed instance method does not conform to 'Codable'}}
8698
fatalError()
8799
}
88100

@@ -93,7 +105,7 @@ distributed actor DistributedActor_1 {
93105
value
94106
}
95107
distributed func distBadGenericParam<T: Sendable>(int: T) async throws {
96-
// expected-error@-1 {{distributed instance method parameter 'int' of type 'T' does not conform to 'Codable'}}
108+
// expected-error@-1 {{parameter 'int' of type 'T' in distributed instance method does not conform to 'Codable'}}
97109
fatalError()
98110
}
99111

test/Distributed/distributed_actor_nonisolated.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@ distributed actor DA {
3838
}
3939

4040
nonisolated distributed func nonisolatedDistributed() async {
41-
// expected-error@-1{{function 'nonisolatedDistributed()' cannot be both 'nonisolated' and 'distributed'}}{{3-15=}}
41+
// expected-error@-1{{cannot declare method 'nonisolatedDistributed()' as both 'nonisolated' and 'distributed'}}{{3-15=}}
4242
fatalError()
4343
}
4444

4545
distributed nonisolated func distributedNonisolated() async {
46-
// expected-error@-1{{function 'distributedNonisolated()' cannot be both 'nonisolated' and 'distributed'}}{{15-27=}}
46+
// expected-error@-1{{cannot declare method 'distributedNonisolated()' as both 'nonisolated' and 'distributed'}}{{15-27=}}
4747
fatalError()
4848
}
4949

test/Distributed/distributed_protocol_isolation.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ typealias DefaultActorTransport = AnyActorTransport
1111
// MARK: Distributed actor protocols
1212

1313
protocol WrongDistFuncs {
14-
distributed func notDistActor() // expected-error{{'distributed' function can only be declared within 'distributed actor'}}{{5-17=}} {{25-25=: DistributedActor}}
14+
distributed func notDistActor() // expected-error{{'distributed' method can only be declared within 'distributed actor'}}{{5-17=}} {{25-25=: DistributedActor}}
1515
}
1616

1717
protocol DistProtocol: DistributedActor {
@@ -199,7 +199,7 @@ extension DistributedTacoMaker {
199199

200200
extension TacoPreparation {
201201
distributed func makeSalsa() -> Salsa {}
202-
// expected-error@-1{{'distributed' function can only be declared within 'distributed actor'}}
202+
// expected-error@-1{{'distributed' method can only be declared within 'distributed actor'}}
203203
}
204204

205205
distributed actor TacoWorker: DistributedTacoMaker {} // implemented in extensions

0 commit comments

Comments
 (0)