mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[Distributed] ResultHandler.onReturn must be ad-hoc because SerializationRequirement (#41916)
* [Distributed] Invoke handler.onReturn ad hoc via ast synthesized func * reformat and cleanup * remove unused var
This commit is contained in:
committed by
GitHub
parent
e508ce39b0
commit
8d3e7d91c0
@@ -30,6 +30,12 @@ bool DerivedConformance::canDeriveDistributedActor(
|
||||
return classDecl && classDecl->isDistributedActor() && dc == nominal;
|
||||
}
|
||||
|
||||
bool DerivedConformance::canDeriveDistributedActorSystem(
|
||||
NominalTypeDecl *nominal, DeclContext *dc) {
|
||||
auto &C = nominal->getASTContext();
|
||||
return C.getLoadedModule(C.Id_Distributed);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************* RESOLVE FUNCTION *****************************/
|
||||
/******************************************************************************/
|
||||
@@ -94,6 +100,321 @@ static FuncDecl *deriveDistributedActor_resolve(DerivedConformance &derived) {
|
||||
return factoryDecl;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*************** INVOKE HANDLER ON-RETURN FUNCTION ****************************/
|
||||
/******************************************************************************/
|
||||
|
||||
namespace {
|
||||
struct DoInvokeOnReturnContext {
|
||||
ParamDecl *handlerParam;
|
||||
ParamDecl *resultBufferParam;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
static std::pair<BraceStmt *, bool>
|
||||
deriveBodyDistributed_doInvokeOnReturn(AbstractFunctionDecl *afd, void *arg) {
|
||||
auto &C = afd->getASTContext();
|
||||
auto *context = static_cast<DoInvokeOnReturnContext *>(arg);
|
||||
|
||||
// mock locations, we're a thunk and don't really need detailed locations
|
||||
const SourceLoc sloc = SourceLoc();
|
||||
const DeclNameLoc dloc = DeclNameLoc();
|
||||
bool implicit = true;
|
||||
|
||||
auto returnTypeParam = afd->getParameters()->get(0);
|
||||
SmallVector<ASTNode, 8> stmts;
|
||||
|
||||
VarDecl *resultVar =
|
||||
new (C) VarDecl(/*isStatic=*/false, VarDecl::Introducer::Let, sloc,
|
||||
C.getIdentifier("result"), afd);
|
||||
{
|
||||
auto resultLoadCall = CallExpr::createImplicit(
|
||||
C,
|
||||
UnresolvedDotExpr::createImplicit(
|
||||
C,
|
||||
/*base=*/
|
||||
new (C) DeclRefExpr(ConcreteDeclRef(context->resultBufferParam),
|
||||
dloc, implicit),
|
||||
/*baseName=*/DeclBaseName(C.getIdentifier("load")),
|
||||
/*argLabels=*/
|
||||
{C.getIdentifier("fromByteOffset"), C.getIdentifier("as")}),
|
||||
ArgumentList::createImplicit(
|
||||
C, {Argument(sloc, C.getIdentifier("as"),
|
||||
new (C) DeclRefExpr(ConcreteDeclRef(returnTypeParam),
|
||||
dloc, implicit))}));
|
||||
|
||||
auto resultPattern = NamedPattern::createImplicit(C, resultVar);
|
||||
auto resultPB = PatternBindingDecl::createImplicit(
|
||||
C, swift::StaticSpellingKind::None, resultPattern,
|
||||
/*expr=*/resultLoadCall, afd);
|
||||
|
||||
stmts.push_back(resultPB);
|
||||
stmts.push_back(resultVar);
|
||||
}
|
||||
|
||||
// call the ad-hoc `handler.onReturn`
|
||||
{
|
||||
// Find the ad-hoc requirement ensured function on the concrete handler:
|
||||
auto onReturnFunc = C.getOnReturnOnDistributedTargetInvocationResultHandler(
|
||||
context->handlerParam->getInterfaceType()->getAnyNominal());
|
||||
assert(onReturnFunc && "did not find ad-hoc requirement witness!");
|
||||
|
||||
Expr *callExpr = CallExpr::createImplicit(
|
||||
C,
|
||||
UnresolvedDotExpr::createImplicit(
|
||||
C,
|
||||
/*base=*/
|
||||
new (C) DeclRefExpr(ConcreteDeclRef(context->handlerParam), dloc,
|
||||
implicit),
|
||||
/*baseName=*/onReturnFunc->getBaseName(),
|
||||
/*paramList=*/onReturnFunc->getParameters()),
|
||||
ArgumentList::forImplicitCallTo(
|
||||
DeclNameRef(onReturnFunc->getName()),
|
||||
{new (C) DeclRefExpr(ConcreteDeclRef(resultVar), dloc, implicit)},
|
||||
C));
|
||||
callExpr = TryExpr::createImplicit(C, sloc, callExpr);
|
||||
callExpr = AwaitExpr::createImplicit(C, sloc, callExpr);
|
||||
|
||||
stmts.push_back(callExpr);
|
||||
}
|
||||
|
||||
auto body = BraceStmt::create(C, sloc, {stmts}, sloc, implicit);
|
||||
return {body, /*isTypeChecked=*/false};
|
||||
}
|
||||
|
||||
// Create local function:
|
||||
// func invokeOnReturn<R: Self.SerializationRequirement>(
|
||||
// _ returnType: R.Type
|
||||
// ) async throws {
|
||||
// let value = resultBuffer.load(as: returnType)
|
||||
// try await handler.onReturn(value: value)
|
||||
// }
|
||||
static FuncDecl* createLocalFunc_doInvokeOnReturn(
|
||||
ASTContext& C, FuncDecl* parentFunc,
|
||||
NominalTypeDecl* systemNominal,
|
||||
ParamDecl* handlerParam,
|
||||
ParamDecl* resultBufParam) {
|
||||
auto DC = parentFunc;
|
||||
auto DAS = C.getDistributedActorSystemDecl();
|
||||
auto doInvokeLocalFuncIdent = C.getIdentifier("doInvokeOnReturn");
|
||||
|
||||
// mock locations, we're a synthesized func and don't need real locations
|
||||
const SourceLoc sloc = SourceLoc();
|
||||
|
||||
// <R: Self.SerializationRequirement>
|
||||
// We create the generic param at invalid depth, which means it'll be filled
|
||||
// by semantic analysis.
|
||||
auto resultGenericParamDecl = GenericTypeParamDecl::create(
|
||||
parentFunc, C.getIdentifier("R"), sloc, /*isTypeSequence=*/false,
|
||||
/*depth=*/0, /*index=*/0,
|
||||
/*isOpaqueType=*/false,
|
||||
/*opaqueTypeRepr=*/nullptr);
|
||||
GenericParamList *doInvokeGenericParamList =
|
||||
GenericParamList::create(C, sloc, {resultGenericParamDecl}, sloc);
|
||||
|
||||
auto returnTypeIdent = C.getIdentifier("returnType");
|
||||
auto resultTyParamDecl =
|
||||
ParamDecl::createImplicit(C,
|
||||
/*argument=*/returnTypeIdent,
|
||||
/*parameter=*/returnTypeIdent,
|
||||
resultGenericParamDecl->getInterfaceType(), DC);
|
||||
ParameterList *doInvokeParamsList =
|
||||
ParameterList::create(C, {resultTyParamDecl});
|
||||
|
||||
SmallVector<Requirement, 2> requirements;
|
||||
for (auto p : getDistributedSerializationRequirementProtocols(systemNominal, DAS)) {
|
||||
auto requirement =
|
||||
Requirement(RequirementKind::Conformance,
|
||||
resultGenericParamDecl->getDeclaredInterfaceType(),
|
||||
p->getInterfaceType()->getMetatypeInstanceType());
|
||||
requirements.push_back(requirement);
|
||||
}
|
||||
GenericSignature doInvokeGenSig =
|
||||
buildGenericSignature(C, parentFunc->getGenericSignature(),
|
||||
{resultGenericParamDecl->getDeclaredInterfaceType()
|
||||
->castTo<GenericTypeParamType>()},
|
||||
std::move(requirements));
|
||||
|
||||
FuncDecl *doInvokeOnReturnFunc = FuncDecl::createImplicit(
|
||||
C, swift::StaticSpellingKind::None,
|
||||
DeclName(C, doInvokeLocalFuncIdent, doInvokeParamsList),
|
||||
sloc,
|
||||
/*async=*/true,
|
||||
/*throws=*/true, doInvokeGenericParamList, doInvokeParamsList,
|
||||
/*returnType=*/C.TheEmptyTupleType, parentFunc);
|
||||
doInvokeOnReturnFunc->setImplicit();
|
||||
doInvokeOnReturnFunc->setSynthesized();
|
||||
doInvokeOnReturnFunc->setGenericSignature(doInvokeGenSig);
|
||||
|
||||
auto *doInvokeContext = C.Allocate<DoInvokeOnReturnContext>();
|
||||
doInvokeContext->handlerParam = handlerParam;
|
||||
doInvokeContext->resultBufferParam = resultBufParam;
|
||||
doInvokeOnReturnFunc->setBodySynthesizer(
|
||||
deriveBodyDistributed_doInvokeOnReturn, doInvokeContext);
|
||||
|
||||
return doInvokeOnReturnFunc;
|
||||
}
|
||||
|
||||
static std::pair<BraceStmt *, bool>
|
||||
deriveBodyDistributed_invokeHandlerOnReturn(AbstractFunctionDecl *afd,
|
||||
void *context) {
|
||||
auto implicit = true;
|
||||
ASTContext &C = afd->getASTContext();
|
||||
auto DC = afd->getDeclContext();
|
||||
auto DAS = C.getDistributedActorSystemDecl();
|
||||
|
||||
// mock locations, we're a thunk and don't really need detailed locations
|
||||
const SourceLoc sloc = SourceLoc();
|
||||
const DeclNameLoc dloc = DeclNameLoc();
|
||||
|
||||
NominalTypeDecl *nominal = dyn_cast<NominalTypeDecl>(DC);
|
||||
assert(nominal);
|
||||
|
||||
auto func = dyn_cast<FuncDecl>(afd);
|
||||
assert(func);
|
||||
|
||||
// === parameters
|
||||
auto params = func->getParameters();
|
||||
assert(params->size() == 3);
|
||||
auto handlerParam = params->get(0);
|
||||
auto resultBufParam = params->get(1);
|
||||
auto metatypeParam = params->get(2);
|
||||
|
||||
auto serializationRequirementTypeTy =
|
||||
getDistributedSerializationRequirementType(nominal, DAS);
|
||||
|
||||
auto serializationRequirementMetaTypeTy =
|
||||
ExistentialMetatypeType::get(serializationRequirementTypeTy);
|
||||
|
||||
// Statements
|
||||
SmallVector<ASTNode, 8> stmts;
|
||||
|
||||
// --- `let m = metatype as! SerializationRequirement.Type`
|
||||
VarDecl *metatypeVar =
|
||||
new (C) VarDecl(/*isStatic=*/false, VarDecl::Introducer::Let, sloc,
|
||||
C.getIdentifier("m"), func);
|
||||
{
|
||||
metatypeVar->setImplicit();
|
||||
metatypeVar->setSynthesized();
|
||||
|
||||
// metatype as! <<concrete SerializationRequirement.Type>>
|
||||
auto metatypeRef =
|
||||
new (C) DeclRefExpr(ConcreteDeclRef(metatypeParam), dloc, implicit);
|
||||
auto metatypeSRCastExpr = ForcedCheckedCastExpr::createImplicit(
|
||||
C, metatypeRef, serializationRequirementMetaTypeTy);
|
||||
|
||||
auto metatypePattern = NamedPattern::createImplicit(C, metatypeVar);
|
||||
auto metatypePB = PatternBindingDecl::createImplicit(
|
||||
C, swift::StaticSpellingKind::None, metatypePattern,
|
||||
/*expr=*/metatypeSRCastExpr, func);
|
||||
|
||||
stmts.push_back(metatypePB);
|
||||
stmts.push_back(metatypeVar);
|
||||
}
|
||||
|
||||
// --- Declare the local function `doInvokeOnReturn`...
|
||||
FuncDecl *doInvokeOnReturnFunc = createLocalFunc_doInvokeOnReturn(
|
||||
C, func,
|
||||
nominal, handlerParam, resultBufParam);
|
||||
stmts.push_back(doInvokeOnReturnFunc);
|
||||
|
||||
// --- try await _openExistential(metatypeVar, do: <<doInvokeLocalFunc>>)
|
||||
{
|
||||
auto openExistentialBaseIdent = C.getIdentifier("_openExistential");
|
||||
auto doIdent = C.getIdentifier("do");
|
||||
|
||||
auto openExArgs = ArgumentList::createImplicit(
|
||||
C, {
|
||||
Argument(sloc, Identifier(),
|
||||
new (C) DeclRefExpr(ConcreteDeclRef(metatypeVar), dloc,
|
||||
implicit)),
|
||||
Argument(sloc, doIdent,
|
||||
new (C) DeclRefExpr(ConcreteDeclRef(doInvokeOnReturnFunc),
|
||||
dloc, implicit)),
|
||||
});
|
||||
Expr *tryAwaitDoOpenExistential =
|
||||
CallExpr::createImplicit(C,
|
||||
UnresolvedDeclRefExpr::createImplicit(
|
||||
C, openExistentialBaseIdent),
|
||||
openExArgs);
|
||||
|
||||
tryAwaitDoOpenExistential =
|
||||
AwaitExpr::createImplicit(C, sloc, tryAwaitDoOpenExistential);
|
||||
tryAwaitDoOpenExistential =
|
||||
TryExpr::createImplicit(C, sloc, tryAwaitDoOpenExistential);
|
||||
|
||||
stmts.push_back(tryAwaitDoOpenExistential);
|
||||
}
|
||||
|
||||
auto body = BraceStmt::create(C, sloc, {stmts}, sloc, implicit);
|
||||
return {body, /*isTypeChecked=*/false};
|
||||
}
|
||||
|
||||
/// Synthesizes the
|
||||
///
|
||||
/// \verbatim
|
||||
/// static func invokeHandlerOnReturn(
|
||||
//// handler: ResultHandler,
|
||||
//// resultBuffer: UnsafeRawPointer,
|
||||
//// metatype _metatype: Any.Type
|
||||
//// ) async throws
|
||||
/// \endverbatim
|
||||
static FuncDecl *deriveDistributedActorSystem_invokeHandlerOnReturn(
|
||||
DerivedConformance &derived) {
|
||||
auto system = derived.Nominal;
|
||||
auto &C = system->getASTContext();
|
||||
|
||||
auto mkParam = [&](Identifier argName, Identifier paramName,
|
||||
Type ty) -> ParamDecl * {
|
||||
auto *param = new (C) ParamDecl(SourceLoc(), SourceLoc(), argName,
|
||||
SourceLoc(), paramName, system);
|
||||
param->setImplicit();
|
||||
param->setSpecifier(ParamSpecifier::Default);
|
||||
param->setInterfaceType(ty);
|
||||
return param;
|
||||
};
|
||||
|
||||
// auto serializationRequirementType = getDistributedActorSystemType(decl);
|
||||
auto resultHandlerType = getDistributedActorSystemResultHandlerType(system);
|
||||
auto unsafeRawPointerType = C.getUnsafeRawPointerType();
|
||||
auto anyTypeType = ExistentialMetatypeType::get(C.TheAnyType); // Any.Type
|
||||
|
||||
// auto serializationRequirementType =
|
||||
// getDistributedSerializationRequirementType(system, DAS);
|
||||
|
||||
// params:
|
||||
// - handler: Self.ResultHandler
|
||||
// - resultBuffer:
|
||||
// - metatype _metatype: Any.Type
|
||||
auto *params = ParameterList::create(
|
||||
C,
|
||||
/*LParenLoc=*/SourceLoc(),
|
||||
/*params=*/
|
||||
{mkParam(C.Id_handler, C.Id_handler,
|
||||
system->mapTypeIntoContext(resultHandlerType)),
|
||||
mkParam(C.Id_resultBuffer, C.Id_resultBuffer, unsafeRawPointerType),
|
||||
mkParam(C.Id_metatype, C.Id_metatype, anyTypeType)},
|
||||
/*RParenLoc=*/SourceLoc());
|
||||
|
||||
// Func name: invokeHandlerOnReturn(handler:resultBuffer:metatype)
|
||||
DeclName name(C, C.Id_invokeHandlerOnReturn, params);
|
||||
|
||||
// Expected type: (Self.ResultHandler, UnsafeRawPointer, any Any.Type) async
|
||||
// throws -> ()
|
||||
auto *funcDecl =
|
||||
FuncDecl::createImplicit(C, StaticSpellingKind::None, name, SourceLoc(),
|
||||
/*async=*/true,
|
||||
/*throws=*/true,
|
||||
/*genericParams=*/nullptr, params,
|
||||
/*returnType*/ TupleType::getEmpty(C), system);
|
||||
funcDecl->setSynthesized(true);
|
||||
funcDecl->copyFormalAccessFrom(system, /*sourceIsParentContext=*/true);
|
||||
funcDecl->setBodySynthesizer(deriveBodyDistributed_invokeHandlerOnReturn);
|
||||
|
||||
derived.addMembersToConformanceContext({funcDecl});
|
||||
return funcDecl;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************* PROPERTIES ***********************************/
|
||||
/******************************************************************************/
|
||||
@@ -193,8 +514,10 @@ deriveDistributedActorType_ActorSystem(
|
||||
/**************************** ENTRY POINTS ************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// IMPORTANT: Remember to update DerivedConformance::getDerivableRequirement
|
||||
// any time the signatures or list of derived requirements change.
|
||||
// !!!!!!!!!!!!! IMPORTANT WHEN MAKING CHANGES TO REQUIREMENTS !!!!!!!!!!!!!!!!!
|
||||
// !! Remember to update DerivedConformance::getDerivableRequirement !!
|
||||
// !! any time the signatures or list of derived requirements change. !!
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
ValueDecl *DerivedConformance::deriveDistributedActor(ValueDecl *requirement) {
|
||||
if (auto var = dyn_cast<VarDecl>(requirement)) {
|
||||
@@ -225,13 +548,24 @@ std::pair<Type, TypeDecl *> DerivedConformance::deriveDistributedActor(
|
||||
return std::make_pair(deriveDistributedActorType_ActorSystem(*this), nullptr);
|
||||
}
|
||||
|
||||
// TODO(distributed): maybe also do Self.ID here?
|
||||
|
||||
Context.Diags.diagnose(assocType->getLoc(),
|
||||
diag::broken_distributed_actor_requirement);
|
||||
return std::make_pair(Type(), nullptr);
|
||||
}
|
||||
|
||||
ValueDecl *
|
||||
DerivedConformance::deriveDistributedActorSystem(ValueDecl *requirement) {
|
||||
if (auto func = dyn_cast<FuncDecl>(requirement)) {
|
||||
// just a simple name check is enough here,
|
||||
// if we are invoked here we know for sure it is for the "right" function
|
||||
if (func->getName().getBaseName() == Context.Id_invokeHandlerOnReturn) {
|
||||
return deriveDistributedActorSystem_invokeHandlerOnReturn(*this);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*************************** ERRORS & DIAGNOSTICS *****************************/
|
||||
/******************************************************************************/
|
||||
@@ -240,3 +574,8 @@ void DerivedConformance::tryDiagnoseFailedDistributedActorDerivation(
|
||||
DeclContext *DC, NominalTypeDecl *nominal) {
|
||||
// TODO: offer better diagnosis for error scenarios here
|
||||
}
|
||||
|
||||
void DerivedConformance::tryDiagnoseFailedDistributedActorSystemDerivation(
|
||||
DeclContext *DC, NominalTypeDecl *nominal) {
|
||||
// TODO: offer better diagnosis for error scenarios here
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user