mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[Concurrency] Distributed actor's unownedExecutor should be optional (#64499)
This commit is contained in:
committed by
GitHub
parent
230dfcc30c
commit
345c221f56
@@ -621,10 +621,13 @@ static Expr *constructDistributedUnownedSerialExecutor(ASTContext &ctx,
|
||||
}
|
||||
|
||||
static std::pair<BraceStmt *, bool>
|
||||
deriveBodyDistributedActor_unownedExecutor(AbstractFunctionDecl *getter, void *) {
|
||||
// var unownedExecutor: UnownedSerialExecutor {
|
||||
deriveBodyDistributedActor_localUnownedExecutor(AbstractFunctionDecl *getter, void *) {
|
||||
// var localUnownedExecutor: UnownedSerialExecutor? {
|
||||
// get {
|
||||
// return Builtin.buildDefaultActorExecutorRef(self)
|
||||
// guard __isLocalActor(self) else {
|
||||
// return nil
|
||||
// }
|
||||
// return Optional(Builtin.buildDefaultActorExecutorRef(self))
|
||||
// }
|
||||
// }
|
||||
ASTContext &ctx = getter->getASTContext();
|
||||
@@ -641,33 +644,53 @@ deriveBodyDistributedActor_unownedExecutor(AbstractFunctionDecl *getter, void *)
|
||||
Expr *selfArg = DerivedConformance::createSelfDeclRef(getter);
|
||||
selfArg->setType(selfType);
|
||||
|
||||
// Prepare the builtin call, we'll use it after the guard, but want to take the type
|
||||
// of its return type earlier, so we prepare it here.
|
||||
|
||||
// The builtin call gives us a Builtin.Executor.
|
||||
auto builtinCall =
|
||||
DerivedConformance::createBuiltinCall(ctx,
|
||||
BuiltinValueKind::BuildDefaultActorExecutorRef,
|
||||
{selfType}, {}, {selfArg});
|
||||
|
||||
// Turn that into an UnownedSerialExecutor.
|
||||
auto initCall = constructDistributedUnownedSerialExecutor(ctx, builtinCall);
|
||||
if (!initCall) return failure();
|
||||
|
||||
auto ret = new (ctx) ReturnStmt(SourceLoc(), initCall, /*implicit*/ true);
|
||||
// guard __isLocalActor(self) else {
|
||||
// return nil
|
||||
// }
|
||||
auto isLocalActorDecl = ctx.getIsLocalDistributedActor();
|
||||
DeclRefExpr *isLocalActorExpr =
|
||||
new (ctx) DeclRefExpr(ConcreteDeclRef(isLocalActorDecl), DeclNameLoc(), /*implicit=*/true,
|
||||
AccessSemantics::Ordinary,
|
||||
FunctionType::get({AnyFunctionType::Param(ctx.getAnyObjectType())},
|
||||
ctx.getBoolType()));
|
||||
Expr *selfForIsLocalArg = DerivedConformance::createSelfDeclRef(getter);
|
||||
selfForIsLocalArg->setType(selfType);
|
||||
auto *argListForIsLocal =
|
||||
ArgumentList::forImplicitSingle(ctx, Identifier(),
|
||||
ErasureExpr::create(ctx, selfForIsLocalArg, ctx.getAnyObjectType(), {}, {}));
|
||||
CallExpr *isLocalActorCall = CallExpr::createImplicit(ctx, isLocalActorExpr, argListForIsLocal);
|
||||
isLocalActorCall->setType(ctx.getBoolType());
|
||||
isLocalActorCall->setThrows(false);
|
||||
auto returnNilIfRemoteStmt = DerivedConformance::returnNilIfFalseGuardTypeChecked(
|
||||
ctx, isLocalActorCall, /*optionalWrappedType=*/initCall->getType());
|
||||
|
||||
|
||||
// Finalize preparing the unowned executor for returning.
|
||||
auto wrappedCall = new (ctx) InjectIntoOptionalExpr(initCall, initCall->getType()->wrapInOptionalType());
|
||||
|
||||
auto ret = new (ctx) ReturnStmt(SourceLoc(), wrappedCall, /*implicit*/ true);
|
||||
|
||||
auto body = BraceStmt::create(
|
||||
ctx, SourceLoc(), { ret }, SourceLoc(), /*implicit=*/true);
|
||||
ctx, SourceLoc(), { returnNilIfRemoteStmt, ret }, SourceLoc(), /*implicit=*/true);
|
||||
return { body, /*isTypeChecked=*/true };
|
||||
}
|
||||
|
||||
/// Derive the declaration of DistributedActor's unownedExecutor property.
|
||||
static ValueDecl *deriveDistributedActor_unownedExecutor(DerivedConformance &derived) {
|
||||
/// Derive the declaration of DistributedActor's localUnownedExecutor property.
|
||||
static ValueDecl *deriveDistributedActor_localUnownedExecutor(DerivedConformance &derived) {
|
||||
ASTContext &ctx = derived.Context;
|
||||
|
||||
if (auto classDecl = dyn_cast<ClassDecl>(derived.Nominal)) {
|
||||
if (auto existing = classDecl->getUnownedExecutorProperty()) {
|
||||
return const_cast<VarDecl*>(existing);
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve the types and declarations we'll need to form this operation.
|
||||
auto executorDecl = ctx.getUnownedSerialExecutorDecl();
|
||||
if (!executorDecl) {
|
||||
@@ -676,16 +699,28 @@ static ValueDecl *deriveDistributedActor_unownedExecutor(DerivedConformance &der
|
||||
return nullptr;
|
||||
}
|
||||
Type executorType = executorDecl->getDeclaredInterfaceType();
|
||||
Type optionalExecutorType = executorType->wrapInOptionalType();
|
||||
|
||||
if (auto classDecl = dyn_cast<ClassDecl>(derived.Nominal)) {
|
||||
if (auto existing = classDecl->getLocalUnownedExecutorProperty()) {
|
||||
if (existing->getInterfaceType()->isEqual(optionalExecutorType)) {
|
||||
return const_cast<VarDecl *>(existing);
|
||||
} else {
|
||||
// bad type, should be diagnosed elsewhere
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto propertyPair = derived.declareDerivedProperty(
|
||||
DerivedConformance::SynthesizedIntroducer::Var, ctx.Id_unownedExecutor,
|
||||
executorType, executorType,
|
||||
DerivedConformance::SynthesizedIntroducer::Var, ctx.Id_localUnownedExecutor,
|
||||
optionalExecutorType, optionalExecutorType,
|
||||
/*static*/ false, /*final*/ false);
|
||||
auto property = propertyPair.first;
|
||||
property->setSynthesized(true);
|
||||
property->getAttrs().add(new (ctx) SemanticsAttr(SEMANTICS_DEFAULT_ACTOR,
|
||||
SourceLoc(), SourceRange(),
|
||||
/*implicit*/ true));
|
||||
/*implicit*/ true));
|
||||
property->getAttrs().add(new (ctx) NonisolatedAttr(/*IsImplicit=*/true));
|
||||
|
||||
// Make the property implicitly final.
|
||||
@@ -703,8 +738,8 @@ static ValueDecl *deriveDistributedActor_unownedExecutor(DerivedConformance &der
|
||||
property, asAvailableAs, ctx);
|
||||
|
||||
auto getter =
|
||||
derived.addGetterToReadOnlyDerivedProperty(property, executorType);
|
||||
getter->setBodySynthesizer(deriveBodyDistributedActor_unownedExecutor);
|
||||
derived.addGetterToReadOnlyDerivedProperty(property, optionalExecutorType);
|
||||
getter->setBodySynthesizer(deriveBodyDistributedActor_localUnownedExecutor);
|
||||
|
||||
// IMPORTANT: MUST BE AFTER [id, actorSystem].
|
||||
if (auto id = derived.Nominal->getDistributedActorIDProperty()) {
|
||||
@@ -747,8 +782,8 @@ static void assertRequiredSynthesizedPropertyOrder(DerivedConformance &derived,
|
||||
if (auto id = Nominal->getDistributedActorIDProperty()) {
|
||||
if (auto system = Nominal->getDistributedActorSystemProperty()) {
|
||||
if (auto classDecl = dyn_cast<ClassDecl>(derived.Nominal)) {
|
||||
if (auto unownedExecutor = classDecl->getUnownedExecutorProperty()) {
|
||||
int idIdx, actorSystemIdx, unownedExecutorIdx = 0;
|
||||
if (auto localUnownedExecutor = classDecl->getLocalUnownedExecutorProperty()) {
|
||||
int idIdx, actorSystemIdx, localUnownedExecutorIdx = 0;
|
||||
int idx = 0;
|
||||
for (auto member: Nominal->getMembers()) {
|
||||
if (auto binding = dyn_cast<PatternBindingDecl>(member)) {
|
||||
@@ -756,15 +791,15 @@ static void assertRequiredSynthesizedPropertyOrder(DerivedConformance &derived,
|
||||
idIdx = idx;
|
||||
} else if (binding->getSingleVar()->getName() == Context.Id_actorSystem) {
|
||||
actorSystemIdx = idx;
|
||||
} else if (binding->getSingleVar()->getName() == Context.Id_unownedExecutor) {
|
||||
unownedExecutorIdx = idx;
|
||||
} else if (binding->getSingleVar()->getName() == Context.Id_localUnownedExecutor) {
|
||||
localUnownedExecutorIdx = idx;
|
||||
}
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
if (idIdx + actorSystemIdx + unownedExecutorIdx >= 0 + 1 + 2) {
|
||||
if (idIdx + actorSystemIdx + localUnownedExecutorIdx >= 0 + 1 + 2) {
|
||||
// we have found all the necessary fields, let's assert their order
|
||||
assert(idIdx < actorSystemIdx < unownedExecutorIdx && "order of fields MUST be exact.");
|
||||
assert(idIdx < actorSystemIdx < localUnownedExecutorIdx && "order of fields MUST be exact.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -786,8 +821,8 @@ ValueDecl *DerivedConformance::deriveDistributedActor(ValueDecl *requirement) {
|
||||
derivedValue = deriveDistributedActor_id(*this);
|
||||
} else if (var->getName() == Context.Id_actorSystem) {
|
||||
derivedValue = deriveDistributedActor_actorSystem(*this);
|
||||
} else if (var->getName() == Context.Id_unownedExecutor) {
|
||||
derivedValue = deriveDistributedActor_unownedExecutor(*this);
|
||||
} else if (var->getName() == Context.Id_localUnownedExecutor) {
|
||||
derivedValue = deriveDistributedActor_localUnownedExecutor(*this);
|
||||
}
|
||||
|
||||
assertRequiredSynthesizedPropertyOrder(*this, derivedValue);
|
||||
|
||||
Reference in New Issue
Block a user