/// Emit a single protocol witness table reference. llvm::Value *irgen::emitArchetypeWitnessTableRef(IRGenFunction &IGF, CanArchetypeType archetype, ProtocolDecl *protocol) { assert(Lowering::TypeConverter::protocolRequiresWitnessTable(protocol) && "looking up witness table for protocol that doesn't have one"); // The following approach assumes that a protocol will only appear in // an archetype's conformsTo array if the archetype is either explicitly // constrained to conform to that protocol (in which case we should have // a cache entry for it) or there's an associated type declaration with // that protocol listed as a direct requirement. auto localDataKind = LocalTypeDataKind::forAbstractProtocolWitnessTable(protocol); // Check immediately for an existing cache entry. // TODO: don't give this absolute precedence over other access paths. auto wtable = IGF.tryGetLocalTypeData(archetype, localDataKind); if (wtable) return wtable; // If we don't have an environment, this must be an implied witness table // reference. // FIXME: eliminate this path when opened types have generic environments. auto environment = archetype->getGenericEnvironment(); if (!environment) { assert(archetype->isOpenedExistential() && "non-opened archetype lacking generic environment?"); SmallVector<ProtocolEntry, 4> entries; for (auto p : archetype->getConformsTo()) { const ProtocolInfo &impl = IGF.IGM.getProtocolInfo(p, ProtocolInfoKind::RequirementSignature); entries.push_back(ProtocolEntry(p, impl)); } return emitImpliedWitnessTableRef(IGF, entries, protocol, [&](unsigned index) -> llvm::Value* { auto localDataKind = LocalTypeDataKind::forAbstractProtocolWitnessTable( entries[index].getProtocol()); auto wtable = IGF.tryGetLocalTypeData(archetype, localDataKind); assert(wtable && "opened type without local type data for direct conformance?"); return wtable; }); } // Otherwise, ask the generic signature for the environment for the best // path to the conformance. // TODO: this isn't necessarily optimal if the direct conformance isn't // concretely available; we really ought to be comparing the full paths // to this conformance from concrete sources. auto signature = environment->getGenericSignature()->getCanonicalSignature(); auto archetypeDepType = archetype->getInterfaceType(); auto astPath = signature->getConformanceAccessPath(archetypeDepType, protocol); auto i = astPath.begin(), e = astPath.end(); assert(i != e && "empty path!"); // The first entry in the path is a direct requirement of the signature, // for which we should always have local type data available. CanType rootArchetype = environment->mapTypeIntoContext(i->first)->getCanonicalType(); ProtocolDecl *rootProtocol = i->second; // Turn the rest of the path into a MetadataPath. auto lastProtocol = rootProtocol; MetadataPath path; while (++i != e) { auto &entry = *i; CanType depType = CanType(entry.first); ProtocolDecl *requirement = entry.second; const ProtocolInfo &lastPI = IGF.IGM.getProtocolInfo(lastProtocol, ProtocolInfoKind::RequirementSignature); // If it's a type parameter, it's self, and this is a base protocol // requirement. if (isa<GenericTypeParamType>(depType)) { assert(depType->isEqual(lastProtocol->getSelfInterfaceType())); WitnessIndex index = lastPI.getBaseIndex(requirement); path.addInheritedProtocolComponent(index); // Otherwise, it's an associated conformance requirement. } else { AssociatedConformance association(lastProtocol, depType, requirement); WitnessIndex index = lastPI.getAssociatedConformanceIndex(association); path.addAssociatedConformanceComponent(index); } lastProtocol = requirement; } assert(lastProtocol == protocol); auto rootWTable = IGF.tryGetLocalTypeData(rootArchetype, LocalTypeDataKind::forAbstractProtocolWitnessTable(rootProtocol)); assert(rootWTable && "root witness table not bound in local context!"); wtable = path.followFromWitnessTable(IGF, rootArchetype, ProtocolConformanceRef(rootProtocol), MetadataResponse::forComplete(rootWTable), /*request*/ MetadataState::Complete, nullptr).getMetadata(); return wtable; }