3333
3434using namespace swift ;
3535
36-
3736/* *****************************************************************************/
3837/* *********************** PROPERTY SYNTHESIS **********************************/
3938/* *****************************************************************************/
4039
4140static VarDecl*
42- lookupDistributedActorProperty (NominalTypeDecl *decl, DeclName name) {
43- assert (decl && " decl was null" );
44- auto &C = decl->getASTContext ();
45-
46- auto clazz = dyn_cast<ClassDecl>(decl);
47- if (!clazz)
48- return nullptr ;
49-
50- auto refs = decl->lookupDirect (name);
51- if (refs.size () != 1 )
52- return nullptr ;
53-
54- auto var = dyn_cast<VarDecl>(refs.front ());
55- if (!var)
56- return nullptr ;
57-
58- Type expectedType = Type ();
59- if (name == C.Id_id ) {
60- expectedType = getDistributedActorIDType (decl);
61- } else if (name == C.Id_actorSystem ) {
62- expectedType = getDistributedActorSystemType (decl);
63- } else {
64- llvm_unreachable (" Unexpected distributed actor property lookup!" );
65- }
66- if (!expectedType)
67- return nullptr ;
68-
69- if (!var->getInterfaceType ()->isEqual (expectedType))
70- return nullptr ;
71-
72- assert (var->isSynthesized () && " Expected compiler synthesized property" );
73- return var;
74- }
75-
41+ lookupDistributedActorProperty (NominalTypeDecl *decl, DeclName name) {
42+ assert (decl && " decl was null" );
43+ auto &C = decl->getASTContext ();
44+
45+ auto clazz = dyn_cast<ClassDecl>(decl);
46+ if (!clazz)
47+ return nullptr ;
48+
49+ auto refs = decl->lookupDirect (name);
50+ if (refs.size () != 1 )
51+ return nullptr ;
52+
53+ auto var = dyn_cast<VarDecl>(refs.front ());
54+ if (!var)
55+ return nullptr ;
56+
57+ Type expectedType = Type ();
58+ if (name == C.Id_id ) {
59+ expectedType = getDistributedActorIDType (decl);
60+ } else if (name == C.Id_actorSystem ) {
61+ expectedType = getDistributedActorSystemType (decl);
62+ } else {
63+ llvm_unreachable (" Unexpected distributed actor property lookup!" );
64+ }
65+ if (!expectedType)
66+ return nullptr ;
67+
68+ if (!var->getInterfaceType ()->isEqual (expectedType))
69+ return nullptr ;
70+
71+ assert (var->isSynthesized () && " Expected compiler synthesized property" );
72+ return var;
73+ }
7674
7775// Note: This would be nice to implement in DerivedConformanceDistributedActor,
7876// but we can't since those are lazily triggered and an implementation exists
@@ -83,7 +81,9 @@ lookupDistributedActorProperty(NominalTypeDecl *decl, DeclName name) {
8381// what already has a witness.
8482static VarDecl *addImplicitDistributedActorIDProperty (
8583 ClassDecl *nominal) {
86- if (!nominal || !nominal->isDistributedActor ())
84+ if (!nominal)
85+ return nullptr ;
86+ if (!nominal->isDistributedActor ())
8787 return nullptr ;
8888
8989 auto &C = nominal->getASTContext ();
@@ -131,6 +131,58 @@ static VarDecl *addImplicitDistributedActorIDProperty(
131131 return propDecl;
132132}
133133
134+ static VarDecl *addImplicitDistributedActorActorSystemProperty (
135+ ClassDecl *nominal) {
136+ if (!nominal)
137+ return nullptr ;
138+ if (!nominal->isDistributedActor ())
139+ return nullptr ;
140+
141+ auto &C = nominal->getASTContext ();
142+
143+ // ==== Synthesize and add 'actorSystem' property to the actor decl
144+ Type propertyType = getDistributedActorSystemType (nominal);
145+
146+ auto *propDecl = new (C)
147+ VarDecl (/* IsStatic*/ false , VarDecl::Introducer::Let,
148+ SourceLoc (), C.Id_actorSystem , nominal);
149+ propDecl->setImplicit ();
150+ propDecl->setSynthesized ();
151+ propDecl->copyFormalAccessFrom (nominal, /* sourceIsParentContext*/ true );
152+ propDecl->setInterfaceType (propertyType);
153+
154+ Pattern *propPat = NamedPattern::createImplicit (C, propDecl);
155+ propPat->setType (propertyType);
156+
157+ propPat = TypedPattern::createImplicit (C, propPat, propertyType);
158+ propPat->setType (propertyType);
159+
160+ PatternBindingDecl *pbDecl = PatternBindingDecl::createImplicit (
161+ C, StaticSpellingKind::None, propPat, /* InitExpr*/ nullptr ,
162+ nominal);
163+
164+ // mark as nonisolated, allowing access to it from everywhere
165+ propDecl->getAttrs ().add (
166+ new (C) NonisolatedAttr (/* IsImplicit=*/ true ));
167+
168+ auto idProperty = nominal->getDistributedActorIDProperty ();
169+ // If the id was not yet synthesized, we need to ensure that eventually
170+ // the order of fields will be: id, actorSystem (because IRGen needs the
171+ // layouts to match with the AST we produce). We do this by inserting FIRST,
172+ // and then as the ID gets synthesized, it'll also force FIRST and therefore
173+ // the order will be okey -- ID and then system.
174+ auto insertAtHead = idProperty == nullptr ;
175+
176+ // IMPORTANT: The `id` MUST be the first field of any distributed actor.
177+ // So we find the property and add the system AFTER it using the hint.
178+ //
179+ // If the `id` was not synthesized yet, we'll end up inserting at head,
180+ // but the id synthesis will force itself to be FIRST anyway, so it works out.
181+ nominal->addMember (propDecl, /* hint=*/ idProperty, /* insertAtHead=*/ insertAtHead);
182+ nominal->addMember (pbDecl, /* hint=*/ idProperty, /* insertAtHead=*/ insertAtHead);
183+ return propDecl;
184+ }
185+
134186/* *****************************************************************************/
135187/* ********************** DISTRIBUTED THUNK SYNTHESIS **************************/
136188/* *****************************************************************************/
@@ -223,6 +275,7 @@ deriveBodyDistributed_thunk(AbstractFunctionDecl *thunk, void *context) {
223275 SmallVector<ASTNode, 8 > remoteBranchStmts;
224276 // --- self.actorSystem
225277 auto systemProperty = nominal->getDistributedActorSystemProperty ();
278+ assert (systemProperty && " Unable to find 'actorSystem' property" );
226279 auto systemRefExpr =
227280 UnresolvedDotExpr::createImplicit (
228281 C, new (C) DeclRefExpr (selfDecl, dloc, implicit), // TODO: make createImplicit
@@ -824,18 +877,21 @@ VarDecl *GetDistributedActorSystemPropertyRequest::evaluate(
824877 return nullptr ;
825878 }
826879
827- for (auto system : nominal->lookupDirect (C.Id_actorSystem )) {
828- if (auto var = dyn_cast<VarDecl>(system)) {
829- auto conformance = module ->conformsToProtocol (
830- var->getInterfaceType (), DAS);
831- if (conformance.isInvalid ())
832- continue ;
880+ auto classDecl = dyn_cast<ClassDecl>(nominal);
881+ if (!classDecl)
882+ return nullptr ;
833883
834- return var;
835- }
884+ // We may be triggered after synthesis was handled via `DerivedConformances`,
885+ // in which case we should locate the existing property, rather than add
886+ // another one. Generally derived conformances are triggered early and are right
887+ // but for some reason sometimes we get a request before synthesis was triggered
888+ // there... so this is to workaround that issue, and ensure we're always
889+ // synthesising correctly, regardless of entry-point.
890+ if (auto existingProp = lookupDistributedActorProperty (classDecl, C.Id_actorSystem )) {
891+ return existingProp;
836892 }
837893
838- return nullptr ;
894+ return addImplicitDistributedActorActorSystemProperty (classDecl) ;
839895}
840896
841897NormalProtocolConformance *GetDistributedActorImplicitCodableRequest::evaluate (
0 commit comments