int ConformanceLookupTable::compareProtocolConformances( ProtocolConformance * const *lhsPtr, ProtocolConformance * const *rhsPtr) { ProtocolConformance *lhs = *lhsPtr; ProtocolConformance *rhs = *rhsPtr; // If the two conformances are normal conformances with locations, // sort by location. if (auto lhsNormal = dyn_cast<NormalProtocolConformance>(lhs)) { if (auto rhsNormal = dyn_cast<NormalProtocolConformance>(rhs)) { if (lhsNormal->getLoc().isValid() && rhsNormal->getLoc().isValid()) { ASTContext &ctx = lhs->getDeclContext()->getASTContext(); unsigned lhsBuffer = ctx.SourceMgr.findBufferContainingLoc(lhsNormal->getLoc()); unsigned rhsBuffer = ctx.SourceMgr.findBufferContainingLoc(rhsNormal->getLoc()); // If the buffers are the same, use source location ordering. if (lhsBuffer == rhsBuffer) { return ctx.SourceMgr.isBeforeInBuffer(lhsNormal->getLoc(), rhsNormal->getLoc()); } // Otherwise, order by buffer identifier. return StringRef(ctx.SourceMgr.getIdentifierForBuffer(lhsBuffer)) .compare(ctx.SourceMgr.getIdentifierForBuffer(rhsBuffer)); } } } // Otherwise, sort by protocol. ProtocolDecl *lhsProto = lhs->getProtocol(); ProtocolDecl *rhsProto = rhs->getProtocol(); return ProtocolType::compareProtocols(&lhsProto, &rhsProto); }
void layout() { // If the conforming type is generic, we just want to emit the // unbound generic type here. auto *Nominal = Conformance->getInterfaceType()->getAnyNominal(); assert(Nominal && "Structural conformance?"); PrettyStackTraceDecl DebugStack("emitting associated type metadata", Nominal); auto *M = IGM.getSILModule().getSwiftModule(); addTypeRef(M, Nominal->getDeclaredType()->getCanonicalType()); auto ProtoTy = Conformance->getProtocol()->getDeclaredType(); addTypeRef(M, ProtoTy->getCanonicalType()); addConstantInt32(AssociatedTypes.size()); addConstantInt32(AssociatedTypeRecordSize); for (auto AssocTy : AssociatedTypes) { auto NameGlobal = IGM.getAddrOfStringForTypeRef(AssocTy.first); addRelativeAddress(NameGlobal); addBuiltinTypeRefs(AssocTy.second); addTypeRef(M, AssocTy.second); } }
/// Compare two declarations to determine whether one is a witness of the other. static Comparison compareWitnessAndRequirement(TypeChecker &tc, DeclContext *dc, ValueDecl *decl1, ValueDecl *decl2) { // We only have a witness/requirement pair if exactly one of the declarations // comes from a protocol. auto proto1 = dyn_cast<ProtocolDecl>(decl1->getDeclContext()); auto proto2 = dyn_cast<ProtocolDecl>(decl2->getDeclContext()); if ((bool)proto1 == (bool)proto2) return Comparison::Unordered; // Figure out the protocol, requirement, and potential witness. ProtocolDecl *proto; ValueDecl *req; ValueDecl *potentialWitness; if (proto1) { proto = proto1; req = decl1; potentialWitness = decl2; } else { proto = proto2; req = decl2; potentialWitness = decl1; } // Cannot compare type declarations this way. // FIXME: Use the same type-substitution approach as lookupMemberType. if (isa<TypeDecl>(req)) return Comparison::Unordered; if (!potentialWitness->getDeclContext()->isTypeContext()) return Comparison::Unordered; // Determine whether the type of the witness's context conforms to the // protocol. auto owningType = potentialWitness->getDeclContext()->getDeclaredTypeInContext(); ProtocolConformance *conformance = nullptr; if (!tc.conformsToProtocol(owningType, proto, dc, ConformanceCheckFlags::InExpression, &conformance) || !conformance) return Comparison::Unordered; // If the witness and the potential witness are not the same, there's no // ordering here. if (conformance->getWitness(req, &tc).getDecl() != potentialWitness) return Comparison::Unordered; // We have a requirement/witness match. return proto1? Comparison::Worse : Comparison::Better; }
void layout() override { // If the conforming type is generic, we just want to emit the // unbound generic type here. auto *Nominal = Conformance->getType()->getAnyNominal(); assert(Nominal && "Structural conformance?"); PrettyStackTraceDecl DebugStack("emitting associated type metadata", Nominal); addTypeRef(Nominal->getDeclaredType()->getCanonicalType()); addNominalRef(Conformance->getProtocol()); B.addInt32(AssociatedTypes.size()); B.addInt32(AssociatedTypeRecordSize); for (auto AssocTy : AssociatedTypes) { auto NameGlobal = IGM.getAddrOfFieldName(AssocTy.first); B.addRelativeAddress(NameGlobal); addBuiltinTypeRefs(AssocTy.second); addTypeRef(AssocTy.second); } }
LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, Type type, Identifier name, NameLookupOptions options) { LookupTypeResult result; // Look through an inout type. if (auto inout = type->getAs<InOutType>()) type = inout->getObjectType(); // Look through the metatype. if (auto metaT = type->getAs<AnyMetatypeType>()) type = metaT->getInstanceType(); // Callers must cope with dependent types directly. assert(!type->isTypeParameter()); // Look for members with the given name. SmallVector<ValueDecl *, 4> decls; NLOptions subOptions = NL_QualifiedDefault | NL_OnlyTypes; if (options.contains(NameLookupFlags::KnownPrivate)) subOptions |= NL_KnownNonCascadingDependency; if (options.contains(NameLookupFlags::ProtocolMembers)) subOptions |= NL_ProtocolMembers; if (options.contains(NameLookupFlags::IgnoreAccessibility)) subOptions |= NL_IgnoreAccessibility; if (!dc->lookupQualified(type, name, subOptions, this, decls)) return result; // Look through the declarations, keeping only the unique type declarations. llvm::SmallPtrSet<CanType, 4> types; SmallVector<AssociatedTypeDecl *, 4> inferredAssociatedTypes; for (auto decl : decls) { auto *typeDecl = cast<TypeDecl>(decl); // FIXME: This should happen before we attempt shadowing checks. validateDecl(typeDecl); if (!typeDecl->hasType()) // FIXME: recursion-breaking hack continue; // If we're looking up a member of a protocol, we must take special care. if (typeDecl->getDeclContext()->getAsProtocolOrProtocolExtensionContext()) { // We don't allow lookups of an associated type or typealias of an // existential type, because we have no way to represent such types. // // This is diagnosed further on down in resolveNestedIdentTypeComponent(). if (type->isExistentialType()) { auto memberType = typeDecl->getInterfaceType()->getRValueInstanceType(); if (memberType->hasTypeParameter()) { // If we haven't seen this type result yet, add it to the result set. if (types.insert(memberType->getCanonicalType()).second) result.Results.push_back({typeDecl, memberType}); continue; } } // If we're looking up an associated type of a concrete type, // record it later for conformance checking; we might find a more // direct typealias with the same name later. if (auto assocType = dyn_cast<AssociatedTypeDecl>(typeDecl)) { if (!type->is<ArchetypeType>()) { inferredAssociatedTypes.push_back(assocType); continue; } } // We are looking up an associated type of an archetype, or a // protocol typealias or an archetype or concrete type. // // Proceed with the usual path below. } // Substitute the base into the member's type. auto memberType = substMemberTypeWithBase(dc->getParentModule(), typeDecl, type, /*isTypeReference=*/true); // FIXME: It is not clear why this substitution can fail, but the // standard library won't build without this check. if (!memberType) continue; // If we haven't seen this type result yet, add it to the result set. if (types.insert(memberType->getCanonicalType()).second) result.Results.push_back({typeDecl, memberType}); } if (result.Results.empty()) { // We couldn't find any normal declarations. Let's try inferring // associated types. ConformanceCheckOptions conformanceOptions; if (options.contains(NameLookupFlags::KnownPrivate)) conformanceOptions |= ConformanceCheckFlags::InExpression; for (AssociatedTypeDecl *assocType : inferredAssociatedTypes) { // If the type does not actually conform to the protocol, skip this // member entirely. auto *protocol = cast<ProtocolDecl>(assocType->getDeclContext()); ProtocolConformance *conformance = nullptr; if (!conformsToProtocol(type, protocol, dc, conformanceOptions, &conformance) || !conformance) { // FIXME: This is an error path. Should we try to recover? continue; } // Use the type witness. Type memberType = conformance->getTypeWitness(assocType, this).getReplacement(); assert(memberType && "Missing type witness?"); // If we haven't seen this type result yet, add it to the result set. if (types.insert(memberType->getCanonicalType()).second) result.Results.push_back({assocType, memberType}); } } return result; }
LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, Type type, Identifier name, NameLookupOptions options) { LookupTypeResult result; // Look through an inout type. if (auto inout = type->getAs<InOutType>()) type = inout->getObjectType(); // Look through the metatype. if (auto metaT = type->getAs<AnyMetatypeType>()) type = metaT->getInstanceType(); // Callers must cope with dependent types directly. assert(!type->isTypeParameter()); // Look for members with the given name. SmallVector<ValueDecl *, 4> decls; NLOptions subOptions = NL_QualifiedDefault; if (options.contains(NameLookupFlags::KnownPrivate)) subOptions |= NL_KnownNonCascadingDependency; if (options.contains(NameLookupFlags::ProtocolMembers)) subOptions |= NL_ProtocolMembers; if (options.contains(NameLookupFlags::IgnoreAccessibility)) subOptions |= NL_IgnoreAccessibility; if (!dc->lookupQualified(type, name, subOptions, this, decls)) return result; // Look through the declarations, keeping only the unique type declarations. llvm::SmallPtrSet<CanType, 4> types; SmallVector<AssociatedTypeDecl *, 4> inferredAssociatedTypes; for (auto decl : decls) { // Ignore non-types found by name lookup. auto typeDecl = dyn_cast<TypeDecl>(decl); if (!typeDecl) continue; // FIXME: This should happen before we attempt shadowing checks. validateDecl(typeDecl); if (!typeDecl->hasType()) // FIXME: recursion-breaking hack continue; // If we found a member of a protocol type when looking into a non-protocol, // non-archetype type, only include this member in the result set if // this member was used as the default definition or otherwise inferred. if (auto assocType = dyn_cast<AssociatedTypeDecl>(typeDecl)) { if (!type->is<ArchetypeType>() && !type->isExistentialType()) { inferredAssociatedTypes.push_back(assocType); continue; } } // Ignore typealiases found in protocol members. if (auto alias = dyn_cast<TypeAliasDecl>(typeDecl)) { auto aliasParent = alias->getParent(); if (aliasParent != dc && isa<ProtocolDecl>(aliasParent)) continue; } // Substitute the base into the member's type. if (Type memberType = substMemberTypeWithBase(dc->getParentModule(), typeDecl, type, /*isTypeReference=*/true)) { // If we haven't seen this type result yet, add it to the result set. if (types.insert(memberType->getCanonicalType()).second) result.Results.push_back({typeDecl, memberType}); } } if (result.Results.empty()) { // We couldn't find any normal declarations. Let's try inferring // associated types. ConformanceCheckOptions conformanceOptions; if (options.contains(NameLookupFlags::KnownPrivate)) conformanceOptions |= ConformanceCheckFlags::InExpression; for (AssociatedTypeDecl *assocType : inferredAssociatedTypes) { // If the type does not actually conform to the protocol, skip this // member entirely. auto *protocol = cast<ProtocolDecl>(assocType->getDeclContext()); ProtocolConformance *conformance = nullptr; if (!conformsToProtocol(type, protocol, dc, conformanceOptions, &conformance) || !conformance) { // FIXME: This is an error path. Should we try to recover? continue; } // Use the type witness. Type memberType = conformance->getTypeWitness(assocType, this).getReplacement(); assert(memberType && "Missing type witness?"); // If we haven't seen this type result yet, add it to the result set. if (types.insert(memberType->getCanonicalType()).second) result.Results.push_back({assocType, memberType}); } } return result; }
ProtocolConformance * ProtocolConformance::getInheritedConformance(ProtocolDecl *protocol) const { // Preserve specialization through this operation by peeling off the // substitutions from a specialized conformance so we can apply them later. const ProtocolConformance *unspecialized; SubstitutionIterator subs; switch (getKind()) { case ProtocolConformanceKind::Specialized: { auto spec = cast<SpecializedProtocolConformance>(this); unspecialized = spec->getGenericConformance(); subs = spec->getGenericSubstitutionIterator(); break; } case ProtocolConformanceKind::Normal: case ProtocolConformanceKind::Inherited: unspecialized = this; break; } ProtocolConformance *foundInherited; // Search for the inherited conformance among our immediate parents. auto &inherited = unspecialized->getInheritedConformances(); auto known = inherited.find(protocol); if (known != inherited.end()) { foundInherited = known->second; goto found_inherited; } // If not there, the inherited conformance must be available through one of // our parents. for (auto &inheritedMapping : inherited) if (inheritedMapping.first->inheritsFrom(protocol)) { foundInherited = inheritedMapping.second-> getInheritedConformance(protocol); goto found_inherited; } llvm_unreachable("Can't find the inherited conformance."); found_inherited: // Specialize the inherited conformance, if necessary. if (!subs.empty()) { TypeSubstitutionMap subMap; ArchetypeConformanceMap conformanceMap; // Fill in the substitution and conformance maps. for (auto archAndSub : subs) { auto arch = archAndSub.first; auto sub = archAndSub.second; conformanceMap[arch] = sub.getConformances(); if (arch->isPrimary()) subMap[arch] = sub.getReplacement(); } return foundInherited->subst(getDeclContext()->getParentModule(), getType(), subs.getSubstitutions(), subMap, conformanceMap); } assert((getType()->isEqual(foundInherited->getType()) || foundInherited->getType()->isSuperclassOf(getType(), nullptr)) && "inherited conformance does not match type"); return foundInherited; }