//===--- Fulfillment.h - Deriving type/conformance metadata -----*- 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 // //===----------------------------------------------------------------------===// // // This file defines interfaces for deriving type metadata and protocol // witness tables from various sources. // //===----------------------------------------------------------------------===// #ifndef SWIFT_IRGEN_FULFILLMENT_H #define SWIFT_IRGEN_FULFILLMENT_H #include "llvm/ADT/DenseMap.h" #include "swift/AST/Types.h" #include "swift/AST/GenericSignature.h" #include "MetadataPath.h" namespace swift { namespace irgen { class IRGenModule; enum IsExact_t : bool; /// The metadata value can be fulfilled by following the given metadata /// path from the given source. struct Fulfillment { Fulfillment() = default; Fulfillment(unsigned sourceIndex, MetadataPath &&path) : SourceIndex(sourceIndex), Path(std::move(path)) {} /// The source index. unsigned SourceIndex; /// The path from the source metadata. MetadataPath Path; }; class FulfillmentMap { using FulfillmentKey = std::pair; llvm::DenseMap Fulfillments; public: struct InterestingKeysCallback { /// Is the given type something that we should add fulfillments for? virtual bool isInterestingType(CanType type) const = 0; /// Is the given type expressed in terms of types that we should add /// fulfillments for? /// /// It's okay to conservatively return true here. virtual bool hasInterestingType(CanType type) const = 0; /// Are we only interested in a subset of the conformances for a /// given type? virtual bool hasLimitedInterestingConformances(CanType type) const = 0; /// Return the limited interesting conformances for an interesting type. virtual GenericSignature::ConformsToArray getInterestingConformances(CanType type) const = 0; /// Return the limited interesting conformances for an interesting type. virtual CanType getSuperclassBound(CanType type) const = 0; virtual ~InterestingKeysCallback() = default; }; FulfillmentMap() = default; using iterator = decltype(Fulfillments)::iterator; iterator begin() { return Fulfillments.begin(); } iterator end() { return Fulfillments.end(); } /// Is it even theoretically possible that we might find a fulfillment /// in the given type? static bool isInterestingTypeForFulfillments(CanType type) { // Some day, if we ever record fulfillments for concrete types, this // optimization will probably no longer be useful. return type->hasTypeParameter(); } /// Search the given type metadata for useful fulfillments. /// /// \return true if any fulfillments were added by this search. bool searchTypeMetadata(IRGenModule &IGM, CanType type, IsExact_t isExact, unsigned sourceIndex, MetadataPath &&path, const InterestingKeysCallback &interestingKeys); bool searchConformance(IRGenModule &IGM, const ProtocolConformance *conformance, unsigned sourceIndex, MetadataPath &&path, const InterestingKeysCallback &interestingKeys); /// Search the given witness table for useful fulfillments. /// /// \return true if any fulfillments were added by this search. bool searchWitnessTable(IRGenModule &IGM, CanType type, ProtocolDecl *protocol, unsigned sourceIndex, MetadataPath &&path, const InterestingKeysCallback &interestingKeys); /// Register a fulfillment for the given key. /// /// \return true if the fulfillment was added, which won't happen if there's /// already a fulfillment that was at least as good bool addFulfillment(FulfillmentKey key, unsigned source, MetadataPath &&path); const Fulfillment *getTypeMetadata(CanType type) const { auto it = Fulfillments.find({type, nullptr}); if (it != Fulfillments.end()) { return &it->second; } else { return nullptr; } } const Fulfillment *getWitnessTable(CanType type, ProtocolDecl *proto) const { auto it = Fulfillments.find({type, proto}); if (it != Fulfillments.end()) { return &it->second; } else { return nullptr; } } void dump() const; void print(llvm::raw_ostream &out) const; friend llvm::raw_ostream &operator<<(llvm::raw_ostream &out, const FulfillmentMap &map) { map.print(out); return out; } private: bool searchNominalTypeMetadata(IRGenModule &IGM, CanType type, unsigned source, MetadataPath &&path, const InterestingKeysCallback &keys); /// Search the given witness table for useful fulfillments. /// /// \return true if any fulfillments were added by this search. bool searchWitnessTable( IRGenModule &IGM, CanType type, ProtocolDecl *protocol, unsigned source, MetadataPath &&path, const InterestingKeysCallback &keys, llvm::SmallPtrSetImpl *interestingConformances); }; } } #endif