//===--- ProtocolConformance.cpp - AST Protocol Conformance -----*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file implements the protocol conformance data structures. // //===----------------------------------------------------------------------===// #include "swift/Basic/Fallthrough.h" #include "swift/AST/ASTContext.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/Decl.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" #include "swift/AST/Substitution.h" #include "swift/AST/Types.h" #include "swift/AST/TypeWalker.h" using namespace swift; void *ProtocolConformance::operator new(size_t bytes, ASTContext &context, AllocationArena arena, unsigned alignment) { return context.Allocate(bytes, alignment, arena); } #define CONFORMANCE_SUBCLASS_DISPATCH(Method, Args) \ switch (getKind()) { \ case ProtocolConformanceKind::Normal: \ static_assert(&ProtocolConformance::Method != \ &NormalProtocolConformance::Method, \ "Must override NormalProtocolConformance::" #Method); \ return cast(this)->Method Args; \ case ProtocolConformanceKind::Specialized: \ static_assert(&ProtocolConformance::Method != \ &SpecializedProtocolConformance::Method, \ "Must override SpecializedProtocolConformance::" #Method); \ return cast(this)->Method Args; \ case ProtocolConformanceKind::Inherited: \ static_assert(&ProtocolConformance::Method != \ &InheritedProtocolConformance::Method, \ "Must override InheritedProtocolConformance::" #Method); \ return cast(this)->Method Args; \ } /// Get the protocol being conformed to. ProtocolDecl *ProtocolConformance::getProtocol() const { CONFORMANCE_SUBCLASS_DISPATCH(getProtocol, ()) } DeclContext *ProtocolConformance::getDeclContext() const { CONFORMANCE_SUBCLASS_DISPATCH(getDeclContext, ()) } /// Retrieve the state of this conformance. ProtocolConformanceState ProtocolConformance::getState() const { CONFORMANCE_SUBCLASS_DISPATCH(getState, ()) } const Substitution & ProtocolConformance::getTypeWitness(AssociatedTypeDecl *assocType, LazyResolver *resolver) const { CONFORMANCE_SUBCLASS_DISPATCH(getTypeWitness, (assocType, resolver)) } ConcreteDeclRef ProtocolConformance::getWitness(ValueDecl *requirement, LazyResolver *resolver) const { CONFORMANCE_SUBCLASS_DISPATCH(getWitness, (requirement, resolver)) } const InheritedConformanceMap & ProtocolConformance::getInheritedConformances() const { CONFORMANCE_SUBCLASS_DISPATCH(getInheritedConformances, ()) } /// Determine whether the witness for the given requirement /// is either the default definition or was otherwise deduced. bool ProtocolConformance::usesDefaultDefinition(ValueDecl *requirement) const { CONFORMANCE_SUBCLASS_DISPATCH(usesDefaultDefinition, (requirement)) } /// FIXME: This should be an independent property of the conformance. /// Assuming a BoundGenericType conformance is always for the /// DeclaredTypeInContext is unsound if we ever add constrained extensions. static GenericParamList *genericParamListForType(Type ty) { while (ty) { if (auto nt = ty->getAs()) ty = nt->getParent(); else break; } if (!ty) return nullptr; if (auto bgt = ty->getAs()) { auto decl = bgt->getDecl(); assert(bgt->isEqual(decl->getDeclaredTypeInContext()) && "conformance for constrained generic type not implemented"); return decl->getGenericParams(); } return nullptr; } /// Return the list of generic params that were substituted if this conformance /// was specialized somewhere along the inheritence chain. GenericParamList *ProtocolConformance::getSubstitutedGenericParams() const { const ProtocolConformance *C = this; bool FoundSpecializedConformance = false; while (true) { switch (C->getKind()) { case ProtocolConformanceKind::Inherited: // If we have an inherited protocol conformance, grab our inherited // conformance and continue. Inheritence in it of itself does not yield // additional type variables. C = cast(C)->getInheritedConformance(); continue; case ProtocolConformanceKind::Specialized: // If we have a specialized protocol conformance, since we do not support // currently partial specialization, we know that it can not have any open // type variables. C = cast(C)->getGenericConformance(); FoundSpecializedConformance = true; continue; case ProtocolConformanceKind::Normal: // If we have a normal protocol conformance and we have not seen a // specialized protocol conformance yet, we know that the normal protocol // conformance can only contain open types. Bail. if (!FoundSpecializedConformance) return nullptr; // Otherwise, this must be the original conformance containing the // specialized generic parameters. Attempt to create the param list. return genericParamListForType(C->getType()); } } } GenericParamList *ProtocolConformance::getGenericParams() const { const ProtocolConformance *C = this; while (true) { switch (C->getKind()) { case ProtocolConformanceKind::Inherited: // If we have an inherited protocol conformance, grab our inherited // conformance and continue. C = cast(C)->getInheritedConformance(); continue; case ProtocolConformanceKind::Specialized: // If we have a specialized protocol conformance, since we do not support // currently partial specialization, we know that it can not have any open // type variables. return nullptr; case ProtocolConformanceKind::Normal: // If we have a normal protocol conformance, attempt to look up its open // generic type variables. return genericParamListForType(C->getType()); } } } Type ProtocolConformance::getInterfaceType() const { switch (getKind()) { case ProtocolConformanceKind::Normal: // FIXME: This should be the type stored in the protocol conformance. // Assuming a generic conformance is always for the DeclaredTypeInContext // is unsound if we ever add constrained extensions. return getType()->getNominalOrBoundGenericNominal() ->getDeclaredInterfaceType(); case ProtocolConformanceKind::Inherited: return cast(this)->getInheritedConformance() ->getInterfaceType(); case ProtocolConformanceKind::Specialized: // Assume a specialized conformance is fully applied. return getType(); } } GenericSignature *ProtocolConformance::getGenericSignature() const { // FIXME: Should be an independent property of the conformance. // Assuming a BoundGenericType conformance is always for the // DeclaredTypeInContext is unsound if we ever add constrained extensions. return getType()->getNominalOrBoundGenericNominal() ->getGenericSignatureOfContext(); } const Substitution &NormalProtocolConformance::getTypeWitness( AssociatedTypeDecl *assocType, LazyResolver *resolver) const { auto known = TypeWitnesses.find(assocType); if (known == TypeWitnesses.end()) { assert(resolver && "Unable to resolve type witness"); resolver->resolveTypeWitness(this, assocType); known = TypeWitnesses.find(assocType); assert(known != TypeWitnesses.end() && "Didn't resolve witness?"); } return known->second; } void NormalProtocolConformance::setTypeWitness( AssociatedTypeDecl *assocType, const Substitution &substitution) const { assert(getProtocol() == cast(assocType->getDeclContext()) && "associated type in wrong protocol"); assert(TypeWitnesses.count(assocType) == 0 && "Type witness already known"); assert(!isComplete() && "Conformance already complete?"); TypeWitnesses[assocType] = substitution; } /// Retrieve the value witness corresponding to the given requirement. ConcreteDeclRef NormalProtocolConformance::getWitness( ValueDecl *requirement, LazyResolver *resolver) const { assert(!isa(requirement) && "Request type witness"); auto known = Mapping.find(requirement); if (known == Mapping.end()) { assert(resolver && "Unable to resolve witness without resolver"); resolver->resolveWitness(this, requirement); known = Mapping.find(requirement); assert(known != Mapping.end() && "Resolver did not resolve requirement"); } return known->second; } void NormalProtocolConformance::setWitness(ValueDecl *requirement, ConcreteDeclRef witness) const { assert(!isa(requirement) && "Request type witness"); assert(getProtocol() == cast(requirement->getDeclContext()) && "requirement in wrong protocol"); assert(Mapping.count(requirement) == 0 && "Witness already known"); assert(!isComplete() && "Conformance already complete?"); Mapping[requirement] = witness; } const Substitution &SpecializedProtocolConformance::getTypeWitness( AssociatedTypeDecl *assocType, LazyResolver *resolver) const { // If we've already created this type witness, return it. auto known = TypeWitnesses.find(assocType); if (known != TypeWitnesses.end()) { return known->second; } // Otherwise, perform substitutions to create this witness now. TypeSubstitutionMap substitutionMap = GenericConformance->getGenericParams() ->getSubstitutionMap(GenericSubstitutions); auto &genericWitness = GenericConformance->getTypeWitness(assocType, resolver); auto conformingDC = getDeclContext(); auto conformingModule = conformingDC->getParentModule(); auto specializedType = genericWitness.Replacement.subst(conformingModule, substitutionMap, /*ignoreMissing=*/false, resolver); // If the type witness was unchanged, just copy it directly. if (specializedType.getPointer() == genericWitness.Replacement.getPointer()) { TypeWitnesses[assocType] = genericWitness; return TypeWitnesses[assocType]; } // Gather the conformances for the type witness. These should never fail. SmallVector conformances; auto archetype = genericWitness.Archetype; for (auto proto : archetype->getConformsTo()) { auto conforms = conformingModule->lookupConformance(specializedType, proto, resolver); assert((conforms.getInt() == ConformanceKind::Conforms || specializedType->is() || specializedType->is()) && "Improperly checked substitution"); conformances.push_back(conforms.getPointer()); } // Form the substitution. auto &ctx = assocType->getASTContext(); TypeWitnesses[assocType] = Substitution{archetype, specializedType, ctx.AllocateCopy(conformances)}; return TypeWitnesses[assocType]; } ConcreteDeclRef SpecializedProtocolConformance::getWitness(ValueDecl *requirement, LazyResolver *resolver) const { // FIXME: Apply substitutions here! return GenericConformance->getWitness(requirement, resolver); } const NormalProtocolConformance * ProtocolConformance::getRootNormalConformance() const { const ProtocolConformance *C = this; while (!isa(C)) { switch (C->getKind()) { case ProtocolConformanceKind::Normal: llvm_unreachable("should have broken out of loop"); case ProtocolConformanceKind::Inherited: C = cast(C) ->getInheritedConformance(); break; case ProtocolConformanceKind::Specialized: C = cast(C) ->getGenericConformance(); break; } } return cast(C); } bool ProtocolConformance::isInheritable(LazyResolver *resolver) const { CONFORMANCE_SUBCLASS_DISPATCH(isInheritable, (resolver)) } ProtocolConformance *ProtocolConformance::subst(Module *module, Type substType, ArrayRef subs, TypeSubstitutionMap &subMap, ArchetypeConformanceMap &conformanceMap) { if (getType()->isEqual(substType)) return this; switch (getKind()) { case ProtocolConformanceKind::Normal: if (substType->isSpecialized()) { assert(getType()->isSpecialized() && "substitution mapped non-specialized to specialized?!"); assert(getType()->getNominalOrBoundGenericNominal() == substType->getNominalOrBoundGenericNominal() && "substitution mapped to different nominal?!"); return module->getASTContext() .getSpecializedConformance(substType, this, substType->gatherAllSubstitutions(module, nullptr)); } assert(substType->isEqual(getType()) && "substitution changed non-specialized type?!"); return this; case ProtocolConformanceKind::Inherited: { // Substitute the base. ProtocolConformance *newBase = cast(this)->getInheritedConformance() ->subst(module, substType, subs, subMap, conformanceMap); return module->getASTContext() .getInheritedConformance(substType, newBase); } case ProtocolConformanceKind::Specialized: { // Substitute the substitutions in the specialized conformance. auto spec = cast(this); SmallVector newSubs; newSubs.reserve(spec->getGenericSubstitutions().size()); for (auto &sub : spec->getGenericSubstitutions()) newSubs.push_back(sub.subst(module, subs, subMap, conformanceMap)); auto ctxNewSubs = module->getASTContext().AllocateCopy(newSubs); return module->getASTContext() .getSpecializedConformance(substType, spec->getGenericConformance(), ctxNewSubs); } } } 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; ArrayRef subs; switch (getKind()) { case ProtocolConformanceKind::Specialized: { auto spec = cast(this); unspecialized = spec->getGenericConformance(); subs = spec->getGenericSubstitutions(); 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()) { return getType()->getASTContext() .getSpecializedConformance(getType(), foundInherited, subs); } assert(getType()->isEqual(foundInherited->getType()) && "inherited conformance does not match type"); return foundInherited; } namespace { /// Describes whether a requirement refers to 'Self', for use in the /// is-inheritable check. enum class SelfReferenceKind { /// The type does not refer to 'Self' at all. No, /// The type refers to 'Self', but only as the result type of a method. Result, /// The type refers to 'Self' in some position that is not the result type /// of a method. Yes }; } /// Determine whether the given type is the 'Self' generic parameter /// of a protocol. static bool isSelf(Type type) { if (auto genericParam = type->getAs()) { return genericParam->getDepth() == 0 && genericParam->getIndex() == 0; } return false; } /// Determine whether the given type contains a reference to the /// 'Self' generic parameter of a protocol that is not the base of a /// dependent member expression. static bool containsSelf(Type type) { struct SelfWalker : public TypeWalker { bool FoundSelf = false; virtual Action walkToTypePre(Type ty) { // If we found a reference to 'Self', note it and stop. if (isSelf(ty)) { FoundSelf = true; return Action::Stop; } // Don't recurse into the base of a dependent member type: it // doesn't contain a bare 'Self'. if (ty->is()) return Action::SkipChildren; return Action::Continue; } } selfWalker; type.walk(selfWalker); return selfWalker.FoundSelf; } /// Find the bare Self references within the given requirement. static SelfReferenceKind findSelfReferences(ValueDecl *value) { // Types never refer to 'Self'. if (isa(value)) return SelfReferenceKind::No; // If the function requirement returns Self and has no other // reference to Self, note that. if (auto afd = dyn_cast(value)) { auto type = afd->getInterfaceType(); // Skip the 'self' type. type = type->castTo()->getResult(); for (unsigned i = 1, n = afd->getNumParamPatterns(); i != n; ++i) { // Check whether the input type contains Self anywhere. auto fnType = type->castTo(); if (containsSelf(fnType->getInput())) return SelfReferenceKind::Yes; type = fnType->getResult(); } // For constructors, we're done. if (isa(afd)) return SelfReferenceKind::No; // The result type remains. auto func = cast(afd); return (isSelf(type) || func->hasDynamicSelf()) ? SelfReferenceKind::Result : containsSelf(type) ? SelfReferenceKind::Yes : SelfReferenceKind::No; } auto type = value->getInterfaceType(); return containsSelf(type) ? SelfReferenceKind::Yes : SelfReferenceKind::No; } bool NormalProtocolConformance::isInheritableSlow(LazyResolver *resolver) const{ auto classDecl = getType()->getClassOrBoundGenericClass(); assert(classDecl && "Conformance can't be inheritable, ever"); (void)classDecl; for (auto member : getProtocol()->getMembers()) { auto req = dyn_cast(member); if (!req) continue; // Skip accessors. if (isa(req) && cast(req)->isAccessor()) continue; // A non-abstract initializer witness makes the conformance non-inheritable. if (isa(req)) { auto ctorWitness = cast_or_null( getWitness(req, resolver).getDecl()); if (ctorWitness && !ctorWitness->isRequired()) { DCAndInheritable.setInt(IsInheritableKind::NotInheritable); return false; } } // Check the kinds of references to Self that show up in the given // requirement. switch (findSelfReferences(req)) { case SelfReferenceKind::No: continue; case SelfReferenceKind::Result: { // When only the result type is 'Self', we can inherit the // conformance if the witness returns DynamicSelf. auto func = cast_or_null( getWitness(req, resolver).getDecl()); if (func && func->hasDynamicSelf()) continue; // Fall through. SWIFT_FALLTHROUGH; } case SelfReferenceKind::Yes: { DCAndInheritable.setInt(IsInheritableKind::NotInheritable); return false; } } } // Note that this conformance is inheritable. DCAndInheritable.setInt(IsInheritableKind::Inheritable); return true; }