diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 14852dcc3a2f4..9416e6d3f4e76 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -2372,6 +2372,9 @@ class TypeDecl : public ValueDecl { return D->getKind() >= DeclKind::First_TypeDecl && D->getKind() <= DeclKind::Last_TypeDecl; } + + /// Compute an ordering between two type declarations that is ABI-stable. + static int compare(const TypeDecl *type1, const TypeDecl *type2); }; /// A type declaration that can have generic parameters attached to it. Because diff --git a/include/swift/AST/DeclContext.h b/include/swift/AST/DeclContext.h index aafc243887132..b3ba6625ad90e 100644 --- a/include/swift/AST/DeclContext.h +++ b/include/swift/AST/DeclContext.h @@ -494,6 +494,19 @@ class alignas(1 << DeclContextAlignInBits) DeclContext { = nullptr, bool sorted = false) const; + /// Retrieve the syntactic depth of this declaration context, i.e., + /// the number of non-module-scoped contexts. + /// + /// For an extension of a nested type, the extension is depth 1. + unsigned getSyntacticDepth() const; + + /// Retrieve the semantic depth of this declaration context, i.e., + /// the number of non-module-scoped contexts. + /// + /// For an extension of a nested type, the depth of the nested type itself + /// is also included. + unsigned getSemanticDepth() const; + /// \returns true if traversal was aborted, false otherwise. bool walkContext(ASTWalker &Walker); diff --git a/include/swift/AST/GenericSignatureBuilder.h b/include/swift/AST/GenericSignatureBuilder.h index cac90b3c6f2f1..f44ad76962d91 100644 --- a/include/swift/AST/GenericSignatureBuilder.h +++ b/include/swift/AST/GenericSignatureBuilder.h @@ -1248,7 +1248,7 @@ class GenericSignatureBuilder::PotentialArchetype { Identifier name; /// The associated type or typealias for a resolved nested type. - TypeDecl *assocTypeOrAlias; + TypeDecl *assocTypeOrConcrete; /// The generic parameter key for a root. GenericParamKey genericParam; @@ -1256,10 +1256,10 @@ class GenericSignatureBuilder::PotentialArchetype { PAIdentifier(Identifier name) : name(name) { } PAIdentifier(AssociatedTypeDecl *assocType) - : assocTypeOrAlias(assocType) { } + : assocTypeOrConcrete(assocType) { } - PAIdentifier(TypeAliasDecl *typeAlias) - : assocTypeOrAlias(typeAlias) { } + PAIdentifier(TypeDecl *concreteDecl) + : assocTypeOrConcrete(concreteDecl) { } PAIdentifier(GenericParamKey genericParam) : genericParam(genericParam) { } } identifier; @@ -1342,9 +1342,9 @@ class GenericSignatureBuilder::PotentialArchetype { assert(parent != nullptr && "Not an associated type?"); } - /// \brief Construct a new potential archetype for a type alias. - PotentialArchetype(PotentialArchetype *parent, TypeAliasDecl *typeAlias) - : parentOrBuilder(parent), identifier(typeAlias), + /// \brief Construct a new potential archetype for a concrete declaration. + PotentialArchetype(PotentialArchetype *parent, TypeDecl *concreteDecl) + : parentOrBuilder(parent), identifier(concreteDecl), isUnresolvedNestedType(false), IsRecursive(false), Invalid(false), DiagnosedRename(false) @@ -1396,16 +1396,19 @@ class GenericSignatureBuilder::PotentialArchetype { if (isUnresolvedNestedType) return nullptr; - return dyn_cast(identifier.assocTypeOrAlias); + return dyn_cast(identifier.assocTypeOrConcrete); } + /// Determine whether this PA is still unresolved. + bool isUnresolved() const { return isUnresolvedNestedType; } + /// Resolve the potential archetype to the given associated type. void resolveAssociatedType(AssociatedTypeDecl *assocType, GenericSignatureBuilder &builder); /// Resolve the potential archetype to the given typealias. - void resolveTypeAlias(TypeAliasDecl *typealias, - GenericSignatureBuilder &builder); + void resolveConcreteType(TypeDecl *concreteDecl, + GenericSignatureBuilder &builder); /// Determine whether this is a generic parameter. bool isGenericParam() const { @@ -1436,16 +1439,19 @@ class GenericSignatureBuilder::PotentialArchetype { if (isUnresolvedNestedType) return identifier.name; - return identifier.assocTypeOrAlias->getName(); + return identifier.assocTypeOrConcrete->getName(); } - /// Retrieve the type alias. - TypeAliasDecl *getTypeAliasDecl() const { + /// Retrieve the concrete type declaration. + TypeDecl *getConcreteTypeDecl() const { assert(getParent() && "not a nested type"); if (isUnresolvedNestedType) return nullptr; - return dyn_cast(identifier.assocTypeOrAlias); + if (isa(identifier.assocTypeOrConcrete)) + return nullptr; + + return identifier.assocTypeOrConcrete; } /// Retrieve the set of protocols to which this potential archetype @@ -1548,8 +1554,9 @@ class GenericSignatureBuilder::PotentialArchetype { PotentialArchetype *getNestedType(AssociatedTypeDecl *assocType, GenericSignatureBuilder &builder); - /// \brief Retrieve (or create) a nested type with a known typealias. - PotentialArchetype *getNestedType(TypeAliasDecl *typealias, + /// \brief Retrieve (or create) a nested type with a known concrete type + /// declaration. + PotentialArchetype *getNestedType(TypeDecl *concreteDecl, GenericSignatureBuilder &builder); /// Describes the kind of update that is performed. @@ -1581,7 +1588,7 @@ class GenericSignatureBuilder::PotentialArchetype { /// type or typealias of the given protocol, unless the \c kind implies that /// a potential archetype should not be created if it's missing. PotentialArchetype *updateNestedTypeForConformance( - PointerUnion type, + PointerUnion type, NestedTypeUpdate kind); /// Update the named nested type when we know this type conforms to the given diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 412a0abbb7a8c..fc702ac4af5e3 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2067,6 +2067,47 @@ Type TypeDecl::getDeclaredInterfaceType() const { return interfaceType->castTo()->getInstanceType(); } +int TypeDecl::compare(const TypeDecl *type1, const TypeDecl *type2) { + // Order based on the enclosing declaration. + auto dc1 = type1->getDeclContext(); + auto dc2 = type2->getDeclContext(); + + // Prefer lower depths. + auto depth1 = dc1->getSemanticDepth(); + auto depth2 = dc2->getSemanticDepth(); + if (depth1 != depth2) + return depth1 < depth2 ? -1 : +1; + + // Prefer module names earlier in the alphabet. + if (dc1->isModuleScopeContext() && dc2->isModuleScopeContext()) { + auto module1 = dc1->getParentModule(); + auto module2 = dc2->getParentModule(); + if (int result = module1->getName().str().compare(module2->getName().str())) + return result; + } + + auto nominal1 = dc1->getAsNominalTypeOrNominalTypeExtensionContext(); + auto nominal2 = dc2->getAsNominalTypeOrNominalTypeExtensionContext(); + if (static_cast(nominal1) != static_cast(nominal2)) { + return static_cast(nominal1) ? -1 : +1; + } + if (nominal1 && nominal2) { + if (int result = compare(nominal1, nominal2)) + return result; + } + + if (int result = type1->getBaseName().getIdentifier().str().compare( + type2->getBaseName().getIdentifier().str())) + return result; + + // Error case: two type declarations that cannot be distinguished. + if (type1 < type2) + return -1; + if (type1 > type2) + return +1; + return 0; +} + bool NominalTypeDecl::hasFixedLayout() const { // Private and (unversioned) internal types always have a // fixed layout. diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index 4926db30679a9..4d5bfdbf3b5b6 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -656,6 +656,30 @@ DeclContext::isCascadingContextForLookup(bool functionsAreNonCascading) const { return getParent()->isCascadingContextForLookup(true); } +unsigned DeclContext::getSyntacticDepth() const { + // Module scope == depth 0. + if (isModuleScopeContext()) + return 0; + + return 1 + getParent()->getSyntacticDepth(); +} + +unsigned DeclContext::getSemanticDepth() const { + // For extensions, count the depth of the nominal type being extended. + if (auto ext = dyn_cast(this)) { + if (auto nominal = getAsNominalTypeOrNominalTypeExtensionContext()) + return nominal->getSemanticDepth(); + + return 1; + } + + // Module scope == depth 0. + if (isModuleScopeContext()) + return 0; + + return 1 + getParent()->getSemanticDepth(); +} + bool DeclContext::walkContext(ASTWalker &Walker) { switch (getContextKind()) { case DeclContextKind::Module: diff --git a/lib/AST/GenericEnvironment.cpp b/lib/AST/GenericEnvironment.cpp index 1292e2f976e0d..979f8995d8033 100644 --- a/lib/AST/GenericEnvironment.cpp +++ b/lib/AST/GenericEnvironment.cpp @@ -33,17 +33,6 @@ GenericEnvironment::GenericEnvironment(GenericSignature *signature, Type()); } -/// Compute the depth of the \c DeclContext chain. -static unsigned declContextDepth(const DeclContext *dc) { - unsigned depth = 0; - while (auto parentDC = dc->getParent()) { - ++depth; - dc = parentDC; - } - - return depth; -} - void GenericEnvironment::setOwningDeclContext(DeclContext *newOwningDC) { if (!OwningDC) { OwningDC = newOwningDC; @@ -54,8 +43,8 @@ void GenericEnvironment::setOwningDeclContext(DeclContext *newOwningDC) { return; // Find the least common ancestor context to be the owner. - unsigned oldDepth = declContextDepth(OwningDC); - unsigned newDepth = declContextDepth(newOwningDC); + unsigned oldDepth = OwningDC->getSyntacticDepth(); + unsigned newDepth = newOwningDC->getSyntacticDepth(); while (oldDepth > newDepth) { OwningDC = OwningDC->getParent(); diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp index 4e4ca684f72c2..283779ad1e0ab 100644 --- a/lib/AST/GenericSignatureBuilder.cpp +++ b/lib/AST/GenericSignatureBuilder.cpp @@ -1057,8 +1057,9 @@ std::string GenericSignatureBuilder::PotentialArchetype::getDebugName() const { ProtocolDecl *proto = nullptr; if (auto assocType = getResolvedAssociatedType()) { proto = assocType->getProtocol(); - } else if (auto typeAlias = getTypeAliasDecl()) { - proto = typeAlias->getParent()->getAsProtocolOrProtocolExtensionContext(); + } else if (auto concreteDecl = getConcreteTypeDecl()) { + proto = concreteDecl->getDeclContext() + ->getAsProtocolOrProtocolExtensionContext(); } if (proto) { @@ -1086,20 +1087,20 @@ void GenericSignatureBuilder::PotentialArchetype::resolveAssociatedType( GenericSignatureBuilder &builder) { assert(isUnresolvedNestedType && "associated type is already resolved"); isUnresolvedNestedType = false; - identifier.assocTypeOrAlias = assocType; + identifier.assocTypeOrConcrete = assocType; assert(assocType->getName() == getNestedName()); assert(builder.Impl->NumUnresolvedNestedTypes > 0 && "Mismatch in number of unresolved nested types"); --builder.Impl->NumUnresolvedNestedTypes; } -void GenericSignatureBuilder::PotentialArchetype::resolveTypeAlias( - TypeAliasDecl *typealias, +void GenericSignatureBuilder::PotentialArchetype::resolveConcreteType( + TypeDecl *concreteDecl, GenericSignatureBuilder &builder) { assert(isUnresolvedNestedType && "nested type is already resolved"); isUnresolvedNestedType = false; - identifier.assocTypeOrAlias = typealias; - assert(typealias->getName() == getNestedName()); + identifier.assocTypeOrConcrete = concreteDecl; + assert(concreteDecl->getName() == getNestedName()); assert(builder.Impl->NumUnresolvedNestedTypes > 0 && "Mismatch in number of unresolved nested types"); --builder.Impl->NumUnresolvedNestedTypes; @@ -1285,7 +1286,7 @@ static void maybeAddSameTypeRequirementForNestedType( if (!superSource) return; auto assocType = nestedPA->getResolvedAssociatedType(); - assert(assocType && "Not resolved to an associated type?"); + if (!assocType) return; // Dig out the type witness. auto superConformance = superSource->getProtocolConformance(); @@ -1408,30 +1409,6 @@ static int compareAssociatedTypes(AssociatedTypeDecl *assocType1, return 0; } -/// Compare two typealiases in protocols. -static int compareTypeAliases(TypeAliasDecl *typealias1, - TypeAliasDecl *typealias2) { - // - by name. - if (int result = typealias1->getName().str().compare( - typealias2->getName().str())) - return result; - - // - by protocol, so t_n_m.`P.T` < t_n_m.`Q.T` (given P < Q) - auto proto1 = - typealias1->getDeclContext()->getAsProtocolOrProtocolExtensionContext(); - auto proto2 = - typealias2->getDeclContext()->getAsProtocolOrProtocolExtensionContext(); - if (int compareProtocols = ProtocolType::compareProtocols(&proto1, &proto2)) - return compareProtocols; - - // Error case: if we have two associated types with the same name in the - // same protocol, just tie-break based on address. - if (typealias1 != typealias2) - return typealias1 < typealias2 ? -1 : +1; - - return 0; -} - /// Canonical ordering for dependent types in generic signatures. static int compareDependentTypes(PotentialArchetype * const* pa, PotentialArchetype * const* pb) { @@ -1441,12 +1418,12 @@ static int compareDependentTypes(PotentialArchetype * const* pa, if (a == b) return 0; - // Typealiases must be ordered *after* everything else, to ensure they - // don't become representatives in the case where a typealias is equated + // Concrete types must be ordered *after* everything else, to ensure they + // don't become representatives in the case where a concrete type is equated // with an associated type. if (a->getParent() && b->getParent() && - !!a->getTypeAliasDecl() != !!b->getTypeAliasDecl()) - return a->getTypeAliasDecl() ? +1 : -1; + !!a->getConcreteTypeDecl() != !!b->getConcreteTypeDecl()) + return a->getConcreteTypeDecl() ? +1 : -1; // Types that are equivalent to concrete types follow types that are still // type parameters. @@ -1489,12 +1466,13 @@ static int compareDependentTypes(PotentialArchetype * const* pa, return +1; } - // Make sure typealiases are properly ordered, to avoid crashers. - if (auto *aa = a->getTypeAliasDecl()) { - auto *ab = b->getTypeAliasDecl(); + // Make sure concrete type declarations are properly ordered, to avoid + // crashers. + if (auto *aa = a->getConcreteTypeDecl()) { + auto *ab = b->getConcreteTypeDecl(); assert(ab != nullptr && "Should have handled this case above"); - if (int result = compareTypeAliases(aa, ab)) + if (int result = TypeDecl::compare(aa, ab)) return result; } @@ -1575,11 +1553,11 @@ namespace { PotentialArchetype *pa; void operator()(Type type1, Type type2) const { - if (pa->getParent() && pa->getTypeAliasDecl() && + if (pa->getParent() && pa->getConcreteTypeDecl() && source->getLoc().isInvalid()) { - diags.diagnose(pa->getTypeAliasDecl()->getLoc(), + diags.diagnose(pa->getConcreteTypeDecl()->getLoc(), diag::protocol_typealias_conflict, - pa->getTypeAliasDecl()->getName(), + pa->getConcreteTypeDecl()->getName(), type1, type2); return; } @@ -1658,9 +1636,9 @@ PotentialArchetype *PotentialArchetype::getNestedType( } PotentialArchetype *PotentialArchetype::getNestedType( - TypeAliasDecl *typealias, + TypeDecl *getConcreteTypeDecl, GenericSignatureBuilder &builder) { - return updateNestedTypeForConformance(typealias, + return updateNestedTypeForConformance(getConcreteTypeDecl, NestedTypeUpdate::AddIfMissing); } @@ -1668,24 +1646,24 @@ PotentialArchetype *PotentialArchetype::getNestedArchetypeAnchor( Identifier name, GenericSignatureBuilder &builder, NestedTypeUpdate kind) { - // Look for the best associated type or typealias within the protocols + // Look for the best associated type or concrete type within the protocols // we know about. AssociatedTypeDecl *bestAssocType = nullptr; - TypeAliasDecl *bestTypeAlias = nullptr; - SmallVector typealiases; + TypeDecl *bestConcreteDecl = nullptr; + SmallVector concreteDecls; auto rep = getRepresentative(); for (auto proto : rep->getConformsTo()) { - // Look for an associated type and/or typealias with this name. + // Look for an associated type and/or concrete type with this name. AssociatedTypeDecl *assocType = nullptr; - TypeAliasDecl *typealias = nullptr; + TypeDecl *concreteDecl = nullptr; for (auto member : proto->lookupDirect(name, /*ignoreNewExtensions=*/true)) { if (!assocType) assocType = dyn_cast(member); - // FIXME: Filter out typealiases that aren't in the protocol itself? - if (!typealias) - typealias = dyn_cast(member); + // FIXME: Filter out type declarations that aren't in the protocol itself? + if (!concreteDecl && !isa(member)) + concreteDecl = dyn_cast(member); } if (assocType && @@ -1693,13 +1671,14 @@ PotentialArchetype *PotentialArchetype::getNestedArchetypeAnchor( compareAssociatedTypes(assocType, bestAssocType) < 0)) bestAssocType = assocType; - if (typealias) { - // Record every typealias. - typealiases.push_back(typealias); + if (concreteDecl) { + // Record every concrete type. + concreteDecls.push_back(concreteDecl); - // Track the best typealias. - if (!bestTypeAlias || compareTypeAliases(typealias, bestTypeAlias) < 0) - bestTypeAlias = typealias; + // Track the best concrete type. + if (!bestConcreteDecl || + TypeDecl::compare(concreteDecl, bestConcreteDecl) < 0) + bestConcreteDecl = concreteDecl; } } @@ -1710,25 +1689,47 @@ PotentialArchetype *PotentialArchetype::getNestedArchetypeAnchor( NestedTypeUpdate::AddIfMissing); } - // If we have an associated type, drop any typealiases that aren't in + // If we have an associated type, drop any concrete decls that aren't in // the same module as the protocol. // FIXME: This is an unprincipled hack for an unprincipled feature. - typealiases.erase( - std::remove_if(typealiases.begin(), typealiases.end(), - [&](TypeAliasDecl *typealias) { - return typealias->getParentModule() != - typealias->getDeclContext() + concreteDecls.erase( + std::remove_if(concreteDecls.begin(), concreteDecls.end(), + [&](TypeDecl *concreteDecl) { + return concreteDecl->getDeclContext()->getParentModule() != + concreteDecl->getDeclContext() ->getAsNominalTypeOrNominalTypeExtensionContext()->getParentModule(); }), - typealiases.end()); + concreteDecls.end()); + + // If we haven't found anything yet but have a superclass, look for a type + // in the superclass. + if (!resultPA && concreteDecls.empty()) { + if (auto superclass = getSuperclass()) { + if (auto classDecl = superclass->getClassOrBoundGenericClass()) { + SmallVector superclassMembers; + classDecl->getParentModule()->lookupQualified(superclass, name, NL_QualifiedDefault | NL_OnlyTypes | NL_ProtocolMembers, nullptr, + superclassMembers); + for (auto member : superclassMembers) { + if (auto concreteDecl = dyn_cast(member)) { + // Track the best concrete type. + if (!bestConcreteDecl || + TypeDecl::compare(concreteDecl, bestConcreteDecl) < 0) + bestConcreteDecl = concreteDecl; + + concreteDecls.push_back(concreteDecl); + } + } + } + } + } - // Update for all of the typealiases with this name, which will introduce + // Update for all of the concrete decls with this name, which will introduce // various same-type constraints. - for (auto typealias : typealiases) { - auto typealiasPA = updateNestedTypeForConformance(typealias, + for (auto concreteDecl : concreteDecls) { + auto concreteDeclPA = updateNestedTypeForConformance(concreteDecl, NestedTypeUpdate::AddIfMissing); - if (!resultPA && typealias == bestTypeAlias) - resultPA = typealiasPA; + if (!resultPA && concreteDecl == bestConcreteDecl) + resultPA = concreteDeclPA; } if (resultPA) @@ -1771,48 +1772,49 @@ PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance( Identifier name, ProtocolDecl *proto, NestedTypeUpdate kind) { - /// Determine whether there is an associated type or typealias with this name - /// in this protocol. If not, there's nothing to do. + /// Determine whether there is an associated type or concrete type with this + /// name in this protocol. If not, there's nothing to do. AssociatedTypeDecl *assocType = nullptr; - TypeAliasDecl *typealias = nullptr; + TypeDecl *concreteDecl = nullptr; for (auto member : proto->lookupDirect(name, /*ignoreNewExtensions=*/true)) { if (!assocType) assocType = dyn_cast(member); - // FIXME: Filter out typealiases that aren't in the protocol itself? - if (!typealias) - typealias = dyn_cast(member); + // FIXME: Filter out concrete types that aren't in the protocol itself? + if (!concreteDecl && !isa(member)) + concreteDecl = dyn_cast(member); } - // There is no associated type or typealias with this name in this protocol - if (!assocType && !typealias) + // There is no associated type or concrete type with this name in this + // protocol + if (!assocType && !concreteDecl) return nullptr; - // If we had both an associated type and a typealias, ignore the latter. This - // is for ill-formed code. + // If we had both an associated type and a concrete type, ignore the latter. + // This is for ill-formed code. if (assocType) return updateNestedTypeForConformance(assocType, kind); - return updateNestedTypeForConformance(typealias, kind); + return updateNestedTypeForConformance(concreteDecl, kind); } PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance( - PointerUnion type, + PointerUnion type, NestedTypeUpdate kind) { auto *assocType = type.dyn_cast(); - auto *typealias = type.dyn_cast(); - if (!assocType && !typealias) + auto *concreteDecl = type.dyn_cast(); + if (!assocType && !concreteDecl) return nullptr; - Identifier name = assocType ? assocType->getName() : typealias->getName(); + Identifier name = assocType ? assocType->getName() : concreteDecl->getName(); ProtocolDecl *proto = assocType ? assocType->getProtocol() - : typealias->getDeclContext() + : concreteDecl->getDeclContext() ->getAsProtocolOrProtocolExtensionContext(); // Look for either an unresolved potential archetype (which we can resolve // now) or a potential archetype with the appropriate associated type or - // typealias. + // concrete type. PotentialArchetype *resultPA = nullptr; auto knownNestedTypes = NestedTypes.find(name); bool shouldUpdatePA = false; @@ -1824,7 +1826,7 @@ PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance( if (assocType) { existingPA->resolveAssociatedType(assocType, builder); } else { - existingPA->resolveTypeAlias(typealias, builder); + existingPA->resolveConcreteType(concreteDecl, builder); } // We've resolved this nested type; nothing more to do. @@ -1839,8 +1841,8 @@ PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance( break; } - // Do we have a typealias match? - if (typealias && existingPA->getTypeAliasDecl() == typealias) { + // Do we have a concrete type match? + if (concreteDecl && existingPA->getConcreteTypeDecl() == concreteDecl) { resultPA = existingPA; break; } @@ -1860,7 +1862,7 @@ PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance( if (assocType) resultPA = new PotentialArchetype(this, assocType); else - resultPA = new PotentialArchetype(this, typealias); + resultPA = new PotentialArchetype(this, concreteDecl); auto &allNested = NestedTypes[name]; allNested.push_back(resultPA); @@ -1903,28 +1905,38 @@ PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance( // If we have a potential archetype that requires more processing, do so now. if (shouldUpdatePA) { - // For typealiases, introduce a same-type requirement to the aliased type. - if (typealias) { + // For concrete types, introduce a same-type requirement to the aliased + // type. + if (concreteDecl) { // FIXME (recursive decl validation): if the alias doesn't have an // interface type when getNestedType is called while building a // protocol's generic signature (i.e. during validation), then it'll // fail completely, because building that alias's interface type // requires the protocol to be validated. This seems to occur when the // alias's RHS involves archetypes from the protocol. - if (!typealias->hasInterfaceType()) - builder.getLazyResolver()->resolveDeclSignature(typealias); - if (typealias->hasInterfaceType()) { - // The protocol typealias has an underlying type written in terms + if (!concreteDecl->hasInterfaceType()) + builder.getLazyResolver()->resolveDeclSignature(concreteDecl); + if (concreteDecl->hasInterfaceType()) { + // The protocol concrete type has an underlying type written in terms // of the protocol's 'Self' type. - auto type = typealias->getDeclaredInterfaceType(); - - // Substitute in the type of the current PotentialArchetype in - // place of 'Self' here. - auto subMap = SubstitutionMap::getProtocolSubstitutions( - proto, getDependentType(/*genericParams=*/{}, - /*allowUnresolved=*/true), - ProtocolConformanceRef(proto)); - type = type.subst(subMap, SubstFlags::UseErrorType); + auto type = concreteDecl->getDeclaredInterfaceType(); + + if (proto) { + // Substitute in the type of the current PotentialArchetype in + // place of 'Self' here. + auto subMap = SubstitutionMap::getProtocolSubstitutions( + proto, getDependentType(/*genericParams=*/{}, + /*allowUnresolved=*/true), + ProtocolConformanceRef(proto)); + type = type.subst(subMap, SubstFlags::UseErrorType); + } else { + // Substitute in the superclass type. + auto superclass = getSuperclass(); + auto superclassDecl = superclass->getClassOrBoundGenericClass(); + type = superclass->getTypeOfMember( + superclassDecl->getParentModule(), concreteDecl, + concreteDecl->getDeclaredInterfaceType()); + } builder.addSameTypeRequirement( UnresolvedType(resultPA), @@ -1936,8 +1948,12 @@ PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance( // If there's a superclass constraint that conforms to the protocol, // add the appropriate same-type relationship. - if (auto superSource = builder.resolveSuperConformance(this, proto)) - maybeAddSameTypeRequirementForNestedType(resultPA, superSource, builder); + if (proto) { + if (auto superSource = builder.resolveSuperConformance(this, proto)) { + maybeAddSameTypeRequirementForNestedType(resultPA, superSource, + builder); + } + } // We know something concrete about the parent PA, so we need to propagate // that information to this new archetype. @@ -2398,18 +2414,6 @@ auto GenericSignatureBuilder::resolve(UnresolvedType paOrT, if (!pa) return None; } - auto rep = pa->getRepresentative(); - if (!rep->getParent() || !rep->getTypeAliasDecl()) - return ResolvedType::forPotentialArchetype(pa); - - // We're assuming that an equivalence class with a type alias representative - // doesn't have a "true" (i.e. associated type) potential archetype. - assert(llvm::all_of(rep->getEquivalenceClassMembers(), - [&](PotentialArchetype *pa) { - return pa->getParent() && pa->getTypeAliasDecl(); - }) && - "unexpected typealias representative with non-typealias equivalent"); - return ResolvedType::forPotentialArchetype(pa); } @@ -2607,16 +2611,16 @@ ConstraintResult GenericSignatureBuilder::addConformanceRequirement( assocType); } - if (auto typealias = dyn_cast(typeDecl)) { - // Resolve the underlying type, if we haven't done so yet. - if (!typealias->hasInterfaceType()) { - getLazyResolver()->resolveDeclSignature(typealias); - } + // Resolve the underlying type, if we haven't done so yet. + if (!typeDecl->hasInterfaceType()) { + getLazyResolver()->resolveDeclSignature(typeDecl); + } + if (auto typealias = dyn_cast(typeDecl)) { return typealias->getUnderlyingTypeLoc().getType(); } - return Type(); + return typeDecl->getDeclaredInterfaceType(); }; // An inferred same-type requirement between the two type declarations @@ -2845,11 +2849,24 @@ void GenericSignatureBuilder::updateSuperclass( } }; + // Local function to resolve nested types found in the superclass. + auto updateSuperclassNestedTypes = [&] { + for (auto &nested : T->getNestedTypes()) { + if (nested.second.empty()) continue; + if (nested.second.front()->isUnresolved()) { + (void)T->getNestedArchetypeAnchor(nested.first, *this, + PotentialArchetype::NestedTypeUpdate::ResolveExisting); + } + } + }; + // If we haven't yet recorded a superclass constraint for this equivalence // class, do so now. if (!equivClass->superclass) { equivClass->superclass = superclass; updateSuperclassConformances(); + updateSuperclassNestedTypes(); + // Presence of a superclass constraint implies a _Class layout // constraint. auto layoutReqSource = source->viaSuperclass(*this, nullptr); @@ -2880,6 +2897,7 @@ void GenericSignatureBuilder::updateSuperclass( // We've strengthened the bound, so update superclass conformances. updateSuperclassConformances(); + updateSuperclassNestedTypes(); return; } @@ -4023,10 +4041,7 @@ GenericSignatureBuilder::finalize(SourceLoc loc, if (Impl->NumUnresolvedNestedTypes > 0) { visitPotentialArchetypes([&](PotentialArchetype *pa) { // We only care about nested types that haven't been resolved. - if (pa->getParent() == nullptr || pa->getResolvedAssociatedType() || - pa->getTypeAliasDecl() || - /* FIXME: Should be able to handle this earlier */pa->getSuperclass()) - return; + if (!pa->isUnresolved()) return; // Try to typo correct to a nested type name. Identifier correction = typoCorrectNestedType(pa); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index eff1302ffe9f0..59dfc2ee35d80 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -948,17 +948,7 @@ static void addMinimumProtocols(Type T, /// \brief Compare two protocols to establish an ordering between them. int ProtocolType::compareProtocols(ProtocolDecl * const* PP1, ProtocolDecl * const* PP2) { - auto *P1 = *PP1; - auto *P2 = *PP2; - ModuleDecl *M1 = P1->getParentModule(); - ModuleDecl *M2 = P2->getParentModule(); - - // Try ordering based on module name, first. - if (int result = M1->getName().str().compare(M2->getName().str())) - return result; - - // Order based on protocol name. - return P1->getName().str().compare(P2->getName().str()); + return TypeDecl::compare(*PP1, *PP2); } bool ProtocolType::visitAllProtocols( diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index d1f4f49158d6f..7d76f182e2e1a 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -209,35 +209,37 @@ Type CompleteGenericTypeResolver::resolveDependentMemberType( return DependentMemberType::get(baseTy, assocType); } - // If the nested type comes from a type alias, use either the alias's - // concrete type, or resolve its components down to another dependent member. - if (auto alias = nestedPA->getTypeAliasDecl()) { - assert(!alias->getGenericParams() && "Generic typealias in protocol"); - ref->setValue(alias); - return TC.substMemberTypeWithBase(DC->getParentModule(), alias, baseTy); - } - - Identifier name = ref->getIdentifier(); - SourceLoc nameLoc = ref->getIdLoc(); + // If the nested type comes from a concrete type, substitute the base type + // into it. + if (auto concrete = nestedPA->getConcreteTypeDecl()) { + ref->setValue(concrete); + + if (baseTy->isTypeParameter()) { + if (auto proto = + concrete->getDeclContext() + ->getAsProtocolOrProtocolExtensionContext()) { + auto subMap = SubstitutionMap::getProtocolSubstitutions( + proto, baseTy, ProtocolConformanceRef(proto)); + return concrete->getDeclaredInterfaceType().subst(subMap); + } - // Check whether the name can be found in the superclass. - // FIXME: The generic signature builder should be doing this and mapping down to a - // concrete type. - if (auto superclassTy = basePA->getSuperclass()) { - if (auto lookup = TC.lookupMemberType(DC, superclassTy, name)) { - if (lookup.isAmbiguous()) { - TC.diagnoseAmbiguousMemberType(baseTy, baseRange, name, nameLoc, - lookup); - return ErrorType::get(TC.Context); + if (auto superclass = basePA->getSuperclass()) { + return superclass->getTypeOfMember( + DC->getParentModule(), concrete, + concrete->getDeclaredInterfaceType()); } - ref->setValue(lookup.front().first); - // FIXME: Record (via type sugar) that this was referenced via baseTy. - return lookup.front().second; + llvm_unreachable("shouldn't have a concrete decl here"); } + + return TC.substMemberTypeWithBase(DC->getParentModule(), concrete, baseTy); } + assert(nestedPA->isUnresolved() && "meaningless unresolved type"); + // Complain that there is no suitable type. + Identifier name = ref->getIdentifier(); + SourceLoc nameLoc = ref->getIdLoc(); TC.diagnose(nameLoc, diag::invalid_member_type, name, baseTy) .highlight(baseRange); return ErrorType::get(TC.Context); diff --git a/test/Generics/superclass_constraint.swift b/test/Generics/superclass_constraint.swift index efb35a3eef15a..0d585e3f36d3a 100644 --- a/test/Generics/superclass_constraint.swift +++ b/test/Generics/superclass_constraint.swift @@ -152,3 +152,18 @@ class Classical : Elementary { } func genericFunc(_: T, _: U) where T.Element == U.Element {} + +// Lookup within superclass constraints. +protocol P8 { + associatedtype B +} + +class C8 { + struct A { } +} + +func superclassLookup1(_: T) where T.A == T.B { } + +func superclassLookup2(_: T) where T.A == T.B, T: C8 { } + +func superclassLookup3(_: T) where T.A == T.B, T: C8, T: P8 { }