Merge pull request #12097 from DougGregor/gsb-nested-type-lookup

[GSB] Centralize, clean up, and cache nested type name lookup
diff --git a/include/swift/AST/GenericSignatureBuilder.h b/include/swift/AST/GenericSignatureBuilder.h
index ddf8ebe..8eecc19 100644
--- a/include/swift/AST/GenericSignatureBuilder.h
+++ b/include/swift/AST/GenericSignatureBuilder.h
@@ -215,6 +215,15 @@
     /// a superclass requirement.
     bool isConformanceSatisfiedBySuperclass(ProtocolDecl *proto) const;
 
+    /// Lookup a nested type with the given name within this equivalence
+    /// class.
+    ///
+    /// \param otherConcreteTypes If non-null, will be filled in the all of the
+    /// concrete types we found (other than the result) with the same name.
+    TypeDecl *lookupNestedType(
+                   Identifier name,
+                   SmallVectorImpl<TypeDecl *> *otherConcreteTypes = nullptr);
+
     /// Dump a debugging representation of this equivalence class.
     void dump(llvm::raw_ostream &out) const;
 
@@ -232,6 +241,17 @@
       /// anchor was cached.
       unsigned numMembers;
     } archetypeAnchorCache;
+
+    /// Describes a cached nested type.
+    struct CachedNestedType {
+      unsigned numConformancesPresent;
+      CanType superclassPresent;
+      llvm::TinyPtrVector<TypeDecl *> types;
+    };
+
+    /// Cached nested-type information, which contains the best declaration
+    /// for a given name.
+    llvm::SmallDenseMap<Identifier, CachedNestedType> nestedTypeNameCache;
   };
 
   friend class RequirementSource;
@@ -522,9 +542,6 @@
   /// \brief Add all of a generic signature's parameters and requirements.
   void addGenericSignature(GenericSignature *sig);
 
-  /// \brief Build the generic signature.
-  GenericSignature *getGenericSignature();
-
   /// Infer requirements from the given type, recursively.
   ///
   /// This routine infers requirements from a type that occurs within the
@@ -558,11 +575,13 @@
   /// \brief Finalize the set of requirements and compute the generic
   /// signature.
   ///
-  /// After this point, one cannot introduce new requirements.
+  /// After this point, one cannot introduce new requirements, and the
+  /// generic signature builder no longer has valid state.
   GenericSignature *computeGenericSignature(
                       SourceLoc loc,
-                      bool allowConcreteGenericParams = false);
+                      bool allowConcreteGenericParams = false) &&;
 
+private:
   /// Finalize the set of requirements, performing any remaining checking
   /// required before generating archetypes.
   ///
@@ -572,6 +591,7 @@
                 ArrayRef<GenericTypeParamType *> genericParams,
                 bool allowConcreteGenericParams=false);
 
+public:
   /// Process any delayed requirements that can be handled now.
   void processDelayedRequirements();
 
@@ -1490,6 +1510,12 @@
     return parentOrBuilder.dyn_cast<PotentialArchetype *>();
   }
 
+  /// Retrieve the type declaration to which this nested type was resolved.
+  TypeDecl *getResolvedType() const {
+    assert(getParent() && "Not an associated type");
+    return identifier.assocTypeOrConcrete;
+  }
+
   /// Retrieve the associated type to which this potential archetype
   /// has been resolved.
   AssociatedTypeDecl *getResolvedAssociatedType() const {
@@ -1632,13 +1658,8 @@
                                     ArchetypeResolutionKind kind,
                                     GenericSignatureBuilder &builder);
 
-  /// \brief Retrieve (or create) a nested type with a known associated type.
-  PotentialArchetype *getNestedType(AssociatedTypeDecl *assocType,
-                                    GenericSignatureBuilder &builder);
-
-  /// \brief Retrieve (or create) a nested type with a known concrete type
-  /// declaration.
-  PotentialArchetype *getNestedType(TypeDecl *concreteDecl,
+  /// \brief Retrieve (or create) a nested type with a known type.
+  PotentialArchetype *getNestedType(TypeDecl *type,
                                     GenericSignatureBuilder &builder);
 
   /// \brief Retrieve (or create) a nested type that is the current best
@@ -1658,8 +1679,8 @@
   /// 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<AssociatedTypeDecl *, TypeDecl *> type,
-                      ArchetypeResolutionKind kind);
+                        TypeDecl *type,
+                        ArchetypeResolutionKind kind);
 
   /// Update the named nested type when we know this type conforms to the given
   /// protocol.
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 7917da8..5bb5519 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -4591,7 +4591,7 @@
     GenericSignatureBuilder::FloatingRequirementSource::forAbstract();
   builder.addRequirement(requirement, source, nullptr);
 
-  CanGenericSignature genericSig(builder.computeGenericSignature(SourceLoc()));
+  CanGenericSignature genericSig(std::move(builder).computeGenericSignature(SourceLoc()));
 
   auto result = Impl.ExistentialSignatures.insert(
     std::make_pair(existential, genericSig));
diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp
index a7c473a..f9af2d2 100644
--- a/lib/AST/Builtins.cpp
+++ b/lib/AST/Builtins.cpp
@@ -491,7 +491,8 @@
         Builder.addGenericParameter(gp);
       }
 
-      auto GenericSig = Builder.computeGenericSignature(SourceLoc());
+      auto GenericSig =
+        std::move(Builder).computeGenericSignature(SourceLoc());
       GenericEnv = GenericSig->createGenericEnvironment(*ctx.TheBuiltinModule);
     }
 
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index bcb698a..e7e7f55 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -3419,7 +3419,8 @@
          nullptr);
 
   // Compute and record the signature.
-  auto requirementSig = builder.computeGenericSignature(SourceLoc());
+  auto requirementSig =
+    std::move(builder).computeGenericSignature(SourceLoc());
   RequirementSignature = requirementSig->getRequirements().data();
   assert(RequirementSignature != nullptr);
   NumRequirementsInSignature = requirementSig->getRequirements().size();
diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp
index f0b85ea..32f8d63 100644
--- a/lib/AST/GenericSignatureBuilder.cpp
+++ b/lib/AST/GenericSignatureBuilder.cpp
@@ -76,6 +76,10 @@
           "# of hits in the archetype anchor cache");
 STATISTIC(NumArchetypeAnchorCacheMisses,
           "# of misses in the archetype anchor cache");
+STATISTIC(NumNestedTypeCacheHits,
+         "# of hits in the equivalence class nested type cache");
+STATISTIC(NumNestedTypeCacheMisses,
+         "# of misses in the equivalence class nested type cache");
 STATISTIC(NumProcessDelayedRequirements,
           "# of times we process delayed requirements");
 STATISTIC(NumProcessDelayedRequirementsUnchanged,
@@ -1554,6 +1558,159 @@
   return false;
 }
 
+/// Compare two associated types.
+static int compareAssociatedTypes(AssociatedTypeDecl *assocType1,
+                                  AssociatedTypeDecl *assocType2) {
+  // - by name.
+  if (int result = assocType1->getName().str().compare(
+                                              assocType2->getName().str()))
+    return result;
+
+  // - by protocol, so t_n_m.`P.T` < t_n_m.`Q.T` (given P < Q)
+  auto proto1 = assocType1->getProtocol();
+  auto proto2 = assocType2->getProtocol();
+  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 (assocType1 != assocType2)
+    return assocType1 < assocType2 ? -1 : +1;
+
+  return 0;
+}
+
+TypeDecl *EquivalenceClass::lookupNestedType(
+                             Identifier name,
+                             SmallVectorImpl<TypeDecl *> *otherConcreteTypes) {
+  // Populates the result structures from the given cache entry.
+  auto populateResult = [&](const CachedNestedType &cache) -> TypeDecl * {
+    if (otherConcreteTypes)
+      otherConcreteTypes->clear();
+
+    // If there aren't any types in the cache, we're done.
+    if (cache.types.empty()) return nullptr;
+
+    // The first type in the cache is always the final result.
+    // Collect the rest in the concrete-declarations list, if needed.
+    if (otherConcreteTypes) {
+      for (auto type : ArrayRef<TypeDecl *>(cache.types).slice(1)) {
+        otherConcreteTypes->push_back(type);
+      }
+    }
+
+    return cache.types.front();
+  };
+
+  // If we have a cached value that is up-to-date, use that.
+  auto cached = nestedTypeNameCache.find(name);
+  if (cached != nestedTypeNameCache.end() &&
+      cached->second.numConformancesPresent == conformsTo.size() &&
+      (!superclass ||
+       cached->second.superclassPresent == superclass->getCanonicalType())) {
+    ++NumNestedTypeCacheHits;
+    return populateResult(cached->second);
+  }
+
+  // Cache miss; go compute the result.
+  ++NumNestedTypeCacheMisses;
+
+  // Look for types with the given name in protocols that we know about.
+  AssociatedTypeDecl *bestAssocType = nullptr;
+  SmallVector<TypeDecl *, 4> concreteDecls;
+  for (const auto &conforms : conformsTo) {
+    ProtocolDecl *proto = conforms.first;
+
+    // Look for an associated type and/or concrete type with this name.
+    for (auto member : proto->lookupDirect(name,
+                                           /*ignoreNewExtensions=*/true)) {
+      // If this is an associated type, record whether it is the best
+      // associated type we've seen thus far.
+      if (auto assocType = dyn_cast<AssociatedTypeDecl>(member)) {
+        if (!bestAssocType ||
+             compareAssociatedTypes(assocType, bestAssocType) < 0)
+          bestAssocType = assocType;
+
+        continue;
+      }
+
+      // If this is another type declaration, determine whether we should
+      // record it.
+      if (auto type = dyn_cast<TypeDecl>(member)) {
+        // FIXME: Filter out type declarations that aren't in the same
+        // module as the protocol itself. This is an unprincipled hack, but
+        // provides consistent lookup semantics for the generic signature
+        // builder in all contents.
+        if (type->getDeclContext()->getParentModule()
+              != proto->getParentModule())
+          continue;
+
+        // Resolve the signature of this type.
+        if (!type->hasInterfaceType()) {
+          type->getASTContext().getLazyResolver()->resolveDeclSignature(type);
+          if (!type->hasInterfaceType())
+            continue;
+        }
+
+        concreteDecls.push_back(type);
+        continue;
+      }
+    }
+  }
+
+  // If we haven't found anything yet but have a superclass, look for a type
+  // in the superclass.
+  // FIXME: Shouldn't we always look in the superclass?
+  if (!bestAssocType && concreteDecls.empty() && superclass) {
+    if (auto classDecl = superclass->getClassOrBoundGenericClass()) {
+      SmallVector<ValueDecl *, 2> superclassMembers;
+      classDecl->getParentModule()->lookupQualified(
+          superclass, name,
+          NL_QualifiedDefault | NL_OnlyTypes | NL_ProtocolMembers, nullptr,
+          superclassMembers);
+      for (auto member : superclassMembers) {
+        if (auto type = dyn_cast<TypeDecl>(member)) {
+          // Resolve the signature of this type.
+          if (!type->hasInterfaceType()) {
+            type->getASTContext().getLazyResolver()->resolveDeclSignature(type);
+            if (!type->hasInterfaceType())
+              continue;
+          }
+
+          concreteDecls.push_back(type);
+        }
+      }
+    }
+  }
+
+  // Form the new cache entry.
+  CachedNestedType entry;
+  entry.numConformancesPresent = conformsTo.size();
+  entry.superclassPresent =
+    superclass ? superclass->getCanonicalType() : CanType();
+  if (bestAssocType) {
+    entry.types.push_back(bestAssocType);
+    entry.types.insert(entry.types.end(),
+                       concreteDecls.begin(), concreteDecls.end());
+  } else if (!concreteDecls.empty()) {
+    // Find the best concrete type.
+    auto bestConcreteTypeIter =
+      std::min_element(concreteDecls.begin(), concreteDecls.end(),
+                       [](TypeDecl *type1, TypeDecl *type2) {
+                         return TypeDecl::compare(type1, type2) < 0;
+                       });
+
+    // Put the best concrete type first; the rest will follow.
+    entry.types.push_back(*bestConcreteTypeIter);
+    entry.types.insert(entry.types.end(),
+                       concreteDecls.begin(), bestConcreteTypeIter);
+    entry.types.insert(entry.types.end(),
+                       bestConcreteTypeIter + 1, concreteDecls.end());
+  }
+
+  return populateResult((nestedTypeNameCache[name] = std::move(entry)));
+}
+
 void EquivalenceClass::dump(llvm::raw_ostream &out) const {
   out << "Equivalence class represented by "
     << members.front()->getRepresentative()->getDebugName() << ":\n";
@@ -1961,28 +2118,6 @@
   return result;
 }
 
-/// Compare two associated types.
-static int compareAssociatedTypes(AssociatedTypeDecl *assocType1,
-                                  AssociatedTypeDecl *assocType2) {
-  // - by name.
-  if (int result = assocType1->getName().str().compare(
-                                              assocType2->getName().str()))
-    return result;
-
-  // - by protocol, so t_n_m.`P.T` < t_n_m.`Q.T` (given P < Q)
-  auto proto1 = assocType1->getProtocol();
-  auto proto2 = assocType2->getProtocol();
-  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 (assocType1 != assocType2)
-    return assocType1 < assocType2 ? -1 : +1;
-
-  return 0;
-}
-
 /// Whether there are any concrete type declarations in the potential archetype.
 static bool hasConcreteDecls(const PotentialArchetype *pa) {
   auto parent = pa->getParent();
@@ -2210,16 +2345,9 @@
 }
 
 PotentialArchetype *PotentialArchetype::getNestedType(
-                                            AssociatedTypeDecl *assocType,
+                                            TypeDecl *type,
                                             GenericSignatureBuilder &builder) {
-  return updateNestedTypeForConformance(assocType,
-                                        ArchetypeResolutionKind::WellFormed);
-}
-
-PotentialArchetype *PotentialArchetype::getNestedType(
-                                            TypeDecl *getConcreteTypeDecl,
-                                            GenericSignatureBuilder &builder) {
-  return updateNestedTypeForConformance(getConcreteTypeDecl,
+  return updateNestedTypeForConformance(type,
                                         ArchetypeResolutionKind::WellFormed);
 }
 
@@ -2227,94 +2355,21 @@
                                            Identifier name,
                                            GenericSignatureBuilder &builder,
                                            ArchetypeResolutionKind kind) {
-  // Look for the best associated type or concrete type within the protocols
-  // we know about.
-  AssociatedTypeDecl *bestAssocType = nullptr;
-  TypeDecl *bestConcreteDecl = nullptr;
   SmallVector<TypeDecl *, 4> concreteDecls;
-  auto rep = getRepresentative();
-  for (auto proto : rep->getConformsTo()) {
-    // Look for an associated type and/or concrete type with this name.
-    AssociatedTypeDecl *assocType = nullptr;
-    TypeDecl *concreteDecl = nullptr;
-    for (auto member : proto->lookupDirect(name,
-                                           /*ignoreNewExtensions=*/true)) {
-      if (!assocType)
-        assocType = dyn_cast<AssociatedTypeDecl>(member);
+  auto bestType =
+    getOrCreateEquivalenceClass()->lookupNestedType(name, &concreteDecls);
 
-      // FIXME: Filter out type declarations that aren't in the protocol itself?
-      if (!concreteDecl && !isa<AssociatedTypeDecl>(member)) {
-        if (!member->hasInterfaceType())
-          builder.getLazyResolver()->resolveDeclSignature(member);
-        if (member->hasInterfaceType())
-          concreteDecl = dyn_cast<TypeDecl>(member);
-      }
-    }
+  // We didn't find any type with this name.
+  if (!bestType) return nullptr;
 
-    if (assocType &&
-        (!bestAssocType ||
-         compareAssociatedTypes(assocType, bestAssocType) < 0))
-      bestAssocType = assocType;
-
-    if (concreteDecl) {
-      // Record every concrete type.
-      concreteDecls.push_back(concreteDecl);
-
-      // Track the best concrete type.
-      if (!bestConcreteDecl ||
-          TypeDecl::compare(concreteDecl, bestConcreteDecl) < 0)
-        bestConcreteDecl = concreteDecl;
-    }
-  }
-
-  // If we found an associated type, use it.
-  PotentialArchetype *resultPA = nullptr;
-  if (bestAssocType) {
-    resultPA = updateNestedTypeForConformance(bestAssocType, kind);
-  }
-
-  // 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.
-  concreteDecls.erase(
-    std::remove_if(concreteDecls.begin(), concreteDecls.end(),
-                   [&](TypeDecl *concreteDecl) {
-      return concreteDecl->getDeclContext()->getParentModule() !=
-        concreteDecl->getDeclContext()
-          ->getAsNominalTypeOrNominalTypeExtensionContext()->getParentModule();
-    }),
-    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<ValueDecl *, 2> superclassMembers;
-        classDecl->getParentModule()->lookupQualified(superclass, name, NL_QualifiedDefault | NL_OnlyTypes | NL_ProtocolMembers, nullptr,
-            superclassMembers);
-        for (auto member : superclassMembers) {
-          if (auto concreteDecl = dyn_cast<TypeDecl>(member)) {
-            // Track the best concrete type.
-            if (!bestConcreteDecl ||
-                TypeDecl::compare(concreteDecl, bestConcreteDecl) < 0)
-              bestConcreteDecl = concreteDecl;
-
-            concreteDecls.push_back(concreteDecl);
-          }
-        }
-      }
-    }
-  }
+  // Resolve the nested type.
+  auto resultPA = updateNestedTypeForConformance(bestType, kind);
 
   // Update for all of the concrete decls with this name, which will introduce
   // various same-type constraints.
   for (auto concreteDecl : concreteDecls) {
-    auto concreteDeclPA = updateNestedTypeForConformance(
-                                      concreteDecl,
-                                      ArchetypeResolutionKind::WellFormed);
-    if (!resultPA && concreteDecl == bestConcreteDecl)
-      resultPA = concreteDeclPA;
+    (void)updateNestedTypeForConformance(concreteDecl,
+                                         ArchetypeResolutionKind::WellFormed);
   }
 
   return resultPA;
@@ -2325,43 +2380,22 @@
                                                  Identifier name,
                                                  ProtocolDecl *proto,
                                                  ArchetypeResolutionKind kind) {
-  /// 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;
-  TypeDecl *concreteDecl = nullptr;
-  for (auto member : proto->lookupDirect(name, /*ignoreNewExtensions=*/true)) {
-    if (!assocType)
-      assocType = dyn_cast<AssociatedTypeDecl>(member);
+  // Lookup the best type for this name.
+  auto bestType =
+    getOrCreateEquivalenceClass()->lookupNestedType(name, nullptr);
+  if (!bestType) return nullptr;
 
-    // FIXME: Filter out concrete types that aren't in the protocol itself?
-    if (!concreteDecl && !isa<AssociatedTypeDecl>(member)) {
-      if (!member->hasInterfaceType())
-        proto->getASTContext().getLazyResolver()->resolveDeclSignature(member);
-      if (member->hasInterfaceType())
-        concreteDecl = dyn_cast<TypeDecl>(member);
-    }
-  }
-
-  // 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 concrete type, ignore the latter.
-  // This is for ill-formed code.
-  if (assocType)
-    return updateNestedTypeForConformance(assocType, kind);
-
-  return updateNestedTypeForConformance(concreteDecl, kind);
+  // Form the potential archetype.
+  return updateNestedTypeForConformance(bestType, kind);
 }
 
 PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance(
-                      PointerUnion<AssociatedTypeDecl *, TypeDecl *> type,
-                      ArchetypeResolutionKind kind) {
-  auto *assocType = type.dyn_cast<AssociatedTypeDecl *>();
-  auto *concreteDecl = type.dyn_cast<TypeDecl *>();
-  if (!assocType && !concreteDecl)
-    return nullptr;
+                                              TypeDecl *type,
+                                              ArchetypeResolutionKind kind) {
+  if (!type) return nullptr;
+
+  AssociatedTypeDecl *assocType = dyn_cast<AssociatedTypeDecl>(type);
+  TypeDecl *concreteDecl = assocType ? nullptr : type;
 
   // If we were asked for a complete, well-formed archetype, make sure we
   // process delayed requirements if anything changed.
@@ -3633,13 +3667,8 @@
   auto parentRepPA = parentPA->getRepresentative();
   if (parentPA == parentRepPA) return;
 
-  PotentialArchetype *existingPA;
-  if (auto assocType = nestedPA->getResolvedAssociatedType()) {
-    existingPA = parentRepPA->getNestedType(assocType, *this);
-  } else {
-    existingPA = parentRepPA->getNestedType(nestedPA->getConcreteTypeDecl(),
-                                            *this);
-  }
+  PotentialArchetype *existingPA =
+    parentRepPA->getNestedType(nestedPA->getResolvedType(), *this);
 
   auto sameNamedSource =
     FloatingRequirementSource::forNestedTypeNameMatch(
@@ -3893,8 +3922,10 @@
                                  UnresolvedHandlingKind unresolvedHandling) {
   return addSameTypeRequirement(paOrT1, paOrT2, source, unresolvedHandling,
                                 [&](Type type1, Type type2) {
-      Diags.diagnose(source.getLoc(), diag::requires_same_concrete_type,
-                     type1, type2);
+      if (source.getLoc().isValid()) {
+        Diags.diagnose(source.getLoc(), diag::requires_same_concrete_type,
+                       type1, type2);
+      }
     });
 }
 
@@ -4170,9 +4201,10 @@
         firstType, secondType, source,
         UnresolvedHandlingKind::GenerateConstraints,
         [&](Type type1, Type type2) {
-          if (source.getLoc().isValid())
+          if (source.getLoc().isValid()) {
             Diags.diagnose(source.getLoc(), diag::requires_same_concrete_type,
                            type1, type2);
+          }
         });
   }
   }
@@ -6293,21 +6325,23 @@
   });
 }
 
-GenericSignature *GenericSignatureBuilder::getGenericSignature() {
-  assert(Impl->finalized && "Must finalize builder first");
+GenericSignature *GenericSignatureBuilder::computeGenericSignature(
+                                          SourceLoc loc,
+                                          bool allowConcreteGenericParams) && {
+  // Finalize the builder, producing any necessary diagnostics.
+  finalize(loc, Impl->GenericParams, allowConcreteGenericParams);
 
   // Collect the requirements placed on the generic parameter types.
   SmallVector<Requirement, 4> requirements;
   collectRequirements(*this, Impl->GenericParams, requirements);
 
+  // Form the generic signature.
   auto sig = GenericSignature::get(Impl->GenericParams, requirements);
-  return sig;
-}
 
-GenericSignature *GenericSignatureBuilder::computeGenericSignature(
-                                          SourceLoc loc,
-                                          bool allowConcreteGenericParams) {
-  finalize(loc, Impl->GenericParams, allowConcreteGenericParams);
-  return getGenericSignature();
+  // Wipe out the internal state, ensuring that nobody uses this builder for
+  // anything more.
+  Impl.reset();
+
+  return sig;
 }
 
diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp
index 16f22e8..66a8338 100644
--- a/lib/ClangImporter/ImportDecl.cpp
+++ b/lib/ClangImporter/ImportDecl.cpp
@@ -7654,7 +7654,7 @@
     (void) result;
   }
 
-  return builder.computeGenericSignature(SourceLoc());
+  return std::move(builder).computeGenericSignature(SourceLoc());
 }
 
 // Calculate the generic environment from an imported generic param list.
diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp
index 829c219..9871d2f 100644
--- a/lib/SILGen/SILGenPoly.cpp
+++ b/lib/SILGen/SILGenPoly.cpp
@@ -2695,7 +2695,7 @@
   builder.addRequirement(newRequirement, source, nullptr);
 
   GenericSignature *genericSig =
-    builder.computeGenericSignature(SourceLoc(),
+    std::move(builder).computeGenericSignature(SourceLoc(),
                                     /*allowConcreteGenericParams=*/true);
   genericEnv = genericSig->createGenericEnvironment(*mod);
 
diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp
index d841f25..b2fa942 100644
--- a/lib/SILOptimizer/Utils/Generics.cpp
+++ b/lib/SILOptimizer/Utils/Generics.cpp
@@ -800,7 +800,7 @@
   }
 
   auto NewGenSig =
-    Builder.computeGenericSignature(SourceLoc(),
+    std::move(Builder).computeGenericSignature(SourceLoc(),
                                    /*allowConcreteGenericParams=*/true);
   auto NewGenEnv = NewGenSig->createGenericEnvironment(*M.getSwiftModule());
   return { NewGenEnv, NewGenSig };
@@ -1490,7 +1490,7 @@
 
   // Finalize the archetype builder.
   auto GenSig =
-      Builder.computeGenericSignature(SourceLoc(),
+      std::move(Builder).computeGenericSignature(SourceLoc(),
                                       /*allowConcreteGenericParams=*/true);
   auto GenEnv = GenSig->createGenericEnvironment(*M.getSwiftModule());
   return { GenEnv, GenSig };
diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp
index 63d7375..072e9ae 100644
--- a/lib/Sema/TypeCheckAttr.cpp
+++ b/lib/Sema/TypeCheckAttr.cpp
@@ -1851,7 +1851,8 @@
     Builder.addRequirement(&req, DC->getParentModule());
 
   // Check the result.
-  (void)Builder.computeGenericSignature(attr->getLocation(),
+  (void)std::move(Builder).computeGenericSignature(
+                                        attr->getLocation(),
                                         /*allowConcreteGenericParams=*/true);
 }
 
diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp
index 949f618..25b90cd 100644
--- a/lib/Sema/TypeCheckGeneric.cpp
+++ b/lib/Sema/TypeCheckGeneric.cpp
@@ -136,20 +136,19 @@
                                     DeclContext *DC,
                                     SourceRange baseRange,
                                     ComponentIdentTypeRepr *ref) {
-  // Resolve the base to a potential archetype.
-  auto basePA =
-    builder.resolveArchetype(baseTy,
-                             ArchetypeResolutionKind::CompleteWellFormed);
-  assert(basePA && "Missing potential archetype for base");
+  auto baseEquivClass =
+    builder.resolveEquivalenceClass(
+                                baseTy,
+                                ArchetypeResolutionKind::CompleteWellFormed);
+  assert(baseEquivClass && "Unknown base type?");
 
-  // Retrieve the potential archetype for the nested type.
-  auto nestedPA =
-    basePA->getNestedType(ref->getIdentifier(),
-                          ArchetypeResolutionKind::CompleteWellFormed,
-                          builder);
-
-  // If there was no such nested type, produce an error.
-  if (!nestedPA) {
+  // Look for a nested type with the given name.
+  if (auto nestedType =
+          baseEquivClass->lookupNestedType(ref->getIdentifier())) {
+    // Record the type we found.
+    ref->setValue(nestedType, nullptr);
+  } else {
+    // Resolve the base to a potential archetype.
     // Perform typo correction.
     LookupResult corrections;
     tc.performTypoCorrection(DC, DeclRefKind::Ordinary,
@@ -189,11 +188,6 @@
     // Correct to the single type result.
     ref->overwriteIdentifier(singleType->getBaseName().getIdentifier());
     ref->setValue(singleType, nullptr);
-  } else if (auto assocType = nestedPA->getResolvedAssociatedType()) {
-    ref->setValue(assocType, nullptr);
-  } else {
-    assert(nestedPA->getConcreteTypeDecl());
-    ref->setValue(nestedPA->getConcreteTypeDecl(), nullptr);
   }
 
   // If the nested type has been resolved to an associated type, use it.
@@ -217,7 +211,7 @@
       return concrete->getDeclaredInterfaceType().subst(subMap);
     }
 
-    if (auto superclass = basePA->getSuperclass()) {
+    if (auto superclass = baseEquivClass->superclass) {
       return superclass->getTypeOfMember(
                                        DC->getParentModule(), concrete,
                                        concrete->getDeclaredInterfaceType());
@@ -752,13 +746,6 @@
   if (auto gp = func->getGenericParams()) {
     prepareGenericParamList(gp, func);
 
-    // Collect the generic parameters.
-    SmallVector<GenericTypeParamType *, 4> allGenericParams;
-    if (auto parentSig = func->getDeclContext()->getGenericSignatureOfContext())
-      allGenericParams.append(parentSig->getGenericParams().begin(),
-                              parentSig->getGenericParams().end());
-    addGenericParamTypes(gp, allGenericParams);
-
     // Create the generic signature builder.
     GenericSignatureBuilder builder(Context, LookUpConformance(*this, func));
 
@@ -768,8 +755,9 @@
     if (checkGenericFuncSignature(*this, &builder, func, dependentResolver))
       invalid = true;
 
-    // Finalize the generic requirements.
-    (void)builder.finalize(func->getLoc(), allGenericParams);
+    // The generic function signature is complete and well-formed. Determine
+    // the type of the generic function.
+    sig = std::move(builder).computeGenericSignature(func->getLoc());
 
     // The generic signature builder now has all of the requirements, although
     // there might still be errors that have not yet been diagnosed. Revert the
@@ -778,16 +766,10 @@
     if (gp)
       revertGenericParamList(gp);
 
-    // The generic function signature is complete and well-formed. Determine
-    // the type of the generic function.
-    sig = builder.getGenericSignature();
-
-    // Debugging of the generic signature builder and generic signature
-    // generation.
+    // Debugging of the generic signature.
     if (Context.LangOpts.DebugGenericSignatures) {
       func->dumpRef(llvm::errs());
       llvm::errs() << "\n";
-      builder.dump(llvm::errs());
       llvm::errs() << "Generic signature: ";
       sig->print(llvm::errs());
       llvm::errs() << "\n";
@@ -987,15 +969,9 @@
   if (auto *gp = subscript->getGenericParams()) {
     prepareGenericParamList(gp, subscript);
 
-    // Collect the generic parameters.
-    SmallVector<GenericTypeParamType *, 4> allGenericParams;
-    if (auto parentSig = subscript->getDeclContext()->getGenericSignatureOfContext())
-      allGenericParams.append(parentSig->getGenericParams().begin(),
-                              parentSig->getGenericParams().end());
-    addGenericParamTypes(gp, allGenericParams);
-
     // Create the generic signature builder.
-    GenericSignatureBuilder builder(Context, LookUpConformance(*this, subscript));
+    GenericSignatureBuilder builder(Context,
+                                    LookUpConformance(*this, subscript));
 
     // Type check the function declaration, treating all generic type
     // parameters as dependent, unresolved.
@@ -1004,8 +980,9 @@
                                        dependentResolver))
       invalid = true;
 
-    // Finalize the generic requirements.
-    (void)builder.finalize(subscript->getLoc(), allGenericParams);
+    // The generic subscript signature is complete and well-formed. Determine
+    // the type of the generic subscript.
+    sig = std::move(builder).computeGenericSignature(subscript->getLoc());
 
     // The generic signature builder now has all of the requirements, although
     // there might still be errors that have not yet been diagnosed. Revert the
@@ -1013,16 +990,10 @@
     revertGenericSubscriptSignature(subscript);
     revertGenericParamList(gp);
 
-    // The generic subscript signature is complete and well-formed. Determine
-    // the type of the generic subscript.
-    sig = builder.getGenericSignature();
-
-    // Debugging of the generic signature builder and generic signature
-    // generation.
+    // Debugging of generic signature generation.
     if (Context.LangOpts.DebugGenericSignatures) {
       subscript->dumpRef(llvm::errs());
       llvm::errs() << "\n";
-      builder.dump(llvm::errs());
       llvm::errs() << "Generic signature: ";
       sig->print(llvm::errs());
       llvm::errs() << "\n";
@@ -1148,10 +1119,10 @@
     /// Perform any necessary requirement inference.
     inferRequirements(builder);
 
-    // Finalize the generic requirements.
-    (void)builder.finalize(genericParams->getSourceRange().Start,
-                           allGenericParams,
-                           allowConcreteGenericParams);
+    // Record the generic type parameter types and the requirements.
+    sig = std::move(builder).computeGenericSignature(
+                                         genericParams->getSourceRange().Start,
+                                         allowConcreteGenericParams);
 
     // The generic signature builder now has all of the requirements, although
     // there might still be errors that have not yet been diagnosed. Revert the
@@ -1165,15 +1136,11 @@
       revertGenericParamList(genericParams);
     }
 
-    // Record the generic type parameter types and the requirements.
-    sig = builder.getGenericSignature();
-
     // Debugging of the generic signature builder and generic signature
     // generation.
     if (Context.LangOpts.DebugGenericSignatures) {
       dc->printContext(llvm::errs());
       llvm::errs() << "\n";
-      builder.dump(llvm::errs());
       llvm::errs() << "Generic signature: ";
       sig->print(llvm::errs());
       llvm::errs() << "\n";
diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp
index d730a4a..686557d 100644
--- a/lib/Sema/TypeCheckProtocol.cpp
+++ b/lib/Sema/TypeCheckProtocol.cpp
@@ -1156,7 +1156,8 @@
   // Produce the generic signature and environment.
   // FIXME: Pass in a source location for the conformance, perhaps? It seems
   // like this could fail.
-  syntheticSignature = builder.computeGenericSignature(SourceLoc());
+  syntheticSignature =
+    std::move(builder).computeGenericSignature(SourceLoc());
   syntheticEnvironment = syntheticSignature->createGenericEnvironment(
                                              *conformanceDC->getParentModule());
 }
diff --git a/test/Generics/associated_type_typo.swift b/test/Generics/associated_type_typo.swift
index f023418..4ac5b86 100644
--- a/test/Generics/associated_type_typo.swift
+++ b/test/Generics/associated_type_typo.swift
@@ -34,13 +34,6 @@
 // expected-error@+1{{'T' does not have a member type named 'Assocp2'; did you mean 'AssocP2'?}}{{39-46=AssocP2}}
 func typoAssoc4<T : P2>(_: T) where T.Assocp2.assoc : P3 {}
 
-
-// CHECK-GENERIC-LABEL: .typoAssoc4@
-// CHECK-GENERIC-NEXT: Requirements:
-// CHECK-GENERIC-NEXT:   τ_0_0 : P2 [τ_0_0: Explicit @ {{.*}}:21]
-// CHECK-GENERIC-NEXT:   τ_0_0[.P2].AssocP2 : P1 [τ_0_0: Explicit @ {{.*}}:21 -> Protocol requirement (via Self.AssocP2 in P2)
-// CHECK-GENERIC-NEXT: Potential archetypes
-
 // <rdar://problem/19620340>
 
 func typoFunc1<T : P1>(x: TypoType) { // expected-error{{use of undeclared type 'TypoType'}}
diff --git a/test/Generics/protocol_type_aliases.swift b/test/Generics/protocol_type_aliases.swift
index afb2661..9c083d4 100644
--- a/test/Generics/protocol_type_aliases.swift
+++ b/test/Generics/protocol_type_aliases.swift
@@ -14,10 +14,6 @@
 }
 
 // CHECK-LABEL: .requirementOnNestedTypeAlias@
-// CHECK-NEXT: Requirements:
-// CHECK-NEXT:   τ_0_0 : Q [τ_0_0: Explicit @ 22:51]
-// CHECK-NEXT:   τ_0_0[.Q].B : P [τ_0_0: Explicit @ 22:51 -> Protocol requirement (via Self.B in Q)
-// CHECK-NEXT:   τ_0_0[.Q].B[.P].A == Int [τ_0_0[.Q].B[.P].X: Explicit @ 22:62]
 // CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : Q, τ_0_0.B.A == Int>
 func requirementOnNestedTypeAlias<T>(_: T) where T: Q, T.B.X == Int {}
 
@@ -33,20 +29,10 @@
 }
 
 // CHECK-LABEL: .requirementOnConcreteNestedTypeAlias@
-// CHECK-NEXT: Requirements:
-// CHECK-NEXT:   τ_0_0 : Q2 [τ_0_0: Explicit @ 42:59]
-// CHECK-NEXT:   τ_0_0[.Q2].B : P2 [τ_0_0: Explicit @ 42:59 -> Protocol requirement (via Self.B in Q2)
-// CHECK-NEXT:   τ_0_0[.Q2].C == S<T.B.A> [τ_0_0[.Q2].C: Explicit]
-// CHECK-NEXT:   τ_0_0[.Q2].B[.P2].X == S<T.B.A> [τ_0_0[.Q2].B[.P2].X: Concrete type binding]
 // CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : Q2, τ_0_0.C == S<τ_0_0.B.A>>
 func requirementOnConcreteNestedTypeAlias<T>(_: T) where T: Q2, T.C == T.B.X {}
 
 // CHECK-LABEL: .concreteRequirementOnConcreteNestedTypeAlias@
-// CHECK-NEXT: Requirements:
-// CHECK-NEXT:   τ_0_0 : Q2 [τ_0_0: Explicit @ 51:67]
-// CHECK-NEXT:   τ_0_0[.Q2].B : P2 [τ_0_0: Explicit @ 51:67 -> Protocol requirement (via Self.B in Q2)
-// CHECK-NEXT:   τ_0_0[.Q2].C == τ_0_0[.Q2].B[.P2].A [τ_0_0[.Q2].C: Explicit]
-// CHECK-NEXT:   τ_0_0[.Q2].B[.P2].X == S<T.B.A> [τ_0_0[.Q2].B[.P2].X: Concrete type binding]
 // CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : Q2, τ_0_0.C == τ_0_0.B.A>
 func concreteRequirementOnConcreteNestedTypeAlias<T>(_: T) where T: Q2, S<T.C> == T.B.X {}
 
diff --git a/test/Generics/requirement_inference.swift b/test/Generics/requirement_inference.swift
index ac124ae..391c9b4 100644
--- a/test/Generics/requirement_inference.swift
+++ b/test/Generics/requirement_inference.swift
@@ -72,16 +72,14 @@
 struct V<T : Canidae> {}
 
 // CHECK-LABEL: .inferSuperclassRequirement1@
-// CHECK-NEXT: Requirements:
-// CHECK-NEXT:   τ_0_0 : Canidae
+// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : Canidae>
 func inferSuperclassRequirement1<T : Carnivora>(
 	_ v: V<T>) {}
 // expected-warning@-2{{redundant superclass constraint 'T' : 'Carnivora'}}
 // expected-note@-2{{superclass constraint 'T' : 'Canidae' inferred from type here}}
 
 // CHECK-LABEL: .inferSuperclassRequirement2@
-// CHECK-NEXT: Requirements:
-// CHECK-NEXT:   τ_0_0 : Canidae
+// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : Canidae>
 func inferSuperclassRequirement2<T : Canidae>(_ v: U<T>) {}
 
 // ----------------------------------------------------------------------------
@@ -110,33 +108,17 @@
 
 struct Model_P3_P4_Eq<T : P3, U : P4> where T.P3Assoc == U.P4Assoc {}
 
-// CHECK-LABEL: .inferSameType1@
-// CHECK-NEXT: Requirements:
-// CHECK-NEXT:   τ_0_0 : P3 [τ_0_0: Inferred @ {{.*}}:32]
-// CHECK-NEXT:   τ_0_1 : P4 [τ_0_1: Inferred @ {{.*}}:32]
-// CHECK-NEXT:   τ_0_0[.P3].P3Assoc : P1 [τ_0_1: Inferred @ {{.*}}:32 -> Protocol requirement (via Self.P4Assoc in P4)
-// CHECK-NEXT:   τ_0_0[.P3].P3Assoc : P2 [τ_0_0: Inferred @ {{.*}}:32 -> Protocol requirement (via Self.P3Assoc in P3)
-// FIXME: τ_0_0[.P3].P3Assoc == τ_0_1[.P4].P4Assoc [τ_0_0: Inferred]
-func inferSameType1<T, U>(_ x: Model_P3_P4_Eq<T, U>) { }
+func inferSameType1<T, U>(_ x: Model_P3_P4_Eq<T, U>) {
+  let u: U.P4Assoc? = nil
+  let _: T.P3Assoc? = u!
+}
 
-// CHECK-LABEL: .inferSameType2@
-// CHECK-NEXT: Requirements:
-// CHECK-NEXT:   τ_0_0 : P3 [τ_0_0: Explicit @ {{.*}}:25]
-// CHECK-NEXT:   τ_0_1 : P4 [τ_0_1: Explicit @ {{.*}}:33]
-// CHECK-NEXT:   τ_0_0[.P3].P3Assoc : P1 [τ_0_1: Explicit @ {{.*}}:33 -> Protocol requirement (via Self.P4Assoc in P4)
-// CHECK-NEXT:   τ_0_0[.P3].P3Assoc : P2 [τ_0_0: Explicit @ {{.*}}:25 -> Protocol requirement (via Self.P3Assoc in P3)
-// CHECK-NEXT:   τ_0_0[.P3].P3Assoc == τ_0_1[.P4].P4Assoc [τ_0_0[.P3].P3Assoc: Explicit]
 func inferSameType2<T : P3, U : P4>(_: T, _: U) where U.P4Assoc : P2, T.P3Assoc == U.P4Assoc {}
 // expected-warning@-1{{redundant conformance constraint 'T.P3Assoc': 'P2'}}
 // expected-note@-2{{conformance constraint 'T.P3Assoc': 'P2' implied here}}
 
-// CHECK-LABEL: .inferSameType3@
-// CHECK-NEXT: Requirements:
-// CHECK-NEXT:   τ_0_0 : PCommonAssoc1 [τ_0_0: Explicit @ {{.*}}:25]
-// CHECK-NEXT:   τ_0_0 : PCommonAssoc2 [τ_0_0: Explicit @ {{.*}}:74]
-// CHECK-NEXT:   τ_0_0[.PCommonAssoc1].CommonAssoc : P1 [τ_0_0[.PCommonAssoc1].CommonAssoc: Explicit @ {{.*}}:66]
-// CHECK-NEXT: Potential archetypes
-func inferSameType3<T : PCommonAssoc1>(_: T) where T.CommonAssoc : P1, T : PCommonAssoc2 {}
+func inferSameType3<T : PCommonAssoc1>(_: T) where T.CommonAssoc : P1, T : PCommonAssoc2 {
+}
 
 protocol P5 {
   associatedtype Element
diff --git a/test/Generics/superclass_constraint.swift b/test/Generics/superclass_constraint.swift
index d02efc5..b27d7af 100644
--- a/test/Generics/superclass_constraint.swift
+++ b/test/Generics/superclass_constraint.swift
@@ -67,10 +67,6 @@
 }
 
 // CHECK: superclassConformance1
-// CHECK: Requirements:
-// CHECK-NEXT: τ_0_0 : C [τ_0_0: Explicit @ {{.*}}:11]
-// CHECK-NEXT: τ_0_0 : _NativeClass [τ_0_0: Explicit @ {{.*}}:11 -> Derived]
-// CHECK-NEXT: τ_0_0 : P3 [τ_0_0: Explicit @ {{.*}}:11 -> Superclass (C: P3)]
 // CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : C>
 func superclassConformance1<T>(t: T)
   where T : C, // expected-note{{conformance constraint 'T': 'P3' implied here}}
@@ -79,10 +75,6 @@
 
 
 // CHECK: superclassConformance2
-// CHECK: Requirements:
-// CHECK-NEXT: τ_0_0 : C [τ_0_0: Explicit @ {{.*}}:11]
-// CHECK-NEXT: τ_0_0 : _NativeClass [τ_0_0: Explicit @ {{.*}}:11 -> Derived]
-// CHECK-NEXT: τ_0_0 : P3 [τ_0_0: Explicit @ {{.*}}:11 -> Superclass (C: P3)]
 // CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : C>
 func superclassConformance2<T>(t: T)
   where T : C, // expected-note{{conformance constraint 'T': 'P3' implied here}}
@@ -93,10 +85,6 @@
 class C2 : C, P4 { }
 
 // CHECK: superclassConformance3
-// CHECK: Requirements:
-// CHECK-NEXT: τ_0_0 : C2 [τ_0_0: Explicit @ {{.*}}:61]
-// CHECK-NEXT: τ_0_0 : _NativeClass [τ_0_0: Explicit @ {{.*}}:46 -> Derived]
-// CHECK-NEXT: τ_0_0 : P4 [τ_0_0: Explicit @ {{.*}}:61 -> Superclass (C2: P4)]
 // CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : C2>
 func superclassConformance3<T>(t: T) where T : C, T : P4, T : C2 {}
 // expected-warning@-1{{redundant superclass constraint 'T' : 'C'}}
diff --git a/test/decl/protocol/recursive_requirement.swift b/test/decl/protocol/recursive_requirement.swift
index 736d2af..30cd1a0 100644
--- a/test/decl/protocol/recursive_requirement.swift
+++ b/test/decl/protocol/recursive_requirement.swift
@@ -76,13 +76,14 @@
   associatedtype Delta: Alpha
 }
 
-// FIXME: Redundancy diagnostics are odd here.
+// FIXME: Redundancy diagnostics are an indication that we're getting
+// the minimization wrong. The errors prove it :D
 struct Epsilon<T: Alpha, // expected-note{{conformance constraint 'U': 'Gamma' implied here}}
 // expected-warning@-1{{redundant conformance constraint 'T': 'Alpha'}}
                U: Gamma> // expected-warning{{redundant conformance constraint 'U': 'Gamma'}}
 // expected-note@-1{{conformance constraint 'T': 'Alpha' implied here}}
-  where T.Beta == U,
-        U.Delta == T {}
+  where T.Beta == U, // expected-error{{'Beta' is not a member type of 'T'}}
+        U.Delta == T {} // expected-error{{'Delta' is not a member type of 'U'}}
 
 // -----
 
diff --git a/validation-test/compiler_crashers/28816-unreachable-executed-at-swift-lib-sema-typecheckgeneric-cpp-214.swift b/validation-test/compiler_crashers_fixed/28816-unreachable-executed-at-swift-lib-sema-typecheckgeneric-cpp-214.swift
similarity index 88%
rename from validation-test/compiler_crashers/28816-unreachable-executed-at-swift-lib-sema-typecheckgeneric-cpp-214.swift
rename to validation-test/compiler_crashers_fixed/28816-unreachable-executed-at-swift-lib-sema-typecheckgeneric-cpp-214.swift
index 1c78fe4..02b9326 100644
--- a/validation-test/compiler_crashers/28816-unreachable-executed-at-swift-lib-sema-typecheckgeneric-cpp-214.swift
+++ b/validation-test/compiler_crashers_fixed/28816-unreachable-executed-at-swift-lib-sema-typecheckgeneric-cpp-214.swift
@@ -5,6 +5,6 @@
 // See https://swift.org/LICENSE.txt for license information
 // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
 
-// RUN: not --crash %target-swift-frontend %s -emit-ir
+// RUN: not %target-swift-frontend %s -emit-ir
 protocol b{{}{}class a{{}class A}{}typealias a
 init(t:Self.a.a.a