Merge pull request #11751 from DougGregor/gsb-nested-same-type-match

diff --git a/include/swift/AST/GenericSignatureBuilder.h b/include/swift/AST/GenericSignatureBuilder.h
index 0b42263..ddf8ebe 100644
--- a/include/swift/AST/GenericSignatureBuilder.h
+++ b/include/swift/AST/GenericSignatureBuilder.h
@@ -317,6 +317,15 @@
                                              const RequirementSource *Source);
 
 public:
+  /// "Expand" the conformance of the given \c pa to the protocol \c proto,
+  /// adding the requirements from its requirement signature, rooted at
+  /// the given requirement \c source.
+  ConstraintResult expandConformanceRequirement(
+                                      PotentialArchetype *pa,
+                                      ProtocolDecl *proto,
+                                      const RequirementSource *source,
+                                      bool onlySameTypeConstraints);
+
   /// \brief Add a new same-type requirement between two fully resolved types
   /// (output of \c GenericSignatureBuilder::resolve).
   ///
@@ -824,6 +833,11 @@
     /// A requirement that was resolved based on structural derivation from
     /// another requirement.
     Derived,
+
+    /// A requirement that was provided for another potential archetype in the
+    /// same equivalence class, but which we want to "re-root" on a new
+    /// potential archetype.
+    EquivalentType,
   };
 
   /// The kind of requirement source.
@@ -882,6 +896,7 @@
     case Parent:
     case Concrete:
     case Derived:
+    case EquivalentType:
       return 0;
     }
 
@@ -927,6 +942,7 @@
     case Parent:
     case Concrete:
     case Derived:
+    case EquivalentType:
       return false;
     }
 
@@ -1011,6 +1027,18 @@
            "RequirementSource kind/storageKind mismatch");
   }
 
+  RequirementSource(Kind kind, const RequirementSource *parent,
+                    PotentialArchetype *newPA)
+    : kind(kind), storageKind(StorageKind::RootArchetype),
+      hasTrailingWrittenRequirementLoc(false),
+      usesRequirementSignature(false), parent(parent) {
+    assert((static_cast<bool>(parent) != isRootKind(kind)) &&
+           "Root RequirementSource should not have parent (or vice versa)");
+    assert(isAcceptableStorageKind(kind, storageKind) &&
+           "RequirementSource kind/storageKind mismatch");
+    storage.rootArchetype = newPA;
+  }
+
 public:
   /// Retrieve an abstract requirement source.
   static const RequirementSource *forAbstract(PotentialArchetype *root);
@@ -1076,6 +1104,11 @@
   /// derived from another constraint but does not require further information.
   const RequirementSource *viaDerived(GenericSignatureBuilder &builder) const;
 
+  /// A constraint source that describes a constraint that is structurally
+  /// derived from another constraint but does not require further information.
+  const RequirementSource *viaEquivalentType(GenericSignatureBuilder &builder,
+                                             PotentialArchetype *newPA) const;
+
   /// Form a new requirement source without the subpath [start, end).
   ///
   /// Removes a redundant sub-path \c [start, end) from the requirement source,
@@ -1427,10 +1460,12 @@
   {
   }
 
+public:
   /// \brief Retrieve the representative for this archetype, performing
   /// path compression on the way.
   PotentialArchetype *getRepresentative() const;
 
+private:
   /// Retrieve the generic signature builder with which this archetype is
   /// associated.
   GenericSignatureBuilder *getBuilder() const {
@@ -1695,6 +1730,12 @@
   UnresolvedType lhs;
   RequirementRHS rhs;
   FloatingRequirementSource source;
+
+  /// Dump a debugging representation of this delayed requirement class.
+  void dump(llvm::raw_ostream &out) const;
+
+  LLVM_ATTRIBUTE_DEPRECATED(void dump() const,
+                            "only for use in the debugger");
 };
 
 /// Whether the given constraint result signals an error.
diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp
index 19f11ec..b29b4db 100644
--- a/lib/AST/GenericSignatureBuilder.cpp
+++ b/lib/AST/GenericSignatureBuilder.cpp
@@ -58,6 +58,7 @@
     GenericSignatureBuilder::Constraint<T>;
   typedef GenericSignatureBuilder::EquivalenceClass EquivalenceClass;
   typedef EquivalenceClass::DerivedSameTypeComponent DerivedSameTypeComponent;
+  typedef GenericSignatureBuilder::DelayedRequirement DelayedRequirement;
 
 } // end anonymous namespace
 
@@ -343,6 +344,7 @@
   case RequirementSignatureSelf:
   case NestedTypeNameMatch:
   case ConcreteTypeBinding:
+  case EquivalentType:
     switch (storageKind) {
     case StorageKind::RootArchetype:
       return true;
@@ -455,14 +457,15 @@
       return true;
 
     case QuietlyInferred:
+    case NestedTypeNameMatch:
       return includeQuietInferred;
 
     case ConcreteTypeBinding:
+    case EquivalentType:
       return false;
 
     case Concrete:
     case Explicit:
-    case NestedTypeNameMatch:
     case Parent:
     case ProtocolRequirement:
     case RequirementSignatureSelf:
@@ -495,6 +498,7 @@
   case Concrete:
   case RequirementSignatureSelf:
   case Derived:
+  case EquivalentType:
     return true;
 
   case ProtocolRequirement:
@@ -638,7 +642,9 @@
     case Concrete:
     case Superclass:
     case Derived:
+    case EquivalentType:
       return false;
+
     case Explicit:
     case Inferred:
     case QuietlyInferred:
@@ -832,6 +838,15 @@
                         0, WrittenRequirementLoc());
 }
 
+const RequirementSource *RequirementSource::viaEquivalentType(
+                                           GenericSignatureBuilder &builder,
+                                           PotentialArchetype *newPA) const {
+  REQUIREMENT_SOURCE_FACTORY_BODY(
+                        (nodeID, EquivalentType, this, newPA, nullptr, nullptr),
+                        (EquivalentType, this, newPA),
+                        0, WrittenRequirementLoc());
+}
+
 #undef REQUIREMENT_SOURCE_FACTORY_BODY
 
 const RequirementSource *RequirementSource::withoutRedundantSubpath(
@@ -884,6 +899,10 @@
     return parent->withoutRedundantSubpath(start, end)
       ->viaDerived(builder);
 
+  case EquivalentType:
+    return parent->withoutRedundantSubpath(start, end)
+      ->viaEquivalentType(builder, getAffectedPotentialArchetype());
+
   case Parent:
     return parent->withoutRedundantSubpath(start, end)
       ->viaParent(builder, getAssociatedType());
@@ -950,6 +969,15 @@
   case RequirementSource::Derived:
     return parent->visitPotentialArchetypesAlongPath(visitor);
 
+  case RequirementSource::EquivalentType: {
+    auto parentPA = parent->visitPotentialArchetypesAlongPath(visitor);
+    if (!parentPA) return nullptr;
+
+    if (visitor(parentPA, this)) return nullptr;
+
+    return storage.rootArchetype;
+  }
+
   case RequirementSource::ProtocolRequirement:
   case RequirementSource::InferredProtocolRequirement: {
     auto parentPA = parent->visitPotentialArchetypesAlongPath(visitor);
@@ -1139,6 +1167,10 @@
   case Derived:
     out << "Derived";
     break;
+
+  case EquivalentType:
+    out << "Equivalent type";
+    break;
   }
 
   // Local function to dump a source location, if we can.
@@ -1299,6 +1331,7 @@
     case RequirementSource::InferredProtocolRequirement:
     case RequirementSource::Superclass:
     case RequirementSource::Derived:
+    case RequirementSource::EquivalentType:
       return false;
     }
 
@@ -1321,6 +1354,7 @@
     case RequirementSource::Parent:
     case RequirementSource::Superclass:
     case RequirementSource::Derived:
+    case RequirementSource::EquivalentType:
       return false;
     }
   }
@@ -1352,6 +1386,10 @@
   llvm::SmallSet<std::pair<CanType, ProtocolDecl *>, 4> visitedAssocReqs;
   for (auto storedSource = storage.dyn_cast<const RequirementSource *>();
        storedSource; storedSource = storedSource->parent) {
+    // FIXME: isRecursive() is completely misnamed
+    if (storedSource->kind == RequirementSource::EquivalentType)
+      return true;
+
     if (!storedSource->isProtocolRequirement())
       continue;
 
@@ -1510,6 +1548,14 @@
   if (layout)
     out << "\nLayout: " << layout.getString();
 
+  if (!delayedRequirements.empty()) {
+    out << "\nDelayed requirements:";
+    for (const auto &req : delayedRequirements) {
+      out << "\n  ";
+      req.dump(out);
+    }
+  }
+
   out << "\n";
 
   {
@@ -1548,6 +1594,38 @@
   dump(llvm::errs());
 }
 
+void DelayedRequirement::dump(llvm::raw_ostream &out) const {
+  // Print LHS.
+  if (auto lhsPA = lhs.dyn_cast<PotentialArchetype *>())
+    out << lhsPA->getDebugName();
+  else
+    lhs.get<swift::Type>().print(out);
+
+  switch (kind) {
+  case Type:
+  case Layout:
+    out << ": ";
+      break;
+
+  case SameType:
+    out << " == ";
+    break;
+  }
+
+  // Print RHS.
+  if (auto rhsPA = rhs.dyn_cast<PotentialArchetype *>())
+    out << rhsPA->getDebugName();
+  else if (auto rhsType = rhs.dyn_cast<swift::Type>())
+    rhsType.print(out);
+  else
+    rhs.get<LayoutConstraint>().print(out);
+}
+
+void DelayedRequirement::dump() const {
+  dump(llvm::errs());
+  llvm::errs() << "\n";
+}
+
 ConstraintResult GenericSignatureBuilder::handleUnresolvedRequirement(
                                    RequirementKind kind,
                                    UnresolvedType lhs,
@@ -2811,7 +2889,7 @@
     // fails, it's because we weren't allowed to resolve anything now.
     auto resolved = resolvePotentialArchetype(type, resolutionKind);
     pa = resolved.dyn_cast<PotentialArchetype *>();
-      if (!pa) return resolved.get<EquivalenceClass *>();
+    if (!pa) return resolved.get<EquivalenceClass *>();
   }
 
   return ResolvedType::forPotentialArchetype(pa);
@@ -2886,26 +2964,27 @@
   return result;
 }
 
-ConstraintResult GenericSignatureBuilder::addConformanceRequirement(
-                               PotentialArchetype *PAT,
-                               ProtocolDecl *Proto,
-                               const RequirementSource *Source) {
-  // Add the requirement, if we haven't done so already.
-  if (!PAT->addConformance(Proto, Source, *this))
-    return ConstraintResult::Resolved;
-
-  auto concreteSelf = PAT->getDependentType({});
+ConstraintResult GenericSignatureBuilder::expandConformanceRequirement(
+                                            PotentialArchetype *pa,
+                                            ProtocolDecl *proto,
+                                            const RequirementSource *source,
+                                            bool onlySameTypeConstraints) {
+  auto concreteSelf = pa->getDependentType({});
   auto protocolSubMap = SubstitutionMap::getProtocolSubstitutions(
-      Proto, concreteSelf, ProtocolConformanceRef(Proto));
+      proto, concreteSelf, ProtocolConformanceRef(proto));
 
   // Use the requirement signature to avoid rewalking the entire protocol.  This
   // cannot compute the requirement signature directly, because that may be
   // infinitely recursive: this code is also used to construct it.
-  if (Proto->isRequirementSignatureComputed()) {
+  if (proto->isRequirementSignatureComputed()) {
     auto innerSource =
-      FloatingRequirementSource::viaProtocolRequirement(Source, Proto,
+      FloatingRequirementSource::viaProtocolRequirement(source, proto,
                                                         /*inferred=*/false);
-    for (const auto &req : Proto->getRequirementSignature()) {
+    for (const auto &req : proto->getRequirementSignature()) {
+      // If we're only looking at same-type constraints, skip everything else.
+      if (onlySameTypeConstraints && req.getKind() != RequirementKind::SameType)
+        continue;
+
       auto reqResult = addRequirement(req, innerSource, nullptr,
                                       &protocolSubMap);
       if (isErrorResult(reqResult)) return reqResult;
@@ -2914,22 +2993,29 @@
     return ConstraintResult::Resolved;
   }
 
-  // Add all of the inherited protocol requirements, recursively.
-  if (auto resolver = getLazyResolver())
-    resolver->resolveInheritedProtocols(Proto);
+  auto protoModule = proto->getParentModule();
 
-  auto protoModule = Proto->getParentModule();
+  if (!onlySameTypeConstraints) {
+    // Add all of the inherited protocol requirements, recursively.
+    if (auto resolver = getLazyResolver())
+      resolver->resolveInheritedProtocols(proto);
 
-  auto inheritedReqResult =
-    addInheritedRequirements(Proto, PAT, Source, protoModule);
-  if (isErrorResult(inheritedReqResult))
-    return inheritedReqResult;
+    auto inheritedReqResult =
+      addInheritedRequirements(proto, pa, source, protoModule);
+    if (isErrorResult(inheritedReqResult))
+      return inheritedReqResult;
+  }
 
   // Add any requirements in the where clause on the protocol.
-  if (auto WhereClause = Proto->getTrailingWhereClause()) {
+  if (auto WhereClause = proto->getTrailingWhereClause()) {
     for (auto &req : WhereClause->getRequirements()) {
+      // If we're only looking at same-type constraints, skip everything else.
+      if (onlySameTypeConstraints &&
+          req.getKind() != RequirementReprKind::SameType)
+        continue;
+
       auto innerSource = FloatingRequirementSource::viaProtocolRequirement(
-          Source, Proto, &req, /*inferred=*/false);
+          source, proto, &req, /*inferred=*/false);
       addRequirement(&req, innerSource, &protocolSubMap, protoModule);
     }
   }
@@ -2938,9 +3024,9 @@
   // inherited protocols (recursively).
   llvm::MapVector<DeclName, TinyPtrVector<TypeDecl *>> inheritedTypeDecls;
   {
-    Proto->walkInheritedProtocols(
+    proto->walkInheritedProtocols(
         [&](ProtocolDecl *inheritedProto) -> TypeWalker::Action {
-      if (inheritedProto == Proto) return TypeWalker::Action::Continue;
+      if (inheritedProto == proto) return TypeWalker::Action::Continue;
 
       for (auto req : getProtocolMembers(inheritedProto)) {
         if (auto typeReq = dyn_cast<TypeDecl>(req))
@@ -2954,11 +3040,11 @@
   // clause, as well as the string to start the insertion ("where" or ",");
   auto getProtocolWhereLoc = [&]() -> std::pair<SourceLoc, const char *> {
     // Already has a trailing where clause.
-    if (auto trailing = Proto->getTrailingWhereClause())
+    if (auto trailing = proto->getTrailingWhereClause())
       return { trailing->getRequirements().back().getSourceRange().End, ", " };
 
     // Inheritance clause.
-    return { Proto->getInherited().back().getSourceRange().End, " where " };
+    return { proto->getInherited().back().getSourceRange().End, " where " };
   };
 
   // Retrieve the set of requirements that a given associated type declaration
@@ -3032,30 +3118,39 @@
 
     auto inferredSameTypeSource =
       FloatingRequirementSource::viaProtocolRequirement(
-                    Source, Proto, WrittenRequirementLoc(), /*inferred=*/true);
+                    source, proto, WrittenRequirementLoc(), /*inferred=*/true);
 
     addRequirement(
       Requirement(RequirementKind::SameType, firstType, secondType),
-      inferredSameTypeSource, Proto->getParentModule(),
+      inferredSameTypeSource, proto->getParentModule(),
       &protocolSubMap);
   };
 
   // Add requirements for each of the associated types.
-  for (auto Member : getProtocolMembers(Proto)) {
+  for (auto Member : getProtocolMembers(proto)) {
     if (auto assocTypeDecl = dyn_cast<AssociatedTypeDecl>(Member)) {
       // Add requirements placed directly on this associated type.
       Type assocType = DependentMemberType::get(concreteSelf, assocTypeDecl);
-      auto assocResult =
-        addInheritedRequirements(assocTypeDecl, assocType, Source, protoModule);
-      if (isErrorResult(assocResult))
-        return assocResult;
+      if (!onlySameTypeConstraints) {
+        auto assocResult =
+          addInheritedRequirements(assocTypeDecl, assocType, source,
+                                   protoModule);
+        if (isErrorResult(assocResult))
+          return assocResult;
+      }
 
       // Add requirements from this associated type's where clause.
       if (auto WhereClause = assocTypeDecl->getTrailingWhereClause()) {
         for (auto &req : WhereClause->getRequirements()) {
+          // If we're only looking at same-type constraints, skip everything
+          // else.
+          if (onlySameTypeConstraints &&
+              req.getKind() != RequirementReprKind::SameType)
+            continue;
+
           auto innerSource =
             FloatingRequirementSource::viaProtocolRequirement(
-                                      Source, Proto, &req, /*inferred=*/false);
+                                      source, proto, &req, /*inferred=*/false);
           addRequirement(&req, innerSource, &protocolSubMap, protoModule);
         }
       }
@@ -3066,7 +3161,7 @@
       if (knownInherited == inheritedTypeDecls.end()) continue;
 
       bool shouldWarnAboutRedeclaration =
-        Source->kind == RequirementSource::RequirementSignatureSelf &&
+        source->kind == RequirementSource::RequirementSignatureSelf &&
         assocTypeDecl->getDefaultDefinitionLoc().isNull();
       for (auto inheritedType : knownInherited->second) {
         // If we have inherited associated type...
@@ -3100,7 +3195,7 @@
 
         // We inherited a type; this associated type will be identical
         // to that typealias.
-        if (Source->kind == RequirementSource::RequirementSignatureSelf) {
+        if (source->kind == RequirementSource::RequirementSignatureSelf) {
           auto inheritedOwningDecl =
             inheritedType->getDeclContext()
               ->getAsNominalTypeOrNominalTypeExtensionContext();
@@ -3124,7 +3219,7 @@
       if (knownInherited == inheritedTypeDecls.end()) continue;
 
       bool shouldWarnAboutRedeclaration =
-        Source->kind == RequirementSource::RequirementSignatureSelf;
+        source->kind == RequirementSource::RequirementSignatureSelf;
 
       for (auto inheritedType : knownInherited->second) {
         // If we have inherited associated type...
@@ -3176,6 +3271,18 @@
   return ConstraintResult::Resolved;
 }
 
+ConstraintResult GenericSignatureBuilder::addConformanceRequirement(
+                               PotentialArchetype *PAT,
+                               ProtocolDecl *Proto,
+                               const RequirementSource *Source) {
+  // Add the requirement, if we haven't done so already.
+  if (!PAT->addConformance(Proto, Source, *this))
+    return ConstraintResult::Resolved;
+
+  return expandConformanceRequirement(PAT, Proto, Source,
+                                      /*onlySameTypeRequirements=*/false);
+}
+
 ConstraintResult GenericSignatureBuilder::addLayoutRequirementDirect(
                                              PotentialArchetype *PAT,
                                              LayoutConstraint Layout,
@@ -3468,11 +3575,10 @@
   assert(allNested.back() == nestedPA);
   if (allNested.size() > 1) {
     auto firstPA = allNested.front();
-    auto sameNamedSource =
-      FloatingRequirementSource::forNestedTypeNameMatch(
-                                                nestedPA->getNestedName());
+    auto quietlyInferredSource =
+      FloatingRequirementSource::forInferred(nullptr, /*quietly=*/true);
 
-    addSameTypeRequirement(firstPA, nestedPA, sameNamedSource,
+    addSameTypeRequirement(firstPA, nestedPA, quietlyInferredSource,
                            UnresolvedHandlingKind::GenerateConstraints);
     return;
   }
@@ -4187,6 +4293,75 @@
   }
 } // end anonymous namespace
 
+/// For each potential archetype within the given equivalence class that is
+/// an associated type, expand the protocol requirements for the enclosing
+/// protocol.
+static void expandSameTypeConstraints(GenericSignatureBuilder &builder,
+                                      EquivalenceClass *equivClass) {
+  auto existingMembers = equivClass->members;
+  for (auto pa : existingMembers) {
+    // Make sure that there are only associated types the chain up to the
+    // parent.
+    bool foundNonAssociatedType = false;
+    for (auto currentPA = pa; auto parentPA = currentPA->getParent();
+         currentPA = parentPA){
+      if (!currentPA->getResolvedAssociatedType()) {
+        foundNonAssociatedType = true;
+        break;
+      }
+    }
+    if (foundNonAssociatedType) continue;
+
+    for (const auto &conforms : equivClass->conformsTo) {
+      auto proto = conforms.first;
+
+      // Check whether we already have a conformance constraint for this
+      // potential archetype.
+      bool alreadyFound = false;
+      const RequirementSource *conformsSource = nullptr;
+      for (const auto &constraint : conforms.second) {
+        if (constraint.source->getAffectedPotentialArchetype() == pa) {
+          alreadyFound = true;
+          break;
+        }
+
+        // Capture the source for later use, skipping
+        if (!conformsSource &&
+            constraint.source->kind
+              != RequirementSource::RequirementSignatureSelf)
+          conformsSource = constraint.source;
+      }
+
+      if (alreadyFound) continue;
+      if (!conformsSource) continue;
+
+      // Pick a source at random and reseat it on this potential archetype.
+      auto source = conformsSource->viaEquivalentType(builder, pa);
+
+      // Expand same-type constraints.
+      builder.expandConformanceRequirement(pa, proto, source,
+                                           /*onlySameTypeConstraints=*/true);
+    }
+  }
+}
+
+/// Retrieve the "local" archetype anchor for the given potential archetype,
+/// which rebuilds this potential archetype using the archetype anchors of
+/// the parent types.
+static PotentialArchetype *getLocalAnchor(PotentialArchetype *pa,
+                                          GenericSignatureBuilder &builder) {
+  auto parent = pa->getParent();
+  if (!parent) return pa;
+
+  auto parentAnchor = getLocalAnchor(parent, builder);
+  if (!parentAnchor) return pa;
+  auto localAnchor =
+    parentAnchor->getNestedArchetypeAnchor(
+                                pa->getNestedName(), builder,
+                                ArchetypeResolutionKind::CompleteWellFormed);
+  return localAnchor ? localAnchor : pa;
+}
+
 void
 GenericSignatureBuilder::finalize(SourceLoc loc,
                            ArrayRef<GenericTypeParamType *> genericParams,
@@ -4328,7 +4503,29 @@
 
     checkConformanceConstraints(genericParams, archetype);
     checkLayoutConstraints(genericParams, archetype);
-    checkSameTypeConstraints(genericParams, archetype);
+  });
+
+  // FIXME: Expand all conformance requirements. This is expensive :(
+  visitPotentialArchetypes([&](PotentialArchetype *archetype) {
+    if (archetype != archetype->getRepresentative()) return;
+
+    // Make sure that we've build the archetype anchors for each potential
+    // archetype in this equivalence class. This is important to do for *all*
+    // potential archetypes because some non-archetype anchors will nonetheless
+    // be used in the canonicalized requirements.
+    for (auto pa : archetype->getEquivalenceClassMembers())
+      (void)getLocalAnchor(pa, *this);
+
+    if (auto equivClass = archetype->getEquivalenceClassIfPresent())
+      expandSameTypeConstraints(*this, equivClass);
+  });
+
+  // Check same-type constraints.
+  visitPotentialArchetypes([&](PotentialArchetype *archetype) {
+    if (archetype != archetype->getRepresentative()) return;
+
+    if (auto equivClass = archetype->getEquivalenceClassIfPresent())
+      checkSameTypeConstraints(genericParams, archetype);
   });
 
   // Check for generic parameters which have been made concrete or equated
@@ -4809,9 +5006,8 @@
 ///
 /// \returns the best archetype anchor seen so far.
 static PotentialArchetype *sameTypeDFS(PotentialArchetype *pa,
-                        unsigned component,
-                        llvm::SmallDenseMap<PotentialArchetype *, unsigned>
-                          &paToComponent) {
+          unsigned component,
+          llvm::SmallDenseMap<PotentialArchetype *, unsigned> &paToComponent) {
   PotentialArchetype *anchor = pa;
 
   // If we've already visited this potential archetype, we're done.
@@ -4819,10 +5015,16 @@
 
   // Visit its adjacent potential archetypes.
   for (const auto &constraint : pa->getSameTypeConstraints()) {
+    // Treat nested-type-name-match constraints specially.
+    if (constraint.source->getRoot()->kind ==
+          RequirementSource::NestedTypeNameMatch)
+      continue;
+
     // Skip non-derived constraints.
     if (!constraint.source->isDerivedRequirement()) continue;
 
-    auto newAnchor = sameTypeDFS(constraint.value, component, paToComponent);
+    auto newAnchor =
+      sameTypeDFS(constraint.value, component, paToComponent);
 
     // If this type is better than the anchor, use it for the anchor.
     if (compareDependentTypes(&newAnchor, &anchor) < 0)
@@ -4839,23 +5041,6 @@
   }
 } // namespace swift
 
-/// Retrieve the "local" archetype anchor for the given potential archetype,
-/// which rebuilds this potential archetype using the archetype anchors of
-/// the parent types.
-static PotentialArchetype *getLocalAnchor(PotentialArchetype *pa,
-                                          GenericSignatureBuilder &builder) {
-  auto parent = pa->getParent();
-  if (!parent) return pa;
-
-  auto parentAnchor = getLocalAnchor(parent, builder);
-  if (!parentAnchor) return pa;
-  auto localAnchor =
-    parentAnchor->getNestedArchetypeAnchor(
-                                pa->getNestedName(), builder,
-                                ArchetypeResolutionKind::CompleteWellFormed);
-  return localAnchor ? localAnchor : pa;
-}
-
 /// Computes the ordered set of archetype anchors required to form a minimum
 /// spanning tree among the connected components formed by only the derived
 /// same-type requirements within the equivalence class of \c rep.
@@ -4933,9 +5118,6 @@
         concrete.source->compare(bestConcreteTypeSource) < 0)
       bestConcreteTypeSource = concrete.source;
   }
-
-  // Sort the components.
-  llvm::array_pod_sort(components.begin(), components.end());
 }
 
 namespace {
@@ -4945,6 +5127,7 @@
     unsigned source;
     unsigned target;
     Constraint<PotentialArchetype *> constraint;
+    bool isSelfDerived = false;
 
     IntercomponentEdge(unsigned source, unsigned target,
                        const Constraint<PotentialArchetype *> &constraint)
@@ -4963,18 +5146,381 @@
 
       // Prefer non-inferred requirement sources.
       bool lhsIsInferred =
-        lhs.constraint.source->isInferredRequirement(
-          /*includeQuietInferred=*/false);
+      lhs.constraint.source->isInferredRequirement(
+                                            /*includeQuietInferred=*/false);
       bool rhsIsInferred =
-        rhs.constraint.source->isInferredRequirement(
-          /*includeQuietInferred=*/false);
+      rhs.constraint.source->isInferredRequirement(
+                                            /*includeQuietInferred=*/false);
       if (lhsIsInferred != rhsIsInferred)
         return rhsIsInferred;;
 
       return lhs.constraint < rhs.constraint;
     }
+
+    LLVM_ATTRIBUTE_DEPRECATED(void dump() const,
+                              "only for use in the debugger");
   };
-} // end anonymous namespace
+}
+
+void IntercomponentEdge::dump() const {
+  llvm::errs() << constraint.archetype->getDebugName() << " -- "
+    << constraint.value->getDebugName() << ": ";
+  constraint.source->print(llvm::errs(), nullptr);
+  llvm::errs() << "\n";
+}
+
+/// Find the representative in a simple union-find data structure of
+/// integral values.
+static unsigned findRepresentative(SmallVectorImpl<unsigned> &parents,
+                                   unsigned index) {
+  if (parents[index] == index) return index;
+
+  return parents[index] = findRepresentative(parents, parents[index]);
+}
+
+
+/// Union the same-type components denoted by \c index1 and \c index2.
+///
+/// \param successThreshold Returns true when two sets have been joined
+/// and both representatives are below the threshold. The default of 0
+/// is equivalent to \c successThreshold == parents.size().
+///
+/// \returns \c true if the two components were separate and have now
+/// been joined; \c false if they were already in the same set.
+static bool unionSets(SmallVectorImpl<unsigned> &parents,
+                      unsigned index1, unsigned index2,
+                      unsigned successThreshold = 0) {
+  // Find the representatives of each component class.
+  unsigned rep1 = findRepresentative(parents, index1);
+  unsigned rep2 = findRepresentative(parents, index2);
+  if (rep1 == rep2) return false;
+
+  // Point at the lowest-numbered representative.
+  if (rep1 < rep2)
+    parents[rep2] = rep1;
+  else
+    parents[rep1] = rep2;
+
+  return (successThreshold == 0) ||
+    (rep1 < successThreshold && rep2 < successThreshold);
+}
+
+/// Determine whether the removal of the given edge will disconnect the
+/// nodes \c from and \c to within the given equivalence class.
+static bool removalDisconnectsEquivalenceClass(
+               EquivalenceClass *equivClass,
+               llvm::SmallDenseMap<PotentialArchetype *, unsigned> &componentOf,
+               std::vector<IntercomponentEdge> &sameTypeEdges,
+               unsigned edgeIndex,
+               PotentialArchetype *from,
+               PotentialArchetype *to) {
+  // Which component are "from" and "to" in within the intercomponent edges?
+  assert(componentOf.count(from) > 0);
+  auto fromComponentIndex = componentOf[from];
+  assert(componentOf.count(to) > 0);
+  auto toComponentIndex = componentOf[to];
+
+  // If they're in the same component, they're always connected (due to
+  // derived edges).
+  if (fromComponentIndex == toComponentIndex) return false;
+
+  /// Describes the parents in the equivalance classes we're forming.
+  SmallVector<unsigned, 4> parents;
+  for (unsigned i : range(equivClass->derivedSameTypeComponents.size())) {
+    parents.push_back(i);
+  }
+
+  for (const auto existingEdgeIndex : indices(sameTypeEdges)) {
+    if (existingEdgeIndex == edgeIndex) continue;
+
+    const auto &edge = sameTypeEdges[existingEdgeIndex];
+    if (edge.isSelfDerived) continue;
+
+    if (unionSets(parents, edge.source, edge.target) &&
+        findRepresentative(parents, fromComponentIndex) ==
+          findRepresentative(parents, toComponentIndex))
+      return false;
+  }
+
+  const auto &edge = sameTypeEdges[edgeIndex];
+
+  return !unionSets(parents, edge.source, edge.target) ||
+    findRepresentative(parents, fromComponentIndex) !=
+      findRepresentative(parents, toComponentIndex);
+}
+
+static bool isSelfDerivedNestedTypeNameMatchEdge(
+              EquivalenceClass *equivClass,
+              llvm::SmallDenseMap<PotentialArchetype *, unsigned> &componentOf,
+              std::vector<IntercomponentEdge> &sameTypeEdges,
+              unsigned edgeIndex) {
+  const auto &edge = sameTypeEdges[edgeIndex];
+  PotentialArchetype *source = edge.constraint.archetype;
+  PotentialArchetype *target = edge.constraint.value;
+  while (source->getParent() && target->getParent() &&
+         source->getResolvedAssociatedType() ==
+           target->getResolvedAssociatedType()) {
+    source = source->getParent();
+    target = target->getParent();
+
+    if (source->isInSameEquivalenceClassAs(target) &&
+        source->getEquivalenceClassIfPresent() == equivClass &&
+        !removalDisconnectsEquivalenceClass(equivClass, componentOf,
+                                            sameTypeEdges, edgeIndex,
+                                            source, target))
+      return true;
+  }
+
+  return false;
+}
+
+/// Collapse same-type components using the "delayed" requirements of the
+/// equivalence class.
+///
+/// This operation looks through the delayed requirements within the equivalence
+/// class to find paths that connect existing potential archetypes.
+static void collapseSameTypeComponentsThroughDelayedRequirements(
+              GenericSignatureBuilder &builder,
+              EquivalenceClass *equivClass,
+              llvm::SmallDenseMap<PotentialArchetype *, unsigned> &componentOf,
+              SmallVectorImpl<unsigned> &collapsedParents,
+              unsigned &remainingComponents) {
+  unsigned numCollapsedParents = collapsedParents.size();
+
+  /// "Virtual" components for types that aren't resolve to potential
+  /// archetypes.
+  llvm::SmallDenseMap<CanType, unsigned> virtualComponents;
+
+  /// Retrieve the component for a type representing a virtual component
+  auto getTypeVirtualComponent = [&](Type type) {
+    CanType canType = type->getCanonicalType();
+    auto knownVirtual = virtualComponents.find(canType);
+    if (knownVirtual != virtualComponents.end())
+      return knownVirtual->second;
+
+    unsigned component = collapsedParents.size();
+    collapsedParents.push_back(component);
+    virtualComponents[canType] = component;
+    return component;
+  };
+
+  /// Retrieve the component for the given potential archetype.
+  auto getPotentialArchetypeVirtualComponent = [&](PotentialArchetype *pa) {
+    if (pa->getEquivalenceClassIfPresent() == equivClass)
+      return componentOf[pa];
+
+    // We found a potential archetype in another equivalence class. Treat it
+    // as a "virtual" component representing that potential archetype's
+    // equivalence class.
+    return getTypeVirtualComponent(
+                             pa->getRepresentative()->getDependentType({ }));
+  };
+
+  /// Local function to retrieve the component with which the given type is
+  /// associated, for a type that we haven't tried to resolve yet.
+  auto getUnknownTypeVirtualComponent = [&](Type type) {
+    if (auto pa =
+            builder.resolveArchetype(type,
+                                     ArchetypeResolutionKind::AlreadyKnown))
+      return getPotentialArchetypeVirtualComponent(pa);
+
+    return getTypeVirtualComponent(type);
+  };
+
+  for (const auto &delayedReq : equivClass->delayedRequirements) {
+    // Only consider same-type requirements.
+    if (delayedReq.kind != DelayedRequirement::SameType) continue;
+
+    unsigned lhsComponent;
+    if (auto lhsPA = delayedReq.lhs.dyn_cast<PotentialArchetype *>())
+      lhsComponent = getPotentialArchetypeVirtualComponent(lhsPA);
+    else
+      lhsComponent = getUnknownTypeVirtualComponent(delayedReq.lhs.get<Type>());
+
+    unsigned rhsComponent;
+    if (auto rhsPA = delayedReq.rhs.dyn_cast<PotentialArchetype *>())
+      rhsComponent = getPotentialArchetypeVirtualComponent(rhsPA);
+    else
+      rhsComponent = getUnknownTypeVirtualComponent(delayedReq.rhs.get<Type>());
+
+    // Collapse the sets
+    if (unionSets(collapsedParents, lhsComponent, rhsComponent,
+                  numCollapsedParents) &&
+        lhsComponent < numCollapsedParents &&
+        rhsComponent < numCollapsedParents)
+      --remainingComponents;
+  }
+
+  /// Remove any additional collapsed parents we added.
+  collapsedParents.erase(collapsedParents.begin() + numCollapsedParents,
+                         collapsedParents.end());
+}
+
+/// Check whether two potential archetypes "structurally" match, e.g.,
+/// the names match up to the root (which must match).
+static bool potentialArchetypesStructurallyMatch(PotentialArchetype *pa1,
+                                                 PotentialArchetype *pa2) {
+  auto parent1 = pa1->getParent();
+  auto parent2 = pa2->getParent();
+  if (!parent1 && !parent2)
+    return pa1->getGenericParamKey() == pa2->getGenericParamKey();
+
+  // Check for depth mismatch.
+  if (static_cast<bool>(parent1) != static_cast<bool>(parent2))
+    return false;
+
+  // Check names.
+  if (pa1->getNestedName() != pa2->getNestedName())
+    return false;
+
+  return potentialArchetypesStructurallyMatch(parent1, parent2);
+}
+
+/// Look for structurally-equivalent types within the given equivalence class,
+/// collapsing their components.
+static void collapseStructurallyEquivalentSameTypeComponents(
+              EquivalenceClass *equivClass,
+              llvm::SmallDenseMap<PotentialArchetype *, unsigned> &componentOf,
+              SmallVectorImpl<unsigned> &collapsedParents,
+              unsigned &remainingComponents) {
+  for (unsigned i : indices(equivClass->members)) {
+    auto pa1 = equivClass->members[i];
+    auto rep1 = findRepresentative(collapsedParents, componentOf[pa1]);
+    for (unsigned j : indices(equivClass->members).slice(i + 1)) {
+      auto pa2 = equivClass->members[j];
+      auto rep2 = findRepresentative(collapsedParents, componentOf[pa2]);
+      if (rep1 == rep2) continue;
+
+      auto depth = pa1->getNestingDepth();
+      if (depth < 2 || depth != pa2->getNestingDepth()) continue;
+
+      if (potentialArchetypesStructurallyMatch(pa1, pa2) &&
+          unionSets(collapsedParents, rep1, rep2)) {
+        --remainingComponents;
+        rep1 = findRepresentative(collapsedParents, componentOf[pa1]);
+      }
+    }
+  }
+}
+
+/// Collapse same-type components within an equivalence class, minimizing the
+/// number of requirements required to express the equivalence class.
+static void collapseSameTypeComponents(
+              GenericSignatureBuilder &builder,
+              EquivalenceClass *equivClass,
+              llvm::SmallDenseMap<PotentialArchetype *, unsigned> &componentOf,
+              std::vector<IntercomponentEdge> &sameTypeEdges) {
+  SmallVector<unsigned, 4> collapsedParents;
+  for (unsigned i : indices(equivClass->derivedSameTypeComponents)) {
+    collapsedParents.push_back(i);
+  }
+
+  unsigned remainingComponents = equivClass->derivedSameTypeComponents.size();
+  for (unsigned edgeIndex : indices(sameTypeEdges)) {
+    auto &edge = sameTypeEdges[edgeIndex];
+
+    // If this edge is self-derived, remove it.
+    if (isSelfDerivedNestedTypeNameMatchEdge(equivClass, componentOf,
+                                             sameTypeEdges, edgeIndex)) {
+      auto eraseConstraint = [&](PotentialArchetype *archetype) {
+        auto &constraints = equivClass->sameTypeConstraints[archetype];
+        auto known =
+          std::find_if(constraints.begin(), constraints.end(),
+                       [&](const Constraint<PotentialArchetype *> &existing) {
+                         // Check the requirement source, first.
+                         if (existing.source != edge.constraint.source)
+                           return false;
+
+                         return
+                           (existing.archetype == edge.constraint.archetype &&
+                            existing.value == edge.constraint.value) ||
+                           (existing.archetype == edge.constraint.value &&
+                            existing.value == edge.constraint.archetype);
+                       });
+        assert(known != constraints.end());
+        constraints.erase(known);
+      };
+
+      // Note that this edge is self-derived, so we don't consider it again.
+      edge.isSelfDerived = true;
+
+      // Erase the constraint in both directions.
+      eraseConstraint(edge.constraint.archetype);
+      eraseConstraint(edge.constraint.value);
+
+      continue;
+    }
+
+    // Otherwise, collapse the derived same-type components along this edge,
+    // because it's derived.
+    if (unionSets(collapsedParents, edge.source, edge.target))
+      --remainingComponents;
+  }
+
+  if (remainingComponents > 1) {
+    // Collapse same-type components by looking at the delayed requirements.
+    collapseSameTypeComponentsThroughDelayedRequirements(
+      builder, equivClass, componentOf, collapsedParents, remainingComponents);
+  }
+
+  if (remainingComponents > 1) {
+    // Collapse structurally-equivalent components.
+    collapseStructurallyEquivalentSameTypeComponents(equivClass,
+                                                     componentOf,
+                                                     collapsedParents,
+                                                     remainingComponents);
+  }
+
+  // If needed, collapse the same-type components merged by a derived
+  // nested-type-name-match edge.
+  unsigned maxComponents = equivClass->derivedSameTypeComponents.size();
+  if (remainingComponents < maxComponents) {
+    std::vector<DerivedSameTypeComponent> newComponents;
+    std::vector<unsigned> newIndices(maxComponents, maxComponents);
+
+    for (unsigned oldIndex : range(0, maxComponents)) {
+      auto &oldComponent = equivClass->derivedSameTypeComponents[oldIndex];
+      unsigned oldRepresentativeIndex =
+        findRepresentative(collapsedParents, oldIndex);
+
+      // If this is the representative, it's a new component; record it.
+      if (oldRepresentativeIndex == oldIndex) {
+        assert(newIndices[oldIndex] == maxComponents &&
+               "Already saw this component?");
+        unsigned newIndex = newComponents.size();
+        newIndices[oldIndex] = newIndex;
+        newComponents.push_back(
+          {oldComponent.anchor, oldComponent.concreteTypeSource});
+        continue;
+      }
+
+      // This is not the representative; merge it into the representative
+      // component.
+      auto newRepresentativeIndex = newIndices[oldRepresentativeIndex];
+      assert(newRepresentativeIndex != maxComponents &&
+             "Representative should have come earlier");
+      auto &newComponent = newComponents[newRepresentativeIndex];
+
+      // If the old component has a better anchor, keep it.
+      if (compareDependentTypes(&oldComponent.anchor, &newComponent.anchor) < 0)
+        newComponent.anchor = oldComponent.anchor;
+
+      // If the old component has a better concrete type source, keep it.
+      if (!newComponent.concreteTypeSource ||
+          (oldComponent.concreteTypeSource &&
+           oldComponent.concreteTypeSource
+             ->compare(newComponent.concreteTypeSource) < 0))
+        newComponent.concreteTypeSource = oldComponent.concreteTypeSource;
+    }
+
+    // Move the new results into place.
+    equivClass->derivedSameTypeComponents = std::move(newComponents);
+  }
+
+  // Sort the components.
+  llvm::array_pod_sort(equivClass->derivedSameTypeComponents.begin(),
+                       equivClass->derivedSameTypeComponents.end());
+}
 
 void GenericSignatureBuilder::checkSameTypeConstraints(
                           ArrayRef<GenericTypeParamType *> genericParams,
@@ -4983,16 +5529,6 @@
   if (!equivClass || !equivClass->derivedSameTypeComponents.empty())
     return;
 
-  // Make sure that we've build the archetype anchors for each potential
-  // archetype in this equivalence class. This is important to do for *all*
-  // potential archetypes because some non-archetype anchors will nonetheless
-  // be used in the canonicalized requirements.
-  for (auto pa : pa->getEquivalenceClassMembers()) {
-    (void)getLocalAnchor(pa, *this);
-  }
-  equivClass = pa->getEquivalenceClassIfPresent();
-  assert(equivClass && "Equivalence class disappeared?");
-
   bool anyDerivedViaConcrete = false;
   for (auto &entry : equivClass->sameTypeConstraints) {
     auto &constraints = entry.second;
@@ -5025,6 +5561,7 @@
   // Intercomponent edges are stored as one big list, which tracks the
   // source/target components.
   std::vector<IntercomponentEdge> intercomponentEdges;
+  std::vector<IntercomponentEdge> nestedTypeNameMatchEdges;
   for (auto &entry : equivClass->sameTypeConstraints) {
     auto &constraints = entry.second;
     for (const auto &constraint : constraints) {
@@ -5054,15 +5591,27 @@
       // Determine which component each of the source/destination fall into.
       assert(componentOf.count(constraint.archetype) > 0 &&
              "unknown potential archetype?");
-      unsigned firstComponent = componentOf[constraint.archetype];
+      unsigned firstComponentIdx = componentOf[constraint.archetype];
       assert(componentOf.count(constraint.value) > 0 &&
              "unknown potential archetype?");
-      unsigned secondComponent = componentOf[constraint.value];
+      unsigned secondComponentIdx = componentOf[constraint.value];
+
+      // Separately track nested-type-name-match constraints.
+      if (constraint.source->getRoot()->kind ==
+            RequirementSource::NestedTypeNameMatch) {
+        // If this is an intercomponent edge, record it separately.
+        if (firstComponentIdx != secondComponentIdx) {
+          nestedTypeNameMatchEdges.push_back(
+            IntercomponentEdge(firstComponentIdx, secondComponentIdx, constraint));
+        }
+
+        continue;
+      }
 
       // If both vertices are within the same component, this is an
       // intra-component edge. Record it as such.
-      if (firstComponent == secondComponent) {
-        intracomponentEdges[firstComponent].push_back(constraint);
+      if (firstComponentIdx == secondComponentIdx) {
+        intracomponentEdges[firstComponentIdx].push_back(constraint);
         continue;
       }
 
@@ -5072,7 +5621,7 @@
 
       // Ignore inferred requirements; we don't want to diagnose them.
       intercomponentEdges.push_back(
-        IntercomponentEdge(firstComponent, secondComponent, constraint));
+        IntercomponentEdge(firstComponentIdx, secondComponentIdx, constraint));
     }
   }
 
@@ -5084,7 +5633,6 @@
 
       // Remove derived-via-concrete constraints.
       (void)removeSelfDerived(constraints, /*proto=*/nullptr);
-        anyDerivedViaConcrete = true;
     }
   }
 
@@ -5097,7 +5645,12 @@
     checkConstraintList<PotentialArchetype *, Type>(
       genericParams, constraints,
       [](const Constraint<PotentialArchetype *> &) { return true; },
-      [](const Constraint<PotentialArchetype *> &) {
+      [](const Constraint<PotentialArchetype *> &constraint) {
+        // Ignore nested-type-name-match constraints.
+        if (constraint.source->getRoot()->kind ==
+              RequirementSource::NestedTypeNameMatch)
+          return ConstraintRelation::Unrelated;
+
         return ConstraintRelation::Redundant;
       },
       None,
@@ -5190,6 +5743,9 @@
       connected[edge.target] = true;
     }
   }
+
+  collapseSameTypeComponents(*this, equivClass, componentOf,
+                             nestedTypeNameMatchEdges);
 }
 
 /// Resolve any unresolved dependent member types using the given builder.
@@ -5486,7 +6042,8 @@
       // If we're at the last anchor in the component, do nothing;
       auto nextAnchor = knownAnchor;
       ++nextAnchor;
-      if (nextAnchor != equivClass->derivedSameTypeComponents.end()) {
+      if (nextAnchor != equivClass->derivedSameTypeComponents.end() /* &&
+          !equivClass->areAllRequirementsDerived()*/) {
         // Form a same-type constraint from this anchor within the component
         // to the next.
         // FIXME: Distinguish between explicit and inferred here?
diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp
index 439ea5d..f3a713f 100644
--- a/lib/Sema/TypeCheckProtocol.cpp
+++ b/lib/Sema/TypeCheckProtocol.cpp
@@ -4157,6 +4157,60 @@
   return TC.compareDeclarations(DC, decl1, decl2);
 }
 
+/// "Sanitize" requirements for conformance checking, removing any requirements
+/// that unnecessarily refer to associated types of other protocols.
+static void sanitizeProtocolRequirements(
+                                     ProtocolDecl *proto,
+                                     ArrayRef<Requirement> requirements,
+                                     SmallVectorImpl<Requirement> &sanitized) {
+  std::function<Type(Type)> sanitizeType;
+  sanitizeType = [&](Type outerType) {
+    return outerType.transformRec([&] (TypeBase *type) -> Optional<Type> {
+      if (auto depMemTy = dyn_cast<DependentMemberType>(type)) {
+        if (!depMemTy->getAssocType() ||
+            depMemTy->getAssocType()->getProtocol() != proto) {
+          for (auto member : proto->lookupDirect(depMemTy->getName())) {
+            if (auto assocType = dyn_cast<AssociatedTypeDecl>(member)) {
+              return Type(DependentMemberType::get(
+                                           sanitizeType(depMemTy->getBase()),
+                                           assocType));
+            }
+          }
+
+          if (depMemTy->getBase()->is<GenericTypeParamType>())
+            return Type();
+        }
+      }
+
+      return None;
+    });
+  };
+
+  for (const auto &req : requirements) {
+    switch (req.getKind()) {
+    case RequirementKind::Conformance:
+    case RequirementKind::SameType:
+    case RequirementKind::Superclass: {
+      Type firstType = sanitizeType(req.getFirstType());
+      Type secondType = sanitizeType(req.getSecondType());
+      if (firstType && secondType) {
+        sanitized.push_back({req.getKind(), firstType, secondType});
+      }
+      break;
+    }
+
+    case RequirementKind::Layout: {
+      Type firstType = sanitizeType(req.getFirstType());
+      if (firstType) {
+        sanitized.push_back({req.getKind(), firstType,
+                             req.getLayoutConstraint()});
+      }
+      break;
+    }
+    }
+  }
+}
+
 void ConformanceChecker::resolveTypeWitnesses() {
   llvm::SetVector<AssociatedTypeDecl *> unresolvedAssocTypes;
 
@@ -4424,9 +4478,12 @@
                                           Proto, Conformance->getType(),
                                           ProtocolConformanceRef(Conformance));
 
+      SmallVector<Requirement, 4> sanitizedRequirements;
+      sanitizeProtocolRequirements(Proto, Proto->getRequirementSignature(),
+                                   sanitizedRequirements);
       auto requirementSig =
         GenericSignature::get({Proto->getProtocolSelfType()},
-                              Proto->getRequirementSignature());
+                               sanitizedRequirements);
       auto result =
         TC.checkGenericArguments(DC, SourceLoc(), SourceLoc(),
                                  Conformance->getType(), requirementSig,
diff --git a/stdlib/public/core/UTFEncoding.swift b/stdlib/public/core/UTFEncoding.swift
index 1a257b7..bab890a 100644
--- a/stdlib/public/core/UTFEncoding.swift
+++ b/stdlib/public/core/UTFEncoding.swift
@@ -17,7 +17,7 @@
 
 
 public protocol _UTFParser {
-  associatedtype Encoding : _UnicodeEncoding_
+  associatedtype Encoding : _UnicodeEncoding
 
   func _parseMultipleCodeUnits() -> (isValid: Bool, bitCount: UInt8)
   func _bufferedScalar(bitCount: UInt8) -> Encoding.EncodedScalar
diff --git a/stdlib/public/core/UnicodeEncoding.swift b/stdlib/public/core/UnicodeEncoding.swift
index 2bde99e..ca81fab 100644
--- a/stdlib/public/core/UnicodeEncoding.swift
+++ b/stdlib/public/core/UnicodeEncoding.swift
@@ -10,7 +10,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-public protocol _UnicodeEncoding_ {
+public protocol _UnicodeEncoding {
   /// The basic unit of encoding
   associatedtype CodeUnit : UnsignedInteger, FixedWidthInteger
   
@@ -44,12 +44,12 @@
   /// A type that can be used to parse `CodeUnits` into
   /// `EncodedScalar`s.
   associatedtype ForwardParser : Unicode.Parser
-  // where ForwardParser.Encoding == Self
+    where ForwardParser.Encoding == Self
   
   /// A type that can be used to parse a reversed sequence of
   /// `CodeUnits` into `EncodedScalar`s.
   associatedtype ReverseParser : Unicode.Parser
-  // where ReverseParser.Encoding == Self
+    where ReverseParser.Encoding == Self
 
   //===--------------------------------------------------------------------===//
   // FIXME: this requirement shouldn't be here and is mitigated by the default
@@ -60,15 +60,10 @@
   static func _isScalar(_ x: CodeUnit) -> Bool
 }
 
-extension _UnicodeEncoding_ {
+extension _UnicodeEncoding {
   // See note on declaration of requirement, above
   public static func _isScalar(_ x: CodeUnit) -> Bool { return false }
-}
 
-public protocol _UnicodeEncoding : _UnicodeEncoding_
-where ForwardParser.Encoding == Self, ReverseParser.Encoding == Self {}
-
-extension _UnicodeEncoding_ {
   public static func transcode<FromEncoding : Unicode.Encoding>(
     _ content: FromEncoding.EncodedScalar, from _: FromEncoding.Type
   ) -> EncodedScalar? {
diff --git a/stdlib/public/core/UnicodeParser.swift b/stdlib/public/core/UnicodeParser.swift
index 0a5ee64..adc4a26 100644
--- a/stdlib/public/core/UnicodeParser.swift
+++ b/stdlib/public/core/UnicodeParser.swift
@@ -43,7 +43,7 @@
 /// scalar values.
 public protocol _UnicodeParser {
   /// The encoding with which this parser is associated
-  associatedtype Encoding : _UnicodeEncoding_
+  associatedtype Encoding : _UnicodeEncoding
 
   /// Constructs an instance that can be used to begin parsing `CodeUnit`s at
   /// any Unicode scalar boundary.
diff --git a/test/Generics/protocol_requirement_signatures.swift b/test/Generics/protocol_requirement_signatures.swift
index 2bb7d20..e3fd609 100644
--- a/test/Generics/protocol_requirement_signatures.swift
+++ b/test/Generics/protocol_requirement_signatures.swift
@@ -33,16 +33,16 @@
 
 // inheritance without any new requirements
 // CHECK-LABEL: .Q3@
-// CHECK-NEXT: Requirement signature: <Self where Self : Q1>
-// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : Q1>
+// CHECK-NEXT: Requirement signature: <Self where Self : Q1, Self.X == Self.X>
+// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : Q1, τ_0_0.X == τ_0_0.X>
 protocol Q3: Q1 {
     associatedtype X // expected-warning{{redeclaration of associated type 'X'}}
 }
 
 // inheritance adding a new conformance
 // CHECK-LABEL: .Q4@
-// CHECK-NEXT: Requirement signature: <Self where Self : Q1, Self.X : P2>
-// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : Q1, τ_0_0.X : P2>
+// CHECK-NEXT: Requirement signature: <Self where Self : Q1, Self.X : P2, Self.X == Self.X>
+// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : Q1, τ_0_0.X : P2, τ_0_0.X == τ_0_0.X>
 protocol Q4: Q1 {
     associatedtype X: P2 // expected-warning{{redeclaration of associated type 'X'}}
                    // expected-note@-1 2{{'X' declared here}}
@@ -56,8 +56,8 @@
 
 // multiple inheritance without any new requirements
 // CHECK-LABEL: .Q6@
-// CHECK-NEXT: Requirement signature: <Self where Self : Q2, Self : Q3, Self : Q4>
-// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : Q2, τ_0_0 : Q3, τ_0_0 : Q4>
+// CHECK-NEXT: Requirement signature: <Self where Self : Q2, Self : Q3, Self : Q4, Self.X == Self.X>
+// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : Q2, τ_0_0 : Q3, τ_0_0 : Q4, τ_0_0.X == τ_0_0.X>
 protocol Q6: Q2, // expected-note{{conformance constraint 'Self.X': 'P1' implied here}}
              Q3, Q4 {
     associatedtype X: P1 // expected-warning{{redundant conformance constraint 'Self.X': 'P1'}}
@@ -66,8 +66,8 @@
 
 // multiple inheritance with a new conformance
 // CHECK-LABEL: .Q7@
-// CHECK-NEXT: Requirement signature: <Self where Self : Q2, Self : Q3, Self : Q4, Self.X : P3>
-// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : Q2, τ_0_0 : Q3, τ_0_0 : Q4, τ_0_0.X : P3>
+// CHECK-NEXT: Requirement signature: <Self where Self : Q2, Self : Q3, Self : Q4, Self.X : P3, Self.X == Self.X>
+// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : Q2, τ_0_0 : Q3, τ_0_0 : Q4, τ_0_0.X : P3, τ_0_0.X == τ_0_0.X>
 protocol Q7: Q2, Q3, Q4 {
     associatedtype X: P3 // expected-warning{{redeclaration of associated type 'X'}}
 }
diff --git a/test/Generics/requirement_inference.swift b/test/Generics/requirement_inference.swift
index 390aafa..755d24d 100644
--- a/test/Generics/requirement_inference.swift
+++ b/test/Generics/requirement_inference.swift
@@ -176,11 +176,11 @@
 }
 
 // CHECK-LABEL: sameTypeConcrete1@
-// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : P10, τ_0_0 : P9, τ_0_0.A == X3, τ_0_0.B == Int, τ_0_0.C == Int>
+// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : P10, τ_0_0 : P9, τ_0_0.A == X3, τ_0_0.A == X3, τ_0_0.B == Int, τ_0_0.C == Int>
 func sameTypeConcrete1<T : P9 & P10>(_: T) where T.A == X3, T.C == T.B, T.C == Int { }
 
 // CHECK-LABEL: sameTypeConcrete2@
-// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : P10, τ_0_0 : P9, τ_0_0.B == X3, τ_0_0.C == X3>
+// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : P10, τ_0_0 : P9, τ_0_0.A == τ_0_0.A, τ_0_0.B == X3, τ_0_0.C == X3>
 func sameTypeConcrete2<T : P9 & P10>(_: T) where T.B : X3, T.C == T.B, T.C == X3 { }
 // expected-warning@-1{{redundant superclass constraint 'T.B' : 'X3'}}
 // expected-note@-2{{same-type constraint 'T.C' == 'X3' written here}}
@@ -188,7 +188,7 @@
 // Note: a standard-library-based stress test to make sure we don't inject
 // any additional requirements.
 // CHECK-LABEL: RangeReplaceableCollection.f()@
-// CHECK: <τ_0_0 where τ_0_0 : MutableCollection, τ_0_0 : RangeReplaceableCollection, τ_0_0.SubSequence == MutableRangeReplaceableSlice<τ_0_0>>
+// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : MutableCollection, τ_0_0 : RangeReplaceableCollection, τ_0_0.SubSequence == MutableRangeReplaceableSlice<τ_0_0>>
 extension RangeReplaceableCollection where
   Self: MutableCollection,
   Self.SubSequence == MutableRangeReplaceableSlice<Self>
@@ -399,8 +399,25 @@
 }
 
 // CHECK-LABEL: .P28@
-// CHECK-NEXT: Requirement signature: <Self where Self : P3>
-// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : P3>
+// CHECK-NEXT: Requirement signature: <Self where Self : P3, Self.P3Assoc == X28>
+// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : P3, τ_0_0.P3Assoc == X28>
 protocol P28: P3 {
   typealias P3Assoc = X28   // expected-warning{{typealias overriding associated type}}
 }
+
+// ----------------------------------------------------------------------------
+// Inference of associated types by name match
+// ----------------------------------------------------------------------------
+protocol P29 {
+  associatedtype X
+}
+
+protocol P30 {
+  associatedtype X
+}
+
+protocol P31 { }
+
+// CHECK-LABEL: .sameTypeNameMatch1@
+// Generic signature: <T where T : P29, T : P30, T.X : P31, T.X == T.X>
+func sameTypeNameMatch1<T: P29 & P30>(_: T) where T.X: P31 { }
diff --git a/test/SILGen/same_type_abstraction.swift b/test/SILGen/same_type_abstraction.swift
index fb84d6b..9da1a8e 100644
--- a/test/SILGen/same_type_abstraction.swift
+++ b/test/SILGen/same_type_abstraction.swift
@@ -50,7 +50,7 @@
 }
 
 extension Refined {
-  // CHECK-LABEL: sil hidden @_T021same_type_abstraction7RefinedPAAEx3KeyQz12withElements_tcfC : $@convention(method) <Self where Self : Refined> (@in Self.Key, @thick Self.Type) -> @out Self
+  // CHECK-LABEL: sil hidden @_T021same_type_abstraction7RefinedPAAEx5AssocQz12withElements_tcfC : $@convention(method) <Self where Self : Refined> (@in Self.Assoc, @thick Self.Type) -> @out Self
   init(withElements newElements: Key) {
     self.init()
   }
diff --git a/test/decl/protocol/recursive_requirement_ok.swift b/test/decl/protocol/recursive_requirement_ok.swift
index cb07937..2266500 100644
--- a/test/decl/protocol/recursive_requirement_ok.swift
+++ b/test/decl/protocol/recursive_requirement_ok.swift
@@ -20,7 +20,7 @@
   associatedtype X : P2
 }
 
-// CHECK: P2
+// CHECK-LABEL: .P2@
 // CHECK: Requirement signature: <Self where Self == Self.Y.X, Self.Y : P1, Self.Z : P1>
 protocol P2 {
   associatedtype Y : P1 where Y.X == Self
@@ -32,9 +32,55 @@
 	associatedtype X : P4
 }
 
-// CHECK: .P4@
+// CHECK-LABEL: .P4@
 // CHECK: Requirement signature: <Self where Self == Self.Y.X, Self.Y : P3, Self.Z : P3, Self.Y.X == Self.Z.X>
 protocol P4 {
 	associatedtype Y: P3 where Y.X == Self
 	associatedtype Z: P3 where Z.X == Self
 }
+
+protocol P5 {
+  associatedtype X : P5
+    where X.X == X
+}
+
+// CHECK-LABEL: .P6@
+// CHECK: Requirement signature: <Self where Self : P5, Self.Y : P5>
+protocol P6 : P5 {
+  associatedtype Y : P5
+}
+
+// CHECK: Generic signature: <Self where Self : P6, Self.X == Self.Y.X>
+extension P6 where X == Y.X { }
+
+// SR-5601
+protocol P7 {
+    associatedtype X: P9 where X.Q == Self, X.R == UInt8
+    associatedtype Y: P9 where Y.Q == Self, Y.R == UInt16
+    // NOTE: Removing either X or Y from P7 (and A7) makes the program compile.
+}
+struct A7: P7 {
+    typealias X = S9<UInt8>
+    typealias Y = S9<UInt16>
+}
+protocol P8 { }
+protocol P9 : P8 { // NOTE: Removing ": P8 " here makes the program compile.
+    associatedtype Q: P7
+    associatedtype R
+}
+struct S9<E> : P9 {
+    typealias R = E
+    typealias Q = A7
+}
+
+// SR-5610
+protocol P10 {
+  associatedtype X : P11 where X.Q == Self
+}
+protocol P11 {
+  associatedtype Q : P10
+
+  // CHECK-LABEL: .P11.map@
+  // CHECK: Generic signature: <Self, T where Self : P11, T : P11, Self.Q == T.Q>
+  func map<T>(_: T.Type) where T : P11, Q == T.Q
+}