mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Distributed] Reimplement distributed call thunks completely in AST (#41616)
* [Distributed] dist actor always has default executor (currently) * [Distributed] extra test for missing makeEncoder * [DistributedDecl] Add DistributedActorSystem to known SDK types * [DistributedActor] ok progress on getting the system via witness * [Distributed] allow hop-to `let any: any X` where X is DistActor * [Distributed] AST: Add an accessor to determine whether type is distributed actor - Classes have specialized method on their declarations - Archetypes and existentials check their conformances for presence of `DistributedActor` protocol. * [Distributed] AST: Account for distributed members declared in class extensions `getConcreteReplacementForProtocolActorSystemType` should use `getSelfClassDecl` otherwise it wouldn't be able to find actor if the member is declared in an extension. * [Distributed] fix ad-hoc requirement checks for 'mutating' [PreChecker] LookupDC might be null, so account for that * [Distributed] Completed AST synthesis for dist thunk * [Distributed][ASTDumper] print pretty distributed in right color in AST dumps * wip on making the local/remote calls * using the _local to mark the localCall as known local * [Distributed] fix passing Never when not throwing * fix lifetime of mangled string * [Distributed] Implement recordGenericSubstitution * [Distributed] Dont add . * [Distributed] dont emit thunk when func broken * [Distributed] fix tests; cleanups * [Distributed] cleanup, move is... funcs to DistributedDecl * [Distributed] Remove SILGen for distributed thunks, it is in Sema now! * [Distributed] no need to check stored props in protocols * remote not used flag * fix mangling test * [Distributed] Synthesis: Don't re-use AST nodes for `decodeArgument` references * [Distributed] Synthesis: Make sure that each thunk parameter has an internal name * [Distributed/Synthesis] NFC: Add a comment regarding empty internal parameter names * [Distributed] NFC: Adjust distributed thunk manglings in the accessor section test-cases * cleanup * [Distributed] NFC: Adjust distributed thunk manglings in the accessor thunk test-cases * review follow ups * xfail some linux tests for now so we can land the AST thunk * Update distributed_actor_remote_functions.swift Co-authored-by: Pavel Yaskevich <xedin@apache.org>
This commit is contained in:
committed by
GitHub
parent
0d87a1084d
commit
5ab8e0834d
@@ -21,6 +21,7 @@
|
||||
#include "swift/AST/Initializer.h"
|
||||
#include "swift/AST/ParameterList.h"
|
||||
#include "swift/AST/TypeCheckRequests.h"
|
||||
#include "swift/AST/ASTMangler.h"
|
||||
#include "swift/AST/DistributedDecl.h"
|
||||
#include "swift/Basic/Defer.h"
|
||||
#include "swift/ClangImporter/ClangModule.h"
|
||||
@@ -30,6 +31,11 @@
|
||||
#include "DerivedConformances.h"
|
||||
using namespace swift;
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/************************ PROPERTY SYNTHESIS **********************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// Note: This would be nice to implement in DerivedConformanceDistributedActor,
|
||||
// but we can't since those are lazily triggered and an implementation exists
|
||||
// for the 'id' property because 'Identifiable.id' has an extension that impls
|
||||
@@ -38,14 +44,11 @@ using namespace swift;
|
||||
// The "derived" mechanisms are not really geared towards emitting for
|
||||
// what already has a witness.
|
||||
static VarDecl *addImplicitDistributedActorIDProperty(
|
||||
NominalTypeDecl *nominal) {
|
||||
ClassDecl *nominal) {
|
||||
if (!nominal || !nominal->isDistributedActor())
|
||||
return nullptr;
|
||||
|
||||
// ==== if the 'id' already exists, return it
|
||||
auto &C = nominal->getASTContext();
|
||||
// if (auto existing = nominal->lookupDirect(C.Id_id))
|
||||
// return existing;
|
||||
|
||||
// ==== Synthesize and add 'id' property to the actor decl
|
||||
Type propertyType = getDistributedActorIDType(nominal);
|
||||
@@ -81,9 +84,517 @@ static VarDecl *addImplicitDistributedActorIDProperty(
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/************************ SYNTHESIS ENTRY POINT *******************************/
|
||||
/*********************** DISTRIBUTED THUNK SYNTHESIS **************************/
|
||||
/******************************************************************************/
|
||||
|
||||
static void forwardParameters(AbstractFunctionDecl *afd,
|
||||
SmallVectorImpl<Expr*> &forwardingParams) {
|
||||
auto &C = afd->getASTContext();
|
||||
for (auto param : *afd->getParameters()) {
|
||||
forwardingParams.push_back(new (C) DeclRefExpr(
|
||||
ConcreteDeclRef(param), DeclNameLoc(), /*implicit=*/true,
|
||||
swift::AccessSemantics::Ordinary,
|
||||
afd->mapTypeIntoContext(param->getInterfaceType())));
|
||||
}
|
||||
}
|
||||
|
||||
static std::pair<BraceStmt *, bool>
|
||||
deriveBodyDistributed_thunk(AbstractFunctionDecl *thunk, void *context) {
|
||||
auto implicit = true;
|
||||
ASTContext &C = thunk->getASTContext();
|
||||
auto module = thunk->getParentModule();
|
||||
|
||||
// mock locations, we're a thunk and don't really need detailed locations
|
||||
const SourceLoc sloc = SourceLoc();
|
||||
const DeclNameLoc dloc = DeclNameLoc();
|
||||
|
||||
auto func = static_cast<FuncDecl *>(context);
|
||||
auto funcDC = func->getDeclContext();
|
||||
NominalTypeDecl *nominal = funcDC->getSelfNominalTypeDecl();
|
||||
assert(nominal && nominal->isDistributedActor() &&
|
||||
"Distributed function must be part of distributed actor");
|
||||
|
||||
auto selfDecl = thunk->getImplicitSelfDecl();
|
||||
selfDecl->getAttrs().add(new (C) KnownToBeLocalAttr(implicit));
|
||||
auto selfRefExpr = new (C) DeclRefExpr(selfDecl, dloc, implicit);
|
||||
|
||||
// === return type
|
||||
Type returnTy = func->getResultInterfaceType();
|
||||
auto isVoidReturn = returnTy->isVoid();
|
||||
|
||||
// === self.actorSystem
|
||||
ProtocolDecl *DAS = C.getDistributedActorSystemDecl();
|
||||
Type systemTy = getConcreteReplacementForProtocolActorSystemType(thunk);
|
||||
assert(systemTy && "distributed thunk can only be synthesized with concrete "
|
||||
"actor system types");
|
||||
NominalTypeDecl *systemDecl = systemTy->getAnyNominal();
|
||||
assert(systemDecl);
|
||||
auto systemConfRef = module->lookupConformance(systemTy, DAS);
|
||||
assert(systemConfRef && "ActorSystem must conform to DistributedActorSystem");
|
||||
|
||||
// === ActorSystem.InvocationEncoder
|
||||
Type invocationEncoderTy =
|
||||
getDistributedActorSystemInvocationEncoderType(systemDecl);
|
||||
NominalTypeDecl *invocationEncoderDecl = invocationEncoderTy->getAnyNominal();
|
||||
|
||||
// === Type:
|
||||
StructDecl *RCT = C.getRemoteCallTargetDecl();
|
||||
Type remoteCallTargetTy = RCT->getDeclaredInterfaceType();
|
||||
|
||||
// === __isRemoteActor(self)
|
||||
ArgumentList *isRemoteArgs =
|
||||
ArgumentList::forImplicitSingle(C, /*label=*/Identifier(), selfRefExpr);
|
||||
|
||||
FuncDecl *isRemoteFn = C.getIsRemoteDistributedActor();
|
||||
assert(isRemoteFn && "Could not find 'is remote' function, is the "
|
||||
"'_Distributed' module available?");
|
||||
auto isRemoteDeclRef =
|
||||
UnresolvedDeclRefExpr::createImplicit(C, isRemoteFn->getName());
|
||||
auto isRemote =
|
||||
CallExpr::createImplicit(C, isRemoteDeclRef, isRemoteArgs);
|
||||
|
||||
// === local branch ----------------------------------------------------------
|
||||
// -- forward arguments
|
||||
SmallVector<Expr*, 4> forwardingParams;
|
||||
forwardParameters(thunk, forwardingParams);
|
||||
auto funcRef = UnresolvedDeclRefExpr::createImplicit(C, func->getName());
|
||||
auto forwardingArgList = ArgumentList::forImplicitCallTo(funcRef->getName(), forwardingParams, C);
|
||||
|
||||
auto funcDeclRef =
|
||||
UnresolvedDotExpr::createImplicit(C, selfRefExpr, func->getBaseName());
|
||||
Expr *localFuncCall = CallExpr::createImplicit(C, funcDeclRef, forwardingArgList);
|
||||
localFuncCall = AwaitExpr::createImplicit(C, sloc, localFuncCall);
|
||||
if (func->hasThrows()) {
|
||||
localFuncCall = TryExpr::createImplicit(C, sloc, localFuncCall);
|
||||
}
|
||||
auto returnLocalFuncCall = new (C) ReturnStmt(sloc, localFuncCall, implicit);
|
||||
auto localBranchStmt =
|
||||
BraceStmt::create(C, sloc, {returnLocalFuncCall}, sloc, implicit);
|
||||
|
||||
// === remote branch --------------------------------------------------------
|
||||
SmallVector<ASTNode, 8> remoteBranchStmts;
|
||||
// --- self.actorSystem
|
||||
auto systemProperty = nominal->getDistributedActorSystemProperty();
|
||||
auto systemRefExpr =
|
||||
UnresolvedDotExpr::createImplicit(
|
||||
C, new (C) DeclRefExpr(selfDecl, dloc, implicit), // TODO: make createImplicit
|
||||
C.Id_actorSystem);
|
||||
|
||||
auto *systemVar =
|
||||
new (C) VarDecl(/*isStatic=*/false, VarDecl::Introducer::Let, sloc,
|
||||
C.Id_system, thunk);
|
||||
systemVar->setInterfaceType(systemProperty->getInterfaceType());
|
||||
systemVar->setImplicit();
|
||||
systemVar->setSynthesized();
|
||||
|
||||
Pattern *systemPattern = NamedPattern::createImplicit(C, systemVar);
|
||||
|
||||
auto systemPB = PatternBindingDecl::createImplicit(
|
||||
C, StaticSpellingKind::None, systemPattern, systemRefExpr,
|
||||
thunk);
|
||||
|
||||
remoteBranchStmts.push_back(systemPB);
|
||||
remoteBranchStmts.push_back(systemVar);
|
||||
|
||||
// --- invocationEncoder = system.makeInvocationEncoder()
|
||||
auto *invocationVar =
|
||||
new (C) VarDecl(/*isStatic=*/false, VarDecl::Introducer::Var, sloc,
|
||||
C.Id_invocation, thunk);
|
||||
invocationVar->setInterfaceType(invocationEncoderTy);
|
||||
invocationVar->setImplicit();
|
||||
invocationVar->setSynthesized();
|
||||
|
||||
{
|
||||
Pattern *invocationPattern = NamedPattern::createImplicit(C, invocationVar);
|
||||
|
||||
FuncDecl *makeInvocationEncoderDecl =
|
||||
C.getMakeInvocationEncoderOnDistributedActorSystem(func);
|
||||
auto makeInvocationExpr = UnresolvedDotExpr::createImplicit(
|
||||
C, new (C) DeclRefExpr(ConcreteDeclRef(systemVar), dloc, implicit),
|
||||
makeInvocationEncoderDecl->getName());
|
||||
auto *makeInvocationArgs = ArgumentList::createImplicit(C, {});
|
||||
auto makeInvocationCallExpr =
|
||||
CallExpr::createImplicit(C, makeInvocationExpr, makeInvocationArgs);
|
||||
makeInvocationCallExpr->setThrows(false);
|
||||
|
||||
auto invocationEncoderPB = PatternBindingDecl::createImplicit(
|
||||
C, StaticSpellingKind::None, invocationPattern, makeInvocationCallExpr,
|
||||
thunk);
|
||||
remoteBranchStmts.push_back(invocationEncoderPB);
|
||||
remoteBranchStmts.push_back(invocationVar);
|
||||
}
|
||||
|
||||
// --- Recording invocation details
|
||||
// -- recordGenericSubstitution(s)
|
||||
if (func->isGeneric() || nominal->isGeneric()) {
|
||||
auto recordGenericSubstitutionDecl =
|
||||
C.getRecordGenericSubstitutionOnDistributedInvocationEncoder(invocationEncoderDecl);
|
||||
assert(recordGenericSubstitutionDecl);
|
||||
auto recordGenericSubstitutionDeclRef =
|
||||
UnresolvedDeclRefExpr::createImplicit(
|
||||
C, recordGenericSubstitutionDecl->getName());
|
||||
|
||||
auto sig = func->getGenericSignature();
|
||||
for (auto genParamType : sig.getGenericParams()) {
|
||||
|
||||
auto subTypeExpr = new (C) DotSelfExpr(
|
||||
TypeExpr::createImplicit(thunk->mapTypeIntoContext(genParamType), C),
|
||||
sloc, sloc, thunk->mapTypeIntoContext(genParamType));
|
||||
|
||||
auto recordGenericSubArgsList =
|
||||
ArgumentList::forImplicitCallTo(
|
||||
recordGenericSubstitutionDeclRef->getName(),
|
||||
{subTypeExpr},
|
||||
C);
|
||||
|
||||
Expr *recordGenericSub =
|
||||
CallExpr::createImplicit(C,
|
||||
UnresolvedDotExpr::createImplicit(C,
|
||||
new (C) DeclRefExpr(ConcreteDeclRef(invocationVar), dloc, implicit, AccessSemantics::Ordinary),
|
||||
recordGenericSubstitutionDecl->getName()),
|
||||
recordGenericSubArgsList);
|
||||
recordGenericSub = TryExpr::createImplicit(C, sloc, recordGenericSub);
|
||||
|
||||
remoteBranchStmts.push_back(recordGenericSub);
|
||||
}
|
||||
}
|
||||
|
||||
// -- recordArgument(s)
|
||||
{
|
||||
auto recordArgumentDecl =
|
||||
C.getRecordArgumentOnDistributedInvocationEncoder(invocationEncoderDecl);
|
||||
assert(recordArgumentDecl);
|
||||
|
||||
for (auto param : *thunk->getParameters()) {
|
||||
auto recordArgumentDeclRef = UnresolvedDeclRefExpr::createImplicit(
|
||||
C, recordArgumentDecl->getName());
|
||||
|
||||
auto recordArgArgsList = ArgumentList::forImplicitCallTo(
|
||||
recordArgumentDeclRef->getName(),
|
||||
{
|
||||
new (C) DeclRefExpr(
|
||||
ConcreteDeclRef(param), dloc, implicit,
|
||||
AccessSemantics::Ordinary,
|
||||
thunk->mapTypeIntoContext(param->getInterfaceType()))
|
||||
}, C);
|
||||
|
||||
auto tryRecordArgExpr = TryExpr::createImplicit(C, sloc,
|
||||
CallExpr::createImplicit(C,
|
||||
UnresolvedDotExpr::createImplicit(C,
|
||||
new (C) DeclRefExpr(ConcreteDeclRef(invocationVar), dloc, implicit, AccessSemantics::Ordinary),
|
||||
recordArgumentDecl->getName()),
|
||||
recordArgArgsList));
|
||||
|
||||
remoteBranchStmts.push_back(tryRecordArgExpr);
|
||||
}
|
||||
}
|
||||
|
||||
// -- recordErrorType
|
||||
if (func->hasThrows()) {
|
||||
// Error.self
|
||||
auto errorDecl = C.getErrorDecl();
|
||||
auto *errorTypeExpr = new (C) DotSelfExpr(
|
||||
UnresolvedDeclRefExpr::createImplicit(C, errorDecl->getName()), sloc,
|
||||
sloc, errorDecl->getDeclaredInterfaceType());
|
||||
|
||||
auto recordErrorDecl = C.getRecordErrorTypeOnDistributedInvocationEncoder(
|
||||
invocationEncoderDecl);
|
||||
assert(recordErrorDecl);
|
||||
auto recordErrorDeclRef =
|
||||
UnresolvedDeclRefExpr::createImplicit(C, recordErrorDecl->getName());
|
||||
|
||||
auto recordArgsList = ArgumentList::forImplicitCallTo(
|
||||
recordErrorDeclRef->getName(),
|
||||
{errorTypeExpr},
|
||||
C);
|
||||
auto tryRecordErrorTyExpr = TryExpr::createImplicit(C, sloc,
|
||||
CallExpr::createImplicit(C,
|
||||
UnresolvedDotExpr::createImplicit(C,
|
||||
new (C) DeclRefExpr(ConcreteDeclRef(invocationVar), dloc, implicit, AccessSemantics::Ordinary),
|
||||
recordErrorDecl->getName()),
|
||||
recordArgsList));
|
||||
|
||||
remoteBranchStmts.push_back(tryRecordErrorTyExpr);
|
||||
}
|
||||
|
||||
// -- recordReturnType
|
||||
if (!isVoidReturn) {
|
||||
// Result.self
|
||||
auto resultType = func->getResultInterfaceType();
|
||||
auto *metaTypeRef = TypeExpr::createImplicit(resultType, C);
|
||||
auto *resultTypeExpr =
|
||||
new (C) DotSelfExpr(metaTypeRef, sloc, sloc, resultType);
|
||||
|
||||
auto recordReturnTypeDecl =
|
||||
C.getRecordReturnTypeOnDistributedInvocationEncoder(
|
||||
invocationEncoderDecl);
|
||||
auto recordReturnTypeDeclRef =
|
||||
UnresolvedDeclRefExpr::createImplicit(C, recordReturnTypeDecl->getName());
|
||||
|
||||
auto recordArgsList = ArgumentList::forImplicitCallTo(
|
||||
recordReturnTypeDeclRef->getName(),
|
||||
{resultTypeExpr},
|
||||
C);
|
||||
auto tryRecordReturnTyExpr = TryExpr::createImplicit(C, sloc,
|
||||
CallExpr::createImplicit(C,
|
||||
UnresolvedDotExpr::createImplicit(C,
|
||||
new (C) DeclRefExpr(ConcreteDeclRef(invocationVar), dloc, implicit,
|
||||
AccessSemantics::Ordinary),
|
||||
recordReturnTypeDecl->getName()),
|
||||
recordArgsList));
|
||||
|
||||
remoteBranchStmts.push_back(tryRecordReturnTyExpr);
|
||||
}
|
||||
|
||||
// -- doneRecording
|
||||
{
|
||||
auto doneRecordingDecl =
|
||||
C.getDoneRecordingOnDistributedInvocationEncoder(invocationEncoderDecl);
|
||||
auto doneRecordingDeclRef =
|
||||
UnresolvedDeclRefExpr::createImplicit(C, doneRecordingDecl->getName());
|
||||
|
||||
auto argsList =
|
||||
ArgumentList::forImplicitCallTo(doneRecordingDeclRef->getName(), {}, C);
|
||||
auto tryDoneRecordingExpr = TryExpr::createImplicit(C, sloc,
|
||||
CallExpr::createImplicit(C,
|
||||
UnresolvedDotExpr::createImplicit(C,
|
||||
new (C) DeclRefExpr(ConcreteDeclRef(invocationVar), dloc, implicit,
|
||||
AccessSemantics::Ordinary,
|
||||
invocationVar->getInterfaceType()),
|
||||
doneRecordingDecl->getName()),
|
||||
argsList));
|
||||
|
||||
remoteBranchStmts.push_back(tryDoneRecordingExpr);
|
||||
}
|
||||
|
||||
// === Prepare the 'RemoteCallTarget'
|
||||
VarDecl *targetVar =
|
||||
new (C) VarDecl(/*isStatic=*/false, VarDecl::Introducer::Let, sloc,
|
||||
C.Id_target, thunk);
|
||||
|
||||
{
|
||||
// --- Mangle the thunk name
|
||||
Mangle::ASTMangler mangler;
|
||||
auto symbolKind = swift::Mangle::ASTMangler::SymbolKind::DistributedThunk;
|
||||
auto mangled = C.AllocateCopy(mangler.mangleEntity(thunk, symbolKind));
|
||||
StringRef mangledTargetStringRef = StringRef(mangled);
|
||||
auto mangledTargetStringLiteral = new (C)
|
||||
StringLiteralExpr(mangledTargetStringRef, SourceRange(), implicit);
|
||||
|
||||
// --- let target = RemoteCallTarget(<mangled name>)
|
||||
targetVar->setInterfaceType(remoteCallTargetTy);
|
||||
targetVar->setImplicit();
|
||||
targetVar->setSynthesized();
|
||||
|
||||
Pattern *targetPattern = NamedPattern::createImplicit(C, targetVar);
|
||||
|
||||
auto remoteCallTargetInitDecl =
|
||||
RCT->getDistributedRemoteCallTargetInitFunction();
|
||||
auto remoteCallTargetInitDeclRef = UnresolvedDeclRefExpr::createImplicit(
|
||||
C, remoteCallTargetInitDecl->getEffectiveFullName());
|
||||
|
||||
auto initTargetExpr = UnresolvedDeclRefExpr::createImplicit(
|
||||
C, RCT->getName());
|
||||
auto initTargetArgs = ArgumentList::forImplicitCallTo(
|
||||
remoteCallTargetInitDeclRef->getName(),
|
||||
{mangledTargetStringLiteral}, C);
|
||||
|
||||
auto initTargetCallExpr =
|
||||
CallExpr::createImplicit(C, initTargetExpr, initTargetArgs);
|
||||
|
||||
auto targetPB = PatternBindingDecl::createImplicit(
|
||||
C, StaticSpellingKind::None, targetPattern, initTargetCallExpr, thunk);
|
||||
|
||||
remoteBranchStmts.push_back(targetPB);
|
||||
remoteBranchStmts.push_back(targetVar);
|
||||
}
|
||||
|
||||
// === Make the 'remoteCall(Void)(...)'
|
||||
{
|
||||
auto remoteCallDecl =
|
||||
C.getRemoteCallOnDistributedActorSystem(systemDecl, isVoidReturn);
|
||||
auto systemRemoteCallRef =
|
||||
UnresolvedDotExpr::createImplicit(
|
||||
C, new (C) DeclRefExpr(ConcreteDeclRef(systemVar), dloc, implicit),
|
||||
remoteCallDecl->getName());
|
||||
|
||||
SmallVector<Expr *, 5> args;
|
||||
// -- on actor: Act
|
||||
args.push_back(new (C) DeclRefExpr(selfDecl, dloc, implicit,
|
||||
swift::AccessSemantics::Ordinary,
|
||||
selfDecl->getInterfaceType()));
|
||||
// -- target: RemoteCallTarget
|
||||
args.push_back(new (C) DeclRefExpr(ConcreteDeclRef(targetVar), dloc, implicit,
|
||||
AccessSemantics::Ordinary,
|
||||
RCT->getDeclaredInterfaceType()));
|
||||
// -- invocation: inout InvocationEncoder
|
||||
args.push_back(new (C) InOutExpr(sloc,
|
||||
new (C) DeclRefExpr(ConcreteDeclRef(invocationVar), dloc,
|
||||
implicit, AccessSemantics::Ordinary, invocationEncoderTy), invocationEncoderTy, implicit));
|
||||
|
||||
// -- throwing: Err.Type
|
||||
if (func->hasThrows()) {
|
||||
// Error.self
|
||||
auto errorDecl = C.getErrorDecl();
|
||||
auto *errorTypeExpr = new (C) DotSelfExpr(
|
||||
UnresolvedDeclRefExpr::createImplicit(C, errorDecl->getName()), sloc,
|
||||
sloc, errorDecl->getDeclaredInterfaceType());
|
||||
|
||||
args.push_back(errorTypeExpr);
|
||||
} else {
|
||||
// Never.self
|
||||
auto neverDecl = C.getNeverDecl();
|
||||
auto *neverTypeExpr = new (C) DotSelfExpr(
|
||||
UnresolvedDeclRefExpr::createImplicit(C, neverDecl->getName()), sloc,
|
||||
sloc, neverDecl->getDeclaredInterfaceType());
|
||||
args.push_back(neverTypeExpr);
|
||||
}
|
||||
|
||||
// -- returning: Res.Type
|
||||
if (!isVoidReturn) {
|
||||
// Result.self
|
||||
auto resultType = func->getResultInterfaceType();
|
||||
auto *metaTypeRef = TypeExpr::createImplicit(resultType, C);
|
||||
auto *resultTypeExpr =
|
||||
new (C) DotSelfExpr(metaTypeRef, sloc, sloc, resultType);
|
||||
|
||||
args.push_back(resultTypeExpr);
|
||||
}
|
||||
|
||||
assert(args.size() == remoteCallDecl->getParameters()->size());
|
||||
auto remoteCallArgs = ArgumentList::forImplicitCallTo(
|
||||
systemRemoteCallRef->getName(), args, C);
|
||||
|
||||
Expr *remoteCallExpr =
|
||||
CallExpr::createImplicit(C, systemRemoteCallRef, remoteCallArgs);
|
||||
remoteCallExpr = AwaitExpr::createImplicit(C, sloc, remoteCallExpr);
|
||||
remoteCallExpr = TryExpr::createImplicit(C, sloc, remoteCallExpr);
|
||||
auto returnRemoteCall =
|
||||
new (C) ReturnStmt(sloc, remoteCallExpr, implicit);
|
||||
remoteBranchStmts.push_back(returnRemoteCall);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
auto remoteBranchStmt =
|
||||
BraceStmt::create(C, sloc, remoteBranchStmts, sloc, implicit);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// === if (isRemote(...) <remote branch> else <local branch>
|
||||
auto ifStmt = new (C) IfStmt(sloc, /*condition=*/isRemote,
|
||||
/*then=*/remoteBranchStmt, sloc,
|
||||
/*else=*/localBranchStmt, implicit, C);
|
||||
|
||||
auto body = BraceStmt::create(C, sloc, {ifStmt}, sloc, implicit);
|
||||
return {body, /*isTypeChecked=*/false};
|
||||
}
|
||||
|
||||
static FuncDecl *createDistributedThunkFunction(FuncDecl *func) {
|
||||
auto &C = func->getASTContext();
|
||||
auto DC = func->getDeclContext();
|
||||
|
||||
auto systemTy = getConcreteReplacementForProtocolActorSystemType(func);
|
||||
assert(systemTy &&
|
||||
"Thunk synthesis must have concrete actor system type available");
|
||||
|
||||
DeclName thunkName = func->getName();
|
||||
|
||||
// --- Prepare generic parameters
|
||||
GenericParamList *genericParamList = nullptr;
|
||||
if (auto genericParams = func->getGenericParams()) {
|
||||
genericParamList = genericParams->clone(DC);
|
||||
}
|
||||
|
||||
GenericSignature thunkGenSig =
|
||||
buildGenericSignature(C, func->getGenericSignature(),
|
||||
/*addedParameters=*/{},
|
||||
/*addedRequirements=*/{});
|
||||
|
||||
// --- Prepare parameters
|
||||
auto funcParams = func->getParameters();
|
||||
SmallVector<ParamDecl*, 2> paramDecls;
|
||||
for (unsigned i : indices(*func->getParameters())) {
|
||||
auto funcParam = funcParams->get(i);
|
||||
|
||||
auto paramName = funcParam->getParameterName();
|
||||
// If internal name is empty it could only mean either
|
||||
// `_:` or `x _: ...`, so let's auto-generate a name
|
||||
// to be used in the body of a thunk.
|
||||
if (paramName.empty()) {
|
||||
paramName = C.getIdentifier("p" + llvm::utostr(i));
|
||||
}
|
||||
|
||||
auto paramDecl = new (C)
|
||||
ParamDecl(SourceLoc(),
|
||||
/*argumentNameLoc=*/SourceLoc(), funcParam->getArgumentName(),
|
||||
/*parameterNameLoc=*/SourceLoc(), paramName, DC);
|
||||
|
||||
paramDecl->setImplicit(true);
|
||||
paramDecl->setSpecifier(funcParam->getSpecifier());
|
||||
paramDecl->setInterfaceType(funcParam->getInterfaceType());
|
||||
|
||||
paramDecls.push_back(paramDecl);
|
||||
}
|
||||
ParameterList *params = ParameterList::create(C, paramDecls); // = funcParams->clone(C);
|
||||
|
||||
auto thunk = FuncDecl::createImplicit(C, swift::StaticSpellingKind::None,
|
||||
thunkName, SourceLoc(),
|
||||
/*async=*/true, /*throws=*/true,
|
||||
genericParamList,
|
||||
params,
|
||||
func->getResultInterfaceType(),
|
||||
DC);
|
||||
thunk->setSynthesized(true);
|
||||
thunk->getAttrs().add(new (C) NonisolatedAttr(/*implicit=*/true));
|
||||
thunk->setGenericSignature(thunkGenSig);
|
||||
thunk->copyFormalAccessFrom(func, /*sourceIsParentContext=*/false);
|
||||
thunk->setBodySynthesizer(deriveBodyDistributed_thunk, func);
|
||||
|
||||
return thunk;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*********************** SYNTHESIS ENTRY POINTS *******************************/
|
||||
/******************************************************************************/
|
||||
|
||||
FuncDecl *GetDistributedThunkRequest::evaluate(
|
||||
Evaluator &evaluator, AbstractFunctionDecl *distributedTarget) const {
|
||||
if (!distributedTarget->isDistributed())
|
||||
return nullptr;
|
||||
|
||||
auto &C = distributedTarget->getASTContext();
|
||||
auto DC = distributedTarget->getDeclContext();
|
||||
|
||||
if (!getConcreteReplacementForProtocolActorSystemType(distributedTarget)) {
|
||||
// Don't synthesize thunks, unless there is a *concrete* ActorSystem.
|
||||
// TODO(distributed): we should be able to lift this eventually,
|
||||
// and allow resolving distributed actor protocols.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Force type-checking the original function, so we can avoid synthesizing
|
||||
// the thunks (which would have many of the same errors, if they are caused
|
||||
// by a bad source function signature, e.g. missing conformances etc).
|
||||
(void) TypeChecker::typeCheckDecl(distributedTarget);
|
||||
if (distributedTarget->getDiags().hadAnyError()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (auto func = dyn_cast<FuncDecl>(distributedTarget)) {
|
||||
// not via `ensureDistributedModuleLoaded` to avoid generating a warning,
|
||||
// we won't be emitting the offending decl after all.
|
||||
if (!C.getLoadedModule(C.Id_Distributed))
|
||||
return nullptr;
|
||||
|
||||
auto nominal = DC->getSelfNominalTypeDecl(); // NOTE: Always from DC
|
||||
assert(nominal);
|
||||
|
||||
// --- Prepare the "distributed thunk" which does the "maybe remote" dance:
|
||||
return createDistributedThunkFunction(func);
|
||||
}
|
||||
|
||||
llvm_unreachable("Unable to synthesize distributed thunk");
|
||||
}
|
||||
|
||||
VarDecl *GetDistributedActorIDPropertyRequest::evaluate(
|
||||
Evaluator &evaluator, NominalTypeDecl *actor) const {
|
||||
if (!actor->isDistributedActor())
|
||||
@@ -96,29 +607,52 @@ VarDecl *GetDistributedActorIDPropertyRequest::evaluate(
|
||||
if (!C.getLoadedModule(C.Id_Distributed))
|
||||
return nullptr;
|
||||
|
||||
return addImplicitDistributedActorIDProperty(actor);
|
||||
}
|
||||
|
||||
VarDecl *GetDistributedActorSystemPropertyRequest::evaluate(
|
||||
Evaluator &evaluator, NominalTypeDecl *actor) const {
|
||||
if (!actor->isDistributedActor())
|
||||
auto classDecl = dyn_cast<ClassDecl>(actor);
|
||||
if (!classDecl)
|
||||
return nullptr;
|
||||
|
||||
auto &C = actor->getASTContext();
|
||||
return addImplicitDistributedActorIDProperty(classDecl);
|
||||
}
|
||||
|
||||
|
||||
VarDecl *GetDistributedActorSystemPropertyRequest::evaluate(
|
||||
Evaluator &evaluator, NominalTypeDecl *nominal) const {
|
||||
auto &C = nominal->getASTContext();
|
||||
auto module = nominal->getParentModule();
|
||||
|
||||
auto DAS = C.getDistributedActorSystemDecl();
|
||||
auto f = DAS->lookupDirect(C.Id_makeInvocationEncoder);
|
||||
|
||||
// not via `ensureDistributedModuleLoaded` to avoid generating a warning,
|
||||
// we won't be emitting the offending decl after all.
|
||||
if (!C.getLoadedModule(C.Id_Distributed))
|
||||
return nullptr;
|
||||
|
||||
auto module = C.getStdlibModule();
|
||||
auto DistSystemProtocol =
|
||||
C.getProtocol(KnownProtocolKind::DistributedActorSystem);
|
||||
if (!nominal->isDistributedActor())
|
||||
return nullptr;
|
||||
|
||||
for (auto system : actor->lookupDirect(C.Id_actorSystem)) {
|
||||
if (auto proto = dyn_cast<ProtocolDecl>(nominal)) {
|
||||
auto DistributedActorProto = C.getDistributedActorDecl();
|
||||
for (auto system : DistributedActorProto->lookupDirect(C.Id_actorSystem)) {
|
||||
if (auto var = dyn_cast<VarDecl>(system)) {
|
||||
auto conformance = module->conformsToProtocol(
|
||||
proto->mapTypeIntoContext(var->getInterfaceType()),
|
||||
DAS);
|
||||
|
||||
if (conformance.isInvalid())
|
||||
continue;
|
||||
|
||||
return var;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (auto system : nominal->lookupDirect(C.Id_actorSystem)) {
|
||||
if (auto var = dyn_cast<VarDecl>(system)) {
|
||||
auto conformance = module->conformsToProtocol(var->getInterfaceType(),
|
||||
DistSystemProtocol);
|
||||
auto conformance = module->conformsToProtocol(
|
||||
var->getInterfaceType(), DAS);
|
||||
if (conformance.isInvalid())
|
||||
continue;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user