Skip to content

Commit fe4ba18

Browse files
authored
[Distributed] Ensure _remote funcs synthesized before dynamic replacement (#38974)
* [Distributed] Ensure _remote funcs synthesized before dynamic replacement * cleanup * remove redundant synthesis cause
1 parent 00124ea commit fe4ba18

18 files changed

+198
-84
lines changed

include/swift/AST/Decl.h

+4
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

+5-7
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 *),
936+
/// Obtain the 'remote' counterpart of a 'distributed func'.
937+
class GetDistributedRemoteFuncRequest :
938+
public SimpleRequest<GetDistributedRemoteFuncRequest,
939+
AbstractFunctionDecl *(AbstractFunctionDecl *),
940940
RequestFlags::Cached> {
941941
public:
942942
using SimpleRequest::SimpleRequest;
943943

944944
private:
945945
friend SimpleRequest;
946946

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

949949
public:
950950
// Caching
@@ -2046,8 +2046,6 @@ enum class ImplicitMemberAction : uint8_t {
20462046
ResolveEncodable,
20472047
ResolveDecodable,
20482048
ResolveDistributedActor,
2049-
ResolveDistributedActorIdentity,
2050-
ResolveDistributedActorTransport,
20512049
};
20522050

20532051
class ResolveImplicitMemberRequest

include/swift/AST/TypeCheckerTypeIDZone.def

+1-1
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

+12-16
Original file line numberDiff line numberDiff line change
@@ -4222,21 +4222,12 @@ void NominalTypeDecl::synthesizeSemanticMembersIfNeeded(DeclName member) {
42224222
if (baseName == DeclBaseName::createConstructor()) {
42234223
if ((member.isSimpleName() || argumentNames.front() == Context.Id_from)) {
42244224
action.emplace(ImplicitMemberAction::ResolveDecodable);
4225-
} else if (argumentNames.front() == Context.Id_transport) {
4226-
action.emplace(ImplicitMemberAction::ResolveDistributedActorTransport);
42274225
}
42284226
} else if (!baseName.isSpecial() &&
42294227
baseName.getIdentifier() == Context.Id_encode &&
42304228
(member.isSimpleName() || argumentNames.front() == Context.Id_to)) {
42314229
action.emplace(ImplicitMemberAction::ResolveEncodable);
42324230
}
4233-
} else if (member.isSimpleName() || argumentNames.size() == 2) {
4234-
if (baseName == DeclBaseName::createConstructor()) {
4235-
if (argumentNames[0] == Context.Id_resolve &&
4236-
argumentNames[1] == Context.Id_using) {
4237-
action.emplace(ImplicitMemberAction::ResolveDistributedActor);
4238-
}
4239-
}
42404231
}
42414232
}
42424233

@@ -7217,14 +7208,19 @@ bool AbstractFunctionDecl::isSendable() const {
72177208
}
72187209

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

7224-
auto mutableFunc = const_cast<FuncDecl *>(func);
7225-
return evaluateOrDefault(getASTContext().evaluator,
7226-
IsDistributedFuncRequest{mutableFunc},
7227-
false);
7214+
AbstractFunctionDecl*
7215+
AbstractFunctionDecl::getDistributedActorRemoteFuncDecl() const {
7216+
if (!this->isDistributed())
7217+
return nullptr;
7218+
7219+
auto mutableThis = const_cast<AbstractFunctionDecl *>(this);
7220+
return evaluateOrDefault(
7221+
getASTContext().evaluator,
7222+
GetDistributedRemoteFuncRequest{mutableThis},
7223+
nullptr);
72287224
}
72297225

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

lib/AST/TypeCheckRequests.cpp

-6
Original file line numberDiff line numberDiff line change
@@ -1035,12 +1035,6 @@ void swift::simple_display(llvm::raw_ostream &out,
10351035
case ImplicitMemberAction::ResolveDistributedActor:
10361036
out << "resolve DistributedActor";
10371037
break;
1038-
case ImplicitMemberAction::ResolveDistributedActorIdentity:
1039-
out << "resolve DistributedActor.id";
1040-
break;
1041-
case ImplicitMemberAction::ResolveDistributedActorTransport:
1042-
out << "resolve DistributedActor.actorTransport";
1043-
break;
10441038
}
10451039
}
10461040

lib/SILGen/SILGenDistributed.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -814,7 +814,6 @@ void SILGenFunction::emitDistributedActor_resignAddress(
814814
void SILGenFunction::emitDistributedActorClassMemberDestruction(
815815
SILLocation cleanupLoc, ManagedValue selfValue, ClassDecl *cd,
816816
SILBasicBlock *normalMemberDestroyBB, SILBasicBlock *finishBB) {
817-
ASTContext &ctx = getASTContext();
818817
auto selfTy = cd->getDeclaredInterfaceType();
819818

820819
Scope scope(Cleanups, CleanupLocation(cleanupLoc));

lib/Sema/CodeSynthesis.cpp

+8-13
Original file line numberDiff line numberDiff line change
@@ -1255,9 +1255,10 @@ ResolveImplicitMemberRequest::evaluate(Evaluator &evaluator,
12551255

12561256
auto &Context = target->getASTContext();
12571257
switch (action) {
1258-
case ImplicitMemberAction::ResolveImplicitInit:
1258+
case ImplicitMemberAction::ResolveImplicitInit: {
12591259
TypeChecker::addImplicitConstructors(target);
12601260
break;
1261+
}
12611262
case ImplicitMemberAction::ResolveCodingKeys: {
12621263
// CodingKeys is a special type which may be synthesized as part of
12631264
// Encodable/Decodable conformance. If the target conforms to either
@@ -1274,17 +1275,17 @@ ResolveImplicitMemberRequest::evaluate(Evaluator &evaluator,
12741275
if (!evaluateTargetConformanceTo(decodableProto)) {
12751276
(void)evaluateTargetConformanceTo(encodableProto);
12761277
}
1277-
}
12781278
break;
1279+
}
12791280
case ImplicitMemberAction::ResolveEncodable: {
12801281
// encode(to:) may be synthesized as part of derived conformance to the
12811282
// Encodable protocol.
12821283
// If the target should conform to the Encodable protocol, check the
12831284
// conformance here to attempt synthesis.
12841285
auto *encodableProto = Context.getProtocol(KnownProtocolKind::Encodable);
12851286
(void)evaluateTargetConformanceTo(encodableProto);
1286-
}
12871287
break;
1288+
}
12881289
case ImplicitMemberAction::ResolveDecodable: {
12891290
// init(from:) may be synthesized as part of derived conformance to the
12901291
// Decodable protocol.
@@ -1293,17 +1294,11 @@ ResolveImplicitMemberRequest::evaluate(Evaluator &evaluator,
12931294
TypeChecker::addImplicitConstructors(target);
12941295
auto *decodableProto = Context.getProtocol(KnownProtocolKind::Decodable);
12951296
(void)evaluateTargetConformanceTo(decodableProto);
1296-
}
12971297
break;
1298-
case ImplicitMemberAction::ResolveDistributedActor:
1299-
case ImplicitMemberAction::ResolveDistributedActorTransport:
1300-
case ImplicitMemberAction::ResolveDistributedActorIdentity: {
1301-
// init(transport:) and init(resolve:using:) may be synthesized as part of
1302-
// derived conformance to the DistributedActor protocol.
1303-
// If the target should conform to the DistributedActor protocol, check the
1304-
// conformance here to attempt synthesis.
1305-
// FIXME(distributed): invoke the requirement adding explicitly here
1306-
TypeChecker::addImplicitConstructors(target);
1298+
}
1299+
case ImplicitMemberAction::ResolveDistributedActor: {
1300+
if (auto classDecl = dyn_cast<ClassDecl>(target))
1301+
swift::addImplicitDistributedActorMembers(classDecl);
13071302
auto *distributedActorProto =
13081303
Context.getProtocol(KnownProtocolKind::DistributedActor);
13091304
(void)evaluateTargetConformanceTo(distributedActorProto);

lib/Sema/CodeSynthesisDistributedActor.cpp

+38-15
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,8 @@ synthesizeRemoteFuncStubBody(AbstractFunctionDecl *func, void *context) {
205205
auto uintInit = ctx.getIntBuiltinInitDecl(uintDecl);
206206

207207
auto missingTransportDecl = ctx.getMissingDistributedActorTransport();
208-
assert(missingTransportDecl && "Could not locate '_missingDistributedActorTransport' function");
208+
assert(missingTransportDecl &&
209+
"Could not locate '_missingDistributedActorTransport' function");
209210

210211
// Create a call to _Distributed._missingDistributedActorTransport
211212
auto loc = func->getLoc();
@@ -243,16 +244,10 @@ synthesizeRemoteFuncStubBody(AbstractFunctionDecl *func, void *context) {
243244
file->setBuiltinInitializer(staticStringInit);
244245

245246
auto startLineAndCol = SM.getPresumedLineAndColumnForLoc(distributedFunc->getStartLoc());
246-
// auto *line = new (ctx) MagicIdentifierLiteralExpr(
247-
// MagicIdentifierLiteralExpr::Line, loc, /*Implicit=*/true);
248-
// auto *line = new (ctx) IntegerLiteralExpr(startLineAndCol.first, loc,
249-
// /*implicit*/ true);
250247
auto *line = IntegerLiteralExpr::createFromUnsigned(ctx, startLineAndCol.first);
251248
line->setType(uintType);
252249
line->setBuiltinInitializer(uintInit);
253250

254-
// auto *column = new (ctx) MagicIdentifierLiteralExpr(
255-
// MagicIdentifierLiteralExpr::Column, loc, /*Implicit=*/true);
256251
auto *column = IntegerLiteralExpr::createFromUnsigned(ctx, startLineAndCol.second);
257252
column->setType(uintType);
258253
column->setBuiltinInitializer(uintInit);
@@ -264,7 +259,6 @@ synthesizeRemoteFuncStubBody(AbstractFunctionDecl *func, void *context) {
264259

265260
SmallVector<ASTNode, 2> stmts;
266261
stmts.push_back(call); // something() -> Never
267-
// stmts.push_back(new (ctx) ReturnStmt(SourceLoc(), /*Result=*/nullptr)); // FIXME: this causes 'different types for return type: String vs. ()'
268262
auto body = BraceStmt::create(ctx, SourceLoc(), stmts, SourceLoc(),
269263
/*implicit=*/true);
270264
return { body, /*isTypeChecked=*/true };
@@ -290,7 +284,8 @@ static Identifier makeRemoteFuncIdentifier(FuncDecl* func) {
290284
///
291285
/// and is intended to be replaced by a transport library by providing an
292286
/// appropriate @_dynamicReplacement function.
293-
static void addImplicitRemoteActorFunction(ClassDecl *decl, FuncDecl *func) {
287+
static FuncDecl*
288+
addImplicitRemoteFunction(ClassDecl *decl, FuncDecl *func) {
294289
auto &C = decl->getASTContext();
295290
auto parentDC = decl;
296291

@@ -315,6 +310,10 @@ static void addImplicitRemoteActorFunction(ClassDecl *decl, FuncDecl *func) {
315310
remoteFuncDecl->getAttrs().add(
316311
new (C) DistributedActorIndependentAttr(/*IsImplicit=*/true));
317312

313+
// nonisolated
314+
remoteFuncDecl->getAttrs().add(
315+
new (C) NonisolatedAttr(/*IsImplicit=*/true));
316+
318317
// users should never have to access this function directly;
319318
// it is only invoked from our distributed function thunk if the actor is remote.
320319
remoteFuncDecl->setUserAccessible(false);
@@ -326,16 +325,16 @@ static void addImplicitRemoteActorFunction(ClassDecl *decl, FuncDecl *func) {
326325
remoteFuncDecl->copyFormalAccessFrom(func, /*sourceIsParentContext=*/false);
327326

328327
decl->addMember(remoteFuncDecl);
328+
return remoteFuncDecl;
329329
}
330330

331331
/// Synthesize dynamic _remote stub functions for each encountered distributed function.
332-
static void addImplicitRemoteActorFunctions(ClassDecl *decl) {
332+
static void addImplicitRemoteFunctions(ClassDecl *decl) {
333333
assert(decl->isDistributedActor());
334-
335334
for (auto member : decl->getMembers()) {
336-
auto func = dyn_cast<FuncDecl>(member);
335+
auto func = dyn_cast<AbstractFunctionDecl>(member);
337336
if (func && func->isDistributed()) {
338-
addImplicitRemoteActorFunction(decl, func);
337+
(void) func->getDistributedActorRemoteFuncDecl();
339338
}
340339
}
341340
}
@@ -344,8 +343,33 @@ static void addImplicitRemoteActorFunctions(ClassDecl *decl) {
344343
/************************ SYNTHESIS ENTRY POINT *******************************/
345344
/******************************************************************************/
346345

346+
AbstractFunctionDecl *TypeChecker::addImplicitDistributedActorRemoteFunction(
347+
ClassDecl *decl, AbstractFunctionDecl *AFD) {
348+
if (!decl->isDistributedActor())
349+
return nullptr;
350+
351+
if (auto func = dyn_cast<FuncDecl>(AFD))
352+
return addImplicitRemoteFunction(decl, func);
353+
354+
return nullptr;
355+
}
356+
357+
void TypeChecker::addImplicitDistributedActorRemoteFunctions(NominalTypeDecl *decl) {
358+
// Bail out if not a distributed actor definition.
359+
if (!decl->isDistributedActor())
360+
return;
361+
362+
// If the _Distributed module is missing we cannot synthesize anything.
363+
if (!swift::ensureDistributedModuleLoaded(decl))
364+
return;
365+
366+
if (auto clazz = dyn_cast<ClassDecl>(decl))
367+
addImplicitRemoteFunctions(clazz);
368+
}
369+
347370
/// Entry point for adding all computed members to a distributed actor decl.
348-
void swift::addImplicitDistributedActorMembersToClass(ClassDecl *decl) {
371+
// TODO(distributed): move the synthesis of protocol requirements to DerivedConformance style
372+
void swift::addImplicitDistributedActorMembers(ClassDecl *decl) {
349373
// Bail out if not a distributed actor definition.
350374
if (!decl->isDistributedActor())
351375
return;
@@ -356,5 +380,4 @@ void swift::addImplicitDistributedActorMembersToClass(ClassDecl *decl) {
356380

357381
addFactoryResolveFunction(decl);
358382
addImplicitDistributedActorStoredProperties(decl);
359-
addImplicitRemoteActorFunctions(decl);
360383
}

lib/Sema/TypeCheckAttr.cpp

+16-2
Original file line numberDiff line numberDiff line change
@@ -2365,7 +2365,7 @@ void AttributeChecker::visitDiscardableResultAttr(DiscardableResultAttr *attr) {
23652365
}
23662366
}
23672367

2368-
/// Lookup the replaced decl in the replacments scope.
2368+
/// Lookup the replaced decl in the replacements scope.
23692369
static void lookupReplacedDecl(DeclNameRef replacedDeclName,
23702370
const DeclAttribute *attr,
23712371
const ValueDecl *replacement,
@@ -2400,9 +2400,10 @@ static void lookupReplacedDecl(DeclNameRef replacedDeclName,
24002400
if (declCtxt->isInSpecializeExtensionContext())
24012401
options |= NL_IncludeUsableFromInline;
24022402

2403-
if (typeCtx)
2403+
if (typeCtx) {
24042404
moduleScopeCtxt->lookupQualified({typeCtx}, replacedDeclName, options,
24052405
results);
2406+
}
24062407
}
24072408

24082409
/// Remove any argument labels from the interface type of the given value that
@@ -3498,6 +3499,19 @@ DynamicallyReplacedDeclRequest::evaluate(Evaluator &evaluator,
34983499
if (attr->isInvalid())
34993500
return nullptr;
35003501

3502+
auto *clazz = VD->getDeclContext()->getSelfClassDecl();
3503+
if (clazz && clazz->isDistributedActor()) {
3504+
// Since distributed actors synthesize their `_remote`
3505+
// counterparts to any `distributed func` declared on them, and such remote
3506+
// function is a popular target for dynamic function replacement - we must
3507+
// force the synthesis has happened here already, such that we can lookup
3508+
// the func for the replacement we're handling right now.
3509+
//
3510+
// This request is cached, so it won't cause wasted/duplicate work.
3511+
TypeChecker::addImplicitDistributedActorRemoteFunctions(clazz);
3512+
}
3513+
3514+
35013515
// If we can lazily resolve the function, do so now.
35023516
if (auto *LazyResolver = attr->Resolver) {
35033517
auto decl = LazyResolver->loadDynamicallyReplacedFunctionDecl(

lib/Sema/TypeCheckDecl.cpp

+11-6
Original file line numberDiff line numberDiff line change
@@ -2580,6 +2580,7 @@ static ArrayRef<Decl *> evaluateMembersRequest(
25802580
TypeChecker::addImplicitConstructors(nominal);
25812581
}
25822582

2583+
25832584
// Force any conformances that may introduce more members.
25842585
for (auto conformance : idc->getLocalConformances()) {
25852586
auto proto = conformance->getProtocol();
@@ -2611,15 +2612,15 @@ static ArrayRef<Decl *> evaluateMembersRequest(
26112612
TypeChecker::checkConformance(conformance->getRootNormalConformance());
26122613
}
26132614

2614-
// If the type conforms to Encodable or Decodable, even via an extension,
2615-
// the CodingKeys enum is synthesized as a member of the type itself.
2616-
// Force it into existence.
26172615
if (nominal) {
2616+
// If the type conforms to Encodable or Decodable, even via an extension,
2617+
// the CodingKeys enum is synthesized as a member of the type itself.
2618+
// Force it into existence.
26182619
(void) evaluateOrDefault(
26192620
ctx.evaluator,
2620-
ResolveImplicitMemberRequest{nominal,
2621-
ImplicitMemberAction::ResolveCodingKeys},
2622-
{});
2621+
ResolveImplicitMemberRequest{nominal,
2622+
ImplicitMemberAction::ResolveCodingKeys},
2623+
{});
26232624
}
26242625

26252626
// If the decl has a @main attribute, we need to force synthesis of the
@@ -2638,6 +2639,10 @@ static ArrayRef<Decl *> evaluateMembersRequest(
26382639
(void) var->getPropertyWrapperInitializerInfo();
26392640
}
26402641
}
2642+
2643+
if (auto *func = dyn_cast<FuncDecl>(member)) {
2644+
(void) func->getDistributedActorRemoteFuncDecl();
2645+
}
26412646
}
26422647

26432648
SortedDeclList synthesizedMembers;

lib/Sema/TypeCheckDeclPrimary.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -2673,7 +2673,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
26732673

26742674
/// FIXME: This is an egregious hack to turn off availability checking
26752675
/// for specific functions that were missing availability in older versions
2676-
/// of existing libraries that we must nonethess still support.
2676+
/// of existing libraries that we must nonetheless still support.
26772677
static bool hasHistoricallyWrongAvailability(FuncDecl *func) {
26782678
return func->getName().isCompoundName("swift_deletedAsyncMethodError", { });
26792679
}

0 commit comments

Comments
 (0)