/// Given that we have a source for a witness table that the given type /// conforms to the given protocol, check to see if it fulfills anything. bool FulfillmentMap::searchWitnessTable(IRGenModule &IGM, CanType type, ProtocolDecl *protocol, unsigned source, MetadataPath &&path, const InterestingKeysCallback &keys) { llvm::SmallPtrSet<ProtocolDecl*, 4> interestingConformancesBuffer; llvm::SmallPtrSetImpl<ProtocolDecl*> *interestingConformances = nullptr; // If the interesting-keys set is limiting the set of interesting // conformances, collect that filter. if (keys.isInterestingType(type) && keys.hasLimitedInterestingConformances(type)) { // Bail out immediately if the set is empty. // This only makes sense because we're not trying to fulfill // associated types this way. auto requiredConformances = keys.getInterestingConformances(type); if (requiredConformances.empty()) return false; interestingConformancesBuffer.insert(requiredConformances.begin(), requiredConformances.end()); interestingConformances = &interestingConformancesBuffer; } return searchWitnessTable(IGM, type, protocol, source, std::move(path), keys, interestingConformances); }
bool FulfillmentMap::searchTypeArgConformances(ModuleDecl &M, CanType arg, ArchetypeType *param, unsigned source, const MetadataPath &path, unsigned argIndex, const InterestingKeysCallback &keys) { // Our sources are the protocol conformances that are recorded in // the generic metadata. auto storedConformances = param->getConformsTo(); if (storedConformances.empty()) return false; bool hadFulfillment = false; // If we're not limiting the interesting conformances, just add fulfillments // for all of the stored conformances. if (!keys.hasLimitedInterestingConformances(arg)) { for (size_t confIndex : indices(storedConformances)) { MetadataPath confPath = path; confPath.addNominalTypeArgumentConformanceComponent(argIndex, confIndex); hadFulfillment |= addFulfillment({arg, storedConformances[confIndex]}, source, std::move(confPath)); } return hadFulfillment; } // Otherwise, our targets are the interesting conformances for the type // argument. auto requiredConformances = keys.getInterestingConformances(arg); if (requiredConformances.empty()) return false; for (auto target : requiredConformances) { // Ignore trivial protocols. if (!Lowering::TypeConverter::protocolRequiresWitnessTable(target)) continue; // Check each of the stored conformances. for (size_t confIndex : indices(storedConformances)) { // TODO: maybe this should consider indirect conformance. // But that should be part of the metadata path. if (target == storedConformances[confIndex]) { MetadataPath confPath = path; confPath.addNominalTypeArgumentConformanceComponent(argIndex, confIndex); hadFulfillment |= addFulfillment({arg, target}, source, std::move(confPath)); } } } return hadFulfillment; }
bool FulfillmentMap::searchBoundGenericTypeMetadata(IRGenModule &IGM, CanBoundGenericType type, unsigned source, MetadataPath &&path, const InterestingKeysCallback &keys) { if (type->getDecl()->hasClangNode()) return false; bool hadFulfillment = false; GenericTypeRequirements requirements(IGM, type->getDecl()); requirements.enumerateFulfillments(IGM, type->getSubstitutions(IGM.getSwiftModule(), nullptr), [&](unsigned reqtIndex, CanType arg, Optional<ProtocolConformanceRef> conf) { // Skip uninteresting type arguments. if (!keys.hasInterestingType(arg)) return; // If the fulfilled value is type metadata, refine the path. if (!conf) { MetadataPath argPath = path; argPath.addNominalTypeArgumentComponent(reqtIndex); hadFulfillment |= searchTypeMetadata(IGM, arg, IsExact, source, std::move(argPath), keys); return; } // Otherwise, it's a conformance. // Ignore it unless the type itself is interesting. if (!keys.isInterestingType(arg)) return; // Refine the path. MetadataPath argPath = path; argPath.addNominalTypeArgumentConformanceComponent(reqtIndex); llvm::SmallPtrSet<ProtocolDecl*, 4> interestingConformancesBuffer; llvm::SmallPtrSetImpl<ProtocolDecl*> *interestingConformances = nullptr; // If the interesting-keys set is limiting the set of interesting // conformances, collect that filter. if (keys.hasLimitedInterestingConformances(arg)) { // Bail out immediately if the set is empty. auto requiredConformances = keys.getInterestingConformances(arg); if (requiredConformances.empty()) return; interestingConformancesBuffer.insert(requiredConformances.begin(), requiredConformances.end()); interestingConformances = &interestingConformancesBuffer; } hadFulfillment |= searchWitnessTable(IGM, arg, conf->getRequirement(), source, std::move(argPath), keys, interestingConformances); }); // Also match against the parent. The polymorphic type // will start with any arguments from the parent. hadFulfillment |= searchParentTypeMetadata(IGM, type->getDecl(), type.getParent(), source, std::move(path), keys); return hadFulfillment; }