Files
swift-mirror/lib/Sema/DerivedConformanceDistributedActor.cpp
Doug Gregor 3da14e6f65 Refactor and generalize distributed actor transport SIL generation.
Refactor the code that generates SIL to call into the distributed actor
transport to eliminate duplication and better cope with concrete actor
transports. Centralize the knowledge of which actor transport is used
with a given distributed actor type.
2021-10-30 21:49:35 -07:00

177 lines
6.3 KiB
C++

//===--- DerivedConformanceActor.cpp - Derived Actor Conformance ----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements implicit derivation of the Actor protocol.
//
//===----------------------------------------------------------------------===//
#include "CodeSynthesis.h"
#include "DerivedConformances.h"
#include "TypeChecker.h"
#include "TypeCheckConcurrency.h"
#include "TypeCheckDistributed.h"
#include "swift/AST/NameLookupRequests.h"
#include "swift/AST/ParameterList.h"
using namespace swift;
bool DerivedConformance::canDeriveDistributedActor(
NominalTypeDecl *nominal, DeclContext *dc) {
auto classDecl = dyn_cast<ClassDecl>(nominal);
return classDecl && classDecl->isDistributedActor() && dc == nominal;
}
/******************************************************************************/
/******************************* RESOLVE FUNCTION *****************************/
/******************************************************************************/
/// Synthesizes the
///
/// \verbatim
/// static resolve(_ address: ActorAddress,
/// using transport: ActorTransport) throws -> Self {
/// <filled in by SILGenDistributed>
/// }
/// \endverbatim
///
/// factory function in the AST, with an empty body. Its body is
/// expected to be filled-in during SILGen.
// TODO(distributed): move this synthesis to DerivedConformance style
static FuncDecl *deriveDistributedActor_resolve(DerivedConformance &derived) {
auto decl = dyn_cast<ClassDecl>(derived.Nominal);
assert(decl->isDistributedActor());
auto &C = decl->getASTContext();
auto mkParam = [&](Identifier argName, Identifier paramName, Type ty) -> ParamDecl* {
auto *param = new (C) ParamDecl(SourceLoc(),
SourceLoc(), argName,
SourceLoc(), paramName, decl);
param->setImplicit();
param->setSpecifier(ParamSpecifier::Default);
param->setInterfaceType(ty);
return param;
};
Type addressType = C.getAnyActorIdentityDecl()->getDeclaredInterfaceType();
Type transportType = getDistributedActorTransportType(decl);
// (_ identity: AnyActorIdentity, using transport: ActorTransport)
auto *params = ParameterList::create(
C,
/*LParenLoc=*/SourceLoc(),
/*params=*/{ mkParam(Identifier(), C.Id_identity, addressType),
mkParam(C.Id_using, C.Id_transport, transportType)
},
/*RParenLoc=*/SourceLoc()
);
// Func name: resolve(_:using:)
DeclName name(C, C.Id_resolve, params);
// Expected type: (Self) -> (AnyActorIdentity, ActorTransport) throws -> (Self)
auto *factoryDecl =
FuncDecl::createImplicit(C, StaticSpellingKind::KeywordStatic,
name, SourceLoc(),
/*async=*/false,
/*throws=*/true,
/*genericParams=*/nullptr,
params,
/*returnType*/decl->getDeclaredInterfaceType(),
decl);
factoryDecl->setDistributedActorFactory(); // TODO(distributed): should we mark this specifically as the resolve factory?
factoryDecl->copyFormalAccessFrom(decl, /*sourceIsParentContext=*/true);
derived.addMembersToConformanceContext({factoryDecl});
return factoryDecl;
}
/******************************************************************************/
/******************************* PROPERTIES ***********************************/
/******************************************************************************/
static ValueDecl *deriveDistributedActor_id(DerivedConformance &derived) {
assert(derived.Nominal->isDistributedActor());
auto &C = derived.Context;
// ```
// nonisolated
// let id: AnyActorIdentity
// ```
auto propertyType = C.getAnyActorIdentityDecl()->getDeclaredInterfaceType();
VarDecl *propDecl;
PatternBindingDecl *pbDecl;
std::tie(propDecl, pbDecl) = derived.declareDerivedProperty(
C.Id_id,
propertyType, propertyType,
/*isStatic=*/false, /*isFinal=*/true);
propDecl->setIntroducer(VarDecl::Introducer::Let);
// mark as nonisolated, allowing access to it from everywhere
propDecl->getAttrs().add(
new (C) NonisolatedAttr(/*IsImplicit=*/true));
derived.addMembersToConformanceContext({ propDecl, pbDecl });
return propDecl;
}
static ValueDecl *deriveDistributedActor_actorTransport(
DerivedConformance &derived) {
assert(derived.Nominal->isDistributedActor());
auto &C = derived.Context;
// ```
// nonisolated
// let actorTransport: ActorTransport
// ```
// (no need for @actorIndependent because it is an immutable let)
Type propertyType = getDistributedActorTransportType(derived.Nominal);
VarDecl *propDecl;
PatternBindingDecl *pbDecl;
std::tie(propDecl, pbDecl) = derived.declareDerivedProperty(
C.Id_actorTransport,
propertyType, propertyType,
/*isStatic=*/false, /*isFinal=*/true);
propDecl->setIntroducer(VarDecl::Introducer::Let);
// mark as nonisolated, allowing access to it from everywhere
propDecl->getAttrs().add(
new (C) NonisolatedAttr(/*IsImplicit=*/true));
derived.addMembersToConformanceContext({ propDecl, pbDecl });
return propDecl;
}
// ==== ------------------------------------------------------------------------
ValueDecl *DerivedConformance::deriveDistributedActor(ValueDecl *requirement) {
if (auto var = dyn_cast<VarDecl>(requirement)) {
if (var->getName() == Context.Id_id)
return deriveDistributedActor_id(*this);
if (var->getName() == Context.Id_actorTransport)
return deriveDistributedActor_actorTransport(*this);
}
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_resolve)
return deriveDistributedActor_resolve(*this);
}
return nullptr;
}