mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
* [Distributed] Initial distributed checking
* [Distributed] initial types shapes and conform to DistributedActor
* [Distributed] Require Codable params and return types
* [Distributed] initial synthesis of fields and constructors
* [Distributed] Field and initializer synthesis
* [Distributed] Codable requirement on distributed funcs; also handle <T: Codable>
* [Distributed] handle generic type params which are Codable in dist func
[Distributed] conformsToProtocol after all
* [Distributed] Implement remote flag on actors
* Implement remote flag on actors
* add test
* actor initializer that sets remote flag
[Distributed] conformances getting there
* [Distributed] dont require async throws; cleanup compile tests
* [Distributed] do not synthesize default implicit init, only our special ones
* [Distributed] properly synth inits and properties; mark actorTransport as _distributedActorIndependent
Also:
- do not synthesize default init() initializer for dist actor
* [Distributed] init(transport:) designated and typechecking
* [Distributed] dist actor initializers MUST delegate to local-init
* [Distributed] check if any ctors in delegation call init(transport:)
* [Distributed] check init(transport:) delegation through many inits; ban invoking init(resolve:using:) explicitly
* [Distributed] disable IRGen test for now
* [Distributed] Rebase cleanups
* [Concurrent] transport and address are concurrent value
* [Distributed] introduce -enable-experimental-distributed flag
* rebase adjustments again
* rebase again...
* [Distributed] distributed functions are implicitly async+throws outside the actor
* [Distributed] implicitly throwing and async distributed funcs
* remove printlns
* add more checks to implicit function test
* [Distributed] resolve initializer now marks the isRemote actor flag
* [Distributed] distributedActor_destroy invoked instead, rather than before normal
* [Distributed] Generate distributed thunk for actors
* [distributed] typechecking for _remote_ functions existing, add tests for remote funcs
* adding one XFAIL'ed task & actor lifetime test
The `executor_deinit1` test fails 100% of the time
(from what I've seen) so I thought we could track
and see when/if someone happens to fix this bug.
Also, added extra coverage for #36298 via `executor_deinit2`
* Fix a memory issue with actors in the runtime system, by @phausler
* add new test that now passes because of patch by @phausler
See previous commit in this PR.
Test is based on one from rdar://74281361
* fix all tests that require the _remote_ function stubs
* Do not infer @actorIndependent onto `let` decls
* REVERT_ME: remove some tests that hacky workarounds will fail
* another flaky test, help build toolchain
* [Distributed] experimental distributed implies experimental concurrency
* [Distributed] Allow distributed function that are not marked async or throws
* [Distributed] make attrs SIMPLE to get serialization generated
* [Distributed] ActorAddress must be Hashable
* [Distributed] Implement transport.actorReady call in local init
* cleanup after rebase
* [Distributed] add availability attributes to all distributed actor code
* cleanup - this fixed some things
* fixing up
* fixing up
* [Distributed] introduce new Distributed module
* [Distributed] diagnose when missing 'import _Distributed'
* [Distributed] make all tests import the module
* more docs on address
* [Distributed] fixup merge issues
* cleanup: remove unnecessary code for now SIMPLE attribute
* fix: fix getActorIsolationOfContext
* [Distributed] cmake: depend on _concurrency module
* fixing tests...
* Revert "another flaky test, help build toolchain"
This reverts commit 83ae6654dd.
* remove xfail
* clenup some IR and SIL tests
* cleanup
* [Distributed] fix cmake test and ScanDependencies/can_import_with_map.swift
* [Distributed] fix flags/build tests
* cleanup: use isDistributed wherever possible
* [Distributed] don't import Dispatch in tests
* dont link distributed in stdlib unittest
* trying always append distributed module
* cleanups
* [Distributed] move all tests to Distributed/ directory
* [lit] try to fix lit test discovery
* [Distributed] update tests after diagnostics for implicit async changed
* [Distributed] Disable remote func tests on Windows for now
* Review cleanups
* [Distributed] fix typo, fixes Concurrency/actor_isolation_objc.swift
* [Distributed] attributes are DistributedOnly (only)
* cleanup
* [Distributed] cleanup: rely on DistributedOnly for guarding the keyword
* Update include/swift/AST/ActorIsolation.h
Co-authored-by: Doug Gregor <dgregor@apple.com>
* introduce isAnyThunk, minor cleanup
* wip
* [Distributed] move some type checking to TypeCheckDistributed.cpp
* [TypeCheckAttr] remove extra debug info
* [Distributed/AutoDiff] fix SILDeclRef creation which caused AutoDiff issue
* cleanups
* [lit] remove json import from lit test suite, not needed after all
* [Distributed] distributed functions only in DistributedActor protocols
* [Distributed] fix flag overlap & build setting
* [Distributed] Simplify noteIsolatedActorMember to not take bool distributed param
* [Distributed] make __isRemote not public
* [Distributed] Fix availability and remove actor class tests
* [actorIndependent] do not apply actorIndependent implicitly to values where it would be illegal to apply
* [Distributed] disable tests until issue fixed
Co-authored-by: Dario Rexin <drexin@apple.com>
Co-authored-by: Kavon Farvardin <kfarvardin@apple.com>
Co-authored-by: Doug Gregor <dgregor@apple.com>
577 lines
21 KiB
C++
577 lines
21 KiB
C++
//===--- CodeSynthesis.cpp - Type Checking for Declarations ---------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "CodeSynthesis.h"
|
|
|
|
#include "TypeChecker.h"
|
|
#include "TypeCheckDecl.h"
|
|
#include "TypeCheckObjC.h"
|
|
#include "TypeCheckType.h"
|
|
#include "swift/AST/ASTPrinter.h"
|
|
#include "swift/AST/Availability.h"
|
|
#include "swift/AST/Expr.h"
|
|
#include "swift/AST/GenericEnvironment.h"
|
|
#include "swift/AST/Initializer.h"
|
|
#include "swift/AST/ParameterList.h"
|
|
#include "swift/AST/PrettyStackTrace.h"
|
|
#include "swift/AST/ProtocolConformance.h"
|
|
#include "swift/AST/SourceFile.h"
|
|
#include "swift/AST/TypeCheckRequests.h"
|
|
#include "swift/Basic/Defer.h"
|
|
#include "swift/ClangImporter/ClangModule.h"
|
|
#include "swift/Sema/ConstraintSystem.h"
|
|
#include "llvm/ADT/SmallString.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "DerivedConformances.h"
|
|
using namespace swift;
|
|
|
|
/******************************************************************************/
|
|
/******************************* INITIALIZERS *********************************/
|
|
/******************************************************************************/
|
|
|
|
// ==== Distributed Actor: Local Initializer -----------------------------------
|
|
|
|
/// Creates a new \c CallExpr representing
|
|
///
|
|
/// transport.assignAddress(Self.self)
|
|
///
|
|
/// \param C The AST context to create the expression in.
|
|
/// \param DC The \c DeclContext to create any decls in.
|
|
/// \param base The base expression to make the call on.
|
|
/// \param returnType The return type of the call.
|
|
/// \param param The parameter to the call.
|
|
static CallExpr *
|
|
createCall_DistributedActor_transport_assignAddress(ASTContext &C,
|
|
DeclContext *DC,
|
|
Expr *base, Type returnType,
|
|
Type param) {
|
|
// (_ actorType:)
|
|
auto *paramDecl = new (C) ParamDecl(SourceLoc(),
|
|
SourceLoc(), Identifier(),
|
|
SourceLoc(), C.Id_actorType, DC);
|
|
paramDecl->setImplicit();
|
|
paramDecl->setSpecifier(ParamSpecifier::Default);
|
|
paramDecl->setInterfaceType(returnType);
|
|
|
|
// transport.assignAddress(_:) expr
|
|
auto *paramList = ParameterList::createWithoutLoc(paramDecl);
|
|
auto *unboundCall = UnresolvedDotExpr::createImplicit(C, base,
|
|
C.Id_assignAddress,
|
|
paramList);
|
|
|
|
// DC->mapTypeIntoContext(param->getInterfaceType());
|
|
auto *selfTypeExpr = TypeExpr::createImplicit(param, C);
|
|
auto *dotSelfTypeExpr = new (C) DotSelfExpr(selfTypeExpr, SourceLoc(),
|
|
SourceLoc(), param);
|
|
|
|
// Full bound self.assignAddress(Self.self) call
|
|
Expr *args[1] = {dotSelfTypeExpr};
|
|
Identifier argLabels[1] = {Identifier()};
|
|
return CallExpr::createImplicit(C, unboundCall, C.AllocateCopy(args),
|
|
C.AllocateCopy(argLabels));
|
|
}
|
|
|
|
|
|
/// Creates a new \c CallExpr representing
|
|
///
|
|
/// transport.actorReady(self)
|
|
static CallExpr *
|
|
createCall_DistributedActor_transport_actorReady(ASTContext &C,
|
|
DeclContext *DC,
|
|
Expr *base, Type actorType,
|
|
Expr *initalizedSelf) {
|
|
// (_ actor:)
|
|
auto *paramDecl = new (C) ParamDecl(SourceLoc(),
|
|
SourceLoc(), Identifier(),
|
|
SourceLoc(), C.Id_actor, DC);
|
|
paramDecl->setImplicit();
|
|
paramDecl->setSpecifier(ParamSpecifier::Default);
|
|
paramDecl->setInterfaceType(actorType);
|
|
|
|
// transport.actorReady(_:) expr
|
|
auto *paramList = ParameterList::createWithoutLoc(paramDecl);
|
|
auto *unboundCall = UnresolvedDotExpr::createImplicit(C, base,
|
|
C.Id_actorReady,
|
|
paramList);
|
|
|
|
// Full bound transport.actorReady(self) call
|
|
Expr *args[1] = {initalizedSelf};
|
|
Identifier argLabels[1] = {Identifier()};
|
|
return CallExpr::createImplicit(C, unboundCall, C.AllocateCopy(args),
|
|
C.AllocateCopy(argLabels));
|
|
}
|
|
|
|
/// Synthesizes the body of the `init(transport:)` initializer as:
|
|
///
|
|
/// ```
|
|
/// init(transport: ActorTransport)
|
|
/// self.actorTransport = transport
|
|
/// self.actorAddress = try transport.assignAddress(Self.self)
|
|
/// }
|
|
/// ```
|
|
///
|
|
/// \param initDecl The function decl whose body to synthesize.
|
|
static std::pair<BraceStmt *, bool>
|
|
createBody_DistributedActor_init_transport(AbstractFunctionDecl *initDecl, void *) {
|
|
|
|
auto *funcDC = cast<DeclContext>(initDecl);
|
|
ASTContext &C = funcDC->getASTContext();
|
|
|
|
SmallVector<ASTNode, 2> statements;
|
|
|
|
auto transportParam = initDecl->getParameters()->get(0);
|
|
auto *transportExpr = new (C) DeclRefExpr(ConcreteDeclRef(transportParam),
|
|
DeclNameLoc(), /*Implicit=*/true);
|
|
|
|
auto *selfRef = DerivedConformance::createSelfDeclRef(initDecl);
|
|
|
|
// ==== `self.actorTransport = transport`
|
|
{
|
|
// self.actorTransport
|
|
auto *varTransportExpr = UnresolvedDotExpr::createImplicit(C, selfRef,
|
|
C.Id_actorTransport);
|
|
auto *assignTransportExpr = new (C) AssignExpr(
|
|
varTransportExpr, SourceLoc(), transportExpr, /*Implicit=*/true);
|
|
statements.push_back(assignTransportExpr);
|
|
}
|
|
|
|
auto selfType = funcDC->getInnermostTypeContext()->getSelfTypeInContext();
|
|
|
|
// ==== `self.actorAddress = transport.assignAddress<Self>(Self.self)`
|
|
{
|
|
// self.actorAddress
|
|
auto *varAddressExpr = UnresolvedDotExpr::createImplicit(C, selfRef,
|
|
C.Id_actorAddress);
|
|
// Bound transport.assignAddress(Self.self) call
|
|
auto addressType = C.getActorAddressDecl()->getDeclaredInterfaceType();
|
|
auto *callExpr = createCall_DistributedActor_transport_assignAddress(C, funcDC,
|
|
/*base=*/transportExpr,
|
|
/*returnType=*/addressType,
|
|
/*param=*/selfType);
|
|
auto *assignAddressExpr = new (C) AssignExpr(
|
|
varAddressExpr, SourceLoc(), callExpr, /*Implicit=*/true);
|
|
statements.push_back(assignAddressExpr);
|
|
}
|
|
|
|
// ---=== Done initializing ===---
|
|
// === `transport.actorReady(self)`
|
|
{
|
|
// Bound transport.actorReady(self) call
|
|
auto selfType = funcDC->getInnermostTypeContext()->getSelfTypeInContext();
|
|
auto *callExpr = createCall_DistributedActor_transport_actorReady(C, funcDC,
|
|
/*base=*/transportExpr,
|
|
/*actorType=*/selfType,
|
|
/*param=*/selfRef);
|
|
statements.push_back(callExpr);
|
|
}
|
|
|
|
auto *body = BraceStmt::create(C, SourceLoc(), statements, SourceLoc(),
|
|
/*implicit=*/true);
|
|
return { body, /*isTypeChecked=*/false };
|
|
}
|
|
|
|
/// Synthesizes the
|
|
///
|
|
/// ```
|
|
/// init(transport: ActorTransport)
|
|
/// ```
|
|
///
|
|
/// local initializer.
|
|
static ConstructorDecl *
|
|
createDistributedActor_init_local(ClassDecl *classDecl,
|
|
ASTContext &ctx) {
|
|
auto &C = ctx;
|
|
|
|
// auto conformanceDC = derived.getConformanceContext();
|
|
auto conformanceDC = classDecl;
|
|
|
|
// Expected type: (Self) -> (ActorTransport) -> (Self)
|
|
//
|
|
// Params: (transport transport: ActorTransport)
|
|
auto transportType = C.getActorTransportDecl()->getDeclaredInterfaceType();
|
|
auto *transportParamDecl = new (C) ParamDecl(
|
|
SourceLoc(), SourceLoc(), C.Id_transport,
|
|
SourceLoc(), C.Id_transport, conformanceDC);
|
|
transportParamDecl->setImplicit();
|
|
transportParamDecl->setSpecifier(ParamSpecifier::Default);
|
|
transportParamDecl->setInterfaceType(transportType);
|
|
|
|
auto *paramList = ParameterList::createWithoutLoc(transportParamDecl);
|
|
|
|
// Func name: init(transport:)
|
|
DeclName name(C, DeclBaseName::createConstructor(), paramList);
|
|
|
|
auto *initDecl =
|
|
new (C) ConstructorDecl(name, SourceLoc(),
|
|
/*Failable=*/false, SourceLoc(),
|
|
/*Async=*/false, SourceLoc(),
|
|
/*Throws=*/false, SourceLoc(),
|
|
paramList,
|
|
/*GenericParams=*/nullptr, conformanceDC);
|
|
initDecl->setImplicit();
|
|
initDecl->setSynthesized();
|
|
initDecl->setBodySynthesizer(&createBody_DistributedActor_init_transport);
|
|
|
|
// This constructor is 'required', all distributed actors MUST invoke it.
|
|
auto *reqAttr = new (C) RequiredAttr(/*IsImplicit*/true);
|
|
initDecl->getAttrs().add(reqAttr);
|
|
|
|
auto *nonIsoAttr = new (C) NonisolatedAttr(/*IsImplicit*/true);
|
|
initDecl->getAttrs().add(nonIsoAttr);
|
|
|
|
initDecl->copyFormalAccessFrom(classDecl, /*sourceIsParentContext=*/true);
|
|
|
|
return initDecl;
|
|
}
|
|
|
|
// ==== Distributed Actor: Resolve Initializer ---------------------------------
|
|
|
|
/// Synthesizes the body for
|
|
///
|
|
/// ```
|
|
/// init(resolve address: ActorAddress, using transport: ActorTransport) throws {
|
|
/// // TODO: implement calling the transport
|
|
/// switch try transport.resolve(address: address, as: Self.self) {
|
|
/// case .instance(let instance):
|
|
/// self = instance
|
|
/// case .makeProxy:
|
|
/// // TODO: use RebindSelfInConstructorExpr here?
|
|
/// self = <<MAGIC MAKE PROXY>>(address, transport) // TODO: implement this
|
|
/// }
|
|
/// }
|
|
/// ```
|
|
///
|
|
/// \param initDecl The function decl whose body to synthesize.
|
|
static std::pair<BraceStmt *, bool>
|
|
createDistributedActor_init_resolve_body(AbstractFunctionDecl *initDecl, void *) {
|
|
|
|
auto *funcDC = cast<DeclContext>(initDecl);
|
|
auto &C = funcDC->getASTContext();
|
|
|
|
SmallVector<ASTNode, 2> statements; // TODO: how many?
|
|
|
|
auto addressParam = initDecl->getParameters()->get(0);
|
|
auto *addressExpr = new (C) DeclRefExpr(ConcreteDeclRef(addressParam),
|
|
DeclNameLoc(), /*Implicit=*/true);
|
|
|
|
auto transportParam = initDecl->getParameters()->get(1);
|
|
auto *transportExpr = new (C) DeclRefExpr(ConcreteDeclRef(transportParam),
|
|
DeclNameLoc(), /*Implicit=*/true);
|
|
|
|
auto *selfRef = DerivedConformance::createSelfDeclRef(initDecl);
|
|
|
|
// ==== `self.actorTransport = transport`
|
|
auto *varTransportExpr = UnresolvedDotExpr::createImplicit(C, selfRef,
|
|
C.Id_actorTransport);
|
|
auto *assignTransportExpr = new (C) AssignExpr(
|
|
varTransportExpr, SourceLoc(), transportExpr, /*Implicit=*/true);
|
|
statements.push_back(assignTransportExpr);
|
|
|
|
// ==== `self.actorAddress = transport.assignAddress<Self>(Self.self)`
|
|
// self.actorAddress
|
|
auto *varAddressExpr = UnresolvedDotExpr::createImplicit(C, selfRef,
|
|
C.Id_actorAddress);
|
|
// TODO implement calling the transport with the address and Self.self
|
|
// FIXME: this must be checking with the transport instead
|
|
auto *assignAddressExpr = new (C) AssignExpr(
|
|
varAddressExpr, SourceLoc(), addressExpr, /*Implicit=*/true);
|
|
statements.push_back(assignAddressExpr);
|
|
// end-of-FIXME: this must be checking with the transport instead
|
|
|
|
auto *body = BraceStmt::create(C, SourceLoc(), statements, SourceLoc(),
|
|
/*implicit=*/true);
|
|
|
|
return { body, /*isTypeChecked=*/false };
|
|
}
|
|
|
|
/// Synthesizes the
|
|
///
|
|
/// ```
|
|
/// init(resolve address: ActorAddress, using transport: ActorTransport) throws
|
|
/// ```
|
|
///
|
|
/// resolve initializer.
|
|
static ConstructorDecl *
|
|
createDistributedActor_init_resolve(ClassDecl *classDecl,
|
|
ASTContext &ctx) {
|
|
auto &C = ctx;
|
|
|
|
auto conformanceDC = classDecl;
|
|
|
|
// Expected type: (Self) -> (ActorAddress, ActorTransport) -> (Self)
|
|
//
|
|
// Param: (resolve address: ActorAddress)
|
|
auto addressType = C.getActorAddressDecl()->getDeclaredInterfaceType();
|
|
auto *addressParamDecl = new (C) ParamDecl(
|
|
SourceLoc(), SourceLoc(), C.Id_resolve,
|
|
SourceLoc(), C.Id_address, conformanceDC);
|
|
addressParamDecl->setImplicit();
|
|
addressParamDecl->setSpecifier(ParamSpecifier::Default);
|
|
addressParamDecl->setInterfaceType(addressType);
|
|
|
|
// Param: (using transport: ActorTransport)
|
|
auto transportType = C.getActorTransportDecl()->getDeclaredInterfaceType();
|
|
auto *transportParamDecl = new (C) ParamDecl(
|
|
SourceLoc(), SourceLoc(), C.Id_using,
|
|
SourceLoc(), C.Id_transport, conformanceDC);
|
|
transportParamDecl->setImplicit();
|
|
transportParamDecl->setSpecifier(ParamSpecifier::Default);
|
|
transportParamDecl->setInterfaceType(transportType);
|
|
|
|
auto *paramList = ParameterList::create(
|
|
C,
|
|
/*LParenLoc=*/SourceLoc(),
|
|
/*params=*/{addressParamDecl, transportParamDecl},
|
|
/*RParenLoc=*/SourceLoc()
|
|
);
|
|
|
|
// Func name: init(resolve:using:)
|
|
DeclName name(C, DeclBaseName::createConstructor(), paramList);
|
|
|
|
auto *initDecl =
|
|
new (C) ConstructorDecl(name, SourceLoc(),
|
|
/*Failable=*/false, SourceLoc(),
|
|
/*Async=*/false, SourceLoc(),
|
|
/*Throws=*/true, SourceLoc(),
|
|
paramList,
|
|
/*GenericParams=*/nullptr, conformanceDC);
|
|
initDecl->setImplicit();
|
|
initDecl->setSynthesized();
|
|
initDecl->setBodySynthesizer(&createDistributedActor_init_resolve_body);
|
|
|
|
// This constructor is 'required', all distributed actors MUST have it.
|
|
initDecl->getAttrs().add(new (C) RequiredAttr(/*IsImplicit*/true));
|
|
|
|
auto *nonIsoAttr = new (C) NonisolatedAttr(/*IsImplicit*/true);
|
|
initDecl->getAttrs().add(nonIsoAttr);
|
|
|
|
initDecl->copyFormalAccessFrom(classDecl, /*sourceIsParentContext=*/true);
|
|
|
|
return initDecl;
|
|
}
|
|
|
|
/// Detects which initializer to create, and does so.
|
|
static ConstructorDecl *
|
|
createDistributedActorInit(ClassDecl *classDecl,
|
|
ConstructorDecl *requirement,
|
|
ASTContext &ctx) {
|
|
assert(classDecl->isDistributedActor());
|
|
|
|
const auto name = requirement->getName();
|
|
auto argumentNames = name.getArgumentNames();
|
|
|
|
switch (argumentNames.size()) {
|
|
case 1: {
|
|
if (requirement->isDistributedActorLocalInit()) {
|
|
return createDistributedActor_init_local(classDecl, ctx);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case 2: {
|
|
if (requirement->isDistributedActorResolveInit()) {
|
|
return createDistributedActor_init_resolve(classDecl, ctx);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
static void collectNonOveriddenDistributedActorInits(
|
|
ASTContext& Context,
|
|
ClassDecl *actorDecl,
|
|
SmallVectorImpl<ConstructorDecl *> &results) {
|
|
assert(actorDecl->isDistributedActor());
|
|
auto protoDecl = Context.getProtocol(KnownProtocolKind::DistributedActor);
|
|
|
|
// // Record all of the initializers the actorDecl has implemented.
|
|
// llvm::SmallPtrSet<ConstructorDecl *, 4> overriddenInits;
|
|
// for (auto member : actorDecl->getMembers())
|
|
// if (auto ctor = dyn_cast<ConstructorDecl>(member))
|
|
// if (!ctor->hasStubImplementation())
|
|
// // if (auto overridden = ctor->getOverriddenDecl())
|
|
// overriddenInits.insert(ctor);
|
|
//
|
|
// actorDecl->synthesizeSemanticMembersIfNeeded(
|
|
// DeclBaseName::createConstructor());
|
|
|
|
NLOptions subOptions = (NL_QualifiedDefault | NL_IgnoreAccessControl);
|
|
SmallVector<ValueDecl *, 4> lookupResults;
|
|
actorDecl->lookupQualified(
|
|
protoDecl, DeclNameRef::createConstructor(),
|
|
subOptions, lookupResults);
|
|
|
|
for (auto decl : lookupResults) {
|
|
// Distributed Actor Constructor
|
|
auto daCtor = cast<ConstructorDecl>(decl);
|
|
|
|
// TODO: Don't require it if overriden
|
|
// if (!overriddenInits.count(daCtor))
|
|
results.push_back(daCtor);
|
|
}
|
|
}
|
|
|
|
|
|
/// For a distributed actor, automatically define initializers
|
|
/// that match the DistributedActor requirements.
|
|
// TODO: inheritance is tricky here?
|
|
static void addImplicitDistributedActorConstructors(ClassDecl *decl) {
|
|
// Bail out if not a distributed actor definition.
|
|
if (!decl->isDistributedActor())
|
|
return;
|
|
|
|
for (auto member : decl->getMembers()) {
|
|
if (auto ctor = dyn_cast<ConstructorDecl>(member)) {
|
|
if (ctor->isRecursiveValidation())
|
|
return;
|
|
}
|
|
}
|
|
|
|
decl->setAddedImplicitInitializers();
|
|
|
|
// Check whether the user has defined a designated initializer for this class,
|
|
// and whether all of its stored properties have initial values.
|
|
auto &ctx = decl->getASTContext();
|
|
// bool foundDesignatedInit = hasUserDefinedDesignatedInit(ctx.evaluator, decl);
|
|
// bool defaultInitable =
|
|
// areAllStoredPropertiesDefaultInitializable(ctx.evaluator, decl);
|
|
//
|
|
// // We can't define these overrides if we have any uninitialized
|
|
// // stored properties.
|
|
// if (!defaultInitable && !foundDesignatedInit)
|
|
// return;
|
|
|
|
SmallVector<ConstructorDecl *, 4> nonOverridenCtors;
|
|
collectNonOveriddenDistributedActorInits(
|
|
ctx, decl, nonOverridenCtors);
|
|
|
|
for (auto *daCtor : nonOverridenCtors) {
|
|
if (auto ctor = createDistributedActorInit(decl, daCtor, ctx)) {
|
|
decl->addMember(ctor);
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/******************************** PROPERTIES **********************************/
|
|
/******************************************************************************/
|
|
|
|
// TODO: deduplicate with 'declareDerivedProperty' from DerivedConformance...
|
|
std::pair<VarDecl *, PatternBindingDecl *>
|
|
createStoredProperty(ClassDecl *classDecl, ASTContext &ctx,
|
|
VarDecl::Introducer introducer, Identifier name,
|
|
Type propertyInterfaceType, Type propertyContextType,
|
|
bool isStatic, bool isFinal) {
|
|
auto parentDC = classDecl;
|
|
|
|
VarDecl *propDecl = new (ctx)
|
|
VarDecl(/*IsStatic*/ isStatic, introducer,
|
|
SourceLoc(), name, parentDC);
|
|
propDecl->setImplicit();
|
|
propDecl->setSynthesized();
|
|
propDecl->copyFormalAccessFrom(classDecl, /*sourceIsParentContext*/ true);
|
|
propDecl->setInterfaceType(propertyInterfaceType);
|
|
|
|
Pattern *propPat = NamedPattern::createImplicit(ctx, propDecl);
|
|
propPat->setType(propertyContextType);
|
|
|
|
propPat = TypedPattern::createImplicit(ctx, propPat, propertyContextType);
|
|
propPat->setType(propertyContextType);
|
|
|
|
auto *pbDecl = PatternBindingDecl::createImplicit(
|
|
ctx, StaticSpellingKind::None, propPat, /*InitExpr*/ nullptr,
|
|
parentDC);
|
|
return {propDecl, pbDecl};
|
|
}
|
|
|
|
/// Adds the following, fairly special, properties to each distributed actor:
|
|
/// - actorTransport
|
|
/// - actorAddress
|
|
static void addImplicitDistributedActorStoredProperties(ClassDecl *decl) {
|
|
assert(decl->isDistributedActor());
|
|
|
|
auto &C = decl->getASTContext();
|
|
|
|
// ```
|
|
// @_distributedActorIndependent
|
|
// let actorAddress: ActorAddress
|
|
// ```
|
|
// (no need for @actorIndependent because it is an immutable let)
|
|
{
|
|
auto propertyType = C.getActorAddressDecl()->getDeclaredInterfaceType();
|
|
|
|
VarDecl *propDecl;
|
|
PatternBindingDecl *pbDecl;
|
|
std::tie(propDecl, pbDecl) = createStoredProperty(
|
|
decl, C,
|
|
VarDecl::Introducer::Let, C.Id_actorAddress,
|
|
propertyType, propertyType,
|
|
/*isStatic=*/false, /*isFinal=*/true);
|
|
|
|
// mark as @_distributedActorIndependent, allowing access to it from everywhere
|
|
propDecl->getAttrs().add(
|
|
new (C) DistributedActorIndependentAttr(/*IsImplicit=*/true));
|
|
|
|
decl->addMember(propDecl);
|
|
decl->addMember(pbDecl);
|
|
}
|
|
|
|
// ```
|
|
// @_distributedActorIndependent
|
|
// let actorTransport: ActorTransport
|
|
// ```
|
|
// (no need for @actorIndependent because it is an immutable let)
|
|
{
|
|
auto propertyType = C.getActorTransportDecl()->getDeclaredInterfaceType();
|
|
|
|
VarDecl *propDecl;
|
|
PatternBindingDecl *pbDecl;
|
|
std::tie(propDecl, pbDecl) = createStoredProperty(
|
|
decl, C,
|
|
VarDecl::Introducer::Let, C.Id_actorTransport,
|
|
propertyType, propertyType,
|
|
/*isStatic=*/false, /*isFinal=*/true);
|
|
|
|
// mark as @_distributedActorIndependent, allowing access to it from everywhere
|
|
propDecl->getAttrs().add(
|
|
new (C) DistributedActorIndependentAttr(/*IsImplicit=*/true));
|
|
|
|
decl->addMember(propDecl);
|
|
decl->addMember(pbDecl);
|
|
}
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/************************ SYNTHESIS ENTRY POINT *******************************/
|
|
/******************************************************************************/
|
|
|
|
/// Entry point for adding all computed members to a distributed actor decl.
|
|
static void addImplicitDistributedActorMembersToClass(ClassDecl *decl) {
|
|
// Bail out if not a distributed actor definition.
|
|
if (!decl->isDistributedActor())
|
|
return;
|
|
|
|
auto &C = decl->getASTContext();
|
|
|
|
if (!C.getLoadedModule(C.Id_Distributed)) {
|
|
// seems we're missing the _Distributed module, ask to import it explicitly
|
|
decl->diagnose(diag::distributed_actor_needs_explicit_distributed_import);
|
|
return;
|
|
}
|
|
|
|
addImplicitDistributedActorConstructors(decl);
|
|
addImplicitDistributedActorStoredProperties(decl);
|
|
}
|