bool FulfillmentMap::searchWitnessTable(IRGenModule &IGM, CanType type, ProtocolDecl *protocol, unsigned source, MetadataPath &&path, const InterestingKeysCallback &keys) { assert(Lowering::TypeConverter::protocolRequiresWitnessTable(protocol)); 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.hasInterestingType(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::searchNominalTypeMetadata(IRGenModule &IGM, CanType type, MetadataState metadataState, unsigned source, MetadataPath &&path, const InterestingKeysCallback &keys) { // Objective-C generics don't preserve their generic parameters at runtime, // so they aren't able to fulfill type metadata requirements. if (type.getAnyNominal()->hasClangNode()) { return false; } auto *nominal = type.getAnyNominal(); if (!nominal->isGenericContext() || isa<ProtocolDecl>(nominal)) { return false; } bool hadFulfillment = false; GenericTypeRequirements requirements(IGM, nominal); requirements.enumerateFulfillments( IGM, type->getContextSubstitutionMap(IGM.getSwiftModule(), nominal), [&](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) { auto argState = getPresumedMetadataStateForTypeArgument(metadataState); MetadataPath argPath = path; argPath.addNominalTypeArgumentComponent(reqtIndex); hadFulfillment |= searchTypeMetadata(IGM, arg, IsExact, argState, 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); hadFulfillment |= searchWitnessTable(IGM, arg, conf->getRequirement(), source, std::move(argPath), keys); }); return hadFulfillment; }
bool FulfillmentMap::searchBoundGenericTypeMetadata(ModuleDecl &M, CanBoundGenericType type, unsigned source, MetadataPath &&path, const InterestingKeysCallback &keys) { auto params = type->getDecl()->getGenericParams()->getAllArchetypes(); auto substitutions = type->getSubstitutions(&M, nullptr); assert(params.size() >= substitutions.size() && "generic decl archetypes should parallel generic type subs"); bool hadFulfillment = false; for (unsigned i = 0, e = substitutions.size(); i != e; ++i) { auto sub = substitutions[i]; CanType arg = sub.getReplacement()->getCanonicalType(); // Skip uninteresting type arguments. if (!keys.hasInterestingType(arg)) continue; // If the argument is a type parameter, fulfill conformances for it. if (keys.isInterestingType(arg)) { hadFulfillment |= searchTypeArgConformances(M, arg, params[i], source, path, i, keys); } // Refine the path. MetadataPath argPath = path; argPath.addNominalTypeArgumentComponent(i); hadFulfillment |= searchTypeMetadata(M, arg, IsExact, source, std::move(argPath), keys); } // Also match against the parent. The polymorphic type // will start with any arguments from the parent. hadFulfillment |= searchParentTypeMetadata(M, type.getParent(), source, std::move(path), keys); 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; }