mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[stdlib] Distributed: Remove invokeOnReturn requirement and its synthesis
This is no longer necessary because `onReturn` is a protocol requirement now.
This commit is contained in:
@@ -121,319 +121,6 @@ static FuncDecl *deriveDistributedActor_resolve(DerivedConformance &derived) {
|
|||||||
return factoryDecl;
|
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::createImplicit(
|
|
||||||
parentFunc, C.getIdentifier("R"), /*depth*/ 0, /*index*/ 0);
|
|
||||||
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->getDeclaredInterfaceType());
|
|
||||||
requirements.push_back(requirement);
|
|
||||||
}
|
|
||||||
GenericSignature doInvokeGenSig =
|
|
||||||
buildGenericSignature(C, parentFunc->getGenericSignature(),
|
|
||||||
{resultGenericParamDecl->getDeclaredInterfaceType()
|
|
||||||
->castTo<GenericTypeParamType>()},
|
|
||||||
std::move(requirements),
|
|
||||||
/*allowInverses=*/true);
|
|
||||||
|
|
||||||
FuncDecl *doInvokeOnReturnFunc = FuncDecl::createImplicit(
|
|
||||||
C, swift::StaticSpellingKind::None,
|
|
||||||
DeclName(C, doInvokeLocalFuncIdent, doInvokeParamsList),
|
|
||||||
sloc,
|
|
||||||
/*async=*/true,
|
|
||||||
/*throws=*/true,
|
|
||||||
/*ThrownType=*/Type(),
|
|
||||||
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 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=*/
|
|
||||||
{
|
|
||||||
ParamDecl::createImplicit(
|
|
||||||
C, C.Id_handler, C.Id_handler,
|
|
||||||
system->mapTypeIntoContext(resultHandlerType), system),
|
|
||||||
ParamDecl::createImplicit(
|
|
||||||
C, C.Id_resultBuffer, C.Id_resultBuffer,
|
|
||||||
unsafeRawPointerType, system),
|
|
||||||
ParamDecl::createImplicit(
|
|
||||||
C, C.Id_metatype, C.Id_metatype,
|
|
||||||
anyTypeType, system)
|
|
||||||
},
|
|
||||||
/*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,
|
|
||||||
/*ThrownType=*/Type(),
|
|
||||||
/*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 ***********************************/
|
/******************************* PROPERTIES ***********************************/
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@@ -936,14 +623,6 @@ std::pair<Type, TypeDecl *> DerivedConformance::deriveDistributedActor(
|
|||||||
|
|
||||||
ValueDecl *
|
ValueDecl *
|
||||||
DerivedConformance::deriveDistributedActorSystem(ValueDecl *requirement) {
|
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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -400,11 +400,6 @@ ValueDecl *DerivedConformance::getDerivableRequirement(NominalTypeDecl *nominal,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DistributedActor.actorSystem
|
|
||||||
if (name.isCompoundName() &&
|
|
||||||
name.getBaseName() == ctx.Id_invokeHandlerOnReturn)
|
|
||||||
return getRequirement(KnownProtocolKind::DistributedActorSystem);
|
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -416,22 +416,6 @@ public protocol DistributedActorSystem<SerializationRequirement>: Sendable {
|
|||||||
where Act: DistributedActor,
|
where Act: DistributedActor,
|
||||||
Act.ID == ActorID,
|
Act.ID == ActorID,
|
||||||
Err: Error
|
Err: Error
|
||||||
|
|
||||||
// Implementation notes:
|
|
||||||
// The `metatype` must be the type of `Value`, and it must conform to
|
|
||||||
// `SerializationRequirement`. If it does not, the method will crash at
|
|
||||||
// runtime. This is because we cannot express
|
|
||||||
// `Value: SerializationRequirement`, however the generic `Value` is still
|
|
||||||
// useful since it allows us to avoid boxing the value into an existential,
|
|
||||||
// before we'd right away unbox it as first thing in the implementation of
|
|
||||||
// this function.
|
|
||||||
/// Implementation synthesized by the compiler.
|
|
||||||
/// Not intended to be invoked explicitly from user code!
|
|
||||||
func invokeHandlerOnReturn(
|
|
||||||
handler: ResultHandler,
|
|
||||||
resultBuffer: UnsafeRawPointer,
|
|
||||||
metatype: Any.Type
|
|
||||||
) async throws
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==== ----------------------------------------------------------------------------------------------------------------
|
// ==== ----------------------------------------------------------------------------------------------------------------
|
||||||
@@ -619,11 +603,12 @@ extension DistributedActorSystem {
|
|||||||
if returnType == Void.self {
|
if returnType == Void.self {
|
||||||
try await handler.onReturnVoid()
|
try await handler.onReturnVoid()
|
||||||
} else {
|
} else {
|
||||||
try await self.invokeHandlerOnReturn(
|
func invokeOnReturn<R>(_ returnType: R.Type) async throws {
|
||||||
handler: handler,
|
let value = resultBuffer.load(as: returnType)
|
||||||
resultBuffer: resultBuffer,
|
try await handler.onReturn(value: value)
|
||||||
metatype: returnType
|
}
|
||||||
)
|
|
||||||
|
try await _openExistential(returnType, do: invokeOnReturn)
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
try await handler.onThrow(error: error)
|
try await handler.onThrow(error: error)
|
||||||
|
|||||||
Reference in New Issue
Block a user