Skip to content

Commit 38c8544

Browse files
authored
Merge pull request #39087 from ktoso/wip-serialization-dist
[Distributed] distributed decls working across files
2 parents a9a1a15 + d76690e commit 38c8544

21 files changed

+681
-136
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5986,6 +5986,10 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
59865986
/// Returns 'true' if the function is distributed.
59875987
bool isDistributed() const;
59885988

5989+
/// Get (or synthesize) the associated remote function for this one.
5990+
/// For example, for `distributed func hi()` get `func _remote_hi()`.
5991+
AbstractFunctionDecl *getDistributedActorRemoteFuncDecl() const;
5992+
59895993
PolymorphicEffectKind getPolymorphicEffectKind(EffectKind kind) const;
59905994

59915995
// FIXME: Hack that provides names with keyword arguments for accessors.

include/swift/AST/TypeCheckRequests.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -933,18 +933,18 @@ class IsDistributedActorRequest :
933933
bool isCached() const { return true; }
934934
};
935935

936-
/// Determine whether the given func is distributed.
937-
class IsDistributedFuncRequest :
938-
public SimpleRequest<IsDistributedFuncRequest,
939-
bool(FuncDecl *),
940-
RequestFlags::Cached> {
936+
/// Obtain the 'remote' counterpart of a 'distributed func'.
937+
class GetDistributedRemoteFuncRequest :
938+
public SimpleRequest<GetDistributedRemoteFuncRequest,
939+
AbstractFunctionDecl *(AbstractFunctionDecl *),
940+
RequestFlags::Cached> {
941941
public:
942-
using SimpleRequest::SimpleRequest;
942+
using SimpleRequest::SimpleRequest;
943943

944944
private:
945-
friend SimpleRequest;
945+
friend SimpleRequest;
946946

947-
bool evaluate(Evaluator &evaluator, FuncDecl *func) const;
947+
AbstractFunctionDecl *evaluate(Evaluator &evaluator, AbstractFunctionDecl *func) const;
948948

949949
public:
950950
// Caching

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ SWIFT_REQUEST(TypeChecker, IsDefaultActorRequest,
100100
Cached, NoLocationInfo)
101101
SWIFT_REQUEST(TypeChecker, IsDistributedActorRequest, bool(NominalTypeDecl *),
102102
Cached, NoLocationInfo)
103-
SWIFT_REQUEST(TypeChecker, IsDistributedFuncRequest, bool(FuncDecl *),
103+
SWIFT_REQUEST(TypeChecker, GetDistributedRemoteFuncRequest, AbstractFunctionDecl *(AbstractFunctionDecl *),
104104
Cached, NoLocationInfo)
105105
SWIFT_REQUEST(TypeChecker, GlobalActorInstanceRequest,
106106
VarDecl *(NominalTypeDecl *),

lib/AST/Decl.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7217,14 +7217,19 @@ bool AbstractFunctionDecl::isSendable() const {
72177217
}
72187218

72197219
bool AbstractFunctionDecl::isDistributed() const {
7220-
auto func = dyn_cast<FuncDecl>(this);
7221-
if (!func)
7222-
return false;
7220+
return this->getAttrs().hasAttribute<DistributedActorAttr>();
7221+
}
72237222

7224-
auto mutableFunc = const_cast<FuncDecl *>(func);
7225-
return evaluateOrDefault(getASTContext().evaluator,
7226-
IsDistributedFuncRequest{mutableFunc},
7227-
false);
7223+
AbstractFunctionDecl*
7224+
AbstractFunctionDecl::getDistributedActorRemoteFuncDecl() const {
7225+
if (!this->isDistributed())
7226+
return nullptr;
7227+
7228+
auto mutableThis = const_cast<AbstractFunctionDecl *>(this);
7229+
return evaluateOrDefault(
7230+
getASTContext().evaluator,
7231+
GetDistributedRemoteFuncRequest{mutableThis},
7232+
nullptr);
72287233
}
72297234

72307235
BraceStmt *AbstractFunctionDecl::getBody(bool canSynthesize) const {

lib/AST/NameLookup.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1672,6 +1672,35 @@ static void installPropertyWrapperMembersIfNeeded(NominalTypeDecl *target,
16721672
}
16731673
}
16741674

1675+
static void installDistributedRemoteFunctionsIfNeeded(NominalTypeDecl *target,
1676+
DeclNameRef member) {
1677+
auto &Context = target->getASTContext();
1678+
auto baseName = member.getBaseName();
1679+
1680+
if (member.isSimpleName() || baseName.isSpecial())
1681+
return;
1682+
1683+
// We only need to install _remote functions.
1684+
if (!baseName.getIdentifier().str().startswith("_remote_"))
1685+
return;
1686+
1687+
// _remote_-prefixed functions can be generated by distributed funcs.
1688+
auto prefixLen = strlen("_remote_");
1689+
auto originalFuncName =
1690+
Context.getIdentifier(
1691+
baseName.getIdentifier().str().substr(prefixLen));
1692+
1693+
for (auto member : target->lookupDirect(originalFuncName)) {
1694+
auto func = dyn_cast<FuncDecl>(member);
1695+
if (!func) continue;
1696+
1697+
auto sourceFile = func->getDeclContext()->getParentSourceFile();
1698+
if (sourceFile && sourceFile->Kind != SourceFileKind::Interface) {
1699+
(void)func->getDistributedActorRemoteFuncDecl();
1700+
}
1701+
}
1702+
}
1703+
16751704
bool DeclContext::lookupQualified(ArrayRef<NominalTypeDecl *> typeDecls,
16761705
DeclNameRef member,
16771706
NLOptions options,
@@ -1725,6 +1754,9 @@ QualifiedLookupRequest::evaluate(Evaluator &eval, const DeclContext *DC,
17251754
// Make sure we've resolved property wrappers, if we need them.
17261755
installPropertyWrapperMembersIfNeeded(current, member);
17271756

1757+
// Make sure we've resolved synthesized _remote funcs for distributed actors.
1758+
installDistributedRemoteFunctionsIfNeeded(current, member);
1759+
17281760
// Look for results within the current nominal type and its extensions.
17291761
bool currentIsProtocol = isa<ProtocolDecl>(current);
17301762
auto flags = OptionSet<NominalTypeDecl::LookupDirectFlags>();

lib/Sema/CodeSynthesis.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,9 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl,
321321
"Only 'distributed actor' type can gain implicit distributed actor init");
322322

323323
if (swift::ensureDistributedModuleLoaded(decl)) {
324+
// copy access level of distributed actor init from the nominal decl
325+
accessLevel = decl->getEffectiveAccess();
326+
324327
auto transportDecl = ctx.getActorTransportDecl();
325328

326329
// Create the parameter.

lib/Sema/CodeSynthesisDistributedActor.cpp

Lines changed: 25 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -91,16 +91,10 @@ synthesizeRemoteFuncStubBody(AbstractFunctionDecl *func, void *context) {
9191
file->setBuiltinInitializer(staticStringInit);
9292

9393
auto startLineAndCol = SM.getPresumedLineAndColumnForLoc(distributedFunc->getStartLoc());
94-
// auto *line = new (ctx) MagicIdentifierLiteralExpr(
95-
// MagicIdentifierLiteralExpr::Line, loc, /*Implicit=*/true);
96-
// auto *line = new (ctx) IntegerLiteralExpr(startLineAndCol.first, loc,
97-
// /*implicit*/ true);
9894
auto *line = IntegerLiteralExpr::createFromUnsigned(ctx, startLineAndCol.first);
9995
line->setType(uintType);
10096
line->setBuiltinInitializer(uintInit);
10197

102-
// auto *column = new (ctx) MagicIdentifierLiteralExpr(
103-
// MagicIdentifierLiteralExpr::Column, loc, /*Implicit=*/true);
10498
auto *column = IntegerLiteralExpr::createFromUnsigned(ctx, startLineAndCol.second);
10599
column->setType(uintType);
106100
column->setBuiltinInitializer(uintInit);
@@ -111,20 +105,24 @@ synthesizeRemoteFuncStubBody(AbstractFunctionDecl *func, void *context) {
111105
call->setThrows(false);
112106

113107
SmallVector<ASTNode, 2> stmts;
114-
stmts.push_back(call); // something() -> Never
115-
// stmts.push_back(new (ctx) ReturnStmt(SourceLoc(), /*Result=*/nullptr)); // FIXME: this causes 'different types for return type: String vs. ()'
108+
stmts.push_back(call);
116109
auto body = BraceStmt::create(ctx, SourceLoc(), stmts, SourceLoc(),
117110
/*implicit=*/true);
118111
return { body, /*isTypeChecked=*/true };
119112
}
120113

121-
static Identifier makeRemoteFuncIdentifier(FuncDecl* func) {
122-
auto &C = func->getASTContext();
123-
auto localFuncName = func->getBaseIdentifier().str().str();
114+
static Identifier makeRemoteFuncIdentifier(FuncDecl* distributedFunc) {
115+
auto &C = distributedFunc->getASTContext();
116+
assert(distributedFunc->isDistributed());
117+
auto localFuncName = distributedFunc->getBaseIdentifier().str().str();
124118
auto remoteFuncIdent = C.getIdentifier("_remote_" + localFuncName);
125119
return remoteFuncIdent;
126120
}
127121

122+
/******************************************************************************/
123+
/************************ SYNTHESIS ENTRY POINT *******************************/
124+
/******************************************************************************/
125+
128126
/// Create a remote stub for the passed in \c func.
129127
/// The remote stub function is not user accessible and mirrors the API of
130128
/// the local function. It is always throwing, async, and user-inaccessible.
@@ -138,7 +136,21 @@ static Identifier makeRemoteFuncIdentifier(FuncDecl* func) {
138136
///
139137
/// and is intended to be replaced by a transport library by providing an
140138
/// appropriate @_dynamicReplacement function.
141-
static void addImplicitRemoteActorFunction(ClassDecl *decl, FuncDecl *func) {
139+
AbstractFunctionDecl *TypeChecker::addImplicitDistributedActorRemoteFunction(
140+
ClassDecl *decl, AbstractFunctionDecl *AFD) {
141+
if (!decl->isDistributedActor())
142+
return nullptr;
143+
144+
auto func = dyn_cast<FuncDecl>(AFD);
145+
if (!func || !func->isDistributed())
146+
return nullptr;
147+
148+
// ==== if the remote func already exists, return it
149+
if (auto existing = decl->lookupDirectRemoteFunc(func))
150+
return existing;
151+
152+
// ==== Synthesize and add 'remote' func to the actor decl
153+
142154
auto &C = decl->getASTContext();
143155
auto parentDC = decl;
144156

@@ -174,33 +186,6 @@ static void addImplicitRemoteActorFunction(ClassDecl *decl, FuncDecl *func) {
174186
remoteFuncDecl->copyFormalAccessFrom(func, /*sourceIsParentContext=*/false);
175187

176188
decl->addMember(remoteFuncDecl);
177-
}
178-
179-
/// Synthesize dynamic _remote stub functions for each encountered distributed function.
180-
static void addImplicitRemoteActorFunctions(ClassDecl *decl) {
181-
assert(decl->isDistributedActor());
182-
183-
for (auto member : decl->getMembers()) {
184-
auto func = dyn_cast<FuncDecl>(member);
185-
if (func && func->isDistributed()) {
186-
addImplicitRemoteActorFunction(decl, func);
187-
}
188-
}
189-
}
190-
191-
/******************************************************************************/
192-
/************************ SYNTHESIS ENTRY POINT *******************************/
193-
/******************************************************************************/
194-
195-
/// Entry point for adding all computed members to a distributed actor decl.
196-
void swift::addImplicitDistributedActorMembersToClass(ClassDecl *decl) {
197-
// Bail out if not a distributed actor definition.
198-
if (!decl->isDistributedActor())
199-
return;
200-
201-
// If the _Distributed module is missing we cannot synthesize anything.
202-
if (!swift::ensureDistributedModuleLoaded(decl))
203-
return;
204189

205-
addImplicitRemoteActorFunctions(decl);
190+
return remoteFuncDecl;
206191
}

lib/Sema/TypeCheckDecl.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2637,6 +2637,10 @@ static ArrayRef<Decl *> evaluateMembersRequest(
26372637
(void) var->getPropertyWrapperAuxiliaryVariables();
26382638
(void) var->getPropertyWrapperInitializerInfo();
26392639
}
2640+
2641+
if (auto *func = dyn_cast<FuncDecl>(member)) {
2642+
(void) func->getDistributedActorRemoteFuncDecl();
2643+
}
26402644
}
26412645
}
26422646

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1410,28 +1410,6 @@ static void maybeDiagnoseClassWithoutInitializers(ClassDecl *classDecl) {
14101410
diagnoseClassWithoutInitializers(classDecl);
14111411
}
14121412

1413-
void TypeChecker::checkResultType(Type resultType,
1414-
DeclContext *owner) {
1415-
// // Only distributed functions have special requirements on return types.
1416-
// if (!owner->isDistributed())
1417-
// return;
1418-
//
1419-
// auto conformanceDC = owner->getConformanceContext();
1420-
//
1421-
// // Result type of distributed functions must be Codable.
1422-
// auto target =
1423-
// conformanceDC->mapTypeIntoContext(it->second->getValueInterfaceType());
1424-
// if (TypeChecker::conformsToProtocol(target, derived.Protocol, conformanceDC)
1425-
// .isInvalid()) {
1426-
// TypeLoc typeLoc = {
1427-
// it->second->getTypeReprOrParentPatternTypeRepr(),
1428-
// it->second->getType(),
1429-
// };
1430-
// it->second->diagnose(diag::codable_non_conforming_property_here,
1431-
// derived.getProtocolType(), typeLoc);
1432-
// propertiesAreValid = false;
1433-
}
1434-
14351413
void TypeChecker::diagnoseDuplicateBoundVars(Pattern *pattern) {
14361414
SmallVector<VarDecl *, 2> boundVars;
14371415
pattern->collectVariables(boundVars);
@@ -2694,7 +2672,6 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
26942672
checkAccessControl(FD);
26952673

26962674
TypeChecker::checkParameterList(FD->getParameters(), FD);
2697-
TypeChecker::checkResultType(FD->getResultInterfaceType(), FD);
26982675
}
26992676

27002677
TypeChecker::checkDeclAttributes(FD);
@@ -2930,11 +2907,6 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
29302907

29312908
TypeChecker::checkDeclAttributes(ED);
29322909

2933-
if (nominal->isDistributedActor()) {
2934-
auto decl = dyn_cast<ClassDecl>(nominal);
2935-
TypeChecker::checkDistributedActor(decl);
2936-
}
2937-
29382910
for (Decl *Member : ED->getMembers())
29392911
visit(Member);
29402912

@@ -2945,6 +2917,9 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
29452917
checkAccessControl(ED);
29462918

29472919
checkExplicitAvailability(ED);
2920+
2921+
if (nominal->isDistributedActor())
2922+
TypeChecker::checkDistributedActor(dyn_cast<ClassDecl>(nominal));
29482923
}
29492924

29502925
void visitTopLevelCodeDecl(TopLevelCodeDecl *TLCD) {

lib/Sema/TypeCheckDistributed.cpp

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,34 @@ bool IsDistributedActorRequest::evaluate(
7171
return classDecl->isExplicitDistributedActor();
7272
}
7373

74-
bool IsDistributedFuncRequest::evaluate(
75-
Evaluator &evaluator, FuncDecl *func) const {
76-
// Check whether the attribute was explicitly specified.
77-
if (auto attr = func->getAttrs().getAttribute<DistributedActorAttr>()) {
78-
return true;
79-
} else {
80-
return false;
74+
AbstractFunctionDecl *GetDistributedRemoteFuncRequest::evaluate(
75+
Evaluator &evaluator, AbstractFunctionDecl *func) const {
76+
77+
if (!func->isDistributed())
78+
return nullptr;
79+
80+
auto &C = func->getASTContext();
81+
DeclContext *DC = func->getDeclContext();
82+
83+
// not via `ensureDistributedModuleLoaded` to avoid generating a warning,
84+
// we won't be emitting the offending decl after all.
85+
if (!C.getLoadedModule(C.Id_Distributed))
86+
return nullptr;
87+
88+
// Locate the actor decl that the member must be synthesized to.
89+
// TODO(distributed): should this just be added to the extension instead when we're in one?
90+
ClassDecl *decl = dyn_cast<ClassDecl>(DC);
91+
if (!decl) {
92+
if (auto ED = dyn_cast<ExtensionDecl>(DC)) {
93+
decl = dyn_cast<ClassDecl>(ED->getExtendedNominal());
94+
}
8195
}
96+
97+
/// A distributed func cannot be added to a non-distributed actor;
98+
/// If the 'decl' was not a distributed actor we must have declared and
99+
/// requested it from a illegal context, let's just ignore the synthesis.
100+
assert(decl && "Can't find actor detect to add implicit _remote function to");
101+
return TypeChecker::addImplicitDistributedActorRemoteFunction(decl, func);
82102
}
83103

84104
// ==== ------------------------------------------------------------------------
@@ -228,17 +248,18 @@ void TypeChecker::checkDistributedActor(ClassDecl *decl) {
228248
// If applicable, this will create the default 'init(transport:)' initializer
229249
(void)decl->getDefaultInitializer();
230250

231-
// --- Check all constructors
232-
for (auto member : decl->getMembers())
251+
for (auto member : decl->getMembers()) {
252+
// --- Check all constructors
233253
if (auto ctor = dyn_cast<ConstructorDecl>(member))
234254
checkDistributedActorConstructor(decl, ctor);
235255

256+
// --- synthesize _remote functions for distributed functions
257+
if (auto func = dyn_cast<FuncDecl>(member))
258+
(void)addImplicitDistributedActorRemoteFunction(decl, func);
259+
}
260+
236261
// ==== Properties
237262
// --- Check for any illegal re-definitions
238263
checkDistributedActorProperties(decl);
239-
240-
// --- Synthesize properties
241-
// TODO: those could technically move to DerivedConformance style
242-
swift::addImplicitDistributedActorMembersToClass(decl);
243264
}
244265

lib/Sema/TypeCheckDistributed.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,6 @@ void checkDistributedActorConstructor(const ClassDecl *decl, ConstructorDecl *ct
4343

4444
bool checkDistributedFunction(FuncDecl *decl, bool diagnose);
4545

46-
/// Synthesis of members which are not directly driven filling in protocol requirements,
47-
/// such as the default local and resolve constructors, and `_remote_` function stubs.
48-
void addImplicitDistributedActorMembersToClass(ClassDecl *decl);
49-
5046
}
5147

5248

0 commit comments

Comments
 (0)