Skip to content

Commit 4681d41

Browse files
authored
Merge pull request #39046 from ktoso/wip-derive-style
2 parents b6f6713 + c868bdd commit 4681d41

14 files changed

+382
-304
lines changed

lib/Sema/CodeSynthesisDistributedActor.cpp

Lines changed: 0 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -30,158 +30,6 @@
3030
#include "DerivedConformances.h"
3131
using namespace swift;
3232

33-
/******************************************************************************/
34-
/******************************* RESOLVE FUNCTION *****************************/
35-
/******************************************************************************/
36-
37-
/// Synthesizes the
38-
///
39-
/// \verbatim
40-
/// static resolve(_ address: ActorAddress,
41-
/// using transport: ActorTransport) throws -> Self {
42-
/// <filled in by SILGenDistributed>
43-
/// }
44-
/// \endverbatim
45-
///
46-
/// factory function in the AST, with an empty body. Its body is
47-
/// expected to be filled-in during SILGen.
48-
// TODO(distributed): move this synthesis to DerivedConformance style
49-
static void addFactoryResolveFunction(ClassDecl *decl) {
50-
assert(decl->isDistributedActor());
51-
auto &C = decl->getASTContext();
52-
53-
auto mkParam = [&](Identifier argName, Identifier paramName, Type ty) -> ParamDecl* {
54-
auto *param = new (C) ParamDecl(SourceLoc(),
55-
SourceLoc(), argName,
56-
SourceLoc(), paramName, decl);
57-
param->setImplicit();
58-
param->setSpecifier(ParamSpecifier::Default);
59-
param->setInterfaceType(ty);
60-
return param;
61-
};
62-
63-
auto addressType = C.getAnyActorIdentityDecl()->getDeclaredInterfaceType();
64-
auto transportType = C.getActorTransportDecl()->getDeclaredInterfaceType();
65-
66-
// (_ identity: AnyActorIdentity, using transport: ActorTransport)
67-
auto *params = ParameterList::create(
68-
C,
69-
/*LParenLoc=*/SourceLoc(),
70-
/*params=*/{ mkParam(Identifier(), C.Id_identity, addressType),
71-
mkParam(C.Id_using, C.Id_transport, transportType)
72-
},
73-
/*RParenLoc=*/SourceLoc()
74-
);
75-
76-
// Func name: resolve(_:using:)
77-
DeclName name(C, C.Id_resolve, params);
78-
79-
// Expected type: (Self) -> (AnyActorIdentity, ActorTransport) throws -> (Self)
80-
auto *factoryDecl =
81-
FuncDecl::createImplicit(C, StaticSpellingKind::KeywordStatic,
82-
name, SourceLoc(),
83-
/*async=*/false,
84-
/*throws=*/true,
85-
/*genericParams=*/nullptr,
86-
params,
87-
/*returnType*/decl->getDeclaredInterfaceType(),
88-
decl);
89-
90-
factoryDecl->setDistributedActorFactory(); // TODO(distributed): should we mark this specifically as the resolve factory?
91-
factoryDecl->copyFormalAccessFrom(decl, /*sourceIsParentContext=*/true);
92-
93-
decl->addMember(factoryDecl);
94-
}
95-
96-
/******************************************************************************/
97-
/******************************** PROPERTIES **********************************/
98-
/******************************************************************************/
99-
100-
// TODO: deduplicate with 'declareDerivedProperty' from DerivedConformance...
101-
std::pair<VarDecl *, PatternBindingDecl *>
102-
createStoredProperty(ClassDecl *classDecl, ASTContext &ctx,
103-
VarDecl::Introducer introducer, Identifier name,
104-
Type propertyInterfaceType, Type propertyContextType,
105-
bool isStatic, bool isFinal) {
106-
auto parentDC = classDecl;
107-
108-
VarDecl *propDecl = new (ctx)
109-
VarDecl(/*IsStatic*/ isStatic, introducer,
110-
SourceLoc(), name, parentDC);
111-
propDecl->setImplicit();
112-
propDecl->setSynthesized();
113-
propDecl->copyFormalAccessFrom(classDecl, /*sourceIsParentContext*/ true);
114-
propDecl->setInterfaceType(propertyInterfaceType);
115-
116-
Pattern *propPat = NamedPattern::createImplicit(ctx, propDecl);
117-
propPat->setType(propertyContextType);
118-
119-
propPat = TypedPattern::createImplicit(ctx, propPat, propertyContextType);
120-
propPat->setType(propertyContextType);
121-
122-
auto *pbDecl = PatternBindingDecl::createImplicit(
123-
ctx, StaticSpellingKind::None, propPat, /*InitExpr*/ nullptr,
124-
parentDC);
125-
return {propDecl, pbDecl};
126-
}
127-
128-
/// Adds the following, fairly special, properties to each distributed actor:
129-
/// - actorTransport
130-
/// - id
131-
// TODO(distributed): move this synthesis to DerivedConformance style
132-
static void addImplicitDistributedActorStoredProperties(ClassDecl *decl) {
133-
assert(decl->isDistributedActor());
134-
135-
auto &C = decl->getASTContext();
136-
137-
// ```
138-
// @_distributedActorIndependent
139-
// let id: AnyActorIdentity
140-
// ```
141-
{
142-
auto propertyType = C.getAnyActorIdentityDecl()->getDeclaredInterfaceType();
143-
144-
VarDecl *propDecl;
145-
PatternBindingDecl *pbDecl;
146-
std::tie(propDecl, pbDecl) = createStoredProperty(
147-
decl, C,
148-
VarDecl::Introducer::Let, C.Id_id,
149-
propertyType, propertyType,
150-
/*isStatic=*/false, /*isFinal=*/true);
151-
152-
// mark as @_distributedActorIndependent, allowing access to it from everywhere
153-
propDecl->getAttrs().add(
154-
new (C) DistributedActorIndependentAttr(/*IsImplicit=*/true));
155-
156-
decl->addMember(propDecl);
157-
decl->addMember(pbDecl);
158-
}
159-
160-
// ```
161-
// @_distributedActorIndependent
162-
// let actorTransport: ActorTransport
163-
// ```
164-
// (no need for @actorIndependent because it is an immutable let)
165-
{
166-
auto propertyType = C.getActorTransportDecl()->getDeclaredInterfaceType();
167-
168-
VarDecl *propDecl;
169-
PatternBindingDecl *pbDecl;
170-
std::tie(propDecl, pbDecl) = createStoredProperty(
171-
decl, C,
172-
VarDecl::Introducer::Let, C.Id_actorTransport,
173-
propertyType, propertyType,
174-
/*isStatic=*/false, /*isFinal=*/true);
175-
176-
// mark as @_distributedActorIndependent, allowing access to it from everywhere
177-
propDecl->getAttrs().add(
178-
new (C) DistributedActorIndependentAttr(/*IsImplicit=*/true));
179-
180-
decl->addMember(propDecl);
181-
decl->addMember(pbDecl);
182-
}
183-
}
184-
18533
/******************************************************************************/
18634
/*************************** _REMOTE_ FUNCTIONS *******************************/
18735
/******************************************************************************/
@@ -354,7 +202,5 @@ void swift::addImplicitDistributedActorMembersToClass(ClassDecl *decl) {
354202
if (!swift::ensureDistributedModuleLoaded(decl))
355203
return;
356204

357-
addFactoryResolveFunction(decl);
358-
addImplicitDistributedActorStoredProperties(decl);
359205
addImplicitRemoteActorFunctions(decl);
360206
}

lib/Sema/DerivedConformanceDistributedActor.cpp

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,151 @@ bool DerivedConformance::canDeriveDistributedActor(
2828
auto classDecl = dyn_cast<ClassDecl>(nominal);
2929
return classDecl && classDecl->isDistributedActor() && dc == nominal;
3030
}
31+
32+
// ==== ------------------------------------------------------------------------
33+
34+
/******************************************************************************/
35+
/******************************* RESOLVE FUNCTION *****************************/
36+
/******************************************************************************/
37+
38+
/// Synthesizes the
39+
///
40+
/// \verbatim
41+
/// static resolve(_ address: ActorAddress,
42+
/// using transport: ActorTransport) throws -> Self {
43+
/// <filled in by SILGenDistributed>
44+
/// }
45+
/// \endverbatim
46+
///
47+
/// factory function in the AST, with an empty body. Its body is
48+
/// expected to be filled-in during SILGen.
49+
// TODO(distributed): move this synthesis to DerivedConformance style
50+
static FuncDecl *deriveDistributedActor_resolve(DerivedConformance &derived) {
51+
auto decl = dyn_cast<ClassDecl>(derived.Nominal);
52+
assert(decl->isDistributedActor());
53+
auto &C = decl->getASTContext();
54+
55+
auto mkParam = [&](Identifier argName, Identifier paramName, Type ty) -> ParamDecl* {
56+
auto *param = new (C) ParamDecl(SourceLoc(),
57+
SourceLoc(), argName,
58+
SourceLoc(), paramName, decl);
59+
param->setImplicit();
60+
param->setSpecifier(ParamSpecifier::Default);
61+
param->setInterfaceType(ty);
62+
return param;
63+
};
64+
65+
auto addressType = C.getAnyActorIdentityDecl()->getDeclaredInterfaceType();
66+
auto transportType = C.getActorTransportDecl()->getDeclaredInterfaceType();
67+
68+
// (_ identity: AnyActorIdentity, using transport: ActorTransport)
69+
auto *params = ParameterList::create(
70+
C,
71+
/*LParenLoc=*/SourceLoc(),
72+
/*params=*/{ mkParam(Identifier(), C.Id_identity, addressType),
73+
mkParam(C.Id_using, C.Id_transport, transportType)
74+
},
75+
/*RParenLoc=*/SourceLoc()
76+
);
77+
78+
// Func name: resolve(_:using:)
79+
DeclName name(C, C.Id_resolve, params);
80+
81+
// Expected type: (Self) -> (AnyActorIdentity, ActorTransport) throws -> (Self)
82+
auto *factoryDecl =
83+
FuncDecl::createImplicit(C, StaticSpellingKind::KeywordStatic,
84+
name, SourceLoc(),
85+
/*async=*/false,
86+
/*throws=*/true,
87+
/*genericParams=*/nullptr,
88+
params,
89+
/*returnType*/decl->getDeclaredInterfaceType(),
90+
decl);
91+
92+
factoryDecl->setDistributedActorFactory(); // TODO(distributed): should we mark this specifically as the resolve factory?
93+
factoryDecl->copyFormalAccessFrom(decl, /*sourceIsParentContext=*/true);
94+
95+
derived.addMembersToConformanceContext({factoryDecl});
96+
return factoryDecl;
97+
}
98+
99+
/******************************************************************************/
100+
/******************************* PROPERTIES ***********************************/
101+
/******************************************************************************/
102+
103+
static ValueDecl *deriveDistributedActor_id(DerivedConformance &derived) {
104+
assert(derived.Nominal->isDistributedActor());
105+
auto &C = derived.Context;
106+
107+
// ```
108+
// @_distributedActorIndependent
109+
// let id: AnyActorIdentity
110+
// ```
111+
auto propertyType = C.getAnyActorIdentityDecl()->getDeclaredInterfaceType();
112+
113+
VarDecl *propDecl;
114+
PatternBindingDecl *pbDecl;
115+
std::tie(propDecl, pbDecl) = derived.declareDerivedProperty(
116+
C.Id_id,
117+
propertyType, propertyType,
118+
/*isStatic=*/false, /*isFinal=*/true);
119+
120+
propDecl->setIntroducer(VarDecl::Introducer::Let);
121+
122+
// mark as @_distributedActorIndependent, allowing access to it from everywhere
123+
propDecl->getAttrs().add(
124+
new (C) DistributedActorIndependentAttr(/*IsImplicit=*/true));
125+
126+
derived.addMembersToConformanceContext({ propDecl, pbDecl });
127+
return propDecl;
128+
}
129+
130+
static ValueDecl *deriveDistributedActor_actorTransport(
131+
DerivedConformance &derived) {
132+
assert(derived.Nominal->isDistributedActor());
133+
auto &C = derived.Context;
134+
135+
// ```
136+
// @_distributedActorIndependent
137+
// let actorTransport: ActorTransport
138+
// ```
139+
// (no need for @actorIndependent because it is an immutable let)
140+
auto propertyType = C.getActorTransportDecl()->getDeclaredInterfaceType();
141+
142+
VarDecl *propDecl;
143+
PatternBindingDecl *pbDecl;
144+
std::tie(propDecl, pbDecl) = derived.declareDerivedProperty(
145+
C.Id_actorTransport,
146+
propertyType, propertyType,
147+
/*isStatic=*/false, /*isFinal=*/true);
148+
149+
propDecl->setIntroducer(VarDecl::Introducer::Let);
150+
151+
// mark as @_distributedActorIndependent, allowing access to it from everywhere
152+
propDecl->getAttrs().add(
153+
new (C) DistributedActorIndependentAttr(/*IsImplicit=*/true));
154+
155+
derived.addMembersToConformanceContext({ propDecl, pbDecl });
156+
return propDecl;
157+
}
158+
31159
// ==== ------------------------------------------------------------------------
32160

33161
ValueDecl *DerivedConformance::deriveDistributedActor(ValueDecl *requirement) {
162+
if (auto var = dyn_cast<VarDecl>(requirement)) {
163+
if (var->getName() == Context.Id_id)
164+
return deriveDistributedActor_id(*this);
165+
166+
if (var->getName() == Context.Id_actorTransport)
167+
return deriveDistributedActor_actorTransport(*this);
168+
}
169+
170+
if (auto func = dyn_cast<FuncDecl>(requirement)) {
171+
// just a simple name check is enough here,
172+
// if we are invoked here we know for sure it is for the "right" function
173+
if (func->getName().getBaseName() == Context.Id_resolve)
174+
return deriveDistributedActor_resolve(*this);
175+
}
176+
34177
return nullptr;
35178
}

lib/Sema/DerivedConformances.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,14 @@ ValueDecl *DerivedConformance::getDerivableRequirement(NominalTypeDecl *nominal,
312312
if (name.isSimpleName(ctx.Id_unownedExecutor))
313313
return getRequirement(KnownProtocolKind::Actor);
314314

315+
// DistributedActor.id
316+
if(name.isSimpleName(ctx.Id_id))
317+
return getRequirement(KnownProtocolKind::DistributedActor);
318+
319+
// DistributedActor.actorTransport
320+
if(name.isSimpleName(ctx.Id_actorTransport))
321+
return getRequirement(KnownProtocolKind::DistributedActor);
322+
315323
return nullptr;
316324
}
317325

@@ -351,6 +359,17 @@ ValueDecl *DerivedConformance::getDerivableRequirement(NominalTypeDecl *nominal,
351359
return getRequirement(KnownProtocolKind::Hashable);
352360
}
353361

362+
// static DistributedActor.resolve(_:using:)
363+
if (name.isCompoundName() && name.getBaseName() == ctx.Id_resolve &&
364+
func->isStatic()) {
365+
auto argumentNames = name.getArgumentNames();
366+
if (argumentNames.size() == 2 &&
367+
argumentNames[0] == Identifier() &&
368+
argumentNames[1] == ctx.Id_using) {
369+
return getRequirement(KnownProtocolKind::DistributedActor);
370+
}
371+
}
372+
354373
return nullptr;
355374
}
356375

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2928,6 +2928,11 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
29282928

29292929
TypeChecker::checkDeclAttributes(ED);
29302930

2931+
if (nominal->isDistributedActor()) {
2932+
auto decl = dyn_cast<ClassDecl>(nominal);
2933+
TypeChecker::checkDistributedActor(decl);
2934+
}
2935+
29312936
for (Decl *Member : ED->getMembers())
29322937
visit(Member);
29332938

lib/Sema/TypeCheckDistributed.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,11 @@ void swift::checkDistributedActorProperties(const ClassDecl *decl) {
154154

155155
for (auto member : decl->getMembers()) {
156156
if (auto prop = dyn_cast<VarDecl>(member)) {
157+
if (prop->isSynthesized())
158+
continue;
159+
157160
auto id = prop->getName();
158-
if (id == C.Id_actorTransport ||
159-
id == C.Id_id) {
161+
if (id == C.Id_actorTransport || id == C.Id_id) {
160162
prop->diagnose(diag::distributed_actor_user_defined_special_property,
161163
id);
162164
}
@@ -213,6 +215,9 @@ void swift::checkDistributedActorConstructor(const ClassDecl *decl, ConstructorD
213215
// ==== ------------------------------------------------------------------------
214216

215217
void TypeChecker::checkDistributedActor(ClassDecl *decl) {
218+
if (!decl)
219+
return;
220+
216221
// ==== Ensure the _Distributed module is available,
217222
// without it there's no reason to check the decl in more detail anyway.
218223
if (!swift::ensureDistributedModuleLoaded(decl))
@@ -235,7 +240,5 @@ void TypeChecker::checkDistributedActor(ClassDecl *decl) {
235240
// --- Synthesize properties
236241
// TODO: those could technically move to DerivedConformance style
237242
swift::addImplicitDistributedActorMembersToClass(decl);
238-
239-
// ==== Functions
240243
}
241244

0 commit comments

Comments
 (0)