Skip to content

Commit 8c27e49

Browse files
committed
[Distributed] move dist. init synthesis to default synthesis
1 parent 8656762 commit 8c27e49

File tree

6 files changed

+70
-160
lines changed

6 files changed

+70
-160
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4566,7 +4566,7 @@ ERROR(distributed_actor_func_not_in_distributed_actor,none,
45664566
"'distributed' function can only be declared within 'distributed actor'",
45674567
())
45684568
ERROR(distributed_actor_designated_ctor_must_have_one_transport_param,none,
4569-
"designated distributed actor initializer %0 must accept exactly one"
4569+
"designated distributed actor initializer %0 must accept exactly one "
45704570
"ActorTransport parameter, found %1",
45714571
(DeclName, int))
45724572
ERROR(distributed_actor_designated_ctor_missing_transport_param,none,

lib/Sema/CodeSynthesis.cpp

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,14 @@ enum class ImplicitConstructorKind {
209209
/// The default constructor, which default-initializes each
210210
/// of the instance variables.
211211
Default,
212+
/// The default constructor of a distributed actor.
213+
/// Similarly to a Default one it initializes each of the instance variables,
214+
/// however it also implicitly gains an ActorTransport parameter.
215+
DefaultDistributedActor,
212216
/// The memberwise constructor, which initializes each of
213217
/// the instance variables from a parameter of the same type and
214218
/// name.
215-
Memberwise
219+
Memberwise,
216220
};
217221

218222
/// Create an implicit struct or class constructor.
@@ -227,16 +231,6 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl,
227231
ASTContext &ctx) {
228232
assert(!decl->hasClangNode());
229233

230-
// Don't synthesize for distributed actors, they're a bit special.
231-
//
232-
// They have their special inits, and should not get the usual
233-
// default/implicit constructor (i.e. `init()` is illegal for them, as they
234-
// always must have an associated transport - via `init(transport:)` or
235-
// `init(resolve:using:)`).
236-
if (auto clazz = dyn_cast<ClassDecl>(decl))
237-
if (clazz->isDistributedActor())
238-
return nullptr;
239-
240234
SourceLoc Loc = decl->getLoc();
241235
auto accessLevel = AccessLevel::Internal;
242236

@@ -319,6 +313,23 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl,
319313

320314
maybeAddMemberwiseDefaultArg(arg, var, params.size(), ctx);
321315

316+
params.push_back(arg);
317+
}
318+
} else if (ICK == ImplicitConstructorKind::DefaultDistributedActor) {
319+
assert(isa<ClassDecl>(decl));
320+
assert(decl->isDistributedActor() &&
321+
"Only 'distributed actor' type can gain implicit distributed actor init");
322+
323+
if (swift::ensureDistributedModuleLoaded(decl)) {
324+
auto transportDecl = ctx.getActorTransportDecl();
325+
326+
// Create the parameter.
327+
auto *arg = new (ctx) ParamDecl(SourceLoc(), Loc, ctx.Id_transport, Loc,
328+
ctx.Id_transport, transportDecl);
329+
arg->setSpecifier(ParamSpecifier::Default);
330+
arg->setInterfaceType(transportDecl->getDeclaredInterfaceType());
331+
arg->setImplicit();
332+
322333
params.push_back(arg);
323334
}
324335
}
@@ -1193,7 +1204,6 @@ static bool shouldAttemptInitializerSynthesis(const NominalTypeDecl *decl) {
11931204
}
11941205

11951206
void TypeChecker::addImplicitConstructors(NominalTypeDecl *decl) {
1196-
fprintf(stderr, "[%s:%d] (%s) ADD IMPLICIT\n", __FILE__, __LINE__, __FUNCTION__);
11971207
// If we already added implicit initializers, we're done.
11981208
if (decl->addedImplicitInitializers())
11991209
return;
@@ -1493,10 +1503,10 @@ SynthesizeDefaultInitRequest::evaluate(Evaluator &evaluator,
14931503
decl);
14941504

14951505
// Create the default constructor.
1496-
if (auto ctor = createImplicitConstructor(decl,
1497-
ImplicitConstructorKind::Default,
1498-
ctx)) {
1499-
1506+
auto ctorKind = decl->isDistributedActor() ?
1507+
ImplicitConstructorKind::DefaultDistributedActor :
1508+
ImplicitConstructorKind::Default;
1509+
if (auto ctor = createImplicitConstructor(decl, ctorKind, ctx)) {
15001510
// Add the constructor.
15011511
decl->addMember(ctor);
15021512

lib/Sema/CodeSynthesisDistributedActor.cpp

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -119,25 +119,6 @@ createDistributedActor_init_default(ClassDecl *classDecl,
119119
return initDecl;
120120
}
121121

122-
static void addImplicitDefaultDistributedActorConstructor(ClassDecl *decl) {
123-
fprintf(stderr, "[%s:%d] (%s) addImplicitDefaultDistributedActorConstructor\n", __FILE__, __LINE__, __FUNCTION__);
124-
decl->setAddedImplicitInitializers();
125-
126-
// Check whether the user has defined a designated initializer for this actor,
127-
// if so, we will not synthesize the init(transport:) initializer.
128-
bool foundDesignatedInit = decl->hasUserDefinedDesignatedInit();
129-
if (foundDesignatedInit) {
130-
fprintf(stderr, "[%s:%d] (%s) FOUND DESIGNATED INIT SKIP SYNTHESIS\n", __FILE__, __LINE__, __FUNCTION__);
131-
decl->dump();
132-
return;
133-
}
134-
135-
fprintf(stderr, "[%s:%d] (%s) MAKE DESIGNATED INIT SYNTHESIS\n", __FILE__, __LINE__, __FUNCTION__);
136-
auto &ctx = decl->getASTContext();
137-
auto init = createDistributedActor_init_default(decl, ctx);
138-
decl->addMember(init);
139-
}
140-
141122
/******************************************************************************/
142123
/******************************** DEINIT **************************************/
143124
/******************************************************************************/
@@ -464,15 +445,10 @@ void swift::addImplicitDistributedActorMembersToClass(ClassDecl *decl) {
464445
if (!decl->isDistributedActor())
465446
return;
466447

467-
// === Ensure the _Distributed module is loaded
468-
auto &C = decl->getASTContext();
469-
if (!C.getLoadedModule(C.Id_Distributed)) {
470-
// seems we're missing the _Distributed module, ask to import it explicitly
471-
decl->diagnose(diag::distributed_actor_needs_explicit_distributed_import);
448+
// If the _Distributed module is missing we cannot synthesize anything.
449+
if (!swift::ensureDistributedModuleLoaded(decl))
472450
return;
473-
}
474451

475-
addImplicitDefaultDistributedActorConstructor(decl);
476452
addImplicitDistributedActorStoredProperties(decl);
477453
addImplicitRemoteActorFunctions(decl);
478454
// addImplicitResignIdentity(decl);

lib/Sema/TypeCheckDistributed.cpp

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,20 @@ using namespace swift;
3131

3232
// ==== ------------------------------------------------------------------------
3333

34+
bool swift::ensureDistributedModuleLoaded(Decl *decl) {
35+
fprintf(stderr, "[%s:%d] (%s) ensureDistributedModuleLoaded\n", __FILE__, __LINE__, __FUNCTION__);
36+
auto &C = decl->getASTContext();
37+
if (!C.getLoadedModule(C.Id_Distributed)) {
38+
// seems we're missing the _Distributed module, ask to import it explicitly
39+
decl->diagnose(diag::distributed_actor_needs_explicit_distributed_import);
40+
return false;
41+
}
42+
43+
return true;
44+
}
45+
46+
// ==== ------------------------------------------------------------------------
47+
3448
bool IsDistributedActorRequest::evaluate(
3549
Evaluator &evaluator, NominalTypeDecl *nominal) const {
3650
// Protocols are actors if they inherit from `DistributedActor`.
@@ -183,14 +197,21 @@ void TypeChecker::checkDistributedActor(const ClassDecl *decl) {
183197

184198
auto mutableDecl = const_cast<ClassDecl*>(decl);
185199

186-
swift::addImplicitDistributedActorMembersToClass(mutableDecl);
200+
// ==== Constructors
201+
// --- Get the default initializer
202+
// If applicable, this will the default 'init(transport:)' initializer
203+
(void)mutableDecl->getDefaultInitializer();
187204

188-
for (auto member : decl->getMembers()) {
189-
if (auto ctor = dyn_cast<ConstructorDecl>(member)) {
190-
fprintf(stderr, "[%s:%d] (%s) CHECK CTOR\n", __FILE__, __LINE__, __FUNCTION__);
191-
member->dump();
205+
// --- Check all constructors
206+
for (auto member : decl->getMembers())
207+
if (auto ctor = dyn_cast<ConstructorDecl>(member))
192208
checkDistributedActorConstructor(decl, ctor);
193-
}
194-
}
209+
210+
// ==== Properties
211+
// Synthesize properties
212+
// TODO: those could technically move to DerivedConformance style
213+
swift::addImplicitDistributedActorMembersToClass(mutableDecl);
214+
215+
// ==== Functions
195216
}
196217

lib/Sema/TypeCheckDistributed.h

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,25 +26,20 @@ namespace swift {
2626

2727
class AbstractFunctionDecl;
2828
class ConstructorDecl;
29-
class ActorIsolation;
30-
class AnyFunctionType;
3129
class ASTContext;
3230
class ClassDecl;
33-
class ClosureExpr;
34-
class ConcreteDeclRef;
35-
class CustomAttr;
3631
class Decl;
3732
class DeclContext;
38-
class EnumElementDecl;
3933
class Expr;
4034
class FuncDecl;
4135
class Initializer;
4236
class PatternBindingDecl;
4337
class ProtocolConformance;
44-
class TopLevelCodeDecl;
45-
class TypeBase;
4638
class ValueDecl;
4739

40+
// Diagnose an error if the _Distributed module is not loaded.
41+
bool ensureDistributedModuleLoaded(Decl *decl);
42+
4843
/// Check distributed actor isolation rules.
4944

5045
/// The local and resolve distributed actor constructors have special rules to check.

test/Distributed/distributed_actor_initialization.swift

Lines changed: 10 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -10,149 +10,57 @@ distributed actor OK0 { }
1010
@available(SwiftStdlib 5.5, *)
1111
distributed actor OK1 {
1212
var x: Int = 1
13-
// ok, since all fields are initialized, the constructors can be synthesized
13+
// ok, since all fields are initialized, the constructor can be synthesized
1414
}
1515

16-
// TODO: test all the FIXITs in this file
16+
// TODO(distributed): test all the FIXITs in this file
1717

1818
@available(SwiftStdlib 5.5, *)
1919
distributed actor Bad1 {
2020
init() {
21-
// expected-error@-1 {{'distributed actor' initializer 'init()' must be 'convenience' initializer. Distributed actors have an implicitly synthesized designated 'init(transport:)' local-initializer, which other initializers must delegate to}}
22-
// expected-error@-2 {{'distributed actor' initializer 'init()' must (directly or indirectly) delegate to 'init(transport:)}}
23-
}
24-
}
25-
26-
@available(SwiftStdlib 5.5, *)
27-
distributed actor Bad11 {
28-
convenience init() {
29-
// expected-error@-1 {{'distributed actor' initializer 'init()' must (directly or indirectly) delegate to 'init(transport:)'}}
21+
// expected-error@-1 {{designated distributed actor initializer 'init()' is missing required ActorTransport parameter}}
3022
}
3123
}
3224

3325
@available(SwiftStdlib 5.5, *)
3426
distributed actor Bad12 {
3527
init(x: String) {
36-
// expected-error@-1 {{'distributed actor' initializer 'init(x:)' must be 'convenience' initializer. Distributed actors have an implicitly synthesized designated 'init(transport:)' local-initializer, which other initializers must delegate to}}
37-
// expected-error@-2 {{'distributed actor' initializer 'init(x:)' must (directly or indirectly) delegate to 'init(transport:)}}
28+
// expected-error@-1 {{designated distributed actor initializer 'init(x:)' is missing required ActorTransport parameter}}
3829
}
3930
}
4031

4132
@available(SwiftStdlib 5.5, *)
4233
distributed actor OK2 {
4334
var x: Int
4435

45-
convenience init(x: Int, transport: ActorTransport) {
46-
self.init(transport: transport)
36+
init(x: Int, transport: ActorTransport) { // ok
4737
self.x = x
4838
}
4939
}
5040

5141
@available(SwiftStdlib 5.5, *)
5242
distributed actor Bad2 {
53-
var x: Int
43+
var x: Int = 1
5444

55-
convenience init(x: Int, transport: ActorTransport) {
56-
self.init(transport: transport)
57-
self.x = x
45+
init(transport: ActorTransport, too many: ActorTransport) {
46+
// expected-error@-1{{designated distributed actor initializer 'init(transport:too:)' must accept exactly one ActorTransport parameter, found 2}}
5847
}
5948
}
6049

6150
@available(SwiftStdlib 5.5, *)
62-
distributed actor Bad3 {
51+
distributed actor OK3 {
6352
var x: Int
6453

65-
convenience init(y: Int, transport: ActorTransport) {
66-
// expected-error@-1 {{'distributed actor' initializer 'init(y:transport:)' must (directly or indirectly) delegate to 'init(transport:)'}}
67-
// forgot to delegate to init(transport:)
54+
init(y: Int, transport: ActorTransport) {
6855
self.x = y
6956
}
7057
}
7158

7259
@available(SwiftStdlib 5.5, *)
7360
distributed actor OKMulti {
74-
// @derived init(transport:)
7561

7662
convenience init(y: Int, transport: ActorTransport) { // ok
7763
self.init(transport: transport)
7864
}
7965

80-
convenience init(x: Int, y: Int, transport: ActorTransport) {
81-
// ok, since we do delegate to init(transport) *eventually*
82-
self.init(y: y, transport: transport)
83-
}
84-
}
85-
86-
@available(SwiftStdlib 5.5, *)
87-
distributed actor BadMulti {
88-
// @derived init(transport:)
89-
90-
convenience init(y: Int, transport: ActorTransport) {
91-
// expected-error@-1 {{'distributed actor' initializer 'init(y:transport:)' must (directly or indirectly) delegate to 'init(transport:)'}}
92-
// self.init(transport: transport) // forgot to delegate to local init!
93-
}
94-
95-
convenience init(x: Int, y: Int, transport: ActorTransport) {
96-
// expected-error@-1 {{'distributed actor' initializer 'init(x:y:transport:)' must (directly or indirectly) delegate to 'init(transport:)'}}
97-
// ok, since we do delegate to init(transport) *eventually*
98-
self.init(y: y, transport: transport)
99-
}
100-
}
101-
102-
// It is illegal to manually invoke the resolve initializer,
103-
// because it may result in "not a real instance" i.e. a proxy
104-
// and a proxy does not have any storage, so it would be wrong to allow other
105-
// initializers to keep running while we actually created a proxy with no storage.
106-
@available(SwiftStdlib 5.5, *)
107-
distributed actor BadResolveInitCall {
108-
convenience init(any: Any, id: AnyActorIdentity, transport: ActorTransport) throws {
109-
// expected-error@-1 {{'distributed actor' initializer 'init(any:id:transport:)' cannot delegate to resolve-initializer 'init(resolve:using:)', as it may result resolving a storageless proxy instance}}
110-
// expected-error@-2 {{'distributed actor' initializer 'init(any:id:transport:)' must (directly or indirectly) delegate to 'init(transport:)'}}
111-
try self.init(resolve: id, using: transport) // TODO: suggest removing this call, since it is illegal
112-
}
113-
}
114-
115-
@available(SwiftStdlib 5.5, *)
116-
distributed actor BadRedeclare1 { // expected-error {{type 'BadRedeclare1' does not conform to protocol 'DistributedActor'}}
117-
convenience init(transport: ActorTransport) {}
118-
// expected-error@-1 {{'distributed actor' local-initializer 'init(transport:)' cannot be implemented explicitly}}
119-
// expected-error@-2 {{invalid redeclaration of synthesized 'init(transport:)'}}
120-
// expected-error@-3 {{invalid redeclaration of synthesized initializer 'init(transport:)'}}
121-
// expected-note@-4 {{candidate exactly matches}}
122-
}
123-
124-
@available(SwiftStdlib 5.5, *)
125-
distributed actor BadRedeclare11 { // expected-error {{type 'BadRedeclare11' does not conform to protocol 'DistributedActor'}}
126-
convenience init(transport xxx: ActorTransport) {}
127-
// expected-error@-1 {{'distributed actor' local-initializer 'init(transport:)' cannot be implemented explicitly}}
128-
// expected-error@-2 {{invalid redeclaration of synthesized 'init(transport:)'}}
129-
// expected-error@-3 {{invalid redeclaration of synthesized initializer 'init(transport:)'}}
130-
// expected-note@-4 {{candidate exactly matches}}
131-
}
132-
133-
@available(SwiftStdlib 5.5, *)
134-
distributed actor BadRedeclare2 { // expected-error {{type 'BadRedeclare2' does not conform to protocol 'DistributedActor'}}
135-
convenience init(resolve id: AnyActorIdentity, using transport: ActorTransport) {}
136-
// expected-error@-1 {{'distributed actor' resolve-initializer 'init(resolve:using:)' cannot be implemented explicitly}}
137-
// expected-note@-2 {{candidate exactly matches}}
138-
// expected-error@-3 {{invalid redeclaration of synthesized 'init(resolve:using:)'}}
139-
// expected-error@-4 {{invalid redeclaration of synthesized initializer 'init(resolve:using:)'}}
140-
}
141-
142-
@available(SwiftStdlib 5.5, *)
143-
distributed actor BadRedeclare21 { //expected-error {{type 'BadRedeclare21' does not conform to protocol 'DistributedActor'}}
144-
convenience init(resolve xxx: AnyActorIdentity, using yyy: ActorTransport) {}
145-
// expected-error@-1 {{'distributed actor' resolve-initializer 'init(resolve:using:)' cannot be implemented explicitly}}
146-
// expected-note@-2 {{candidate exactly matches}}
147-
// expected-error@-3 {{invalid redeclaration of synthesized 'init(resolve:using:)'}}
148-
// expected-error@-4 {{invalid redeclaration of synthesized initializer 'init(resolve:using:)'}}
149-
}
150-
151-
@available(SwiftStdlib 5.5, *)
152-
distributed actor BadRedeclare22 { //expected-error {{type 'BadRedeclare22' does not conform to protocol 'DistributedActor'}}
153-
convenience init(resolve: AnyActorIdentity, using yyy: ActorTransport) throws {}
154-
// expected-error@-1 {{'distributed actor' resolve-initializer 'init(resolve:using:)' cannot be implemented explicitly}}
155-
// expected-note@-2 {{candidate exactly matches}}
156-
// expected-error@-3 {{invalid redeclaration of synthesized 'init(resolve:using:)'}}
157-
// expected-error@-4 {{invalid redeclaration of synthesized initializer 'init(resolve:using:)'}}
15866
}

0 commit comments

Comments
 (0)