Merge pull request #20005 from DougGregor/more-symbolic-references

[ABI] Introduce indirect symbolic references to context descriptors.
diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst
index d4bade7..93cb49d 100644
--- a/docs/ABI/Mangling.rst
+++ b/docs/ABI/Mangling.rst
@@ -9,9 +9,15 @@
 --------
 ::
 
-  mangled-name ::= '$s' global
+  mangled-name ::= '$s' global  // Swift stable mangling
+  mangled-name ::= '_T0' global // Swift 4.0
+  mangled-name ::= '$S' global  // Swift 4.2
 
-All Swift-mangled names begin with this prefix.
+All Swift-mangled names begin with a common prefix. Since Swift 4.0, the
+compiler has used variations of the mangling described in this document, though
+pre-stable versions may not exactly conform to this description. By using
+distinct prefixes, tools can attempt to accommodate bugs and version variations
+in pre-stable versions of Swift.
 
 The basic mangling scheme is a list of 'operators' where the operators are
 structured in a post-fix order. For example the mangling may start with an
@@ -20,8 +26,6 @@
 
   4Test3FooC   // The trailing 'C' says that 'Foo' is a class in module 'Test'
 
-
-
 Operators are either identifiers or a sequence of one or more characters,
 like ``C`` for class.
 All operators share the same name-space. Important operators are a single
@@ -42,6 +46,48 @@
 In the following, productions which are only _part_ of an operator, are
 named with uppercase letters.
 
+Symbolic references
+~~~~~~~~~~~~~~~~~~~
+
+The Swift compiler emits mangled names into binary images to encode
+references to types for runtime instantiation and reflection. In a binary,
+these mangled names may embed pointers to runtime data
+structures in order to more efficiently represent locally-defined types.
+We call these pointers **symbolic references**.
+These references will be introduced by a control character in the range
+`\x01` ... `\x1F`, which indicates the kind of symbolic reference, followed by
+some number of arbitrary bytes *which may include null bytes*. Code that
+processes mangled names out of Swift binaries needs to be aware of symbolic
+references in order to properly terminate strings; a null terminator may be
+part of a symbolic reference.
+
+::
+
+  symbolic-reference ::= [\x01-\x17] .{4} // Relative symbolic reference
+   #if sizeof(void*) == 8
+     symbolic-reference ::= [\x18-\x1F] .{8} // Absolute symbolic reference
+   #elif sizeof(void*) == 4
+     symbolic-reference ::= [\x18-\x1F] .{4} // Absolute symbolic reference
+   #endif
+
+Symbolic references are only valid in compiler-emitted metadata structures
+and must only appear in read-only parts of a binary image. APIs and tools
+that interpret Swift mangled names from potentially uncontrolled inputs must
+refuse to interpret symbolic references.
+
+The following symbolic reference kinds are currently implemented:
+
+::
+
+   {any-generic-type, protocol} ::= '\x01' .{4}              // Reference points directly to context descriptor
+   {any-generic-type, protocol} ::= '\x02' .{4}              // Reference points indirectly to context descriptor
+   // The grammatical role of the symbolic reference is determined by the
+   // kind of context descriptor referenced
+
+   protocol-conformance-ref ::= '\x03' .{4}  // Reference points directly to protocol conformance descriptor (NOT IMPLEMENTED)
+   protocol-conformance-ref ::= '\x04' .{4}  // Reference points indirectly to protocol conformance descriptor (NOT IMPLEMENTED)
+
+
 Globals
 ~~~~~~~
 
@@ -549,7 +595,9 @@
 
 ::
 
-  protocol-conformance ::= type protocol module generic-signature?
+  protocol-conformance-context ::= protocol module generic-signature?
+
+  protocol-conformance ::= type protocol-conformance-context
 
 ``<protocol-conformance>`` refers to a type's conformance to a protocol. The
 named module is the one containing the extension or type declaration that
@@ -557,12 +605,28 @@
 
 ::
 
+  protocol-conformance ::= type protocol
+
+If ``type`` is a generic parameter or associated type of one, then no module
+is mangled, because the conformance must be resolved from the generic
+environment.
+
   protocol-conformance ::= context identifier protocol identifier generic-signature?  // Property behavior conformance
 
 Property behaviors are implemented using private protocol conformances.
 
 ::
 
+  concrete-protocol-conformance ::= type protocol-conformance-ref
+  protocol-conformance-ref ::= protocol module?
+
+A compact representation used to represent mangled protocol conformance witness
+arguments at runtime. The ``module`` is only specified for conformances that
+are "retroactive", meaning that the context in which the conformance is defined
+is in neither the protocol or type module.
+
+::
+
   generic-signature ::= requirement* 'l'     // one generic parameter
   generic-signature ::= requirement* 'r' GENERIC-PARAM-COUNT* 'l'
 
diff --git a/include/swift/AST/ASTMangler.h b/include/swift/AST/ASTMangler.h
index 6b6f6bf..07c64f8 100644
--- a/include/swift/AST/ASTMangler.h
+++ b/include/swift/AST/ASTMangler.h
@@ -46,12 +46,22 @@
   /// If disabled, it is an error to try to mangle such an entity.
   bool AllowNamelessEntities = false;
 
-  /// If nonnull, provides a callback to encode symbolic references to
-  /// type contexts.
-  std::function<bool (const DeclContext *Context)>
-    CanSymbolicReference;
-  
-  std::vector<std::pair<const DeclContext *, unsigned>> SymbolicReferences;
+  /// If enabled, some entities will be emitted as symbolic reference
+  /// placeholders. The offsets of these references will be stored in the
+  /// `SymbolicReferences` vector, and it is up to the consumer of the mangling
+  /// to fill these in.
+  bool AllowSymbolicReferences = false;
+
+public:
+  using SymbolicReferent = llvm::PointerUnion<const NominalTypeDecl *,
+                                              const ProtocolConformance *>;
+protected:
+
+  /// If set, the mangler calls this function to determine whether to symbolic
+  /// reference a given entity. Defaults to always returning true.
+  std::function<bool (SymbolicReferent)> CanSymbolicReference;
+
+  std::vector<std::pair<SymbolicReferent, unsigned>> SymbolicReferences;
   
 public:
   enum class SymbolKind {
@@ -292,7 +302,7 @@
 
   void appendOpParamForLayoutConstraint(LayoutConstraint Layout);
   
-  void appendSymbolicReference(const DeclContext *context);
+  void appendSymbolicReference(SymbolicReferent referent);
   
   std::string mangleTypeWithoutPrefix(Type type) {
     appendType(type);
diff --git a/include/swift/Demangling/Demangle.h b/include/swift/Demangling/Demangle.h
index 55f5347..7621fae 100644
--- a/include/swift/Demangling/Demangle.h
+++ b/include/swift/Demangling/Demangle.h
@@ -33,6 +33,8 @@
 namespace swift {
 namespace Demangle {
 
+enum class SymbolicReferenceKind : uint8_t;
+
 struct DemangleOptions {
   bool SynthesizeSugarOnTypes = false;
   bool DisplayDebuggerGeneratedModule = true;
@@ -473,7 +475,9 @@
 /// This should always round-trip perfectly with demangleSymbolAsNode.
 std::string mangleNode(const NodePointer &root);
 
-using SymbolicResolver = llvm::function_ref<Demangle::NodePointer (const void *)>;
+using SymbolicResolver =
+  llvm::function_ref<Demangle::NodePointer (SymbolicReferenceKind,
+                                            const void *)>;
 
 /// \brief Remangle a demangled parse tree, using a callback to resolve
 /// symbolic references.
@@ -537,6 +541,8 @@
     return std::move(*this << std::forward<T>(x));
   }
   
+  DemanglerPrinter &writeHex(unsigned long long n) &;
+ 
   std::string &&str() && { return std::move(Stream); }
 
   llvm::StringRef getStringRef() const { return Stream; }
diff --git a/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def
index ed283d6..418435d 100644
--- a/include/swift/Demangling/DemangleNodes.def
+++ b/include/swift/Demangling/DemangleNodes.def
@@ -143,6 +143,7 @@
 NODE(PrivateDeclName)
 NODE(PropertyDescriptor)
 CONTEXT_NODE(Protocol)
+CONTEXT_NODE(ProtocolSymbolicReference)
 NODE(ProtocolConformance)
 NODE(ProtocolDescriptor)
 NODE(ProtocolConformanceDescriptor)
@@ -172,13 +173,13 @@
 CONTEXT_NODE(Static)
 CONTEXT_NODE(Structure)
 CONTEXT_NODE(Subscript)
-CONTEXT_NODE(SymbolicReference)
 NODE(Suffix)
 NODE(ThinFunctionType)
 NODE(Tuple)
 NODE(TupleElement)
 NODE(TupleElementName)
 NODE(Type)
+CONTEXT_NODE(TypeSymbolicReference)
 CONTEXT_NODE(TypeAlias)
 NODE(TypeList)
 NODE(TypeMangling)
@@ -192,7 +193,6 @@
 NODE(UncurriedFunctionType)
 #define REF_STORAGE(Name, ...) NODE(Name)
 #include "swift/AST/ReferenceStorage.def"
-CONTEXT_NODE(UnresolvedSymbolicReference)
 CONTEXT_NODE(UnsafeAddressor)
 CONTEXT_NODE(UnsafeMutableAddressor)
 NODE(ValueWitness)
diff --git a/include/swift/Demangling/Demangler.h b/include/swift/Demangling/Demangler.h
index cbc309e..6651002 100644
--- a/include/swift/Demangling/Demangler.h
+++ b/include/swift/Demangling/Demangler.h
@@ -280,6 +280,17 @@
   }
 };
 
+/// Kinds of symbolic reference supported.
+enum class SymbolicReferenceKind : uint8_t {
+  /// A symbolic reference to a context descriptor, representing the
+  /// (unapplied generic) context.
+  Context,  
+};
+
+using SymbolicReferenceResolver_t = NodePointer (SymbolicReferenceKind,
+                                                 Directness,
+                                                 int32_t, const void *);
+
 /// The demangler.
 ///
 /// It de-mangles a string and it also owns the returned node-tree. This means
@@ -301,7 +312,7 @@
   StringRef Words[MaxNumWords];
   int NumWords = 0;
   
-  std::function<NodePointer (int32_t, const void *)> SymbolicReferenceResolver;
+  std::function<SymbolicReferenceResolver_t> SymbolicReferenceResolver;
 
   bool nextIf(StringRef str) {
     if (!Text.substr(Pos).startswith(str)) return false;
@@ -472,7 +483,8 @@
 
   NodePointer demangleObjCTypeName();
   NodePointer demangleTypeMangling();
-  NodePointer demangleSymbolicReference(const void *at);
+  NodePointer demangleSymbolicReference(unsigned char rawKind,
+                                        const void *at);
 
   void dump();
 
@@ -483,7 +495,7 @@
 
   /// Install a resolver for symbolic references in a mangled string.
   void setSymbolicReferenceResolver(
-                  std::function<NodePointer (int32_t, const void*)> resolver) {
+                          std::function<SymbolicReferenceResolver_t> resolver) {
     SymbolicReferenceResolver = resolver;
   }
   
diff --git a/include/swift/Demangling/TypeDecoder.h b/include/swift/Demangling/TypeDecoder.h
index 5f41b8f..6d847ad 100644
--- a/include/swift/Demangling/TypeDecoder.h
+++ b/include/swift/Demangling/TypeDecoder.h
@@ -114,7 +114,7 @@
     case NodeKind::Enum:
     case NodeKind::Structure:
     case NodeKind::TypeAlias: // This can show up for imported Clang decls.
-    case NodeKind::SymbolicReference:
+    case NodeKind::TypeSymbolicReference:
     {
       BuiltNominalTypeDecl typeDecl = BuiltNominalTypeDecl();
       BuiltType parent = BuiltType();
@@ -228,7 +228,8 @@
                                                    IsClassBound);
     }
 
-    case NodeKind::Protocol: {
+    case NodeKind::Protocol:
+    case NodeKind::ProtocolSymbolicReference: {
       if (auto Proto = decodeMangledProtocolType(Node)) {
         return Builder.createProtocolCompositionType(Proto, BuiltType(),
                                                      /*IsClassBound=*/false);
@@ -473,14 +474,14 @@
   }
 
 private:
-  bool decodeMangledNominalType(const Demangle::NodePointer &node,
+  bool decodeMangledNominalType(Demangle::NodePointer node,
                                 BuiltNominalTypeDecl &typeDecl,
                                 BuiltType &parent) {
     if (node->getKind() == NodeKind::Type)
       return decodeMangledNominalType(node->getChild(0), typeDecl, parent);
 
     Demangle::NodePointer nominalNode;
-    if (node->getKind() == NodeKind::SymbolicReference) {
+    if (node->getKind() == NodeKind::TypeSymbolicReference) {
       // A symbolic reference can be directly resolved to a nominal type.
       nominalNode = node;
     } else {
@@ -519,19 +520,19 @@
     return true;
   }
 
-  BuiltProtocolDecl decodeMangledProtocolType(
-                                            const Demangle::NodePointer &node) {
+  BuiltProtocolDecl decodeMangledProtocolType(Demangle::NodePointer node) {
     if (node->getKind() == NodeKind::Type)
       return decodeMangledProtocolType(node->getChild(0));
 
-    if (node->getNumChildren() < 2 || node->getKind() != NodeKind::Protocol)
+    if ((node->getNumChildren() < 2 || node->getKind() != NodeKind::Protocol)
+        && node->getKind() != NodeKind::ProtocolSymbolicReference)
       return BuiltProtocolDecl();
 
     return Builder.createProtocolDecl(node);
   }
 
   bool decodeMangledFunctionInputType(
-      const Demangle::NodePointer &node,
+      Demangle::NodePointer node,
       std::vector<FunctionParam<BuiltType>> &params,
       bool &hasParamFlags) {
     // Look through a couple of sugar nodes.
@@ -542,7 +543,7 @@
     }
 
     auto decodeParamTypeAndFlags =
-        [&](const Demangle::NodePointer &typeNode,
+        [&](Demangle::NodePointer typeNode,
             FunctionParam<BuiltType> &param) -> bool {
       Demangle::NodePointer node = typeNode;
 
diff --git a/include/swift/IRGen/Linking.h b/include/swift/IRGen/Linking.h
index 1991df6..d995632 100644
--- a/include/swift/IRGen/Linking.h
+++ b/include/swift/IRGen/Linking.h
@@ -32,6 +32,7 @@
 namespace swift {
 namespace irgen {
 class IRGenModule;
+class Alignment;
 
 /// Determine if the triple uses the DLL storage.
 bool useDllStorage(const llvm::Triple &triple);
@@ -936,6 +937,17 @@
 
     return getDecl()->isWeakImported(module);
   }
+  
+  /// Return the source file whose codegen should trigger emission of this
+  /// link entity, if one can be identified.
+  const SourceFile *getSourceFileForEmission() const;
+  
+  /// Get the preferred alignment for the definition of this entity.
+  Alignment getAlignment(IRGenModule &IGM) const;
+  
+  /// Get the default LLVM type to use for forward declarations of this
+  /// entity.
+  llvm::Type *getDefaultDeclarationType(IRGenModule &IGM) const;
 #undef LINKENTITY_GET_FIELD
 #undef LINKENTITY_SET_FIELD
 };
diff --git a/include/swift/Reflection/TypeRefBuilder.h b/include/swift/Reflection/TypeRefBuilder.h
index 921b925..8574a22 100644
--- a/include/swift/Reflection/TypeRefBuilder.h
+++ b/include/swift/Reflection/TypeRefBuilder.h
@@ -354,15 +354,30 @@
     // demangling out of the referenced context descriptors in the target
     // process.
     Dem.setSymbolicReferenceResolver(
-      [this, &reader](int32_t offset, const void *base) -> Demangle::NodePointer {
-        // Resolve the reference to a remote address.
-        auto remoteAddress = getRemoteAddrOfTypeRefPointer(base);
-        if (remoteAddress == 0)
+    [this, &reader](SymbolicReferenceKind kind,
+                    Directness directness,
+                    int32_t offset, const void *base) -> Demangle::NodePointer {
+      // Resolve the reference to a remote address.
+      auto remoteAddress = getRemoteAddrOfTypeRefPointer(base);
+      if (remoteAddress == 0)
+        return nullptr;
+      
+      auto address = remoteAddress + offset;
+      if (directness == Directness::Indirect) {
+        if (auto indirectAddress = reader.readPointerValue(address)) {
+          address = *indirectAddress;
+        } else {
           return nullptr;
-        
-        return reader.readDemanglingForContextDescriptor(remoteAddress + offset,
-                                                         Dem);
-      });
+        }
+      }
+      
+      switch (kind) {
+      case Demangle::SymbolicReferenceKind::Context:
+        return reader.readDemanglingForContextDescriptor(address, Dem);
+      }
+      
+      return nullptr;
+    });
   }
 
   TypeConverter &getTypeConverter() { return TC; }
diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h
index f87dd42..c271635 100644
--- a/include/swift/Remote/MetadataReader.h
+++ b/include/swift/Remote/MetadataReader.h
@@ -573,8 +573,8 @@
 
       // Build the demangling tree from the context tree.
       Demangle::NodeFactory nodeFactory;
-      auto node = buildNominalTypeMangling(descriptor, nodeFactory);
-      if (!node)
+      auto node = buildContextMangling(descriptor, nodeFactory);
+      if (!node || node->getKind() != Node::Kind::Type)
         return BuiltType();
 
       auto name = Demangle::mangleNode(node);
@@ -614,7 +614,7 @@
     auto context = readContextDescriptor(contextAddress);
     if (!context)
       return nullptr;
-    return buildNominalTypeMangling(context, Dem);
+    return buildContextMangling(context, Dem);
   }
 
   /// Read the isa pointer of a class or closure context instance and apply
@@ -1244,7 +1244,7 @@
       metadataInitSize = readMetadataInitSize();
       break;
     case ContextDescriptorKind::Protocol:
-      baseSize = sizeof(TargetProtocolDescriptorRef<Runtime>);
+      baseSize = sizeof(TargetProtocolDescriptor<Runtime>);
       break;
     default:
       // We don't know about this kind of context.
@@ -1427,9 +1427,21 @@
       // TODO: Remangle something about the extension context here.
       return nullptr;
       
-    case ContextDescriptorKind::Anonymous:
-      // TODO: Remangle something about the anonymous context here.
-      return nullptr;
+    case ContextDescriptorKind::Anonymous: {
+      // Use the remote address to identify the anonymous context.
+      char addressBuf[18];
+      snprintf(addressBuf, sizeof(addressBuf), "$%" PRIx64,
+               (uint64_t)descriptor.getAddress());
+      auto anonNode = nodeFactory.createNode(Node::Kind::AnonymousContext);
+      CharVector addressStr;
+      addressStr.append(addressBuf, nodeFactory);
+      auto name = nodeFactory.createNode(Node::Kind::Identifier, addressStr);
+      anonNode->addChild(name, nodeFactory);
+      if (parentDemangling)
+        anonNode->addChild(parentDemangling, nodeFactory);
+      
+      return anonNode;
+    }
 
     case ContextDescriptorKind::Module: {
       // Modules shouldn't have a parent.
@@ -1481,6 +1493,18 @@
 
     auto nameNode = nodeFactory.createNode(Node::Kind::Identifier,
                                            std::move(nodeName));
+
+    // Use private declaration names for anonymous context references.
+    if (parentDemangling->getKind() == Node::Kind::AnonymousContext) {
+      auto privateDeclName =
+        nodeFactory.createNode(Node::Kind::PrivateDeclName);
+      privateDeclName->addChild(parentDemangling->getChild(0), nodeFactory);
+      privateDeclName->addChild(nameNode, nodeFactory);
+
+      nameNode = privateDeclName;
+      parentDemangling = parentDemangling->getChild(1);
+    }
+
     if (importInfo && !importInfo->RelatedEntityName.empty()) {
       auto relatedNode =
         nodeFactory.createNode(Node::Kind::RelatedEntityDeclName,
@@ -1495,17 +1519,25 @@
     return demangling;
   }
 
-  /// Given a read nominal type descriptor, attempt to build a demangling tree
+  /// Given a read context descriptor, attempt to build a demangling tree
   /// for it.
   Demangle::NodePointer
-  buildNominalTypeMangling(ContextDescriptorRef descriptor,
-                           Demangle::NodeFactory &nodeFactory) {
+  buildContextMangling(ContextDescriptorRef descriptor,
+                       Demangle::NodeFactory &nodeFactory) {
     auto demangling = buildContextDescriptorMangling(descriptor, nodeFactory);
     if (!demangling)
       return nullptr;
 
-    auto top = nodeFactory.createNode(Node::Kind::Type);
-    top->addChild(demangling, nodeFactory);
+    NodePointer top;
+    // References to type nodes behave as types in the mangling.
+    if (isa<TargetTypeContextDescriptor<Runtime>>(descriptor.getLocalBuffer()) ||
+        isa<TargetProtocolDescriptor<Runtime>>(descriptor.getLocalBuffer())) {
+      top = nodeFactory.createNode(Node::Kind::Type);
+      top->addChild(demangling, nodeFactory);
+    } else {
+      top = demangling;
+    }
+    
     return top;
   }
 
@@ -1515,8 +1547,8 @@
   buildNominalTypeDecl(ContextDescriptorRef descriptor) {
     // Build the demangling tree from the context tree.
     Demangle::NodeFactory nodeFactory;
-    auto node = buildNominalTypeMangling(descriptor, nodeFactory);
-    if (!node)
+    auto node = buildContextMangling(descriptor, nodeFactory);
+    if (!node || node->getKind() != Node::Kind::Type)
       return BuiltNominalTypeDecl();
     BuiltNominalTypeDecl decl = Builder.createNominalTypeDecl(node);
     return decl;
diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp
index a92a97b..0b58ffb 100644
--- a/lib/AST/ASTMangler.cpp
+++ b/lib/AST/ASTMangler.cpp
@@ -462,7 +462,7 @@
   assert(Root->getKind() == Node::Kind::Global);
   Node *NomTy = Root->getFirstChild();
   if (NomTy->getKind() == Node::Kind::Protocol) {
-    // Protocols are actually mangled as protocol lists.
+    // Protocol types are mangled as protocol lists.
     Node *PTy = Dem.createNode(Node::Kind::Type);
     PTy->addChild(NomTy, Dem);
     Node *TList = Dem.createNode(Node::Kind::TypeList);
@@ -1499,6 +1499,19 @@
   if (allowStandardSubstitution && tryAppendStandardSubstitution(protocol))
     return;
 
+  // We can use a symbolic reference if they're allowed in this context.
+  if (AllowSymbolicReferences
+      && (!CanSymbolicReference || CanSymbolicReference(protocol))) {
+    // Try to use a symbolic reference substitution.
+    if (tryMangleSubstitution(protocol))
+      return;
+  
+    appendSymbolicReference(protocol);
+    // Substitutions can refer back to the symbolic reference.
+    addSubstitution(protocol);
+    return;
+  }
+
   appendContextOf(protocol);
   auto *clangDecl = protocol->getClangDecl();
   if (auto *clangProto = cast_or_null<clang::ObjCProtocolDecl>(clangDecl))
@@ -1525,13 +1538,12 @@
   return namedDecl;
 }
 
-void ASTMangler::appendSymbolicReference(const DeclContext *context) {
+void ASTMangler::appendSymbolicReference(SymbolicReferent referent) {
   // Drop in a placeholder. The real reference value has to be filled in during
   // lowering to IR.
-  Buffer << '\1';
   auto offset = Buffer.str().size();
-  Buffer << StringRef("\0\0\0\0", 4);
-  SymbolicReferences.emplace_back(context, offset);
+  Buffer << StringRef("\0\0\0\0\0", 5);
+  SymbolicReferences.emplace_back(referent, offset);
 }
 
 void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl) {
@@ -1554,13 +1566,16 @@
   if (tryMangleSubstitution(key.getPointer()))
     return;
   
-  // Try to mangle a symbolic reference.
-  if (CanSymbolicReference
-      && CanSymbolicReference(key->getAnyNominal())) {
-    appendSymbolicReference(key->getAnyNominal());
-    // Substitutions can refer back to the symbolic reference.
-    addSubstitution(key.getPointer());
-    return;
+  // Try to mangle a symbolic reference for a nominal type.
+  if (AllowSymbolicReferences) {
+    auto nominal = key->getAnyNominal();
+    if (nominal && !isa<ProtocolDecl>(nominal)
+        && (!CanSymbolicReference || CanSymbolicReference(nominal))) {
+      appendSymbolicReference(nominal);
+      // Substitutions can refer back to the symbolic reference.
+      addSubstitution(key.getPointer());
+      return;
+    }
   }
 
   appendContextOf(decl);
@@ -2183,7 +2198,8 @@
     appendOperator("Z");
 }
 
-void ASTMangler::appendProtocolConformance(const ProtocolConformance *conformance){
+void
+ASTMangler::appendProtocolConformance(const ProtocolConformance *conformance) {
   GenericSignature *contextSig = nullptr;
   auto topLevelContext =
       conformance->getDeclContext()->getModuleScopeContext();
@@ -2199,6 +2215,7 @@
   } else {
     auto conformingType = conformance->getType();
     appendType(conformingType->getCanonicalType());
+    
     appendProtocolName(conformance->getProtocol());
 
     bool needsModule = true;
diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp
index f874234..8654bf6 100644
--- a/lib/Demangling/Demangler.cpp
+++ b/lib/Demangling/Demangler.cpp
@@ -39,8 +39,8 @@
     case Node::Kind::PrefixOperator:
     case Node::Kind::PostfixOperator:
     case Node::Kind::InfixOperator:
-    case Node::Kind::UnresolvedSymbolicReference:
-    case Node::Kind::SymbolicReference:
+    case Node::Kind::TypeSymbolicReference:
+    case Node::Kind::ProtocolSymbolicReference:
       return true;
     default:
       return false;
@@ -65,10 +65,10 @@
     case Node::Kind::Class:
     case Node::Kind::Enum:
     case Node::Kind::Protocol:
+    case Node::Kind::ProtocolSymbolicReference:
     case Node::Kind::OtherNominalType:
     case Node::Kind::TypeAlias:
-    case Node::Kind::SymbolicReference:
-    case Node::Kind::UnresolvedSymbolicReference:
+    case Node::Kind::TypeSymbolicReference:
       return true;
     default:
       return false;
@@ -241,6 +241,7 @@
   case Demangle::Node::Kind::Type:
     return isProtocolNode(Node->getChild(0));
   case Demangle::Node::Kind::Protocol:
+  case Demangle::Node::Kind::ProtocolSymbolicReference:
     return true;
   default:
     return false;
@@ -547,31 +548,52 @@
   return TypeMangling;
 }
   
-NodePointer Demangler::demangleSymbolicReference(const void *at) {
+NodePointer Demangler::demangleSymbolicReference(unsigned char rawKind,
+                                                 const void *at) {
   // The symbolic reference is a 4-byte machine integer encoded in the following
   // four bytes.
   int32_t value;
   memcpy(&value, Text.data() + Pos, 4);
   Pos += 4;
   
+  // Map the encoded kind to a specific kind and directness.
+  SymbolicReferenceKind kind;
+  Directness direct;
+  switch (rawKind) {
+  case 1:
+    kind = SymbolicReferenceKind::Context;
+    direct = Directness::Direct;
+    break;
+  case 2:
+    kind = SymbolicReferenceKind::Context;
+    direct = Directness::Indirect;
+    break;
+  default:
+    return nullptr;
+  }
+  
   // Use the resolver, if any, to produce the demangling tree the symbolic
   // reference represents.
   NodePointer resolved = nullptr;
   if (SymbolicReferenceResolver)
-    resolved = SymbolicReferenceResolver(value, at);
-  // With no resolver, or a resolver that failed, simply preserve the raw
-  // information in the node.
+    resolved = SymbolicReferenceResolver(kind, direct, value, at);
+  // With no resolver, or a resolver that failed, refuse to demangle further.
   if (!resolved)
-    resolved = createNode(Node::Kind::UnresolvedSymbolicReference, value);
+    return nullptr;
   
-  // Register the result as a substitution.
-  addSubstitution(resolved);
+  // Types register as substitutions even when symbolically referenced.
+  if (kind == SymbolicReferenceKind::Context)
+    addSubstitution(resolved);
   return resolved;
 }
 
 NodePointer Demangler::demangleOperator() {
   switch (char c = nextChar()) {
-    case '\1': return demangleSymbolicReference(Text.data() + Pos);
+    case '\1':
+    case '\2':
+    case '\3':
+    case '\4':
+      return demangleSymbolicReference((unsigned char)c, Text.data() + Pos);
     case 'A': return demangleMultiSubstitutions();
     case 'B': return demangleBuiltinType();
     case 'C': return demangleAnyGenericType(Node::Kind::Class);
@@ -1204,12 +1226,15 @@
     if (Type->getNumChildren() < 1)
       return nullptr;
 
-    NodePointer Proto = Type->getChild(0);
-    if (Proto->getKind() != Node::Kind::Protocol)
+    if (!isProtocolNode(Type))
       return nullptr;
 
     return Type;
   }
+  
+  if (NodePointer SymbolicRef = popNode(Node::Kind::ProtocolSymbolicReference)){
+    return SymbolicRef;
+  }
 
   NodePointer Name = popNode(isDeclName);
   NodePointer Ctx = popContext();
@@ -1273,9 +1298,10 @@
   if (TypeListIdx >= TypeLists.size())
     return nullptr;
 
-  // Associate a symbolic reference with all remaining generic arguments.
-  if (Nominal->getKind() == Node::Kind::SymbolicReference
-      || Nominal->getKind() == Node::Kind::UnresolvedSymbolicReference) {
+  // Associate a context symbolic reference with all remaining generic
+  // arguments.
+  if (Nominal->getKind() == Node::Kind::TypeSymbolicReference
+      || Nominal->getKind() == Node::Kind::ProtocolSymbolicReference) {
     auto remainingTypeList = createNode(Node::Kind::TypeList);
     for (unsigned i = TypeLists.size() - 1;
          i >= TypeListIdx && i < TypeLists.size();
@@ -1349,30 +1375,30 @@
 
   Node::Kind kind;
   switch (Nominal->getKind()) {
-    case Node::Kind::Class:
-      kind = Node::Kind::BoundGenericClass;
-      break;
-    case Node::Kind::Structure:
-      kind = Node::Kind::BoundGenericStructure;
-      break;
-    case Node::Kind::Enum:
-      kind = Node::Kind::BoundGenericEnum;
-      break;
-    case Node::Kind::Protocol:
-      kind = Node::Kind::BoundGenericProtocol;
-      break;
-    case Node::Kind::OtherNominalType:
-      kind = Node::Kind::BoundGenericOtherNominalType;
-      break;
-    case Node::Kind::TypeAlias:
-      kind = Node::Kind::BoundGenericTypeAlias;
-      break;
-    case Node::Kind::Function:
-    case Node::Kind::Constructor:
-      // Well, not really a nominal type.
-      return createWithChildren(Node::Kind::BoundGenericFunction, Nominal, args);
-    default:
-      return nullptr;
+  case Node::Kind::Class:
+    kind = Node::Kind::BoundGenericClass;
+    break;
+  case Node::Kind::Structure:
+    kind = Node::Kind::BoundGenericStructure;
+    break;
+  case Node::Kind::Enum:
+    kind = Node::Kind::BoundGenericEnum;
+    break;
+  case Node::Kind::Protocol:
+    kind = Node::Kind::BoundGenericProtocol;
+    break;
+  case Node::Kind::OtherNominalType:
+    kind = Node::Kind::BoundGenericOtherNominalType;
+    break;
+  case Node::Kind::TypeAlias:
+    kind = Node::Kind::BoundGenericTypeAlias;
+    break;
+  case Node::Kind::Function:
+  case Node::Kind::Constructor:
+    // Well, not really a nominal type.
+    return createWithChildren(Node::Kind::BoundGenericFunction, Nominal, args);
+  default:
+    return nullptr;
   }
   return createWithChildren(kind, createType(Nominal), args);
 }
@@ -1655,7 +1681,7 @@
 
 NodePointer Demangler::popAssocTypeName() {
   NodePointer Proto = popNode(Node::Kind::Type);
-  if (Proto && Proto->getFirstChild()->getKind() != Node::Kind::Protocol)
+  if (Proto && !isProtocolNode(Proto))
     return nullptr;
 
   NodePointer Id = popNode(Node::Kind::Identifier);
diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp
index 363d552..d9228b1 100644
--- a/lib/Demangling/NodePrinter.cpp
+++ b/lib/Demangling/NodePrinter.cpp
@@ -37,6 +37,12 @@
   Stream.append(buffer);
   return *this;
 }
+DemanglerPrinter &DemanglerPrinter::writeHex(unsigned long long n) & {
+  char buffer[32];
+  snprintf(buffer, sizeof(buffer), "%llX", n);
+  Stream.append(buffer);
+  return *this;
+}
 DemanglerPrinter &DemanglerPrinter::operator<<(long long n) & {
   char buffer[32];
   snprintf(buffer, sizeof(buffer), "%lld",n);
@@ -285,6 +291,7 @@
     case Node::Kind::Module:
     case Node::Kind::Tuple:
     case Node::Kind::Protocol:
+    case Node::Kind::ProtocolSymbolicReference:
     case Node::Kind::ReturnType:
     case Node::Kind::SILBoxType:
     case Node::Kind::SILBoxTypeWithLayout:
@@ -295,8 +302,7 @@
     case Node::Kind::TypeAlias:
     case Node::Kind::TypeList:
     case Node::Kind::LabelList:
-    case Node::Kind::SymbolicReference:
-    case Node::Kind::UnresolvedSymbolicReference:
+    case Node::Kind::TypeSymbolicReference:
       return true;
 
     case Node::Kind::ProtocolList:
@@ -1499,11 +1505,13 @@
       Printer << "merged ";
     }
     return nullptr;
-  case Node::Kind::SymbolicReference:
-    Printer << "symbolic reference " << Node->getIndex();
+  case Node::Kind::TypeSymbolicReference:
+    Printer << "type symbolic reference 0x";
+    Printer.writeHex(Node->getIndex());
     return nullptr;
-  case Node::Kind::UnresolvedSymbolicReference:
-    Printer << "$" << Node->getIndex();
+  case Node::Kind::ProtocolSymbolicReference:
+    Printer << "protocol symbolic reference 0x";
+    Printer.writeHex(Node->getIndex());
     return nullptr;
   case Node::Kind::GenericTypeMetadataPattern:
     Printer << "generic type metadata pattern for ";
diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp
index e4f08ee..ebb2c27 100644
--- a/lib/Demangling/OldRemangler.cpp
+++ b/lib/Demangling/OldRemangler.cpp
@@ -2156,11 +2156,11 @@
   unreachable("unsupported");
 }
 
-void Remangler::mangleUnresolvedSymbolicReference(Node *node, EntityContext&) {
+void Remangler::mangleTypeSymbolicReference(Node *node, EntityContext&) {
   unreachable("unsupported");
 }
 
-void Remangler::mangleSymbolicReference(Node *node, EntityContext&) {
+void Remangler::mangleProtocolSymbolicReference(Node *node, EntityContext&) {
   unreachable("unsupported");
 }
 
diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp
index 348b288..f497f90 100644
--- a/lib/Demangling/Remangler.cpp
+++ b/lib/Demangling/Remangler.cpp
@@ -948,7 +948,8 @@
 void Remangler::mangleAnonymousContext(Node *node) {
   mangleChildNode(node, 1);
   mangleChildNode(node, 0);
-  mangleTypeList(node->getChild(2));
+  if (node->getNumChildren() >= 3)
+    mangleTypeList(node->getChild(2));
   Buffer << "XZ";
 }
 
@@ -2115,23 +2116,21 @@
   Buffer << "MXA";
 }
   
-void Remangler::mangleUnresolvedSymbolicReference(Node *node) {
-  Buffer << "$";
-  char bytes[4];
-  uint32_t value = node->getIndex();
-  memcpy(bytes, &value, 4);
-  Buffer << StringRef(bytes, 4);
+void Remangler::mangleTypeSymbolicReference(Node *node) {
+  return mangle(Resolver(SymbolicReferenceKind::Context,
+                         (const void *)node->getIndex()));
 }
 
-void Remangler::mangleSymbolicReference(Node *node) {
-  return mangle(Resolver((const void *)node->getIndex()));
+void Remangler::mangleProtocolSymbolicReference(Node *node) {
+  return mangle(Resolver(SymbolicReferenceKind::Context,
+                         (const void *)node->getIndex()));
 }
 
 } // anonymous namespace
 
 /// The top-level interface to the remangler.
 std::string Demangle::mangleNode(const NodePointer &node) {
-  return mangleNode(node, [](const void *) -> NodePointer {
+  return mangleNode(node, [](SymbolicReferenceKind, const void *) -> NodePointer {
     unreachable("should not try to mangle a symbolic reference; "
                 "resolve it to a non-symbolic demangling tree instead");
   });
diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp
index 26b4476..c7af260 100644
--- a/lib/IRGen/GenDecl.cpp
+++ b/lib/IRGen/GenDecl.cpp
@@ -801,10 +801,9 @@
           ? ConstantReference::Indirect
           : ConstantReference::Direct;
         
+        IRGen.noteUseOfTypeContextDescriptor(nominal, DontRequireMetadata);
         return getAddrOfLLVMVariableOrGOTEquivalent(
                                 LinkEntity::forNominalTypeDescriptor(nominal),
-                                Alignment(4),
-                                TypeContextDescriptorTy,
                                 shouldBeIndirect);
       }
     }
@@ -868,9 +867,7 @@
   // Try to form a direct reference to the nominal type descriptor if it's in
   // the same binary, or use the GOT entry if it's from another binary.
   return getAddrOfLLVMVariableOrGOTEquivalent(
-                                     LinkEntity::forProtocolDescriptor(proto),
-                                     getPointerAlignment(),
-                                     ProtocolDescriptorStructTy);
+                                     LinkEntity::forProtocolDescriptor(proto));
 }
 
 llvm::Constant *IRGenModule::getAddrOfAssociatedTypeGenericParamRef(
@@ -911,8 +908,7 @@
     // Add a reference to the associated type descriptor.
     auto assocTypeDescriptor =
       getAddrOfLLVMVariableOrGOTEquivalent(
-        LinkEntity::forAssociatedTypeDescriptor(assocType),
-      Alignment(4), ProtocolRequirementStructTy);
+        LinkEntity::forAssociatedTypeDescriptor(assocType));
     B.addRelativeAddress(assocTypeDescriptor);
   }
   
@@ -1228,10 +1224,13 @@
 void IRGenerator::noteUseOfTypeGlobals(NominalTypeDecl *type,
                                        bool isUseOfMetadata,
                                        RequireMetadata_t requireMetadata) {
+  if (!type)
+    return;
+  
   // Try to create a new record of the fact that we used this type.
   auto insertResult = LazyTypeGlobals.try_emplace(type);
   auto &entry = insertResult.first->second;
-
+  
   bool metadataWasUsed = entry.IsMetadataUsed;
   bool descriptorWasUsed = entry.IsDescriptorUsed;
 
@@ -2053,11 +2052,11 @@
 /// result to emitRelativeReference, passing the correct base-address
 /// information.
 ConstantReference
-IRGenModule::getAddrOfLLVMVariable(LinkEntity entity, Alignment alignment,
+IRGenModule::getAddrOfLLVMVariable(LinkEntity entity,
                                    ConstantInit definition,
-                                   llvm::Type *defaultType,
                                    DebugTypeInfo debugType,
-                                   SymbolReferenceKind refKind) {
+                                   SymbolReferenceKind refKind,
+                                   llvm::Type *overrideDeclType) {
   switch (refKind) {
   case SymbolReferenceKind::Relative_Direct:
   case SymbolReferenceKind::Far_Relative_Direct:
@@ -2067,15 +2066,15 @@
     LLVM_FALLTHROUGH;
 
   case SymbolReferenceKind::Absolute:
-    return { getAddrOfLLVMVariable(entity, alignment, definition,
-                                   defaultType, debugType),
+    return { getAddrOfLLVMVariable(entity, definition, debugType,
+                                   overrideDeclType),
              ConstantReference::Direct };
 
 
   case SymbolReferenceKind::Relative_Indirectable:
   case SymbolReferenceKind::Far_Relative_Indirectable:
     assert(!definition);
-    return getAddrOfLLVMVariableOrGOTEquivalent(entity, alignment, defaultType);
+    return getAddrOfLLVMVariableOrGOTEquivalent(entity);
   }
   llvm_unreachable("bad reference kind");
 }
@@ -2083,14 +2082,13 @@
 /// A convenient wrapper around getAddrOfLLVMVariable which uses the
 /// default type as the definition type.
 llvm::Constant *
-IRGenModule::getAddrOfLLVMVariable(LinkEntity entity, Alignment alignment,
+IRGenModule::getAddrOfLLVMVariable(LinkEntity entity,
                                    ForDefinition_t forDefinition,
-                                   llvm::Type *defaultType,
                                    DebugTypeInfo debugType) {
-  auto definition =
-    (forDefinition ? ConstantInit::getDelayed(defaultType) : ConstantInit());
-  return getAddrOfLLVMVariable(entity, alignment, definition,
-                               defaultType, debugType);
+  auto definition = forDefinition
+      ? ConstantInit::getDelayed(entity.getDefaultDeclarationType(*this))
+      : ConstantInit();
+  return getAddrOfLLVMVariable(entity, definition, debugType);
 }
 
 /// Get or create an llvm::GlobalVariable.
@@ -2099,15 +2097,18 @@
 /// llvm::GlobalVariable of that type.  Otherwise, the result will
 /// have type pointerToDefaultType and may involve bitcasts.
 llvm::Constant *
-IRGenModule::getAddrOfLLVMVariable(LinkEntity entity, Alignment alignment,
+IRGenModule::getAddrOfLLVMVariable(LinkEntity entity,
                                    ConstantInit definition,
-                                   llvm::Type *defaultType,
-                                   DebugTypeInfo DbgTy) {
+                                   DebugTypeInfo DbgTy,
+                                   llvm::Type *overrideDeclType) {
   // This function assumes that 'globals' only contains GlobalValue
   // values for the entities that it will look up.
 
   llvm::Type *definitionType = (definition ? definition.getType() : nullptr);
-
+  auto defaultType = overrideDeclType
+    ? overrideDeclType
+    : entity.getDefaultDeclarationType(*this);
+  
   auto &entry = GlobalVars[entity];
   if (entry) {
     auto existing = cast<llvm::GlobalValue>(entry);
@@ -2151,7 +2152,8 @@
   if (!definitionType) definitionType = defaultType;
 
   // Create the variable.
-  auto var = createVariable(*this, link, definitionType, alignment, DbgTy);
+  auto var = createVariable(*this, link, definitionType,
+                            entity.getAlignment(*this), DbgTy);
 
   // Install the concrete definition if we have one.
   if (definition && definition.hasInit()) {
@@ -2196,8 +2198,6 @@
 /// relative references to the GOT entry for the variable in the object file.
 ConstantReference
 IRGenModule::getAddrOfLLVMVariableOrGOTEquivalent(LinkEntity entity,
-                              Alignment alignment,
-                              llvm::Type *defaultType,
                               ConstantReference::Directness forceIndirectness) {
   // ObjC class references can always be directly referenced, even in
   // the weird cases where we don't see a definition.
@@ -2214,8 +2214,7 @@
       = getAddrOfForeignTypeMetadataCandidate(entity.getType());
     (void)foreignCandidate;
   } else {
-    getAddrOfLLVMVariable(entity, alignment, ConstantInit(),
-                          defaultType, DebugTypeInfo());
+    getAddrOfLLVMVariable(entity, ConstantInit(), DebugTypeInfo());
   }
 
   // Guess whether a global entry is a definition from this TU. This isn't
@@ -2232,44 +2231,70 @@
     // Assume anything else isn't a definition.
     return false;
   };
-
-  // If the variable has already been defined in this TU,
-  // then it definitely doesn't need a GOT entry, and we can
-  // relative-reference it directly.
+  
   //
-  // TODO: If we know the target entry is going to be linked into the same
-  // binary, then we ought to be able to directly relative-reference the
-  // symbol. However, some platforms don't have the necessary relocations to
-  // represent a relative reference to an undefined symbol, so conservatively
-  // produce an indirect reference in this case. Also, the integrated REPL
-  // incrementally adds new definitions that refer back to existing ones
-  // relatively, so always use indirect references in this situation.
   auto entry = GlobalVars[entity];
-  if (forceIndirectness == ConstantReference::Direct &&
-      !IRGen.Opts.IntegratedREPL &&
-      (!entity.isAvailableExternally(*this) || isDefinition(entry))) {
+  
+  /// Returns a direct reference.
+  auto direct = [&]() -> ConstantReference {
     // FIXME: Relative references to aliases break MC on 32-bit Mach-O
     // platforms (rdar://problem/22450593 ), so substitute an alias with its
     // aliasee to work around that.
     if (auto alias = dyn_cast<llvm::GlobalAlias>(entry))
-      entry = alias->getAliasee();
+      return {alias->getAliasee(), ConstantReference::Direct};
     return {entry, ConstantReference::Direct};
+  };
+  
+  /// Returns an indirect reference.
+  auto indirect = [&]() -> ConstantReference {
+    auto &gotEntry = GlobalGOTEquivalents[entity];
+    if (gotEntry) {
+      return {gotEntry, ConstantReference::Indirect};
+    }
+
+    // Look up the global variable.
+    auto global = cast<llvm::GlobalValue>(entry);
+    // Use it as the initializer for an anonymous constant. LLVM can treat this as
+    // equivalent to the global's GOT entry.
+    llvm::SmallString<64> name;
+    entity.mangle(name);
+    auto gotEquivalent = createGOTEquivalent(*this, global, name);
+    gotEntry = gotEquivalent;
+    return {gotEquivalent, ConstantReference::Indirect};
+  };
+  
+  // Return the GOT entry if we were asked to.
+  if (forceIndirectness == ConstantReference::Indirect)
+    return indirect();
+  
+  // The integrated REPL incrementally adds new definitions, so always use
+  // indirect references in this mode.
+  if (IRGen.Opts.IntegratedREPL)
+    return indirect();
+  
+  // If the variable has already been defined in this TU,
+  // then it definitely doesn't need a GOT entry, and we can
+  // relative-reference it directly.
+  if ((!entity.isAvailableExternally(*this) || isDefinition(entry))) {
+    return direct();
   }
 
-  auto &gotEntry = GlobalGOTEquivalents[entity];
-  if (gotEntry) {
-    return {gotEntry, ConstantReference::Indirect};
-  }
+  // If the entity will be emitted as part of the current source file
+  // (if we know what that is), then we can reference it directly.
+  if (CurSourceFile
+      && !isa<ClangModuleUnit>(CurSourceFile)
+      && CurSourceFile == entity.getSourceFileForEmission())
+    return direct();
+  
+  // TODO: If we know the target entry is going to be linked into the same
+  // binary, then we ought to be able to directly relative-reference the
+  // symbol. However, some platforms don't have the necessary relocations to
+  // represent a relative reference to an undefined symbol, so conservatively
+  // produce an indirect reference in this case.
 
-  // Look up the global variable.
-  auto global = cast<llvm::GlobalValue>(entry);
-  // Use it as the initializer for an anonymous constant. LLVM can treat this as
-  // equivalent to the global's GOT entry.
-  llvm::SmallString<64> name;
-  entity.mangle(name);
-  auto gotEquivalent = createGOTEquivalent(*this, global, name);
-  gotEntry = gotEquivalent;
-  return {gotEquivalent, ConstantReference::Indirect};
+  // Fall back to an indirect reference if we can't establish that a direct
+  // reference is OK.
+  return indirect();
 }
 
 static TypeEntityReference
@@ -2280,10 +2305,9 @@
   // to be looked up dynamically) for types defined outside the module.
   auto kind = TypeReferenceKind::DirectNominalTypeDescriptor;
   auto entity = LinkEntity::forNominalTypeDescriptor(decl);
-  auto defaultTy = IGM.TypeContextDescriptorTy;
 
-  auto ref = IGM.getAddrOfLLVMVariableOrGOTEquivalent(
-      entity, IGM.getPointerAlignment(), defaultTy);
+  IGM.IRGen.noteUseOfTypeContextDescriptor(decl, DontRequireMetadata);
+  auto ref = IGM.getAddrOfLLVMVariableOrGOTEquivalent(entity);
 
   if (ref.isIndirect()) {
     kind = TypeReferenceKind::IndirectNominalTypeDescriptor;
@@ -2299,10 +2323,8 @@
 
   auto kind = TypeReferenceKind::IndirectObjCClass;
   auto entity = LinkEntity::forObjCClassRef(cls);
-  auto defaultTy = IGM.TypeMetadataPtrTy;
 
-  auto ref = IGM.getAddrOfLLVMVariableOrGOTEquivalent(
-      entity, IGM.getPointerAlignment(), defaultTy);
+  auto ref = IGM.getAddrOfLLVMVariableOrGOTEquivalent(entity);
   assert(!ref.isIndirect());
 
   return TypeEntityReference(kind, ref.getValue());
@@ -2413,8 +2435,7 @@
 
     // Relative reference to the protocol descriptor.
     auto descriptorRef = getAddrOfLLVMVariableOrGOTEquivalent(
-                  LinkEntity::forProtocolDescriptor(protocol),
-                  getPointerAlignment(), ProtocolDescriptorStructTy);
+                                   LinkEntity::forProtocolDescriptor(protocol));
     record.addRelativeAddress(descriptorRef);
 
     record.finishAndAddTo(recordsArray);
@@ -2489,8 +2510,7 @@
 
     auto entity = LinkEntity::forProtocolConformanceDescriptor(conformance);
     auto descriptor =
-      getAddrOfLLVMVariable(entity, getPointerAlignment(), ConstantInit(),
-                            ProtocolConformanceDescriptorTy, DebugTypeInfo());
+      getAddrOfLLVMVariable(entity, ConstantInit(), DebugTypeInfo());
     descriptorArray.addRelativeAddress(descriptor);
   }
 
@@ -2568,7 +2588,7 @@
   for (auto type : RuntimeResolvableTypes) {
     auto ref = getTypeEntityReference(type);
 
-    // Form the relative address, with the type refernce kind in the low bits.
+    // Form the relative address, with the type reference kind in the low bits.
     unsigned arrayIdx = elts.size();
     llvm::Constant *relativeAddr =
       emitDirectRelativeReference(ref.getValue(), var, { arrayIdx, 0 });
@@ -2650,13 +2670,10 @@
 Address IRGenModule::getAddrOfObjCClassRef(ClassDecl *theClass) {
   assert(ObjCInterop && "getting address of ObjC class ref in no-interop mode");
 
-  Alignment alignment = getPointerAlignment();
-
   LinkEntity entity = LinkEntity::forObjCClassRef(theClass);
   auto DbgTy = DebugTypeInfo::getObjCClass(
       theClass, ObjCClassPtrTy, getPointerSize(), getPointerAlignment());
-  auto addr = getAddrOfLLVMVariable(entity, alignment, ConstantInit(),
-                                    ObjCClassPtrTy, DbgTy);
+  auto addr = getAddrOfLLVMVariable(entity, ConstantInit(), DbgTy);
 
   // Define it lazily.
   if (auto global = dyn_cast<llvm::GlobalVariable>(addr)) {
@@ -2670,7 +2687,7 @@
     }
   }
 
-  return Address(addr, alignment);
+  return Address(addr, entity.getAlignment(*this));
 }
 
 /// Fetch a global reference to the given Objective-C class.  The
@@ -2682,8 +2699,7 @@
   LinkEntity entity = LinkEntity::forObjCClass(theClass);
   auto DbgTy = DebugTypeInfo::getObjCClass(
       theClass, ObjCClassPtrTy, getPointerSize(), getPointerAlignment());
-  auto addr = getAddrOfLLVMVariable(entity, getPointerAlignment(),
-                                    forDefinition, ObjCClassStructTy, DbgTy);
+  auto addr = getAddrOfLLVMVariable(entity, forDefinition, DbgTy);
   return addr;
 }
 
@@ -2703,8 +2719,7 @@
 
   auto DbgTy = DebugTypeInfo::getObjCClass(
       decl, ObjCClassPtrTy, getPointerSize(), getPointerAlignment());
-  auto addr = getAddrOfLLVMVariable(entity, getPointerAlignment(),
-                                    forDefinition, ObjCClassStructTy, DbgTy);
+  auto addr = getAddrOfLLVMVariable(entity, forDefinition, DbgTy);
   return addr;
 }
 
@@ -2785,8 +2800,7 @@
   assert(!type->hasArchetype() && !type->hasTypeParameter());
   LinkEntity entity = LinkEntity::forTypeMetadataLazyCacheVariable(type);
   auto variable =
-    getAddrOfLLVMVariable(entity, getPointerAlignment(), forDefinition,
-                          TypeMetadataPtrTy, DebugTypeInfo());
+    getAddrOfLLVMVariable(entity, forDefinition, DebugTypeInfo());
 
   // Zero-initialize if we're asking for a definition.
   if (forDefinition) {
@@ -2801,25 +2815,14 @@
 IRGenModule::getAddrOfTypeMetadataSingletonInitializationCache(
                                            NominalTypeDecl *D,
                                            ForDefinition_t forDefinition) {
-  // Build the cache type.
-  llvm::Type *cacheTy;
-  if (isa<StructDecl>(D) || isa<EnumDecl>(D) || isa<ClassDecl>(D)) {
-    // This is struct SingletonMetadataCache.
-    cacheTy = llvm::StructType::get(getLLVMContext(),
-                                    {TypeMetadataPtrTy, Int8PtrTy});
-  } else {
-    llvm_unreachable("in-place initialization for classes not yet supported");
-  }
-
   auto entity = LinkEntity::forTypeMetadataSingletonInitializationCache(D);
   auto variable =
-    getAddrOfLLVMVariable(entity, getPointerAlignment(), forDefinition,
-                          cacheTy, DebugTypeInfo());
+    getAddrOfLLVMVariable(entity, forDefinition, DebugTypeInfo());
 
   // Zero-initialize if we're asking for a definition.
   if (forDefinition) {
     cast<llvm::GlobalVariable>(variable)->setInitializer(
-      llvm::Constant::getNullValue(cacheTy));
+      llvm::Constant::getNullValue(variable->getType()->getPointerElementType()));
   }
 
   return variable;
@@ -2890,29 +2893,25 @@
   /// For concrete metadata, we want to use the initializer on the
   /// "full metadata", and define the "direct" address point as an alias.
   TypeMetadataAddress addrKind;
-  llvm::Type *defaultVarTy;
   unsigned adjustmentIndex;
-  Alignment alignment = getPointerAlignment();
 
   if (concreteType->getClassOrBoundGenericClass()) {
     addrKind = TypeMetadataAddress::FullMetadata;
-    defaultVarTy = FullHeapMetadataStructTy;
     adjustmentIndex = MetadataAdjustmentIndex::Class;
   } else {
     addrKind = TypeMetadataAddress::FullMetadata;
-    defaultVarTy = FullTypeMetadataStructTy;
     adjustmentIndex = MetadataAdjustmentIndex::ValueType;
   }
 
   auto entity = LinkEntity::forTypeMetadata(concreteType, addrKind);
 
   auto DbgTy = DebugTypeInfo::getMetadata(MetatypeType::get(concreteType),
-                                          defaultVarTy->getPointerTo(), Size(0),
-                                          Alignment(1));
+    entity.getDefaultDeclarationType(*this)->getPointerTo(),
+    Size(0), Alignment(1));
 
   // Define the variable.
   llvm::GlobalVariable *var = cast<llvm::GlobalVariable>(
-      getAddrOfLLVMVariable(entity, alignment, init, defaultVarTy, DbgTy));
+      getAddrOfLLVMVariable(entity, init, DbgTy));
 
   var->setConstant(isConstant);
   if (!section.empty())
@@ -2928,7 +2927,7 @@
 
   // For concrete metadata, declare the alias to its address point.
   auto directEntity = LinkEntity::forTypeMetadata(concreteType,
-                                              TypeMetadataAddress::AddressPoint);
+                                             TypeMetadataAddress::AddressPoint);
 
   llvm::Constant *addr = var;
   // Do an adjustment if necessary.
@@ -2970,7 +2969,6 @@
 
   llvm::Type *defaultVarTy;
   unsigned adjustmentIndex;
-  Alignment alignment = getPointerAlignment();
 
   ClassDecl *ObjCClass = nullptr;
   
@@ -3025,8 +3023,8 @@
                                        defaultVarTy->getPointerTo(), Size(0),
                                        Alignment(1));
 
-  auto addr = getAddrOfLLVMVariable(entity, alignment, ConstantInit(),
-                                    defaultVarTy, DbgTy, refKind);
+  auto addr = getAddrOfLLVMVariable(entity, ConstantInit(), DbgTy, refKind,
+                                    defaultVarTy);
 
   // FIXME: MC breaks when emitting alias references on some platforms
   // (rdar://problem/22450593 ). Work around this by referring to the aliasee
@@ -3061,10 +3059,8 @@
   if (!init)
     IRGen.noteUseOfTypeMetadata(D);
 
-  auto alignment = getPointerAlignment();
   LinkEntity entity = LinkEntity::forTypeMetadataPattern(D);
-  auto addr = getAddrOfLLVMVariable(entity, alignment, init,
-                                   Int8Ty, DebugTypeInfo());
+  auto addr = getAddrOfLLVMVariable(entity, init, DebugTypeInfo());
 
   if (init) {
     auto var = cast<llvm::GlobalVariable>(addr);
@@ -3083,16 +3079,8 @@
 llvm::Constant *
 IRGenModule::getAddrOfClassMetadataBounds(ClassDecl *D,
                                           ForDefinition_t forDefinition) {
-  // StoredClassMetadataBounds
-  auto layoutTy = llvm::StructType::get(getLLVMContext(), {
-    SizeTy,  // Immediate members offset
-    Int32Ty, // Negative size in words
-    Int32Ty  // Positive size in words
-  });
-
   LinkEntity entity = LinkEntity::forClassMetadataBaseOffset(D);
-  return getAddrOfLLVMVariable(entity, getPointerAlignment(), forDefinition,
-                               layoutTy, DebugTypeInfo());
+  return getAddrOfLLVMVariable(entity, forDefinition, DebugTypeInfo());
 }
 
 /// Return the address of a generic type's metadata instantiation cache.
@@ -3100,9 +3088,7 @@
 IRGenModule::getAddrOfTypeMetadataInstantiationCache(NominalTypeDecl *D,
                                                 ForDefinition_t forDefinition) {
   auto entity = LinkEntity::forTypeMetadataInstantiationCache(D);
-  auto ty = llvm::ArrayType::get(Int8PtrTy, NumGenericMetadataPrivateDataWords);
-  return getAddrOfLLVMVariable(entity, getPointerAlignment(),
-                               forDefinition, ty, DebugTypeInfo());
+  return getAddrOfLLVMVariable(entity, forDefinition, DebugTypeInfo());
 }
 
 llvm::Function *
@@ -3186,9 +3172,8 @@
   IRGen.noteUseOfTypeContextDescriptor(D, requireMetadata);
 
   auto entity = LinkEntity::forNominalTypeDescriptor(D);
-  return getAddrOfLLVMVariable(entity, Alignment(4),
+  return getAddrOfLLVMVariable(entity,
                                definition,
-                               TypeContextDescriptorTy,
                                DebugTypeInfo());
 }
 
@@ -3196,9 +3181,8 @@
 getAddrOfReflectionBuiltinDescriptor(CanType type,
                                      ConstantInit definition) {
   auto entity = LinkEntity::forReflectionBuiltinDescriptor(type);
-  return getAddrOfLLVMVariable(entity, Alignment(4),
+  return getAddrOfLLVMVariable(entity,
                                definition,
-                               FieldDescriptorTy,
                                DebugTypeInfo());
 }
 
@@ -3206,9 +3190,8 @@
 getAddrOfReflectionFieldDescriptor(CanType type,
                                    ConstantInit definition) {
   auto entity = LinkEntity::forReflectionFieldDescriptor(type);
-  return getAddrOfLLVMVariable(entity, Alignment(4),
+  return getAddrOfLLVMVariable(entity,
                                definition,
-                               FieldDescriptorTy,
                                DebugTypeInfo());
 }
 
@@ -3216,9 +3199,8 @@
 getAddrOfReflectionAssociatedTypeDescriptor(const ProtocolConformance *c,
                                             ConstantInit definition) {
   auto entity = LinkEntity::forReflectionAssociatedTypeDescriptor(c);
-  return getAddrOfLLVMVariable(entity, Alignment(4),
+  return getAddrOfLLVMVariable(entity,
                                definition,
-                               FieldDescriptorTy,
                                DebugTypeInfo());
 }
 
@@ -3226,9 +3208,8 @@
 llvm::Constant *IRGenModule::getAddrOfPropertyDescriptor(AbstractStorageDecl *D,
                                                       ConstantInit definition) {
   auto entity = LinkEntity::forPropertyDescriptor(D);
-  return getAddrOfLLVMVariable(entity, Alignment(4),
+  return getAddrOfLLVMVariable(entity,
                                definition,
-                               TypeContextDescriptorTy,
                                DebugTypeInfo());
 }
 
@@ -3241,15 +3222,14 @@
   }
 
   auto entity = LinkEntity::forProtocolDescriptor(D);
-  return getAddrOfLLVMVariable(entity, getPointerAlignment(), definition,
-                               ProtocolDescriptorStructTy, DebugTypeInfo());
+  return getAddrOfLLVMVariable(entity, definition,
+                               DebugTypeInfo());
 }
 
 llvm::Constant *IRGenModule::getAddrOfProtocolRequirementsBaseDescriptor(
                                                          ProtocolDecl *proto) {
   auto entity = LinkEntity::forProtocolRequirementsBaseDescriptor(proto);
-  return getAddrOfLLVMVariable(entity, getPointerAlignment(), ConstantInit(),
-                               ProtocolRequirementStructTy,
+  return getAddrOfLLVMVariable(entity, ConstantInit(),
                                DebugTypeInfo());
 }
 
@@ -3263,8 +3243,7 @@
 llvm::Constant *IRGenModule::getAddrOfAssociatedTypeDescriptor(
                                                AssociatedTypeDecl *assocType) {
   auto entity = LinkEntity::forAssociatedTypeDescriptor(assocType);
-  return getAddrOfLLVMVariable(entity, getPointerAlignment(), ConstantInit(),
-                               ProtocolRequirementStructTy,
+  return getAddrOfLLVMVariable(entity, ConstantInit(),
                                DebugTypeInfo());
 }
 
@@ -3278,8 +3257,7 @@
 llvm::Constant *IRGenModule::getAddrOfAssociatedConformanceDescriptor(
                                           AssociatedConformance conformance) {
   auto entity = LinkEntity::forAssociatedConformanceDescriptor(conformance);
-  return getAddrOfLLVMVariable(entity, getPointerAlignment(), ConstantInit(),
-                               ProtocolRequirementStructTy, DebugTypeInfo());
+  return getAddrOfLLVMVariable(entity, ConstantInit(), DebugTypeInfo());
 }
 
 llvm::GlobalValue *IRGenModule::defineAssociatedConformanceDescriptor(
@@ -3293,8 +3271,7 @@
                                 const NormalProtocolConformance *conformance,
                                 ConstantInit definition) {
   auto entity = LinkEntity::forProtocolConformanceDescriptor(conformance);
-  return getAddrOfLLVMVariable(entity, getPointerAlignment(), definition,
-                               ProtocolConformanceDescriptorTy,
+  return getAddrOfLLVMVariable(entity, definition,
                                DebugTypeInfo());
 }
 
@@ -3348,16 +3325,16 @@
 IRGenModule::getAddrOfValueWitnessTable(CanType concreteType,
                                         ConstantInit definition) {
   LinkEntity entity = LinkEntity::forValueWitnessTable(concreteType);
-  return getAddrOfLLVMVariable(entity, getPointerAlignment(), definition,
-                               WitnessTableTy, DebugTypeInfo());
+  return getAddrOfLLVMVariable(entity, definition, DebugTypeInfo());
 }
 
 static Address getAddrOfSimpleVariable(IRGenModule &IGM,
-                            llvm::DenseMap<LinkEntity, llvm::Constant*> &cache,
-                                       LinkEntity entity,
-                                       llvm::Type *type,
-                                       Alignment alignment,
-                                       ForDefinition_t forDefinition) {
+                             llvm::DenseMap<LinkEntity, llvm::Constant*> &cache,
+                             LinkEntity entity,
+                             ForDefinition_t forDefinition) {
+  auto alignment = entity.getAlignment(IGM);
+  auto type = entity.getDefaultDeclarationType(IGM);
+  
   // Check whether it's already cached.
   llvm::Constant *&entry = cache[entity];
   if (entry) {
@@ -3385,15 +3362,13 @@
                                           ForDefinition_t forDefinition) {
   LinkEntity entity = LinkEntity::forFieldOffset(var);
   return getAddrOfSimpleVariable(*this, GlobalVars, entity,
-                                 SizeTy, getPointerAlignment(),
                                  forDefinition);
 }
 
 Address IRGenModule::getAddrOfEnumCase(EnumElementDecl *Case,
                                        ForDefinition_t forDefinition) {
   LinkEntity entity = LinkEntity::forEnumCase(Case);
-  auto addr = getAddrOfSimpleVariable(*this, GlobalVars, entity, Int32Ty,
-                                      getPointerAlignment(), forDefinition);
+  auto addr = getAddrOfSimpleVariable(*this, GlobalVars, entity, forDefinition);
 
   auto *global = cast<llvm::GlobalVariable>(addr.getAddress());
   global->setConstant(true);
@@ -3729,8 +3704,8 @@
   assert(!conformingType->hasArchetype());
   LinkEntity entity =
     LinkEntity::forProtocolWitnessTableLazyCacheVariable(conf, conformingType);
-  auto variable = getAddrOfLLVMVariable(entity, getPointerAlignment(),
-                                        forDefinition, WitnessTablePtrTy,
+  auto variable = getAddrOfLLVMVariable(entity,
+                                        forDefinition,
                                         DebugTypeInfo());
 
   // Zero-initialize if we're asking for a definition.
@@ -3751,8 +3726,7 @@
   IRGen.addLazyWitnessTable(conf);
 
   auto entity = LinkEntity::forDirectProtocolWitnessTable(conf);
-  return getAddrOfLLVMVariable(entity, getPointerAlignment(), definition,
-                               WitnessTableTy, DebugTypeInfo());
+  return getAddrOfLLVMVariable(entity, definition, DebugTypeInfo());
 }
 
 /// Look up the address of a witness table pattern.
@@ -3765,8 +3739,7 @@
   IRGen.addLazyWitnessTable(conf);
 
   auto entity = LinkEntity::forProtocolWitnessTablePattern(conf);
-  return getAddrOfLLVMVariable(entity, getPointerAlignment(), definition,
-                               WitnessTableTy, DebugTypeInfo());
+  return getAddrOfLLVMVariable(entity, definition, DebugTypeInfo());
 }
 
 llvm::Function *
diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp
index 028c140..de875cd 100644
--- a/lib/IRGen/GenMeta.cpp
+++ b/lib/IRGen/GenMeta.cpp
@@ -1552,19 +1552,16 @@
 
       // The class containing the base method.
       auto *baseClass = cast<ClassDecl>(baseRef.getDecl()->getDeclContext());
+      IGM.IRGen.noteUseOfTypeContextDescriptor(baseClass, DontRequireMetadata);
       auto baseClassEntity = LinkEntity::forNominalTypeDescriptor(baseClass);
       auto baseClassDescriptor =
-        IGM.getAddrOfLLVMVariableOrGOTEquivalent(
-          baseClassEntity, IGM.getPointerAlignment(),
-          IGM.Int8Ty);
+        IGM.getAddrOfLLVMVariableOrGOTEquivalent(baseClassEntity);
       descriptor.addRelativeAddress(baseClassDescriptor);
 
       // The base method.
       auto baseMethodEntity = LinkEntity::forMethodDescriptor(baseRef);
       auto baseMethodDescriptor =
-        IGM.getAddrOfLLVMVariableOrGOTEquivalent(
-          baseMethodEntity, Alignment(4),
-          IGM.MethodDescriptorStructTy);
+        IGM.getAddrOfLLVMVariableOrGOTEquivalent(baseMethodEntity);
       descriptor.addRelativeAddress(baseMethodDescriptor);
 
       // The implementation of the override.
@@ -1714,9 +1711,8 @@
     }
   }
   
-  return getAddrOfLLVMVariable(entity, Alignment(4),
+  return getAddrOfLLVMVariable(entity,
                                definition,
-                               TypeContextDescriptorTy,
                                DebugTypeInfo());
 }
 
diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp
index 8d329e7..4719410 100644
--- a/lib/IRGen/GenProto.cpp
+++ b/lib/IRGen/GenProto.cpp
@@ -2046,8 +2046,7 @@
       // Relative reference to the protocol descriptor.
       auto protocol = Conformance->getProtocol();
       auto descriptorRef = IGM.getAddrOfLLVMVariableOrGOTEquivalent(
-                    LinkEntity::forProtocolDescriptor(protocol),
-                    IGM.getPointerAlignment(), IGM.ProtocolDescriptorStructTy);
+                                   LinkEntity::forProtocolDescriptor(protocol));
       B.addRelativeAddress(descriptorRef);
     }
 
@@ -2143,8 +2142,7 @@
           auto assocType = entry.getAssociatedTypeWitness().Requirement;
           auto assocTypeDescriptor =
             IGM.getAddrOfLLVMVariableOrGOTEquivalent(
-              LinkEntity::forAssociatedTypeDescriptor(assocType),
-              Alignment(4), IGM.ProtocolRequirementStructTy);
+              LinkEntity::forAssociatedTypeDescriptor(assocType));
           B.addRelativeAddress(assocTypeDescriptor);
         } else if (entry.getKind() == SILWitnessTable::AssociatedTypeProtocol) {
           // Associated conformance descriptor.
@@ -2156,16 +2154,14 @@
                                   witness.Protocol);
           auto assocConformanceDescriptor =
             IGM.getAddrOfLLVMVariableOrGOTEquivalent(
-              LinkEntity::forAssociatedConformanceDescriptor(requirement),
-              Alignment(4), IGM.ProtocolRequirementStructTy);
+              LinkEntity::forAssociatedConformanceDescriptor(requirement));
           B.addRelativeAddress(assocConformanceDescriptor);
         } else if (entry.getKind() == SILWitnessTable::Method) {
           // Method descriptor.
           auto declRef = entry.getMethodWitness().Requirement;
           auto requirement =
             IGM.getAddrOfLLVMVariableOrGOTEquivalent(
-              LinkEntity::forMethodDescriptor(declRef),
-              Alignment(4), IGM.ProtocolRequirementStructTy);
+              LinkEntity::forMethodDescriptor(declRef));
           B.addRelativeAddress(requirement);
         } else {
           // Not part of the resilient witness table.
diff --git a/lib/IRGen/GenThunk.cpp b/lib/IRGen/GenThunk.cpp
index 9a8e547..e9f0872 100644
--- a/lib/IRGen/GenThunk.cpp
+++ b/lib/IRGen/GenThunk.cpp
@@ -129,8 +129,7 @@
   assert(declRef.getOverriddenWitnessTableEntry() == declRef &&
          "Overriding protocol requirements do not have method descriptors");
   LinkEntity entity = LinkEntity::forMethodDescriptor(declRef);
-  return getAddrOfLLVMVariable(entity, Alignment(4), forDefinition,
-                               MethodDescriptorStructTy, DebugTypeInfo());
+  return getAddrOfLLVMVariable(entity, forDefinition, DebugTypeInfo());
 }
 
 /// Fetch the method lookup function for a resilient class.
diff --git a/lib/IRGen/IRGenMangler.cpp b/lib/IRGen/IRGenMangler.cpp
index 7ece4ac..107498b 100644
--- a/lib/IRGen/IRGenMangler.cpp
+++ b/lib/IRGen/IRGenMangler.cpp
@@ -79,37 +79,70 @@
 }
 
 SymbolicMangling
-IRGenMangler::mangleTypeForReflection(IRGenModule &IGM,
-                                      Type Ty) {
+IRGenMangler::withSymbolicReferences(IRGenModule &IGM,
+                                  llvm::function_ref<void ()> body) {
   Mod = IGM.getSwiftModule();
   OptimizeProtocolNames = false;
 
-  llvm::SaveAndRestore<std::function<bool (const DeclContext *)>>
-    SymbolicReferencesForLocalTypes(CanSymbolicReference);
-  
-  if (IGM.CurSourceFile
-      && !isa<ClangModuleUnit>(IGM.CurSourceFile)
-      && !IGM.getOptions().IntegratedREPL) {
-    CanSymbolicReference = [&](const DeclContext *dc) -> bool {
-      // Symbolically reference types that are defined in the same file unit
-      // as we're referencing from.
-      //
-      // We could eventually improve this to reference any type that ends
-      // up with its nominal type descriptor in the same linked binary as us,
-      // but IRGen doesn't know that with much certainty currently.
-      return dc->getModuleScopeContext() == IGM.CurSourceFile
-        && isa<NominalTypeDecl>(dc)
-        && !isa<ProtocolDecl>(dc);
-    };
-  }
-  
+  llvm::SaveAndRestore<bool>
+    AllowSymbolicReferencesLocally(AllowSymbolicReferences);
+  llvm::SaveAndRestore<std::function<bool (SymbolicReferent)>>
+    CanSymbolicReferenceLocally(CanSymbolicReference);
+
+  AllowSymbolicReferences = true;
+  CanSymbolicReference = [&IGM](SymbolicReferent s) -> bool {
+    if (auto type = s.dyn_cast<const NominalTypeDecl *>()) {
+      // FIXME: Sometimes we fail to emit metadata for Clang imported types
+      // even after noting use of their type descriptor or metadata. Work
+      // around by not symbolic-referencing imported types for now.
+      if (type->hasClangNode())
+        return false;
+      
+      // TODO: We ought to be able to use indirect symbolic references even
+      // when the referent may be in another file, once the on-disk
+      // ObjectMemoryReader can handle them.
+      if (!IGM.CurSourceFile || IGM.CurSourceFile != type->getParentSourceFile())
+        return false;
+      
+      // @objc protocols don't have descriptors.
+      if (auto proto = dyn_cast<ProtocolDecl>(type))
+        if (proto->isObjC())
+          return false;
+      
+      return true;
+    } else {
+      llvm_unreachable("symbolic referent not handled");
+    }
+  };
   SymbolicReferences.clear();
   
-  appendType(Ty);
+  body();
   
   return {finalize(), std::move(SymbolicReferences)};
 }
 
+SymbolicMangling
+IRGenMangler::mangleTypeForReflection(IRGenModule &IGM,
+                                      Type Ty) {
+  return withSymbolicReferences(IGM, [&]{
+    appendType(Ty);
+  });
+}
+
+SymbolicMangling
+IRGenMangler::mangleProtocolConformanceForReflection(IRGenModule &IGM,
+                                  Type ty, ProtocolConformanceRef conformance) {
+  return withSymbolicReferences(IGM, [&]{
+    if (conformance.isConcrete()) {
+      appendProtocolConformance(conformance.getConcrete());
+    } else {
+      // Use a special mangling for abstract conformances.
+      appendType(ty);
+      appendProtocolName(conformance.getAbstract());
+    }
+  });
+}
+
 std::string IRGenMangler::mangleTypeForLLVMTypeName(CanType Ty) {
   // To make LLVM IR more readable we always add a 'T' prefix so that type names
   // don't start with a digit and don't need to be quoted.
@@ -183,12 +216,19 @@
 
   for (auto &symbol : mangling.SymbolicReferences) {
     // Fill in the placeholder space with something printable.
-    auto dc = symbol.first;
+    auto referent = symbol.first;
     auto offset = symbol.second;
-    Storage[prefixLen + offset] = Storage[prefixLen + offset+1] =
-      Storage[prefixLen + offset+2] = Storage[prefixLen + offset+3] = '_';
+    Storage[prefixLen + offset]
+      = Storage[prefixLen + offset+1]
+      = Storage[prefixLen + offset+2]
+      = Storage[prefixLen + offset+3]
+      = Storage[prefixLen + offset+4]
+      = '_';
     Buffer << ' ';
-    appendContext(dc);
+    if (auto ty = referent.dyn_cast<const NominalTypeDecl*>())
+      appendContext(ty);
+    else
+      llvm_unreachable("unhandled referent");
   }
   
   return finalize();
diff --git a/lib/IRGen/IRGenMangler.h b/lib/IRGen/IRGenMangler.h
index 3c1eb22..11551a9 100644
--- a/lib/IRGen/IRGenMangler.h
+++ b/lib/IRGen/IRGenMangler.h
@@ -30,7 +30,8 @@
 /// A mangling string that includes embedded symbolic references.
 struct SymbolicMangling {
   std::string String;
-  std::vector<std::pair<const DeclContext *, unsigned>> SymbolicReferences;
+  std::vector<std::pair<Mangle::ASTMangler::SymbolicReferent, unsigned>>
+    SymbolicReferences;
 };
 
 /// The mangler for all kind of symbols produced in IRGen.
@@ -412,6 +413,10 @@
 
   SymbolicMangling mangleTypeForReflection(IRGenModule &IGM,
                                            Type Ty);
+  
+  SymbolicMangling mangleProtocolConformanceForReflection(IRGenModule &IGM,
+                                            Type Ty,
+                                            ProtocolConformanceRef conformance);
 
   std::string mangleTypeForLLVMTypeName(CanType Ty);
 
@@ -421,6 +426,9 @@
                                               const SymbolicMangling &mangling,
                                               MangledTypeRefRole role);
 protected:
+  SymbolicMangling
+  withSymbolicReferences(IRGenModule &IGM,
+                         llvm::function_ref<void ()> body);
 
   std::string mangleTypeSymbol(Type type, const char *Op) {
     beginMangling();
diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h
index 84db7b8..daba542 100644
--- a/lib/IRGen/IRGenModule.h
+++ b/lib/IRGen/IRGenModule.h
@@ -1321,7 +1321,8 @@
                                                ForDefinition_t forDefinition);
   llvm::Constant *getAddrOfWitnessTable(const NormalProtocolConformance *C,
                                       ConstantInit definition = ConstantInit());
-  llvm::Constant *getAddrOfWitnessTablePattern(const NormalProtocolConformance *C,
+  llvm::Constant *getAddrOfWitnessTablePattern(
+                                      const NormalProtocolConformance *C,
                                       ConstantInit definition = ConstantInit());
 
   llvm::Function *
@@ -1341,8 +1342,7 @@
   GenericEnvironment *getGenericEnvironment();
 
   ConstantReference
-  getAddrOfLLVMVariableOrGOTEquivalent(LinkEntity entity, Alignment alignment,
-       llvm::Type *defaultType,
+  getAddrOfLLVMVariableOrGOTEquivalent(LinkEntity entity,
        ConstantReference::Directness forceIndirect = ConstantReference::Direct);
 
   llvm::Constant *
@@ -1376,21 +1376,17 @@
                                    llvm::function_ref<void()> emit);
   
   llvm::Constant *getAddrOfLLVMVariable(LinkEntity entity,
-                                        Alignment alignment,
                                         ConstantInit definition,
-                                        llvm::Type *defaultType,
-                                        DebugTypeInfo debugType);
+                                        DebugTypeInfo debugType,
+                                        llvm::Type *overrideDeclType = nullptr);
   llvm::Constant *getAddrOfLLVMVariable(LinkEntity entity,
-                                        Alignment alignment,
                                         ForDefinition_t forDefinition,
-                                        llvm::Type *defaultType,
                                         DebugTypeInfo debugType);
   ConstantReference getAddrOfLLVMVariable(LinkEntity entity,
-                                        Alignment alignment,
                                         ConstantInit definition,
-                                        llvm::Type *defaultType,
                                         DebugTypeInfo debugType,
-                                        SymbolReferenceKind refKind);
+                                        SymbolReferenceKind refKind,
+                                        llvm::Type *overrideDeclType = nullptr);
 
   void emitLazyPrivateDefinitions();
   void addRuntimeResolvableType(NominalTypeDecl *nominal);
diff --git a/lib/IRGen/Linking.cpp b/lib/IRGen/Linking.cpp
index f8f1a21..70dd96e 100644
--- a/lib/IRGen/Linking.cpp
+++ b/lib/IRGen/Linking.cpp
@@ -639,3 +639,238 @@
   }
   llvm_unreachable("bad link entity kind");
 }
+
+llvm::Type *LinkEntity::getDefaultDeclarationType(IRGenModule &IGM) const {
+  switch (getKind()) {
+  case Kind::ModuleDescriptor:
+  case Kind::ExtensionDescriptor:
+  case Kind::AnonymousDescriptor:
+  case Kind::NominalTypeDescriptor:
+  case Kind::PropertyDescriptor:
+    return IGM.TypeContextDescriptorTy;
+  case Kind::ProtocolDescriptor:
+    return IGM.ProtocolDescriptorStructTy;
+  case Kind::AssociatedTypeDescriptor:
+  case Kind::AssociatedConformanceDescriptor:
+  case Kind::ProtocolRequirementsBaseDescriptor:
+    return IGM.ProtocolRequirementStructTy;
+  case Kind::ProtocolConformanceDescriptor:
+    return IGM.ProtocolConformanceDescriptorTy;
+  case Kind::ObjCClassRef:
+    return IGM.ObjCClassPtrTy;
+  case Kind::ObjCClass:
+  case Kind::ObjCMetaclass:
+  case Kind::SwiftMetaclassStub:
+    return IGM.ObjCClassStructTy;
+  case Kind::TypeMetadataLazyCacheVariable:
+    return IGM.TypeMetadataPtrTy;
+  case Kind::TypeMetadataSingletonInitializationCache:
+    // TODO: put a cache variable on IGM
+    return llvm::StructType::get(IGM.getLLVMContext(),
+                                 {IGM.TypeMetadataPtrTy, IGM.Int8PtrTy});
+  case Kind::TypeMetadata:
+    switch (getMetadataAddress()) {
+    case TypeMetadataAddress::FullMetadata:
+      if (getType().getClassOrBoundGenericClass())
+        return IGM.FullHeapMetadataStructTy;
+      else
+        return IGM.FullTypeMetadataStructTy;
+    case TypeMetadataAddress::AddressPoint:
+      return IGM.TypeMetadataStructTy;
+    }
+    
+  case Kind::TypeMetadataPattern:
+    // TODO: Use a real type?
+    return IGM.Int8Ty;
+    
+  case Kind::ClassMetadataBaseOffset:
+    // TODO: put a cache variable on IGM
+    return llvm::StructType::get(IGM.getLLVMContext(), {
+      IGM.SizeTy,  // Immediate members offset
+      IGM.Int32Ty, // Negative size in words
+      IGM.Int32Ty  // Positive size in words
+    });
+    
+  case Kind::TypeMetadataInstantiationCache:
+    // TODO: put a cache variable on IGM
+    return llvm::ArrayType::get(IGM.Int8PtrTy,
+                                NumGenericMetadataPrivateDataWords);
+  case Kind::ReflectionBuiltinDescriptor:
+  case Kind::ReflectionFieldDescriptor:
+  case Kind::ReflectionAssociatedTypeDescriptor:
+    return IGM.FieldDescriptorTy;
+  case Kind::ValueWitnessTable:
+  case Kind::DirectProtocolWitnessTable:
+  case Kind::ProtocolWitnessTablePattern:
+    return IGM.WitnessTableTy;
+  case Kind::FieldOffset:
+    return IGM.SizeTy;
+  case Kind::EnumCase:
+    return IGM.Int32Ty;
+  case Kind::ProtocolWitnessTableLazyCacheVariable:
+    return IGM.WitnessTablePtrTy;
+  case Kind::SILFunction:
+    return IGM.FunctionPtrTy->getPointerTo();
+  case Kind::MethodDescriptor:
+  case Kind::MethodDescriptorInitializer:
+  case Kind::MethodDescriptorAllocator:
+    return IGM.MethodDescriptorStructTy;
+    
+  default:
+    llvm_unreachable("declaration LLVM type not specified");
+  }
+}
+
+Alignment LinkEntity::getAlignment(IRGenModule &IGM) const {
+  switch (getKind()) {
+  case Kind::ModuleDescriptor:
+  case Kind::ExtensionDescriptor:
+  case Kind::AnonymousDescriptor:
+  case Kind::NominalTypeDescriptor:
+  case Kind::ProtocolDescriptor:
+  case Kind::AssociatedTypeDescriptor:
+  case Kind::AssociatedConformanceDescriptor:
+  case Kind::ProtocolConformanceDescriptor:
+  case Kind::ProtocolRequirementsBaseDescriptor:
+  case Kind::ReflectionBuiltinDescriptor:
+  case Kind::ReflectionFieldDescriptor:
+  case Kind::ReflectionAssociatedTypeDescriptor:
+  case Kind::PropertyDescriptor:
+  case Kind::EnumCase:
+  case Kind::MethodDescriptor:
+  case Kind::MethodDescriptorInitializer:
+  case Kind::MethodDescriptorAllocator:
+    return Alignment(4);
+  case Kind::ObjCClassRef:
+  case Kind::ObjCClass:
+  case Kind::TypeMetadataLazyCacheVariable:
+  case Kind::TypeMetadataSingletonInitializationCache:
+  case Kind::TypeMetadata:
+  case Kind::TypeMetadataPattern:
+  case Kind::ClassMetadataBaseOffset:
+  case Kind::TypeMetadataInstantiationCache:
+  case Kind::ValueWitnessTable:
+  case Kind::FieldOffset:
+  case Kind::ProtocolWitnessTableLazyCacheVariable:
+  case Kind::DirectProtocolWitnessTable:
+  case Kind::ProtocolWitnessTablePattern:
+  case Kind::ObjCMetaclass:
+  case Kind::SwiftMetaclassStub:
+    return IGM.getPointerAlignment();
+  case Kind::SILFunction:
+    return Alignment(1);
+  default:
+    llvm_unreachable("alignment not specified");
+  }
+}
+
+const SourceFile *LinkEntity::getSourceFileForEmission() const {
+  const SourceFile *sf;
+  
+  // Shared-linkage entities don't get emitted with any particular file.
+  if (hasSharedVisibility(getLinkage(NotForDefinition)))
+    return nullptr;
+  
+  auto getSourceFileForDeclContext =
+  [](const DeclContext *dc) -> const SourceFile * {
+    if (!dc)
+      return nullptr;
+    return dc->getParentSourceFile();
+  };
+  
+  switch (getKind()) {
+  case Kind::DispatchThunk:
+  case Kind::DispatchThunkInitializer:
+  case Kind::DispatchThunkAllocator:
+  case Kind::MethodDescriptor:
+  case Kind::MethodDescriptorInitializer:
+  case Kind::MethodDescriptorAllocator:
+  case Kind::MethodLookupFunction:
+  case Kind::EnumCase:
+  case Kind::FieldOffset:
+  case Kind::ObjCClass:
+  case Kind::ObjCMetaclass:
+  case Kind::SwiftMetaclassStub:
+  case Kind::ClassMetadataBaseOffset:
+  case Kind::PropertyDescriptor:
+  case Kind::NominalTypeDescriptor:
+  case Kind::TypeMetadataPattern:
+  case Kind::TypeMetadataInstantiationCache:
+  case Kind::TypeMetadataInstantiationFunction:
+  case Kind::TypeMetadataSingletonInitializationCache:
+  case Kind::TypeMetadataCompletionFunction:
+  case Kind::ProtocolDescriptor:
+  case Kind::ProtocolRequirementsBaseDescriptor:
+  case Kind::AssociatedTypeDescriptor:
+  case Kind::AssociatedConformanceDescriptor:
+  case Kind::DefaultAssociatedConformanceAccessor:
+    sf = getSourceFileForDeclContext(getDecl()->getDeclContext());
+    if (!sf)
+      return nullptr;
+    break;
+  
+  case Kind::SILFunction:
+    sf = getSourceFileForDeclContext(getSILFunction()->getDeclContext());
+    if (!sf)
+      return nullptr;
+    break;
+  
+  case Kind::SILGlobalVariable:
+    if (auto decl = getSILGlobalVariable()->getDecl()) {
+      sf = getSourceFileForDeclContext(decl->getDeclContext());
+      if (!sf)
+        return nullptr;
+    } else {
+      return nullptr;
+    }
+    break;
+    
+  case Kind::DirectProtocolWitnessTable:
+  case Kind::ProtocolWitnessTablePattern:
+  case Kind::ProtocolWitnessTableAccessFunction:
+  case Kind::GenericProtocolWitnessTableInstantiationFunction:
+  case Kind::AssociatedTypeWitnessTableAccessFunction:
+  case Kind::ReflectionAssociatedTypeDescriptor:
+  case Kind::ProtocolConformanceDescriptor:
+  case Kind::ProtocolWitnessTableLazyCacheVariable:
+  case Kind::ProtocolWitnessTableLazyAccessFunction:
+    sf = getSourceFileForDeclContext(
+      getProtocolConformance()->getRootNormalConformance()->getDeclContext());
+    if (!sf)
+      return nullptr;
+    break;
+    
+  case Kind::TypeMetadata: {
+    auto ty = getType();
+    // Only fully concrete nominal type metadata gets emitted eagerly.
+    auto nom = ty->getAnyNominal();
+    if (!nom || nom->isGenericContext())
+      return nullptr;
+    
+    sf = getSourceFileForDeclContext(nom);
+    if (!sf)
+      return nullptr;
+    break;
+  }
+
+  // Always shared linkage
+  case Kind::ModuleDescriptor:
+  case Kind::ExtensionDescriptor:
+  case Kind::AnonymousDescriptor:
+  case Kind::ObjCClassRef:
+  case Kind::TypeMetadataAccessFunction:
+  case Kind::TypeMetadataLazyCacheVariable:
+  case Kind::ForeignTypeMetadataCandidate:
+    return nullptr;
+
+  // TODO
+  case Kind::CoroutineContinuationPrototype:
+  case Kind::ReflectionFieldDescriptor:
+  case Kind::ReflectionBuiltinDescriptor:
+  case Kind::ValueWitness:
+  case Kind::ValueWitnessTable:
+    return nullptr;
+  }
+  
+  return sf;
+}
diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp
index da05192..61d8397 100644
--- a/lib/IRGen/MetadataRequest.cpp
+++ b/lib/IRGen/MetadataRequest.cpp
@@ -34,6 +34,7 @@
 #include "swift/AST/IRGenOptions.h"
 #include "swift/AST/SubstitutionMap.h"
 #include "swift/ClangImporter/ClangModule.h"
+#include "swift/IRGen/Linking.h"
 #include "swift/SIL/FormalLinkage.h"
 #include "swift/SIL/TypeLowering.h"
 
@@ -261,22 +262,40 @@
       // Emit the preceding literal chunk.
       auto literalChunk = StringRef(mangling.String.data() + pos,
                                     symbolic.second - pos);
-      assert(literalChunk.back() == '\1' && "should be prefixed with \\1");
       auto literal = llvm::ConstantDataArray::getString(getLLVMContext(),
                                                         literalChunk,
                                                         /*null*/ false);
       S.add(literal);
     }
     
-    // The symbolic reference is to the type context descriptor of the
-    // referenced type.
-    // We currently only allow symbolic references to nominal type contexts.
-    auto nominal = cast<NominalTypeDecl>(symbolic.first);
-    S.addRelativeAddress(
-         getAddrOfTypeContextDescriptor(const_cast<NominalTypeDecl*>(nominal),
-                                        DontRequireMetadata));
+    ConstantReference ref;
+    unsigned char baseKind;
+    if (auto ctype = symbolic.first.dyn_cast<const NominalTypeDecl*>()) {
+      auto type = const_cast<NominalTypeDecl*>(ctype);
+      if (auto proto = dyn_cast<ProtocolDecl>(type)) {
+        // The symbolic reference is to the protocol descriptor of the
+        // referenced protocol.
+        ref = getAddrOfLLVMVariableOrGOTEquivalent(
+          LinkEntity::forProtocolDescriptor(proto));
+      } else {
+        // The symbolic reference is to the type context descriptor of the
+        // referenced type.
+        IRGen.noteUseOfTypeContextDescriptor(type, DontRequireMetadata);
+        ref = getAddrOfLLVMVariableOrGOTEquivalent(
+          LinkEntity::forNominalTypeDescriptor(type));
+      }
+      // \1 - direct reference, \2 - indirect reference
+      baseKind = 1;
+    } else {
+      llvm_unreachable("unhandled symbolic referent");
+    }
     
-    pos = symbolic.second + 4;
+    // add kind byte. indirect kinds are the direct kind + 1
+    unsigned char kind = ref.isIndirect() ? baseKind + 1 : baseKind;
+    S.add(llvm::ConstantInt::get(Int8Ty, kind));
+    // add relative reference
+    S.addRelativeAddress(ref.getValue());
+    pos = symbolic.second + 5;
   }
   
   // Add the last literal bit, if any.
diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp
index adc35fe..cdb6641 100644
--- a/stdlib/public/runtime/MetadataLookup.cpp
+++ b/stdlib/public/runtime/MetadataLookup.cpp
@@ -54,17 +54,88 @@
   // Resolve symbolic references to type contexts into the absolute address of
   // the type context descriptor, so that if we see a symbolic reference in the
   // mangled name we can immediately find the associated metadata.
-  dem.setSymbolicReferenceResolver([&](int32_t offset,
-                                       const void *base) -> NodePointer {
-    auto absolute_addr = (uintptr_t)detail::applyRelativeOffset(base, offset);
-    auto reference = dem.createNode(Node::Kind::SymbolicReference, absolute_addr);
-    auto type = dem.createNode(Node::Kind::Type);
-    type->addChild(reference, dem);
-    return type;
-  });
+  dem.setSymbolicReferenceResolver(ResolveAsSymbolicReference(dem));
   return dem;
 }
 
+NodePointer
+ResolveAsSymbolicReference::operator()(SymbolicReferenceKind kind,
+                                       Directness isIndirect,
+                                       int32_t offset,
+                                       const void *base) {
+  // Resolve the absolute pointer to the entity being referenced.
+  auto ptr = detail::applyRelativeOffset(base, offset);
+  if (isIndirect == Directness::Indirect) {
+    ptr = *(const uintptr_t *)ptr;
+  }
+
+  // Figure out this symbolic reference's grammatical role.
+  Node::Kind nodeKind;
+  bool isType;
+  switch (kind) {
+  case Demangle::SymbolicReferenceKind::Context: {
+    auto descriptor = (const ContextDescriptor *)ptr;
+    switch (descriptor->getKind()) {
+    case ContextDescriptorKind::Protocol:
+      nodeKind = Node::Kind::ProtocolSymbolicReference;
+      isType = false;
+      break;
+      
+    default:
+      if (auto typeContext = dyn_cast<TypeContextDescriptor>(descriptor)) {
+        nodeKind = Node::Kind::TypeSymbolicReference;
+        isType = true;
+        break;
+      }
+      
+      // References to other kinds of context aren't yet implemented.
+      return nullptr;
+    }
+    break;
+  }
+  }
+  
+  auto node = Dem.createNode(nodeKind, ptr);
+  if (isType) {
+    auto typeNode = Dem.createNode(Node::Kind::Type);
+    typeNode->addChild(node, Dem);
+    node = typeNode;
+  }
+  return node;
+}
+
+static NodePointer
+_buildDemanglingForSymbolicReference(SymbolicReferenceKind kind,
+                                     const void *resolvedReference,
+                                     Demangler &Dem) {
+  switch (kind) {
+  case SymbolicReferenceKind::Context:
+    return _buildDemanglingForContext(
+      (const ContextDescriptor *)resolvedReference, {}, Dem);
+  }
+  
+  swift_runtime_unreachable("invalid symbolic reference kind");
+}
+  
+NodePointer
+ResolveToDemanglingForContext::operator()(SymbolicReferenceKind kind,
+                                          Directness isIndirect,
+                                          int32_t offset,
+                                          const void *base) {
+  auto ptr = detail::applyRelativeOffset(base, offset);
+  if (isIndirect == Directness::Indirect) {
+    ptr = *(const uintptr_t *)ptr;
+  }
+  
+  return _buildDemanglingForSymbolicReference(kind, (const void *)ptr, Dem);
+}
+
+NodePointer
+ExpandResolvedSymbolicReferences::operator()(SymbolicReferenceKind kind,
+                                             const void *ptr) {
+  return _buildDemanglingForSymbolicReference(kind, (const void *)ptr, Dem);
+}
+
 #pragma mark Nominal type descriptor cache
 // Type Metadata Cache.
 
@@ -310,10 +381,13 @@
       node = node->getChild(0);
     
     // We can directly match symbolic references to the current context.
-    if (node && node->getKind() == Demangle::Node::Kind::SymbolicReference) {
-      if (equalContexts(context, reinterpret_cast<const ContextDescriptor *>(
-                                     node->getIndex()))) {
-        return true;
+    if (node) {
+      if (node->getKind() == Demangle::Node::Kind::TypeSymbolicReference
+         || node->getKind() == Demangle::Node::Kind::ProtocolSymbolicReference){
+        if (equalContexts(context,
+               reinterpret_cast<const ContextDescriptor *>(node->getIndex()))) {
+          return true;
+        }
       }
     }
 
@@ -518,17 +592,12 @@
   NodePointer symbolicNode = node;
   if (symbolicNode->getKind() == Node::Kind::Type)
     symbolicNode = symbolicNode->getChild(0);
-  if (symbolicNode->getKind() == Node::Kind::SymbolicReference)
+  if (symbolicNode->getKind() == Node::Kind::TypeSymbolicReference)
     return cast<TypeContextDescriptor>(
       (const ContextDescriptor *)symbolicNode->getIndex());
 
   auto mangledName =
-    Demangle::mangleNode(node,
-                         [&](const void *context) -> NodePointer {
-                           return _buildDemanglingForContext(
-                               (const ContextDescriptor *) context,
-                               {}, Dem);
-                         });
+    Demangle::mangleNode(node, ExpandResolvedSymbolicReferences(Dem));
 
   // Look for an existing entry.
   // Find the bucket for the metadata entry.
@@ -653,17 +722,12 @@
   NodePointer symbolicNode = node;
   if (symbolicNode->getKind() == Node::Kind::Type)
     symbolicNode = symbolicNode->getChild(0);
-  if (symbolicNode->getKind() == Node::Kind::SymbolicReference)
+  if (symbolicNode->getKind() == Node::Kind::ProtocolSymbolicReference)
     return cast<ProtocolDescriptor>(
       (const ContextDescriptor *)symbolicNode->getIndex());
 
   mangledName =
-    Demangle::mangleNode(node,
-                         [&](const void *context) -> NodePointer {
-                           return _buildDemanglingForContext(
-                               (const ContextDescriptor *) context,
-                               {}, Dem);
-                         });
+    Demangle::mangleNode(node, ExpandResolvedSymbolicReferences(Dem));
 
   // Look for an existing entry.
   // Find the bucket for the metadata entry.
@@ -1155,13 +1219,23 @@
 
   // Check whether this is the convenience syntax "ModuleName.ClassName".
   auto getDotPosForConvenienceSyntax = [&]() -> size_t {
-    size_t dotPos = typeName.find('.');
-    if (dotPos == llvm::StringRef::npos)
-      return llvm::StringRef::npos;
-    if (typeName.find('.', dotPos + 1) != llvm::StringRef::npos)
-      return llvm::StringRef::npos;
-    if (typeName.find('\1') != llvm::StringRef::npos)
-      return llvm::StringRef::npos;
+    size_t dotPos = llvm::StringRef::npos;
+    for (unsigned i = 0; i < typeName.size(); ++i) {
+      // Should only contain one dot.
+      if (typeName[i] == '.') {
+        if (dotPos == llvm::StringRef::npos) {
+          dotPos = i;
+          continue;
+        } else {
+          return llvm::StringRef::npos;
+        }
+      }
+      
+      // Should not contain symbolic references.
+      if ((unsigned char)typeName[i] <= '\x1F') {
+        return llvm::StringRef::npos;
+      }
+    }
     return dotPos;
   };
 
diff --git a/stdlib/public/runtime/Private.h b/stdlib/public/runtime/Private.h
index d04866f..f1b6961 100644
--- a/stdlib/public/runtime/Private.h
+++ b/stdlib/public/runtime/Private.h
@@ -404,12 +404,36 @@
     explicit ResolveToDemanglingForContext(Demangle::Demangler &Dem)
       : Dem(Dem) {}
     
-    Demangle::NodePointer operator()(int32_t offset, const void *base) {
-      auto descriptor =
-        (const ContextDescriptor *)detail::applyRelativeOffset(base, offset);
-      
-      return _buildDemanglingForContext(descriptor, {}, Dem);
-    }
+    Demangle::NodePointer operator()(Demangle::SymbolicReferenceKind kind,
+                                     Demangle::Directness isIndirect,
+                                     int32_t offset,
+                                     const void *base);
+  };
+
+  /// Symbolic reference resolver that resolves the absolute addresses of
+  /// symbolic references but leaves them as references.
+  class ResolveAsSymbolicReference {
+    Demangle::Demangler &Dem;
+  public:
+    explicit ResolveAsSymbolicReference(Demangle::Demangler &Dem)
+      : Dem(Dem) {}
+    
+    Demangle::NodePointer operator()(Demangle::SymbolicReferenceKind kind,
+                                     Demangle::Directness isIndirect,
+                                     int32_t offset,
+                                     const void *base);
+  };
+  
+  /// Demangler resolver that turns resolved symbolic references into their
+  /// demangling trees.
+  class ExpandResolvedSymbolicReferences {
+    Demangle::Demangler &Dem;
+  public:
+    explicit ExpandResolvedSymbolicReferences(Demangle::Demangler &Dem)
+      : Dem(Dem) {}
+    
+    Demangle::NodePointer operator()(Demangle::SymbolicReferenceKind kind,
+                                     const void *resolvedReference);
   };
 
   /// Is the given type imported from a C tag type?
diff --git a/test/IRGen/class_metadata.swift b/test/IRGen/class_metadata.swift
index abcc61d..d79b78e 100644
--- a/test/IRGen/class_metadata.swift
+++ b/test/IRGen/class_metadata.swift
@@ -51,7 +51,7 @@
 //   Metadata access function.
 // CHECK-SAME: i32 {{.*}} @"$s14class_metadata1BCMa"
 //   Superclass type.
-// CHECK-SAME: @"symbolic \01____ 14class_metadata1AC"
+// CHECK-SAME: @"symbolic _____ 14class_metadata1AC"
 //   Negative size in words.
 // CHECK-SAME: i32 2,
 //   Positive size in words.
@@ -89,7 +89,7 @@
 //   Metadata access function.
 // CHECK-SAME: i32 {{.*}} @"$s14class_metadata1CCMa"
 //   Superclass type.
-// CHECK-SAME: @"symbolic \01____ 14class_metadata1BC"
+// CHECK-SAME: @"symbolic _____ 14class_metadata1BC"
 //   Negative size in words.
 // CHECK-SAME: i32 2,
 //   Positive size in words.
@@ -150,7 +150,7 @@
 //   Metadata access function.
 // CHECK-SAME: i32 {{.*}} @"$s14class_metadata1DCMa"
 //   Superclass type.
-// CHECK-SAME: @"symbolic \01____ 14class_metadata1EC"
+// CHECK-SAME: @"symbolic _____ 14class_metadata1EC"
 //   Negative size in words.
 // CHECK-SAME: i32 2,
 //   Positive size in words.
@@ -167,14 +167,14 @@
 // CHECK-SAME: i32 1,
 // CHECK-SAME: %swift.method_override_descriptor {
 //   Override table entry #1: base class.
-// CHECK-SAME: @"got.$s14class_metadata1ECMn.1"
+// CHECK-SAME: @"$s14class_metadata1ECMn"
 //   Override table entry #1: base method.
-// CHECK-SAME: @"got.$s14class_metadata1ECACycfCTq"
+// CHECK-SAME: @"$s14class_metadata1ECMn"
 //   Override table entry #1: invocation function.
 // CHECK-SAME: @"$s14class_metadata1DCACycfC"
 // CHECK-SAME: }>, section
 class E {}
 
 // CHECK-LABEL: @"$s14class_metadata1FCMn" =
-// CHECK-SAME: @"symbolic \01____yq_G 14class_metadata1CC"
+// CHECK-SAME: @"symbolic _____yq_G 14class_metadata1CC"
 class F<T, U> : C<U> { }
diff --git a/test/IRGen/protocol_resilience_descriptors.swift b/test/IRGen/protocol_resilience_descriptors.swift
index 9e6d766..2af58e7 100644
--- a/test/IRGen/protocol_resilience_descriptors.swift
+++ b/test/IRGen/protocol_resilience_descriptors.swift
@@ -23,7 +23,7 @@
 
 // Associated type default + flags
 // CHECK-DEFINITION-SAME: [[INT]] add
-// CHECK-DEFINITION-SAME: @"default assoc type \01____y2T118resilient_protocol29ProtocolWithAssocTypeDefaultsPQzG 18resilient_protocol7WrapperV"
+// CHECK-DEFINITION-SAME: @"default assoc type _____y2T118resilient_protocol29ProtocolWithAssocTypeDefaultsPQzG 18resilient_protocol7WrapperV"
 // CHECK-DEFINITION-SAME: [[INT]] 1
 
 // Protocol requirements base descriptor
diff --git a/test/Reflection/typeref_decoding.swift b/test/Reflection/typeref_decoding.swift
index 6e8c0b8..401504a 100644
--- a/test/Reflection/typeref_decoding.swift
+++ b/test/Reflection/typeref_decoding.swift
@@ -652,14 +652,14 @@
 // CHECK: TypesToReflect.ClassBoundP
 // CHECK: --------------------------
 
-// CHECK: TypesToReflect.(FileprivateProtocol in _{{[0-9A-F]+}})
+// CHECK: TypesToReflect.(FileprivateProtocol in _{{[0-9a-fA-F]+}})
 // CHECK: -------------------------------------------------------------------------
 
 // CHECK: TypesToReflect.HasFileprivateProtocol
 // CHECK: -------------------------------------
-// CHECK: x: TypesToReflect.(FileprivateProtocol in _{{[0-9A-F]+}})
+// CHECK: x: TypesToReflect.(FileprivateProtocol in ${{[0-9a-fA-F]+}})
 // CHECK: (protocol_composition
-// CHECK-NEXT: (protocol TypesToReflect.(FileprivateProtocol in _{{[0-9A-F]+}})))
+// CHECK-NEXT: (protocol TypesToReflect.(FileprivateProtocol in ${{[0-9a-fA-F]+}})))
 
 // CHECK: ASSOCIATED TYPES:
 // CHECK: =================
diff --git a/test/Reflection/typeref_decoding_asan.swift b/test/Reflection/typeref_decoding_asan.swift
index 9a40e21..573b601 100644
--- a/test/Reflection/typeref_decoding_asan.swift
+++ b/test/Reflection/typeref_decoding_asan.swift
@@ -657,9 +657,9 @@
 
 // CHECK: TypesToReflect.HasFileprivateProtocol
 // CHECK: -------------------------------------
-// CHECK: x: TypesToReflect.(FileprivateProtocol in _{{[0-9A-F]+}})
+// CHECK: x: TypesToReflect.(FileprivateProtocol in ${{[0-9a-fA-F]+}})
 // CHECK: (protocol_composition
-// CHECK-NEXT: (protocol TypesToReflect.(FileprivateProtocol in _{{[0-9A-F]+}})))
+// CHECK-NEXT: (protocol TypesToReflect.(FileprivateProtocol in ${{[0-9a-fA-F]+}})))
 
 // CHECK: ASSOCIATED TYPES:
 // CHECK: =================