//===--- CodeSynthesisDistributedActor.cpp --------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2021 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 "TypeCheckDistributed.h" #include "TypeChecker.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/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; // 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 // it for ObjectIdentifier, and we have to instead emit this stored property. // // The "derived" mechanisms are not really geared towards emitting for // what already has a witness. static VarDecl *addImplicitDistributedActorIDProperty( // DeclContext *parentDC, NominalTypeDecl *nominal) { if (!nominal || !nominal->isDistributedActor()) return nullptr; // ==== if the 'id' already exists, return it auto &C = nominal->getASTContext(); // if (auto existing = nominal->lookupDirect(C.Id_id)) // return existing; // ==== Synthesize and add 'id' property to the actor decl Type propertyType = getDistributedActorIDType(nominal); VarDecl *propDecl = new (C) VarDecl(/*IsStatic*/false, VarDecl::Introducer::Let, SourceLoc(), C.Id_id, 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); propDecl->setIntroducer(VarDecl::Introducer::Let); // mark as nonisolated, allowing access to it from everywhere propDecl->getAttrs().add( new (C) NonisolatedAttr(/*IsImplicit=*/true)); nominal->addMember(propDecl); nominal->addMember(pbDecl); return propDecl; } /******************************************************************************/ /************ LOCATING AD-HOC PROTOCOL REQUIREMENT IMPLS **********************/ /******************************************************************************/ AbstractFunctionDecl* GetDistributedActorSystemRemoteCallFunctionRequest::evaluate( Evaluator &evaluator, NominalTypeDecl *decl, bool isVoidReturn) const { auto &C = decl->getASTContext(); // It would be nice to check if this is a DistributedActorSystem // "conforming" type, but we can't do this as we invoke this function WHILE // deciding if the type conforms or not; // Not via `ensureDistributedModuleLoaded` to avoid generating a warning, // we won't be emitting the offending decl after all. if (!C.getLoadedModule(C.Id_Distributed)) { return nullptr; } auto callId = isVoidReturn ? C.Id_remoteCallVoid : C.Id_remoteCall; AbstractFunctionDecl *remoteCallFunc = nullptr; for (auto value : decl->lookupDirect(callId)) { auto func = dyn_cast(value); if (func && func->isDistributedActorSystemRemoteCall(isVoidReturn)) { remoteCallFunc = func; break; } } return remoteCallFunc; } /******************************************************************************/ /************************ SYNTHESIS ENTRY POINT *******************************/ /******************************************************************************/ VarDecl *GetDistributedActorIDPropertyRequest::evaluate( Evaluator &evaluator, NominalTypeDecl *actor) const { if (!actor->isDistributedActor()) return nullptr; auto &C = actor->getASTContext(); // not via `ensureDistributedModuleLoaded` to avoid generating a warning, // we won't be emitting the offending decl after all. if (!C.getLoadedModule(C.Id_Distributed)) return nullptr; return addImplicitDistributedActorIDProperty(actor); } VarDecl *GetDistributedActorSystemPropertyRequest::evaluate( Evaluator &evaluator, NominalTypeDecl *actor) const { if (!actor->isDistributedActor()) return nullptr; auto &C = actor->getASTContext(); // not via `ensureDistributedModuleLoaded` to avoid generating a warning, // we won't be emitting the offending decl after all. if (!C.getLoadedModule(C.Id_Distributed)) return nullptr; if (auto system = actor->lookupDirect(C.Id_actorSystem).begin()) { // TODO(distributed): may need to check conformance here? return dyn_cast(*system); } return nullptr; }