//===--- AnyFunctionRef.h - A Universal Function Reference ------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://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/Basic/LLVM.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" #include "swift/AST/Types.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerUnion.h" namespace swift { class CaptureInfo; /// \brief 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); } } CaptureInfo &getCaptureInfo() const { if (auto *AFD = TheFunction.dyn_cast()) return AFD->getCaptureInfo(); return TheFunction.get()->getCaptureInfo(); } void getLocalCaptures(SmallVectorImpl &Result) const { getCaptureInfo().getLocalCaptures(Result); } ArrayRef getParameterLists() const { if (auto *AFD = TheFunction.dyn_cast()) return AFD->getParameterLists(); return TheFunction.get()->getParameterLists(); } bool hasType() const { if (auto *AFD = TheFunction.dyn_cast()) return AFD->hasType(); return !TheFunction.get()->getType().isNull(); } Type getType() const { if (auto *AFD = TheFunction.dyn_cast()) return AFD->getType(); return TheFunction.get()->getType(); } /// FIXME: This should just be getType() when interface types take over in /// the AST. Type getInterfaceType() const { if (auto *AFD = TheFunction.dyn_cast()) return AFD->getInterfaceType(); return TheFunction.get()->getType(); } Type getBodyResultType() const { if (auto *AFD = TheFunction.dyn_cast()) { if (auto *FD = dyn_cast(AFD)) return FD->getBodyResultType(); return TupleType::getEmpty(AFD->getASTContext()); } return TheFunction.get()->getResultType(); } BraceStmt *getBody() const { if (auto *AFD = TheFunction.dyn_cast()) return AFD->getBody(); auto *ACE = TheFunction.get(); if (auto *CE = dyn_cast(ACE)) return CE->getBody(); return cast(ACE)->getBody(); } DeclContext *getAsDeclContext() const { if (auto *AFD = TheFunction.dyn_cast()) return AFD; return TheFunction.get(); } AbstractFunctionDecl *getAbstractFunctionDecl() const { return TheFunction.dyn_cast(); } AbstractClosureExpr *getAbstractClosureExpr() const { return TheFunction.dyn_cast(); } /// Return true if this closure is passed as an argument to a function and is /// known not to escape from that function. In this case, captures can be /// more efficient. bool isKnownNoEscape() const { if (auto afd = TheFunction.dyn_cast()) { // As a hack, assume defer bodies are noescape. if (auto fd = dyn_cast(afd)) return fd->isDeferBody(); return false; } auto *CE = TheFunction.get(); if (!CE->getType() || CE->getType()->is()) return false; return CE->getType()->castTo()->isNoEscape(); } }; } // 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