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; }
clang::CanQualType GenClangType::visitBoundGenericType(CanBoundGenericType type) { // We only expect *Pointer<T>, ImplicitlyUnwrappedOptional<T>, and Optional<T>. // The first two are structs; the last is an enum. if (auto underlyingTy = SILType::getPrimitiveObjectType(type).getAnyOptionalObjectType()) { // The underlying type could be a bridged type, which makes any // sort of casual assertion here difficult. return Converter.convert(IGM, underlyingTy.getSwiftRValueType()); } auto swiftStructDecl = type->getDecl(); enum class StructKind { Invalid, UnsafeMutablePointer, UnsafePointer, AutoreleasingUnsafeMutablePointer, Unmanaged, CFunctionPointer, } kind = llvm::StringSwitch<StructKind>(swiftStructDecl->getName().str()) .Case("UnsafeMutablePointer", StructKind::UnsafeMutablePointer) .Case("UnsafePointer", StructKind::UnsafePointer) .Case( "AutoreleasingUnsafeMutablePointer", StructKind::AutoreleasingUnsafeMutablePointer) .Case("Unmanaged", StructKind::Unmanaged) .Case("CFunctionPointer", StructKind::CFunctionPointer) .Default(StructKind::Invalid); auto args = type.getGenericArgs(); switch (kind) { case StructKind::Invalid: llvm_unreachable("Unexpected non-pointer generic struct type in imported" " Clang module!"); case StructKind::UnsafeMutablePointer: case StructKind::Unmanaged: case StructKind::AutoreleasingUnsafeMutablePointer: { assert(args.size() == 1 && "*Pointer<T> should have a single generic argument!"); auto clangCanTy = Converter.convert(IGM, args.front()); if (!clangCanTy) return clang::CanQualType(); return getClangASTContext().getPointerType(clangCanTy); } case StructKind::UnsafePointer: { assert(args.size() == 1 && "*Pointer<T> should have a single generic argument!"); clang::QualType clangTy = Converter.convert(IGM, args.front()).withConst(); return getCanonicalType(getClangASTContext().getPointerType(clangTy)); } case StructKind::CFunctionPointer: { auto &clangCtx = getClangASTContext(); assert(args.size() == 1 && "CFunctionPointer should have a single generic argument!"); clang::QualType functionTy; if (auto ft = dyn_cast<FunctionType>(args[0])) { functionTy = convertFunctionType(ft); } else { // Fall back to void(). functionTy = clangCtx.getFunctionNoProtoType(clangCtx.VoidTy); } auto fnPtrTy = clangCtx.getPointerType(functionTy); return getCanonicalType(fnPtrTy); } } llvm_unreachable("Not a valid StructKind."); }
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; }