/// Given that we have a source for metadata of the given type, check /// to see if it fulfills anything. /// /// \param isExact - true if the metadata is known to be exactly the /// metadata for the given type, false if it might be a subtype bool FulfillmentMap::searchTypeMetadata(IRGenModule &IGM, CanType type, IsExact_t isExact, MetadataState metadataState, unsigned source, MetadataPath &&path, const InterestingKeysCallback &keys) { // If this is an exact source, and it's an interesting type, add this // as a fulfillment. if (isExact && keys.isInterestingType(type)) { // If the type isn't a leaf type, also check it as an inexact match. bool hadFulfillment = false; if (!isLeafTypeMetadata(type)) { hadFulfillment |= searchTypeMetadata(IGM, type, IsInexact, metadataState, source, MetadataPath(path), keys); } // Consider its super class bound. if (metadataState == MetadataState::Complete) { if (auto superclassTy = keys.getSuperclassBound(type)) { hadFulfillment |= searchNominalTypeMetadata( IGM, superclassTy, metadataState, source, std::move(path), keys); } } // Add the fulfillment. hadFulfillment |= addFulfillment({type, nullptr}, source, std::move(path), metadataState); return hadFulfillment; } // Search the superclass fields. We can only do this if the metadata // is complete. if (metadataState == MetadataState::Complete && keys.isInterestingType(type)) { if (auto superclassTy = keys.getSuperclassBound(type)) { return searchNominalTypeMetadata(IGM, superclassTy, metadataState, source, std::move(path), keys); } } // Inexact metadata will be a problem if we ever try to use this // to remember that we already have the metadata for something. if (isa<NominalType>(type) || isa<BoundGenericType>(type)) { return searchNominalTypeMetadata(IGM, type, metadataState, source, std::move(path), keys); } // TODO: tuples // TODO: functions // TODO: metatypes return false; }
/// 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::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; }
/// Given that we have a source for metadata of the given type, check /// to see if it fulfills anything. /// /// \param isExact - true if the metadata is known to be exactly the /// metadata for the given type, false if it might be a subtype bool FulfillmentMap::searchTypeMetadata(IRGenModule &IGM, CanType type, IsExact_t isExact, unsigned source, MetadataPath &&path, const InterestingKeysCallback &keys) { // If this is an exact source, and it's an interesting type, add this // as a fulfillment. if (isExact && keys.isInterestingType(type)) { // If the type isn't a leaf type, also check it as an inexact match. bool hadFulfillment = false; if (!isLeafTypeMetadata(type)) { hadFulfillment |= searchTypeMetadata(IGM, type, IsInexact, source, MetadataPath(path), keys); } // Add the fulfillment. hadFulfillment |= addFulfillment({type, nullptr}, source, std::move(path)); return hadFulfillment; } // Inexact metadata will be a problem if we ever try to use this // to remember that we already have the metadata for something. if (auto nomTy = dyn_cast<NominalType>(type)) { return searchNominalTypeMetadata(IGM, nomTy, source, std::move(path), keys); } if (auto boundTy = dyn_cast<BoundGenericType>(type)) { return searchBoundGenericTypeMetadata(IGM, boundTy, source, std::move(path), keys); } // TODO: tuples // TODO: functions // TODO: metatypes return false; }
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; }