| //===--- 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/Basic/Compiler.h" |
| #include "swift/Basic/Debug.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; |
| |
| /// A universal function reference -- can wrap all AST nodes that |
| /// represent functions and exposes a common interface to them. |
| class AnyFunctionRef { |
| PointerUnion<AbstractFunctionDecl *, AbstractClosureExpr *> TheFunction; |
| |
| friend struct llvm::DenseMapInfo<AnyFunctionRef>; |
| |
| 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<AbstractFunctionDecl>(dc)) { |
| return fn; |
| } else { |
| return cast<AbstractClosureExpr>(dc); |
| } |
| } |
| |
| /// Construct an AnyFunctionRef from a decl context that might be |
| /// some sort of function. |
| static Optional<AnyFunctionRef> fromDeclContext(DeclContext *dc) { |
| if (auto fn = dyn_cast<AbstractFunctionDecl>(dc)) { |
| return AnyFunctionRef(fn); |
| } |
| |
| if (auto ace = dyn_cast<AbstractClosureExpr>(dc)) { |
| return AnyFunctionRef(ace); |
| } |
| |
| return None; |
| } |
| |
| CaptureInfo getCaptureInfo() const { |
| if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>()) |
| return AFD->getCaptureInfo(); |
| return TheFunction.get<AbstractClosureExpr *>()->getCaptureInfo(); |
| } |
| |
| void setCaptureInfo(CaptureInfo captures) const { |
| if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>()) { |
| AFD->setCaptureInfo(captures); |
| return; |
| } |
| TheFunction.get<AbstractClosureExpr *>()->setCaptureInfo(captures); |
| } |
| |
| void getLocalCaptures(SmallVectorImpl<CapturedValue> &Result) const { |
| getCaptureInfo().getLocalCaptures(Result); |
| } |
| |
| bool hasType() const { |
| if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>()) |
| return AFD->hasInterfaceType(); |
| return !TheFunction.get<AbstractClosureExpr *>()->getType().isNull(); |
| } |
| |
| bool hasSingleExpressionBody() const { |
| if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>()) |
| return AFD->hasSingleExpressionBody(); |
| return TheFunction.get<AbstractClosureExpr *>()->hasSingleExpressionBody(); |
| } |
| |
| Expr *getSingleExpressionBody() const { |
| if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>()) |
| return AFD->getSingleExpressionBody(); |
| return TheFunction.get<AbstractClosureExpr *>()->getSingleExpressionBody(); |
| } |
| |
| Type getType() const { |
| if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>()) |
| return AFD->getInterfaceType(); |
| return TheFunction.get<AbstractClosureExpr *>()->getType(); |
| } |
| |
| Type getBodyResultType() const { |
| if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>()) { |
| if (auto *FD = dyn_cast<FuncDecl>(AFD)) |
| return FD->mapTypeIntoContext(FD->getResultInterfaceType()); |
| return TupleType::getEmpty(AFD->getASTContext()); |
| } |
| return TheFunction.get<AbstractClosureExpr *>()->getResultType(); |
| } |
| |
| ArrayRef<AnyFunctionType::Yield> |
| getYieldResults(SmallVectorImpl<AnyFunctionType::Yield> &buffer) const { |
| return getYieldResultsImpl(buffer, /*mapIntoContext*/ false); |
| } |
| |
| ArrayRef<AnyFunctionType::Yield> |
| getBodyYieldResults(SmallVectorImpl<AnyFunctionType::Yield> &buffer) const { |
| return getYieldResultsImpl(buffer, /*mapIntoContext*/ true); |
| } |
| |
| BraceStmt *getBody() const { |
| if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>()) |
| return AFD->getBody(); |
| auto *ACE = TheFunction.get<AbstractClosureExpr *>(); |
| if (auto *CE = dyn_cast<ClosureExpr>(ACE)) |
| return CE->getBody(); |
| return cast<AutoClosureExpr>(ACE)->getBody(); |
| } |
| |
| void setTypecheckedBody(BraceStmt *stmt, bool isSingleExpression) { |
| if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>()) { |
| AFD->setBody(stmt, AbstractFunctionDecl::BodyKind::TypeChecked); |
| AFD->setHasSingleExpressionBody(isSingleExpression); |
| return; |
| } |
| |
| auto *ACE = TheFunction.get<AbstractClosureExpr *>(); |
| if (auto *CE = dyn_cast<ClosureExpr>(ACE)) { |
| return CE->setBody(stmt, isSingleExpression); |
| } |
| |
| llvm_unreachable("autoclosures don't have statement bodies"); |
| } |
| |
| DeclContext *getAsDeclContext() const { |
| if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>()) |
| return AFD; |
| return TheFunction.get<AbstractClosureExpr *>(); |
| } |
| |
| AbstractFunctionDecl *getAbstractFunctionDecl() const { |
| return TheFunction.dyn_cast<AbstractFunctionDecl*>(); |
| } |
| |
| AbstractClosureExpr *getAbstractClosureExpr() const { |
| return TheFunction.dyn_cast<AbstractClosureExpr*>(); |
| } |
| |
| bool isDeferBody() const { |
| if (auto *fd = dyn_cast_or_null<FuncDecl>(getAbstractFunctionDecl())) |
| return fd->isDeferBody(); |
| return false; |
| } |
| |
| /// 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 (hasType() && !getType()->hasError()) |
| return getType()->castTo<AnyFunctionType>()->isNoEscape(); |
| return false; |
| } |
| |
| bool isObjC() const { |
| if (auto afd = TheFunction.dyn_cast<AbstractFunctionDecl *>()) { |
| return afd->isObjC(); |
| } |
| if (TheFunction.dyn_cast<AbstractClosureExpr *>()) { |
| // Closures are never @objc. |
| return false; |
| } |
| llvm_unreachable("unexpected AnyFunctionRef representation"); |
| } |
| |
| SourceLoc getLoc() const { |
| if (auto afd = TheFunction.dyn_cast<AbstractFunctionDecl *>()) { |
| return afd->getLoc(); |
| } |
| if (auto ce = TheFunction.dyn_cast<AbstractClosureExpr *>()) { |
| 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<AbstractFunctionDecl *>()) { |
| return afd->dump(); |
| } |
| if (auto ce = TheFunction.dyn_cast<AbstractClosureExpr *>()) { |
| return ce->dump(); |
| } |
| llvm_unreachable("unexpected AnyFunctionRef representation"); |
| } |
| |
| GenericEnvironment *getGenericEnvironment() const { |
| if (auto afd = TheFunction.dyn_cast<AbstractFunctionDecl *>()) { |
| return afd->getGenericEnvironment(); |
| } |
| if (auto ce = TheFunction.dyn_cast<AbstractClosureExpr *>()) { |
| return ce->getGenericEnvironmentOfContext(); |
| } |
| llvm_unreachable("unexpected AnyFunctionRef representation"); |
| } |
| |
| GenericSignature getGenericSignature() const { |
| if (auto afd = TheFunction.dyn_cast<AbstractFunctionDecl *>()) { |
| return afd->getGenericSignature(); |
| } |
| if (auto ce = TheFunction.dyn_cast<AbstractClosureExpr *>()) { |
| return ce->getGenericSignatureOfContext(); |
| } |
| llvm_unreachable("unexpected AnyFunctionRef representation"); |
| } |
| |
| 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(); |
| } |
| |
| private: |
| ArrayRef<AnyFunctionType::Yield> |
| getYieldResultsImpl(SmallVectorImpl<AnyFunctionType::Yield> &buffer, |
| bool mapIntoContext) const { |
| assert(buffer.empty()); |
| if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>()) { |
| if (auto *AD = dyn_cast<AccessorDecl>(AFD)) { |
| if (AD->isCoroutine()) { |
| auto valueTy = AD->getStorage()->getValueInterfaceType() |
| ->getReferenceStorageReferent(); |
| if (mapIntoContext) |
| valueTy = AD->mapTypeIntoContext(valueTy); |
| YieldTypeFlags flags(AD->getAccessorKind() == AccessorKind::Modify |
| ? ValueOwnership::InOut |
| : ValueOwnership::Shared); |
| 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<swift::AnyFunctionRef> { |
| using PointerUnion = decltype(swift::AnyFunctionRef::TheFunction); |
| using PointerUnionTraits = DenseMapInfo<PointerUnion>; |
| 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 |
| |