//===--- AnyFunctionRef.h - A Universal Function Reference ------*- C++ -*-===// // // 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 // //===----------------------------------------------------------------------===// #ifndef SWIFT_AST_ANY_FUNCTION_REF_H #define SWIFT_AST_ANY_FUNCTION_REF_H #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Types.h" #include "swift/Basic/Compiler.h" #include "swift/Basic/Debug.h" #include "swift/Basic/LLVM.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerUnion.h" #include namespace swift { class CaptureInfo; /// A universal function reference -- can wrap all AST nodes that /// represent functions and exposes a common interface to them. class AnyFunctionRef { PointerUnion TheFunction; friend struct llvm::DenseMapInfo; AnyFunctionRef(decltype(TheFunction) TheFunction) : TheFunction(TheFunction) {} public: AnyFunctionRef(AbstractFunctionDecl *AFD) : TheFunction(AFD) { assert(AFD && "should have a function"); } AnyFunctionRef(AbstractClosureExpr *ACE) : TheFunction(ACE) { assert(ACE && "should have a closure"); } /// Construct an AnyFunctionRef from a decl context that's known to /// be some sort of function. static AnyFunctionRef fromFunctionDeclContext(DeclContext *dc) { if (auto fn = dyn_cast(dc)) { return fn; } else { return cast(dc); } } /// Construct an AnyFunctionRef from a decl context that might be /// some sort of function. static std::optional fromDeclContext(DeclContext *dc) { if (auto fn = dyn_cast(dc)) { return AnyFunctionRef(fn); } if (auto ace = dyn_cast(dc)) { return AnyFunctionRef(ace); } return std::nullopt; } CaptureInfo getCaptureInfo() const { if (auto *AFD = TheFunction.dyn_cast()) return AFD->getCaptureInfo(); return cast(TheFunction)->getCaptureInfo(); } ParameterList *getParameters() const { if (auto *AFD = TheFunction.dyn_cast()) return AFD->getParameters(); return cast(TheFunction)->getParameters(); } bool hasExternalPropertyWrapperParameters() const { return llvm::any_of(*getParameters(), [](const ParamDecl *param) { return param->hasExternalPropertyWrapper(); }); } Type getType() const { if (auto *AFD = TheFunction.dyn_cast()) return AFD->getInterfaceType(); return cast(TheFunction)->getType(); } Type getBodyResultType() const { if (auto *AFD = TheFunction.dyn_cast()) { if (auto *FD = dyn_cast(AFD)) return FD->mapTypeIntoEnvironment(FD->getResultInterfaceType()); return TupleType::getEmpty(AFD->getASTContext()); } return cast(TheFunction)->getResultType(); } ArrayRef getYieldResults(SmallVectorImpl &buffer) const { return getYieldResultsImpl(buffer, /*mapIntoContext*/ false); } ArrayRef getBodyYieldResults(SmallVectorImpl &buffer) const { return getYieldResultsImpl(buffer, /*mapIntoContext*/ true); } BraceStmt *getBody() const { if (auto *AFD = TheFunction.dyn_cast()) return AFD->getBody(); auto *ACE = cast(TheFunction); if (auto *CE = dyn_cast(ACE)) return CE->getBody(); return cast(ACE)->getBody(); } void setParsedBody(BraceStmt *stmt) { if (auto *AFD = TheFunction.dyn_cast()) { AFD->setBody(stmt, AbstractFunctionDecl::BodyKind::Parsed); return; } auto *ACE = cast(TheFunction); if (auto *CE = dyn_cast(ACE)) { CE->setBody(stmt); CE->setBodyState(ClosureExpr::BodyState::Parsed); return; } llvm_unreachable("autoclosures don't have statement bodies"); } void setTypecheckedBody(BraceStmt *stmt) { if (auto *AFD = TheFunction.dyn_cast()) { AFD->setBody(stmt, AbstractFunctionDecl::BodyKind::TypeChecked); return; } auto *ACE = cast(TheFunction); if (auto *CE = dyn_cast(ACE)) { CE->setBody(stmt); CE->setBodyState(ClosureExpr::BodyState::TypeChecked); return; } llvm_unreachable("autoclosures don't have statement bodies"); } /// Returns a boolean value indicating whether the body, if any, contains /// an explicit `return` statement. /// /// \returns `true` if the body contains an explicit `return` statement, /// `false` otherwise. bool bodyHasExplicitReturnStmt() const; /// Finds occurrences of explicit `return` statements within the body, if any. /// /// \param results An out container to which the results are added. void getExplicitReturnStmts(SmallVectorImpl &results) const; DeclContext *getAsDeclContext() const { if (auto *AFD = TheFunction.dyn_cast()) return AFD; return cast(TheFunction); } AbstractFunctionDecl *getAbstractFunctionDecl() const { return TheFunction.dyn_cast(); } AbstractClosureExpr *getAbstractClosureExpr() const { return TheFunction.dyn_cast(); } AccessorDecl *getAccessorDecl() const { if (auto *accessor = dyn_cast_or_null( TheFunction.dyn_cast())) { return accessor; } return nullptr; } /// Whether this function is @Sendable. bool isSendable() const { if (auto *fnType = getType()->getAs()) return fnType->isSendable(); return false; } bool isObjC() const { if (auto afd = TheFunction.dyn_cast()) { return afd->isObjC(); } if (TheFunction.dyn_cast()) { // Closures are never @objc. return false; } llvm_unreachable("unexpected AnyFunctionRef representation"); } SourceLoc getLoc(bool SerializedOK = true) const { if (auto afd = TheFunction.dyn_cast()) { return afd->getLoc(SerializedOK); } if (auto ce = TheFunction.dyn_cast()) { return ce->getLoc(); } llvm_unreachable("unexpected AnyFunctionRef representation"); } // Disable "only for use within the debugger" warning. #if SWIFT_COMPILER_IS_MSVC #pragma warning(push) #pragma warning(disable: 4996) #endif SWIFT_DEBUG_DUMP { if (auto afd = TheFunction.dyn_cast()) { return afd->dump(); } if (auto ce = TheFunction.dyn_cast()) { return ce->dump(); } llvm_unreachable("unexpected AnyFunctionRef representation"); } GenericEnvironment *getGenericEnvironment() const { if (auto afd = TheFunction.dyn_cast()) { return afd->getGenericEnvironment(); } if (auto ce = TheFunction.dyn_cast()) { return ce->getGenericEnvironmentOfContext(); } llvm_unreachable("unexpected AnyFunctionRef representation"); } GenericSignature getGenericSignature() const { if (auto afd = TheFunction.dyn_cast()) { return afd->getGenericSignature(); } if (auto ce = TheFunction.dyn_cast()) { return ce->getGenericSignatureOfContext(); } llvm_unreachable("unexpected AnyFunctionRef representation"); } DeclAttributes getDeclAttributes() const { if (auto afd = TheFunction.dyn_cast()) { return afd->getExpandedAttrs(); } if (auto ace = TheFunction.dyn_cast()) { if (auto *ce = dyn_cast(ace)) { return ce->getAttrs(); } } return DeclAttributes(); } using MacroCallback = llvm::function_ref; void forEachAttachedMacro(MacroRole role, MacroCallback macroCallback) const { auto attrs = getDeclAttributes(); for (auto *customAttr : attrs.getAttributes()) { auto *macroDecl = customAttr->getResolvedMacro(); if (!macroDecl || !macroDecl->getMacroRoles().contains(role)) continue; macroCallback(customAttr, macroDecl); } } friend bool operator==(AnyFunctionRef lhs, AnyFunctionRef rhs) { return lhs.TheFunction == rhs.TheFunction; } friend bool operator!=(AnyFunctionRef lhs, AnyFunctionRef rhs) { return lhs.TheFunction != rhs.TheFunction; } friend llvm::hash_code hash_value(AnyFunctionRef fn) { using llvm::hash_value; return hash_value(fn.TheFunction.getOpaqueValue()); } friend SourceLoc extractNearestSourceLoc(AnyFunctionRef fn) { return fn.getLoc(/*SerializedOK=*/false); } private: ArrayRef getYieldResultsImpl(SmallVectorImpl &buffer, bool mapIntoContext) const { assert(buffer.empty()); if (auto *AFD = TheFunction.dyn_cast()) { if (auto *AD = dyn_cast(AFD)) { if (AD->isCoroutine()) { auto valueTy = AD->getStorage()->getValueInterfaceType() ->getReferenceStorageReferent(); if (mapIntoContext) valueTy = AD->mapTypeIntoEnvironment(valueTy); YieldTypeFlags flags(isYieldingMutableAccessor(AD->getAccessorKind()) ? ParamSpecifier::InOut : ParamSpecifier::LegacyShared); buffer.push_back(AnyFunctionType::Yield(valueTy, flags)); return buffer; } } } return {}; } }; #if SWIFT_COMPILER_IS_MSVC #pragma warning(pop) #endif void simple_display(llvm::raw_ostream &out, AnyFunctionRef fn); } // namespace swift namespace llvm { template<> struct DenseMapInfo { using PointerUnion = decltype(swift::AnyFunctionRef::TheFunction); using PointerUnionTraits = DenseMapInfo; using AnyFunctionRef = swift::AnyFunctionRef; static inline AnyFunctionRef getEmptyKey() { return AnyFunctionRef(PointerUnionTraits::getEmptyKey()); } static inline AnyFunctionRef getTombstoneKey() { return AnyFunctionRef(PointerUnionTraits::getTombstoneKey()); } static inline unsigned getHashValue(AnyFunctionRef ref) { return PointerUnionTraits::getHashValue(ref.TheFunction); } static bool isEqual(AnyFunctionRef a, AnyFunctionRef b) { return a.TheFunction == b.TheFunction; } }; } #endif // LLVM_SWIFT_AST_ANY_FUNCTION_REF_H