void ConformanceLookupTable::expandImpliedConformances(NominalTypeDecl *nominal, DeclContext *dc, LazyResolver *resolver) { // Note: recursive type-checking implies that AllConformances // may be reallocated during this traversal, so pay the lookup cost // during each iteration. for (unsigned i = 0; i != AllConformances[dc].size(); ++i) { /// FIXME: Avoid the possibility of an infinite loop by fixing the root /// cause instead (incomplete circularity detection). assert(i <= 16384 && "Infinite loop due to circular protocol inheritance?"); ConformanceEntry *conformanceEntry = AllConformances[dc][i]; ProtocolDecl *conformingProtocol = conformanceEntry->getProtocol(); // Visit the protocols inherited by this protocol, adding them as // implied conformances. if (resolver) { if (nominal == dc) resolver->resolveInheritanceClause(nominal); else resolver->resolveInheritanceClause(cast<ExtensionDecl>(dc)); } // An @objc enum that explicitly conforms to the Error protocol // also implicitly conforms to _ObjectiveCBridgeableError, via the // known protocol _BridgedNSError. if (conformingProtocol->isSpecificProtocol( KnownProtocolKind::Error) && isa<EnumDecl>(nominal) && nominal->isObjC() && cast<EnumDecl>(nominal)->hasOnlyCasesWithoutAssociatedValues()) { ASTContext &ctx = nominal->getASTContext(); if (auto bridgedNSError = ctx.getProtocol(KnownProtocolKind::BridgedNSError)) { addProtocol(nominal, bridgedNSError, SourceLoc(), ConformanceSource::forImplied(conformanceEntry)); } } // Add inherited protocols. addProtocols(nominal, conformingProtocol->getInherited(), ConformanceSource::forImplied(conformanceEntry), resolver); } }
static void initDocGenericParams(const Decl *D, DocEntityInfo &Info) { auto *DC = dyn_cast<DeclContext>(D); if (DC == nullptr || !DC->isInnermostContextGeneric()) return; GenericSignature *GenericSig = DC->getGenericSignatureOfContext(); if (!GenericSig) return; // FIXME: Not right for extensions of nested generic types for (auto *GP : GenericSig->getInnermostGenericParams()) { if (GP->getDecl()->isImplicit()) continue; DocGenericParam Param; Param.Name = GP->getName().str(); Info.GenericParams.push_back(Param); } ProtocolDecl *proto = nullptr; if (auto *typeDC = DC->getInnermostTypeContext()) proto = typeDC->getAsProtocolOrProtocolExtensionContext(); for (auto &Req : GenericSig->getRequirements()) { if (Req.getKind() == RequirementKind::WitnessMarker) continue; // Skip protocol Self requirement. if (proto && Req.getKind() == RequirementKind::Conformance && Req.getFirstType()->isEqual(proto->getSelfInterfaceType()) && Req.getSecondType()->getAnyNominal() == proto) continue; std::string ReqStr; PrintOptions Opts; llvm::raw_string_ostream OS(ReqStr); Req.print(OS, Opts); OS.flush(); Info.GenericRequirements.push_back(std::move(ReqStr)); } }
Substitution Substitution::subst(Module *module, ArrayRef<Substitution> subs, TypeSubstitutionMap &subMap, ArchetypeConformanceMap &conformanceMap) const { // Substitute the replacement. Type substReplacement = Replacement.subst(module, subMap, None); assert(substReplacement && "substitution replacement failed"); if (substReplacement->isEqual(Replacement)) return *this; if (Conformance.empty()) { return {substReplacement, Conformance}; } bool conformancesChanged = false; SmallVector<ProtocolConformanceRef, 4> substConformances; substConformances.reserve(Conformance.size()); for (auto c : Conformance) { // If we have a concrete conformance, we need to substitute the // conformance to apply to the new type. if (c.isConcrete()) { auto substC = c.getConcrete()->subst(module, substReplacement, subs, subMap, conformanceMap); substConformances.push_back(ProtocolConformanceRef(substC)); if (c != substConformances.back()) conformancesChanged = true; continue; } // Otherwise, we may need to fill in the conformance. ProtocolDecl *proto = c.getAbstract(); Optional<ProtocolConformanceRef> conformance; // If the original type was an archetype, check the conformance map. if (auto replacementArch = Replacement->getAs<ArchetypeType>()) { // Check for conformances for the type that apply to the original // substituted archetype. auto it = conformanceMap.find(replacementArch); assert(it != conformanceMap.end()); for (ProtocolConformanceRef found : it->second) { auto foundProto = found.getRequirement(); if (foundProto == proto) { conformance = found; break; } else if (foundProto->inheritsFrom(proto)) { if (found.isConcrete()) { conformance = ProtocolConformanceRef( found.getConcrete()->getInheritedConformance(proto)); } else { conformance = found; } break; } } } // If that didn't find anything, we can still synthesize AnyObject // conformances from thin air. FIXME: gross. if (!conformance && proto->isSpecificProtocol(KnownProtocolKind::AnyObject)) { auto classDecl = substReplacement->getClassOrBoundGenericClass(); SmallVector<ProtocolConformance *, 1> lookupResults; classDecl->lookupConformance(classDecl->getParentModule(), proto, lookupResults); conformance = ProtocolConformanceRef(lookupResults.front()); } if (conformance) { if (conformance->isConcrete()) conformancesChanged = true; substConformances.push_back(*conformance); } else { assert(substReplacement->hasDependentProtocolConformances() && "couldn't find concrete conformance for concrete type?"); substConformances.push_back(ProtocolConformanceRef(proto)); } } assert(substConformances.size() == Conformance.size()); ArrayRef<ProtocolConformanceRef> substConfs; if (conformancesChanged) substConfs = module->getASTContext().AllocateCopy(substConformances); else substConfs = Conformance; return Substitution{substReplacement, substConfs}; }