Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/AST/DistributedDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ using namespace swift;
/********************** Distributed Actor Properties **************************/
/******************************************************************************/

VarDecl* swift::lookupDistributedActorProperty(NominalTypeDecl *decl, DeclName name) {
VarDecl*
swift::lookupDistributedActorProperty(NominalTypeDecl *decl, DeclName name) {
assert(decl && "decl was null");
auto &C = decl->getASTContext();

Expand Down
115 changes: 68 additions & 47 deletions lib/Sema/CodeSynthesisDistributedActor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,47 +33,10 @@

using namespace swift;


/******************************************************************************/
/************************ PROPERTY SYNTHESIS **********************************/
/******************************************************************************/

static VarDecl*
lookupDistributedActorProperty(NominalTypeDecl *decl, DeclName name) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method was duped, we have it already

swift::lookupDistributedActorProperty(NominalTypeDecl *decl, DeclName name) {

with the same impl, so we dont need it here

assert(decl && "decl was null");
auto &C = decl->getASTContext();

auto clazz = dyn_cast<ClassDecl>(decl);
if (!clazz)
return nullptr;

auto refs = decl->lookupDirect(name);
if (refs.size() != 1)
return nullptr;

auto var = dyn_cast<VarDecl>(refs.front());
if (!var)
return nullptr;

Type expectedType = Type();
if (name == C.Id_id) {
expectedType = getDistributedActorIDType(decl);
} else if (name == C.Id_actorSystem) {
expectedType = getDistributedActorSystemType(decl);
} else {
llvm_unreachable("Unexpected distributed actor property lookup!");
}
if (!expectedType)
return nullptr;

if (!var->getInterfaceType()->isEqual(expectedType))
return nullptr;

assert(var->isSynthesized() && "Expected compiler synthesized property");
return var;
}


// 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
Expand All @@ -83,7 +46,9 @@ lookupDistributedActorProperty(NominalTypeDecl *decl, DeclName name) {
// what already has a witness.
static VarDecl *addImplicitDistributedActorIDProperty(
ClassDecl *nominal) {
if (!nominal || !nominal->isDistributedActor())
if (!nominal)
return nullptr;
if (!nominal->isDistributedActor())
return nullptr;

auto &C = nominal->getASTContext();
Expand Down Expand Up @@ -131,6 +96,58 @@ static VarDecl *addImplicitDistributedActorIDProperty(
return propDecl;
}

static VarDecl *addImplicitDistributedActorActorSystemProperty(
ClassDecl *nominal) {
if (!nominal)
return nullptr;
if (!nominal->isDistributedActor())
return nullptr;

auto &C = nominal->getASTContext();

// ==== Synthesize and add 'actorSystem' property to the actor decl
Type propertyType = getDistributedActorSystemType(nominal);

auto *propDecl = new (C)
VarDecl(/*IsStatic*/false, VarDecl::Introducer::Let,
SourceLoc(), C.Id_actorSystem, nominal);
propDecl->setImplicit();
propDecl->setSynthesized();
propDecl->copyFormalAccessFrom(nominal, /*sourceIsParentContext*/ true);
propDecl->setInterfaceType(propertyType);

Pattern *propPat = NamedPattern::createImplicit(C, propDecl);
propPat->setType(propertyType);

propPat = TypedPattern::createImplicit(C, propPat, propertyType);
propPat->setType(propertyType);

PatternBindingDecl *pbDecl = PatternBindingDecl::createImplicit(
C, StaticSpellingKind::None, propPat, /*InitExpr*/ nullptr,
nominal);

// mark as nonisolated, allowing access to it from everywhere
propDecl->getAttrs().add(
new (C) NonisolatedAttr(/*IsImplicit=*/true));

auto idProperty = nominal->getDistributedActorIDProperty();
// If the id was not yet synthesized, we need to ensure that eventually
// the order of fields will be: id, actorSystem (because IRGen needs the
// layouts to match with the AST we produce). We do this by inserting FIRST,
// and then as the ID gets synthesized, it'll also force FIRST and therefore
// the order will be okey -- ID and then system.
auto insertAtHead = idProperty == nullptr;

// IMPORTANT: The `id` MUST be the first field of any distributed actor.
// So we find the property and add the system AFTER it using the hint.
//
// If the `id` was not synthesized yet, we'll end up inserting at head,
// but the id synthesis will force itself to be FIRST anyway, so it works out.
nominal->addMember(propDecl, /*hint=*/idProperty, /*insertAtHead=*/insertAtHead);
nominal->addMember(pbDecl, /*hint=*/idProperty, /*insertAtHead=*/insertAtHead);
return propDecl;
}

/******************************************************************************/
/*********************** DISTRIBUTED THUNK SYNTHESIS **************************/
/******************************************************************************/
Expand Down Expand Up @@ -223,6 +240,7 @@ deriveBodyDistributed_thunk(AbstractFunctionDecl *thunk, void *context) {
SmallVector<ASTNode, 8> remoteBranchStmts;
// --- self.actorSystem
auto systemProperty = nominal->getDistributedActorSystemProperty();
assert(systemProperty && "Unable to find 'actorSystem' property");
auto systemRefExpr =
UnresolvedDotExpr::createImplicit(
C, new (C) DeclRefExpr(selfDecl, dloc, implicit), // TODO: make createImplicit
Expand Down Expand Up @@ -824,18 +842,21 @@ VarDecl *GetDistributedActorSystemPropertyRequest::evaluate(
return nullptr;
}

for (auto system : nominal->lookupDirect(C.Id_actorSystem)) {
if (auto var = dyn_cast<VarDecl>(system)) {
auto conformance = module->conformsToProtocol(
var->getInterfaceType(), DAS);
if (conformance.isInvalid())
continue;
auto classDecl = dyn_cast<ClassDecl>(nominal);
if (!classDecl)
return nullptr;

return var;
}
// We may be triggered after synthesis was handled via `DerivedConformances`,
// in which case we should locate the existing property, rather than add
// another one. Generally derived conformances are triggered early and are right
// but for some reason sometimes we get a request before synthesis was triggered
// there... so this is to workaround that issue, and ensure we're always
// synthesising correctly, regardless of entry-point.
if (auto existingProp = lookupDistributedActorProperty(classDecl, C.Id_actorSystem)) {
return existingProp;
}

return nullptr;
return addImplicitDistributedActorActorSystemProperty(classDecl);
}

NormalProtocolConformance *GetDistributedActorImplicitCodableRequest::evaluate(
Expand Down
4 changes: 2 additions & 2 deletions lib/Sema/DerivedConformances.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,11 +338,11 @@ ValueDecl *DerivedConformance::getDerivableRequirement(NominalTypeDecl *nominal,
return getRequirement(KnownProtocolKind::Actor);

// DistributedActor.id
if(name.isSimpleName(ctx.Id_id))
if (name.isSimpleName(ctx.Id_id))
return getRequirement(KnownProtocolKind::DistributedActor);

// DistributedActor.actorSystem
if(name.isSimpleName(ctx.Id_actorSystem))
if (name.isSimpleName(ctx.Id_actorSystem))
return getRequirement(KnownProtocolKind::DistributedActor);

return nullptr;
Expand Down