Merge pull request #5961 from DougGregor/archetype-representation

[AST] Improve the representation of `ArchetypeType`
diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h
index 46456c8..b98f548 100644
--- a/include/swift/AST/Types.h
+++ b/include/swift/AST/Types.h
@@ -3822,9 +3822,7 @@
   Type Superclass;
 
   llvm::PointerUnion<ArchetypeType *, TypeBase *> ParentOrOpened;
-  AssociatedTypeDecl *AssocType;
-  Identifier Name;
-  unsigned isRecursive: 1;
+  llvm::PointerUnion<AssociatedTypeDecl *, Identifier> AssocTypeOrName;
   MutableArrayRef<std::pair<Identifier, NestedType>> NestedTypes;
 
   /// Set the ID number of this opened existential.
@@ -3843,21 +3841,18 @@
   static CanTypeWrapper<ArchetypeType>
                         getNew(const ASTContext &Ctx, ArchetypeType *Parent,
                                AssociatedTypeDecl *AssocType,
-                               Identifier Name, ArrayRef<Type> ConformsTo,
-                               Type Superclass,
-                               bool isRecursive = false);
+                               SmallVectorImpl<ProtocolDecl *> &ConformsTo,
+                               Type Superclass);
 
   /// getNew - Create a new archetype with the given name.
   ///
   /// The ConformsTo array will be minimized then copied into the ASTContext
   /// by this routine.
   static CanTypeWrapper<ArchetypeType>
-                        getNew(const ASTContext &Ctx, ArchetypeType *Parent,
-                               AssociatedTypeDecl *AssocType,
+                        getNew(const ASTContext &Ctx,
                                Identifier Name,
                                SmallVectorImpl<ProtocolDecl *> &ConformsTo,
-                               Type Superclass,
-                               bool isRecursive = false);
+                               Type Superclass);
 
   /// Create a new archetype that represents the opened type
   /// of an existential value.
@@ -3877,7 +3872,7 @@
   static CanType getAnyOpened(Type existential);
 
   /// \brief Retrieve the name of this archetype.
-  Identifier getName() const { return Name; }
+  Identifier getName() const;
 
   /// \brief Retrieve the fully-dotted name that should be used to display this
   /// archetype.
@@ -3901,7 +3896,7 @@
   /// be a member of one of the protocols to which the parent archetype
   /// conforms.
   AssociatedTypeDecl *getAssocType() const {
-    return AssocType;
+    return AssocTypeOrName.dyn_cast<AssociatedTypeDecl *>();
   }
 
   /// getConformsTo - Retrieve the set of protocols to which this substitutable
@@ -3971,34 +3966,28 @@
   static bool classof(const TypeBase *T) {
     return T->getKind() == TypeKind::Archetype;
   }
-  
-  /// getIsRecursive - The archetype type refers back to itself.
-  bool getIsRecursive() { return this->isRecursive; }
-  
+
 private:
-  ArchetypeType(const ASTContext &Ctx, ArchetypeType *Parent,
-                AssociatedTypeDecl *AssocType,
-                Identifier Name, ArrayRef<ProtocolDecl *> ConformsTo,
-                Type Superclass,
-                bool isRecursive = false)
+  ArchetypeType(
+          const ASTContext &Ctx, ArchetypeType *Parent,
+          llvm::PointerUnion<AssociatedTypeDecl *, Identifier> AssocTypeOrName,
+          ArrayRef<ProtocolDecl *> ConformsTo,
+          Type Superclass)
     : SubstitutableType(TypeKind::Archetype, &Ctx,
                         RecursiveTypeProperties::HasArchetype),
       ConformsTo(ConformsTo), Superclass(Superclass), ParentOrOpened(Parent),
-      AssocType(AssocType), Name(Name),
-      isRecursive(isRecursive) { }
+      AssocTypeOrName(AssocTypeOrName) { }
 
   ArchetypeType(const ASTContext &Ctx, 
                 Type Existential,
                 ArrayRef<ProtocolDecl *> ConformsTo,
-                Type Superclass, bool isRecursive = false)
+                Type Superclass)
     : SubstitutableType(TypeKind::Archetype, &Ctx,
                         RecursiveTypeProperties(
                           RecursiveTypeProperties::HasArchetype |
                           RecursiveTypeProperties::HasOpenedExistential)),
       ConformsTo(ConformsTo), Superclass(Superclass),
-      ParentOrOpened(Existential.getPointer()),
-      AssocType(nullptr),
-      isRecursive(isRecursive) { }
+      ParentOrOpened(Existential.getPointer()) { }
 };
 BEGIN_CAN_TYPE_WRAPPER(ArchetypeType, SubstitutableType)
 CanArchetypeType getParent() const {
diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h
index 27a0870..889ad45 100644
--- a/include/swift/Serialization/ModuleFormat.h
+++ b/include/swift/Serialization/ModuleFormat.h
@@ -54,7 +54,7 @@
 /// in source control, you should also update the comment to briefly
 /// describe what change you made. The content of this comment isn't important;
 /// it just ensures a conflict if two people change the module format.
-const uint16_t VERSION_MINOR = 284; // Last change: Self archetype protocol removed
+const uint16_t VERSION_MINOR = 285; // Last change: simplified archetype format
 
 using DeclID = PointerEmbeddedInt<unsigned, 31>;
 using DeclIDField = BCFixed<31>;
@@ -624,9 +624,8 @@
 
   using ArchetypeTypeLayout = BCRecordLayout<
     ARCHETYPE_TYPE,
-    IdentifierIDField,   // name
-    TypeIDField,         // index if primary, parent if non-primary
-    DeclIDField,         // associated type decl
+    TypeIDField,         // parent if non-primary
+    DeclIDField,         // associated type decl if non-primary, name if primary
     TypeIDField,         // superclass
     BCArray<DeclIDField> // conformances
     // Trailed by the nested types record.
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index 499c79a..29f0c34 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -489,9 +489,6 @@
         defaultDef.print(OS);
       }
       
-      if (decl->isRecursive())
-        OS << " <<RECURSIVE>>";
-      
       OS << ")";
     }
 
diff --git a/lib/AST/ArchetypeBuilder.cpp b/lib/AST/ArchetypeBuilder.cpp
index 0b04fbb..23bcd78 100644
--- a/lib/AST/ArchetypeBuilder.cpp
+++ b/lib/AST/ArchetypeBuilder.cpp
@@ -711,10 +711,24 @@
     }
   }
 
-  auto arch
-    = ArchetypeType::getNew(builder.getASTContext(), ParentArchetype,
-                            assocType, getName(), Protos,
-                            superclass, isRecursive());
+  ArchetypeType *arch;
+  if (ParentArchetype) {
+    // If we were unable to resolve this as an associated type, produce an
+    // error type.
+    if (!assocType) {
+      representative->ArchetypeOrConcreteType =
+        NestedType::forConcreteType(
+          ErrorType::get(getDependentType(builder, true)));
+
+      return representative->ArchetypeOrConcreteType;
+    }
+
+    arch = ArchetypeType::getNew(builder.getASTContext(), ParentArchetype,
+                                 assocType, Protos, superclass);
+  } else {
+    arch = ArchetypeType::getNew(builder.getASTContext(), getName(), Protos,
+                                 superclass);
+  }
 
   representative->ArchetypeOrConcreteType = NestedType::forArchetype(arch);
   
diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp
index 08e6a4d..57d9ca0 100644
--- a/lib/AST/Builtins.cpp
+++ b/lib/AST/Builtins.cpp
@@ -432,10 +432,8 @@
 createGenericParam(ASTContext &ctx, const char *name, unsigned index) {
   Module *M = ctx.TheBuiltinModule;
   Identifier ident = ctx.getIdentifier(name);
-  ArchetypeType *archetype
-    = ArchetypeType::getNew(ctx, nullptr,
-                            static_cast<AssociatedTypeDecl *>(nullptr),
-                            ident, ArrayRef<Type>(), Type(), false);
+  SmallVector<ProtocolDecl *, 1> protos;
+  ArchetypeType *archetype = ArchetypeType::getNew(ctx, ident, protos, Type());
   auto genericParam =
     new (ctx) GenericTypeParamDecl(&M->getMainFile(FileUnitKind::Builtin),
                                    ident, SourceLoc(), 0, index);
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 44833db..95b1888 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -2490,41 +2490,34 @@
 }
 
 
-CanArchetypeType ArchetypeType::getNew(const ASTContext &Ctx,
-                                       ArchetypeType *Parent,
-                                       AssociatedTypeDecl *AssocType,
-                                       Identifier Name,
-                                       ArrayRef<Type> ConformsTo,
-                                       Type Superclass,
-                                       bool isRecursive) {
-  // Gather the set of protocol declarations to which this archetype conforms.
-  SmallVector<ProtocolDecl *, 4> ConformsToProtos;
-  for (auto P : ConformsTo) {
-    addProtocols(P, ConformsToProtos);
-  }
-  ProtocolType::canonicalizeProtocols(ConformsToProtos);
-
-  auto arena = AllocationArena::Permanent;
-  return CanArchetypeType(
-           new (Ctx, arena) ArchetypeType(Ctx, Parent, AssocType, Name,
-                                          Ctx.AllocateCopy(ConformsToProtos),
-                                          Superclass, isRecursive));
-}
-
-CanArchetypeType
-ArchetypeType::getNew(const ASTContext &Ctx, ArchetypeType *Parent,
-                      AssociatedTypeDecl *AssocType,
-                      Identifier Name,
-                      SmallVectorImpl<ProtocolDecl *> &ConformsTo,
-                      Type Superclass, bool isRecursive) {
+CanArchetypeType ArchetypeType::getNew(
+                                   const ASTContext &Ctx,
+                                   ArchetypeType *Parent,
+                                   AssociatedTypeDecl *AssocType,
+                                   SmallVectorImpl<ProtocolDecl *> &ConformsTo,
+                                   Type Superclass) {
   // Gather the set of protocol declarations to which this archetype conforms.
   ProtocolType::canonicalizeProtocols(ConformsTo);
 
   auto arena = AllocationArena::Permanent;
   return CanArchetypeType(
-           new (Ctx, arena) ArchetypeType(Ctx, Parent, AssocType, Name,
+           new (Ctx, arena) ArchetypeType(Ctx, Parent, AssocType,
                                           Ctx.AllocateCopy(ConformsTo),
-                                          Superclass, isRecursive));
+                                          Superclass));
+}
+
+CanArchetypeType
+ArchetypeType::getNew(const ASTContext &Ctx, Identifier Name,
+                      SmallVectorImpl<ProtocolDecl *> &ConformsTo,
+                      Type Superclass) {
+  // Gather the set of protocol declarations to which this archetype conforms.
+  ProtocolType::canonicalizeProtocols(ConformsTo);
+
+  auto arena = AllocationArena::Permanent;
+  return CanArchetypeType(
+           new (Ctx, arena) ArchetypeType(Ctx, nullptr, Name,
+                                          Ctx.AllocateCopy(ConformsTo),
+                                          Superclass));
 }
 
 bool ArchetypeType::requiresClass() const {
@@ -2573,37 +2566,11 @@
 ArchetypeType::NestedType ArchetypeType::getNestedType(Identifier Name) const {
   auto Pos = std::lower_bound(NestedTypes.begin(), NestedTypes.end(), Name,
                               OrderArchetypeByName());
-  if ((Pos == NestedTypes.end() || Pos->first != Name) && this->isRecursive) {
-    if (Name == this->getName()) {
-      NestedType rec = NestedType::forArchetype((ArchetypeType*)this);
-    
-      return rec;
-    } else {
-      auto conformances = this->getConformsTo();
-      
-      for (auto conformance : conformances) {
-        auto conformanceType = conformance->getType().getPointer();
-        
-        if (auto metatypeType = dyn_cast<MetatypeType>(conformanceType)) {
-          conformanceType = metatypeType->getInstanceType().getPointer();
-          
-          if (auto protocolType = dyn_cast<ProtocolType>(conformanceType)) {
-            conformanceType = protocolType->getDecl()
-                                          ->getSelfTypeInContext().getPointer();
-          }
-        }
-        
-        if (auto conformedArchetype = dyn_cast<ArchetypeType>(conformanceType)){
-          return conformedArchetype->getNestedType(Name);
-        }
-      }
-    }
-  }
-
-  if (Pos == NestedTypes.end() || Pos->first != Name)
+  if (Pos == NestedTypes.end() || Pos->first != Name) {
     return NestedType::forConcreteType(
              ErrorType::get(
                const_cast<ArchetypeType *>(this)->getASTContext()));
+  }
 
   // If the type is null, lazily resolve it. 
   if (!Pos->second) {
@@ -2648,6 +2615,13 @@
                 Archetype->getName().str().end());
 }
 
+Identifier ArchetypeType::getName() const {
+  if (auto assocType = getAssocType())
+    return assocType->getName();
+
+  return AssocTypeOrName.get<Identifier>();
+}
+
 std::string ArchetypeType::getFullName() const {
   llvm::SmallString<64> Result;
   collectFullName(this, Result);
diff --git a/lib/IDE/TypeReconstruction.cpp b/lib/IDE/TypeReconstruction.cpp
index e4b4d6d..330d623 100644
--- a/lib/IDE/TypeReconstruction.cpp
+++ b/lib/IDE/TypeReconstruction.cpp
@@ -814,14 +814,14 @@
     }
   }
 
-  SmallVector<Type, 1> conforms_to;
-  if (protocol_list.HasSingleType())
-    conforms_to.push_back(protocol_list.GetFirstType());
+  SmallVector<ProtocolDecl *, 1> conforms_to;
+  if (protocol_list.HasSingleType()) {
+    (void)protocol_list.GetFirstType()->isExistentialType(conforms_to);
+  }
 
   if (ast) {
     result._types.push_back(ArchetypeType::getNew(
-        *ast, nullptr, (AssociatedTypeDecl *)nullptr,
-        ast->getIdentifier(archetype_name), conforms_to, Type()));
+        *ast, ast->getIdentifier(archetype_name), conforms_to, Type()));
   } else {
     result._error = "invalid ASTContext";
   }
@@ -848,9 +848,9 @@
     result._types.push_back(result_type);
   else {
     if (ast) {
+      SmallVector<ProtocolDecl *, 1> protocols;
       result._types.push_back(ArchetypeType::getNew(
-          *ast, nullptr, (AssociatedTypeDecl *)nullptr,
-          ast->getIdentifier(archetype_name), ArrayRef<Type>(), Type()));
+          *ast, ast->getIdentifier(archetype_name), protocols, Type()));
     } else {
       result._error = "invalid ASTContext";
     }
diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp
index 94e18f8..ff033ab 100644
--- a/lib/Serialization/Deserialization.cpp
+++ b/lib/Serialization/Deserialization.cpp
@@ -3607,14 +3607,13 @@
   }
 
   case decls_block::ARCHETYPE_TYPE: {
-    IdentifierID nameID;
     TypeID parentID;
-    DeclID assocTypeID;
+    DeclID assocTypeOrNameID;
     TypeID superclassID;
     ArrayRef<uint64_t> rawConformanceIDs;
 
-    decls_block::ArchetypeTypeLayout::readRecord(scratch, nameID, parentID,
-                                                 assocTypeID,
+    decls_block::ArchetypeTypeLayout::readRecord(scratch, parentID,
+                                                 assocTypeOrNameID,
                                                  superclassID,
                                                  rawConformanceIDs);
 
@@ -3625,8 +3624,6 @@
     if (auto parentType = getType(parentID))
       parent = parentType->castTo<ArchetypeType>();
 
-    auto assocTypeDecl = dyn_cast_or_null<AssociatedTypeDecl>(
-        getDecl(assocTypeID));
 
     superclass = getType(superclassID);
 
@@ -3637,9 +3634,16 @@
     if (typeOrOffset.isComplete())
       break;
 
-    auto archetype = ArchetypeType::getNew(ctx, parent, assocTypeDecl,
-                                           getIdentifier(nameID), conformances,
-                                           superclass, false);
+    ArchetypeType *archetype;
+    if (parent) {
+      auto assocTypeDecl = cast<AssociatedTypeDecl>(getDecl(assocTypeOrNameID));
+      archetype = ArchetypeType::getNew(ctx, parent, assocTypeDecl,
+                                        conformances, superclass);
+    } else {
+      archetype = ArchetypeType::getNew(ctx, getIdentifier(assocTypeOrNameID),
+                                        conformances, superclass);
+    }
+
     typeOrOffset = archetype;
     
     // Read the associated type names.
diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp
index 1e8d165..6bd5e60 100644
--- a/lib/Serialization/Serialization.cpp
+++ b/lib/Serialization/Serialization.cpp
@@ -2962,13 +2962,16 @@
     for (auto proto : archetypeTy->getConformsTo())
       conformances.push_back(addDeclRef(proto));
 
-    DeclID assocTypeID = addDeclRef(archetypeTy->getAssocType());
+    DeclID assocTypeOrNameID;
+    if (archetypeTy->getParent())
+      assocTypeOrNameID = addDeclRef(archetypeTy->getAssocType());
+    else
+      assocTypeOrNameID = addIdentifierRef(archetypeTy->getName());
 
     unsigned abbrCode = DeclTypeAbbrCodes[ArchetypeTypeLayout::Code];
     ArchetypeTypeLayout::emitRecord(Out, ScratchRecord, abbrCode,
-                                    addIdentifierRef(archetypeTy->getName()),
                                     parentID,
-                                    assocTypeID,
+                                    assocTypeOrNameID,
                                     addTypeRef(archetypeTy->getSuperclass()),
                                     conformances);