//===--- Demangler.cpp - String to Node-Tree Demangling -------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
//  This file implements new Swift de-mangler.
//
//===----------------------------------------------------------------------===//

#include "swift/Demangling/Demangler.h"
#include "swift/Demangling/ManglingUtils.h"
#include "swift/Demangling/ManglingMacros.h"
#include "swift/Demangling/Punycode.h"
#include "swift/Strings.h"

using namespace swift;
using namespace Mangle;
using swift::Demangle::FunctionSigSpecializationParamKind;

//////////////////////////////////
// Private utility functions    //
//////////////////////////////////

namespace {

static bool isDeclName(Node::Kind kind) {
  switch (kind) {
    case Node::Kind::Identifier:
    case Node::Kind::LocalDeclName:
    case Node::Kind::PrivateDeclName:
    case Node::Kind::RelatedEntityDeclName:
    case Node::Kind::PrefixOperator:
    case Node::Kind::PostfixOperator:
    case Node::Kind::InfixOperator:
    case Node::Kind::TypeSymbolicReference:
    case Node::Kind::ProtocolSymbolicReference:
      return true;
    default:
      return false;
  }
}

static bool isAnyGeneric(Node::Kind kind) {
  switch (kind) {
    case Node::Kind::Structure:
    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::TypeSymbolicReference:
      return true;
    default:
      return false;
  }
}

static bool isEntity(Node::Kind kind) {
  // Also accepts some kind which are not entities.
  if (kind == Node::Kind::Type)
    return true;
  return isContext(kind);
}

static bool isRequirement(Node::Kind kind) {
  switch (kind) {
    case Node::Kind::DependentGenericSameTypeRequirement:
    case Node::Kind::DependentGenericLayoutRequirement:
    case Node::Kind::DependentGenericConformanceRequirement:
      return true;
    default:
      return false;
  }
}

} // anonymous namespace

//////////////////////////////////
// Public utility functions    //
//////////////////////////////////

bool swift::Demangle::isContext(Node::Kind kind) {
  switch (kind) {
#define NODE(ID)
#define CONTEXT_NODE(ID)                                                \
    case Node::Kind::ID:
#include "swift/Demangling/DemangleNodes.def"
      return true;
    default:
      return false;
  }
}

bool swift::Demangle::isFunctionAttr(Node::Kind kind) {
  switch (kind) {
    case Node::Kind::FunctionSignatureSpecialization:
    case Node::Kind::GenericSpecialization:
    case Node::Kind::GenericSpecializationPrespecialized:
    case Node::Kind::InlinedGenericFunction:
    case Node::Kind::GenericSpecializationNotReAbstracted:
    case Node::Kind::GenericPartialSpecialization:
    case Node::Kind::GenericPartialSpecializationNotReAbstracted:
    case Node::Kind::GenericSpecializationInResilienceDomain:
    case Node::Kind::ObjCAttribute:
    case Node::Kind::NonObjCAttribute:
    case Node::Kind::DynamicAttribute:
    case Node::Kind::DirectMethodReferenceAttribute:
    case Node::Kind::VTableAttribute:
    case Node::Kind::PartialApplyForwarder:
    case Node::Kind::PartialApplyObjCForwarder:
    case Node::Kind::OutlinedVariable:
    case Node::Kind::OutlinedBridgedMethod:
    case Node::Kind::MergedFunction:
    case Node::Kind::DynamicallyReplaceableFunctionImpl:
    case Node::Kind::DynamicallyReplaceableFunctionKey:
    case Node::Kind::DynamicallyReplaceableFunctionVar:
    case Node::Kind::AsyncFunctionPointer:
    case Node::Kind::AsyncAwaitResumePartialFunction:
    case Node::Kind::AsyncSuspendResumePartialFunction:
      return true;
    default:
      return false;
  }
}

llvm::StringRef
swift::Demangle::makeSymbolicMangledNameStringRef(const char *base) {
  if (!base)
    return {};

  auto end = base;
  while (*end != '\0') {
    // Skip over symbolic references.
    if (*end >= '\x01' && *end <= '\x17')
      end += sizeof(uint32_t);
    else if (*end >= '\x18' && *end <= '\x1F')
      end += sizeof(void*);
    ++end;
  }
  return StringRef(base, end - base);
}

int swift::Demangle::getManglingPrefixLength(llvm::StringRef mangledName) {
  if (mangledName.empty()) return 0;

  llvm::StringRef prefixes[] = {
    /*Swift 4*/   "_T0",
    /*Swift 4.x*/ "$S", "_$S",
    /*Swift 5+*/  "$s", "_$s"};

  // Look for any of the known prefixes
  for (auto prefix : prefixes) {
    if (mangledName.startswith(prefix))
      return prefix.size();
  }

  return 0;
}

bool swift::Demangle::isSwiftSymbol(llvm::StringRef mangledName) {
  if (isOldFunctionTypeMangling(mangledName))
    return true;

  return getManglingPrefixLength(mangledName) != 0;
}

bool swift::Demangle::isSwiftSymbol(const char *mangledName) {
  StringRef mangledNameRef(mangledName);
  return isSwiftSymbol(mangledNameRef);
}

bool swift::Demangle::isObjCSymbol(llvm::StringRef mangledName) {
  StringRef nameWithoutPrefix = dropSwiftManglingPrefix(mangledName);
  return nameWithoutPrefix.startswith("So") ||
         nameWithoutPrefix.startswith("SC");
}

bool swift::Demangle::isOldFunctionTypeMangling(llvm::StringRef mangledName) {
  return mangledName.startswith("_T");
}

llvm::StringRef swift::Demangle::dropSwiftManglingPrefix(StringRef mangledName){
  return mangledName.drop_front(getManglingPrefixLength(mangledName));
}

static bool isAliasNode(Demangle::NodePointer Node) {
  switch (Node->getKind()) {
  case Demangle::Node::Kind::Type:
    return isAliasNode(Node->getChild(0));
  case Demangle::Node::Kind::TypeAlias:
    return true;
  default:
    return false;
  }
  assert(0 && "unknown node kind");
}

bool swift::Demangle::isAlias(llvm::StringRef mangledName) {
  Demangle::Demangler Dem;
  return isAliasNode(Dem.demangleType(mangledName));
}

static bool isClassNode(Demangle::NodePointer Node) {
  switch (Node->getKind()) {
  case Demangle::Node::Kind::Type:
    return isClassNode(Node->getChild(0));
  case Demangle::Node::Kind::Class:
  case Demangle::Node::Kind::BoundGenericClass:
    return true;
  default:
    return false;
  }
  assert(0 && "unknown node kind");
}

bool swift::Demangle::isClass(llvm::StringRef mangledName) {
  Demangle::Demangler Dem;
  return isClassNode(Dem.demangleType(mangledName));
}

static bool isEnumNode(Demangle::NodePointer Node) {
  switch (Node->getKind()) {
  case Demangle::Node::Kind::Type:
    return isEnumNode(Node->getChild(0));
  case Demangle::Node::Kind::Enum:
  case Demangle::Node::Kind::BoundGenericEnum:
    return true;
  default:
    return false;
  }
  assert(0 && "unknown node kind");
}

bool swift::Demangle::isEnum(llvm::StringRef mangledName) {
  Demangle::Demangler Dem;
  return isEnumNode(Dem.demangleType(mangledName));
}

static bool isProtocolNode(Demangle::NodePointer Node) {
  switch (Node->getKind()) {
  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;
  }
  assert(0 && "unknown node kind");
}

bool swift::Demangle::isProtocol(llvm::StringRef mangledName) {
  Demangle::Demangler Dem;
  return isProtocolNode(Dem.demangleType(dropSwiftManglingPrefix(mangledName)));
}

static bool isStructNode(Demangle::NodePointer Node) {
  switch (Node->getKind()) {
  case Demangle::Node::Kind::Type:
    return isStructNode(Node->getChild(0));
  case Demangle::Node::Kind::Structure:
  case Demangle::Node::Kind::BoundGenericStructure:
    return true;
  default:
    return false;
  }
  assert(0 && "unknown node kind");
}

bool swift::Demangle::isStruct(llvm::StringRef mangledName) {
  Demangle::Demangler Dem;
  return isStructNode(Dem.demangleType(mangledName));
}

using namespace swift;
using namespace Demangle;

//////////////////////////////////
// Node member functions        //
//////////////////////////////////

size_t Node::getNumChildren() const {
  switch (NodePayloadKind) {
    case PayloadKind::OneChild: return 1;
    case PayloadKind::TwoChildren: return 2;
    case PayloadKind::ManyChildren: return Children.Number;
    default: return 0;
  }
}

Node::iterator Node::begin() const {
  switch (NodePayloadKind) {
    case PayloadKind::OneChild:
    case PayloadKind::TwoChildren:
      return &InlineChildren[0];
    case PayloadKind::ManyChildren:
      return Children.Nodes;
    default:
      return nullptr;
  }
}

Node::iterator Node::end() const {
  switch (NodePayloadKind) {
    case PayloadKind::OneChild:
      return &InlineChildren[1];
    case PayloadKind::TwoChildren:
      return &InlineChildren[2];
    case PayloadKind::ManyChildren:
      return Children.Nodes + Children.Number;
    default:
      return nullptr;
  }
}

void Node::addChild(NodePointer Child, NodeFactory &Factory) {
  assert(Child);
  switch (NodePayloadKind) {
    case PayloadKind::None:
      InlineChildren[0] = Child;
      InlineChildren[1] = nullptr;
      NodePayloadKind = PayloadKind::OneChild;
      break;
    case PayloadKind::OneChild:
      assert(!InlineChildren[1]);
      InlineChildren[1] = Child;
      NodePayloadKind = PayloadKind::TwoChildren;
      break;
    case PayloadKind::TwoChildren: {
      NodePointer Child0 = InlineChildren[0];
      NodePointer Child1 = InlineChildren[1];
      Children.Nodes = nullptr;
      Children.Number = 0;
      Children.Capacity = 0;
      Factory.Reallocate(Children.Nodes, Children.Capacity, 3);
      assert(Children.Capacity >= 3);
      Children.Nodes[0] = Child0;
      Children.Nodes[1] = Child1;
      Children.Nodes[2] = Child;
      Children.Number = 3;
      NodePayloadKind = PayloadKind::ManyChildren;
      break;
    }
    case PayloadKind::ManyChildren:
      if (Children.Number >= Children.Capacity) {
        Factory.Reallocate(Children.Nodes, Children.Capacity, 1);
      }
      assert(Children.Number < Children.Capacity);
      Children.Nodes[Children.Number++] = Child;
      break;
    default:
      assert(false && "cannot add child");
  }
}

void Node::removeChildAt(unsigned Pos) {
  switch (NodePayloadKind) {
    case PayloadKind::OneChild:
      assert(Pos == 0);
      NodePayloadKind = PayloadKind::None;
      break;
    case PayloadKind::TwoChildren: {
      assert(Pos < 2);
      if (Pos == 0)
        InlineChildren[0] = InlineChildren[1];
      NodePayloadKind = PayloadKind::OneChild;
      break;
    }
    case PayloadKind::ManyChildren:
      for (unsigned i = Pos, n = Children.Number - 1; i != n; ++i) {
        Children.Nodes[i] = Children.Nodes[i + 1];
      }
      --Children.Number;
      break;
    default:
      assert(false && "cannot remove child");
  }
}

void Node::reverseChildren(size_t StartingAt) {
  assert(StartingAt <= getNumChildren());
  switch (NodePayloadKind) {
    case PayloadKind::TwoChildren:
      if (StartingAt == 0)
        std::swap(InlineChildren[0], InlineChildren[1]);
      break;
    case PayloadKind::ManyChildren:
      std::reverse(Children.Nodes + StartingAt,
                   Children.Nodes + Children.Number);
      break;
    default:
      break;
  }
}

//////////////////////////////////
// NodeFactory member functions //
//////////////////////////////////

void NodeFactory::freeSlabs(Slab *slab) {
  while (slab) {
    Slab *prev = slab->Previous;
    free(slab);
    slab = prev;
  }
}
  
void NodeFactory::clear() {
  assert(!isBorrowed);
  if (CurrentSlab) {
#ifdef NODE_FACTORY_DEBUGGING
    fprintf(stderr, "%s## clear: allocated memory = %zu\n", indent().c_str(), allocatedMemory);
#endif

    freeSlabs(CurrentSlab->Previous);
    
    // Recycle the last allocated slab.
    // Note that the size of the last slab is at least as big as all previous
    // slabs combined. Therefore it's not worth the effort of reusing all slabs.
    // The slab size also stays the same. So at some point the demangling
    // process converges to a single large slab across repeated demangle-clear
    // cycles.
    CurrentSlab->Previous = nullptr;
    CurPtr = (char *)(CurrentSlab + 1);
    assert(End == CurPtr + SlabSize);
#ifdef NODE_FACTORY_DEBUGGING
    allocatedMemory = 0;
#endif
  }
}

NodePointer NodeFactory::createNode(Node::Kind K) {
  return new (Allocate<Node>()) Node(K);
}
NodePointer NodeFactory::createNode(Node::Kind K, Node::IndexType Index) {
  return new (Allocate<Node>()) Node(K, Index);
}
NodePointer NodeFactory::createNodeWithAllocatedText(Node::Kind K,
                                                     llvm::StringRef Text) {
  return new (Allocate<Node>()) Node(K, Text);
}
NodePointer NodeFactory::createNode(Node::Kind K, const CharVector &Text) {
  return createNodeWithAllocatedText(K, Text.str());
}
NodePointer NodeFactory::createNode(Node::Kind K, const char *Text) {
  return new (Allocate<Node>()) Node(K, llvm::StringRef(Text));
}

#ifdef NODE_FACTORY_DEBUGGING
int NodeFactory::nestingLevel = 0;
#endif

//////////////////////////////////
// CharVector member functions  //
//////////////////////////////////

void CharVector::append(StringRef Rhs, NodeFactory &Factory) {
  if (NumElems + Rhs.size() > Capacity)
    Factory.Reallocate(Elems, Capacity, /*Growth*/ Rhs.size());
  memcpy(Elems + NumElems, Rhs.data(), Rhs.size());
  NumElems += Rhs.size();
  assert(NumElems <= Capacity);
}

void CharVector::append(int Number, NodeFactory &Factory) {
  const int MaxIntPrintSize = 11;
  if (NumElems + MaxIntPrintSize > Capacity)
    Factory.Reallocate(Elems, Capacity, /*Growth*/ MaxIntPrintSize);
  int Length = snprintf(Elems + NumElems, MaxIntPrintSize, "%d", Number);
  assert(Length > 0 && Length < MaxIntPrintSize);
  NumElems += Length;
}

void CharVector::append(unsigned long long Number, NodeFactory &Factory) {
  const int MaxPrintSize = 21;
  if (NumElems + MaxPrintSize > Capacity)
    Factory.Reallocate(Elems, Capacity, /*Growth*/ MaxPrintSize);
  int Length = snprintf(Elems + NumElems, MaxPrintSize, "%llu", Number);
  assert(Length > 0 && Length < MaxPrintSize);
  NumElems += Length;
}

//////////////////////////////////
// Demangler member functions   //
//////////////////////////////////

void Demangler::clear() {
  NodeStack.free();
  Substitutions.free();
  NodeFactory::clear();
}

Demangler::DemangleInitRAII::DemangleInitRAII(Demangler &Dem,
        StringRef MangledName,
        std::function<SymbolicReferenceResolver_t> TheSymbolicReferenceResolver)
// Save the current demangler state so we can restore it.
  : Dem(Dem),
    NodeStack(Dem.NodeStack), Substitutions(Dem.Substitutions),
    NumWords(Dem.NumWords), Text(Dem.Text), Pos(Dem.Pos),
    SymbolicReferenceResolver(std::move(Dem.SymbolicReferenceResolver))
{
  // Reset the demangler state for a nested job.
  Dem.NodeStack.init(Dem, 16);
  Dem.Substitutions.init(Dem, 16);
  Dem.NumWords = 0;
  Dem.Text = MangledName;
  Dem.Pos = 0;
  Dem.SymbolicReferenceResolver = std::move(TheSymbolicReferenceResolver);
}

Demangler::DemangleInitRAII::~DemangleInitRAII() {
  // Restore the saved state.
  Dem.NodeStack = NodeStack;
  Dem.Substitutions = Substitutions;
  Dem.NumWords = NumWords;
  Dem.Text = Text;
  Dem.Pos = Pos;
  Dem.SymbolicReferenceResolver = std::move(SymbolicReferenceResolver);
}

NodePointer Demangler::demangleSymbol(StringRef MangledName,
        std::function<SymbolicReferenceResolver_t> SymbolicReferenceResolver) {
  DemangleInitRAII state(*this, MangledName,
                         std::move(SymbolicReferenceResolver));

  // Demangle old-style class and protocol names, which are still used in the
  // ObjC metadata.
  if (nextIf("_Tt"))
    return demangleOldSymbolAsNode(Text, *this);

  unsigned PrefixLength = getManglingPrefixLength(MangledName);
  if (PrefixLength == 0)
    return nullptr;

  IsOldFunctionTypeMangling = isOldFunctionTypeMangling(MangledName);
  Pos += PrefixLength;

  // If any other prefixes are accepted, please update Mangler::verify.

  if (!parseAndPushNodes())
    return nullptr;

  NodePointer topLevel = createNode(Node::Kind::Global);

  NodePointer Parent = topLevel;
  while (NodePointer FuncAttr = popNode(isFunctionAttr)) {
    Parent->addChild(FuncAttr, *this);
    if (FuncAttr->getKind() == Node::Kind::PartialApplyForwarder ||
        FuncAttr->getKind() == Node::Kind::PartialApplyObjCForwarder)
      Parent = FuncAttr;
  }
  for (Node *Nd : NodeStack) {
    switch (Nd->getKind()) {
      case Node::Kind::Type:
        Parent->addChild(Nd->getFirstChild(), *this);
        break;
      default:
        Parent->addChild(Nd, *this);
        break;
    }
  }
  if (topLevel->getNumChildren() == 0)
    return nullptr;

  return topLevel;
}

NodePointer Demangler::demangleType(StringRef MangledName,
        std::function<SymbolicReferenceResolver_t> SymbolicReferenceResolver) {
  DemangleInitRAII state(*this, MangledName,
                         std::move(SymbolicReferenceResolver));

  parseAndPushNodes();

  if (NodePointer Result = popNode())
    return Result;

  return createNode(Node::Kind::Suffix, Text);
}

bool Demangler::parseAndPushNodes() {
  const auto textSize = Text.size();
  while (Pos < textSize) {
    NodePointer Node = demangleOperator();
    if (!Node)
      return false;
    pushNode(Node);
  }
  return true;
}

NodePointer Demangler::addChild(NodePointer Parent, NodePointer Child) {
  if (!Parent || !Child)
    return nullptr;
  Parent->addChild(Child, *this);
  return Parent;
}

NodePointer Demangler::createWithChild(Node::Kind kind,
                                            NodePointer Child) {
  if (!Child)
    return nullptr;
  NodePointer Nd = createNode(kind);
  Nd->addChild(Child, *this);
  return Nd;
}

NodePointer Demangler::createType(NodePointer Child) {
  return createWithChild(Node::Kind::Type, Child);
}

NodePointer Demangler::Demangler::createWithChildren(Node::Kind kind,
                                       NodePointer Child1, NodePointer Child2) {
  if (!Child1 || !Child2)
    return nullptr;
  NodePointer Nd = createNode(kind);
  Nd->addChild(Child1, *this);
  Nd->addChild(Child2, *this);
  return Nd;
}

NodePointer Demangler::createWithChildren(Node::Kind kind,
                                               NodePointer Child1,
                                               NodePointer Child2,
                                               NodePointer Child3) {
  if (!Child1 || !Child2 || !Child3)
    return nullptr;
  NodePointer Nd = createNode(kind);
  Nd->addChild(Child1, *this);
  Nd->addChild(Child2, *this);
  Nd->addChild(Child3, *this);
  return Nd;
}

NodePointer Demangler::createWithChildren(Node::Kind kind, NodePointer Child1,
                                          NodePointer Child2,
                                          NodePointer Child3,
                                          NodePointer Child4) {
  if (!Child1 || !Child2 || !Child3 || !Child4)
    return nullptr;
  NodePointer Nd = createNode(kind);
  Nd->addChild(Child1, *this);
  Nd->addChild(Child2, *this);
  Nd->addChild(Child3, *this);
  Nd->addChild(Child4, *this);
  return Nd;
}

NodePointer Demangler::changeKind(NodePointer Node, Node::Kind NewKind) {
  if (!Node)
    return nullptr;
  NodePointer NewNode = nullptr;
  if (Node->hasText()) {
    NewNode = createNodeWithAllocatedText(NewKind, Node->getText());
  } else if (Node->hasIndex()) {
    NewNode = createNode(NewKind, Node->getIndex());
  } else {
    NewNode = createNode(NewKind);
  }
  for (NodePointer Child : *Node) {
    NewNode->addChild(Child, *this);
  }
  return NewNode;
}

NodePointer Demangler::demangleTypeMangling() {
  auto Type = popNode(Node::Kind::Type);
  auto LabelList = popFunctionParamLabels(Type);
  auto TypeMangling = createNode(Node::Kind::TypeMangling);

  addChild(TypeMangling, LabelList);
  TypeMangling = addChild(TypeMangling, Type);
  return TypeMangling;
}

NodePointer Demangler::demangleSymbolicReference(unsigned char rawKind) {
  // The symbolic reference is a 4-byte machine integer encoded in the following
  // four bytes.
  if (Pos + 4 > Text.size())
    return nullptr;
  const void *at = Text.data() + Pos;
  int32_t value;
  memcpy(&value, at, 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;
  case 9:
    kind = SymbolicReferenceKind::AccessorFunctionReference;
    direct = Directness::Direct;
    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(kind, direct, value, at);
    
  // With no resolver, or a resolver that failed, refuse to demangle further.
  if (!resolved)
    return nullptr;
  
  // Types register as substitutions even when symbolically referenced.
  // OOPS: Except for opaque type references!
  if (kind == SymbolicReferenceKind::Context &&
      resolved->getKind() != Node::Kind::OpaqueTypeDescriptorSymbolicReference &&
      resolved->getKind() != Node::Kind::OpaqueReturnTypeOf)
    addSubstitution(resolved);
  return resolved;
}

NodePointer Demangler::demangleTypeAnnotation() {
  switch (char c2 = nextChar()) {
  case 'a':
    return createNode(Node::Kind::AsyncAnnotation);
  case 'b':
    return createNode(Node::Kind::ConcurrentFunctionType);
  case 'c':
    return createWithChild(
        Node::Kind::GlobalActorFunctionType, popTypeAndGetChild());
  case 'i':
    return createType(
        createWithChild(Node::Kind::Isolated, popTypeAndGetChild()));
  case 'j':
    return demangleDifferentiableFunctionType();
  case 'k':
    return createType(
        createWithChild(Node::Kind::NoDerivative, popTypeAndGetChild()));
  default:
    return nullptr;
  }
}

NodePointer Demangler::demangleOperator() {
recur:
  switch (unsigned char c = nextChar()) {
    case 0xFF:
      // A 0xFF byte is used as alignment padding for symbolic references
      // when the platform toolchain has alignment restrictions for the
      // relocations that form the reference value. It can be skipped.
      goto recur;
    case 1: case 2:   case 3:   case 4:   case 5: case 6: case 7: case 8:
    case 9: case 0xA: case 0xB: case 0xC:
      return demangleSymbolicReference((unsigned char)c);
    case 'A': return demangleMultiSubstitutions();
    case 'B': return demangleBuiltinType();
    case 'C': return demangleAnyGenericType(Node::Kind::Class);
    case 'D': return demangleTypeMangling();
    case 'E': return demangleExtensionContext();
    case 'F': return demanglePlainFunction();
    case 'G': return demangleBoundGenericType();
    case 'H':
      switch (char c2 = nextChar()) {
      case 'A': return demangleDependentProtocolConformanceAssociated();
      case 'C': return demangleConcreteProtocolConformance();
      case 'D': return demangleDependentProtocolConformanceRoot();
      case 'I': return demangleDependentProtocolConformanceInherited();
      case 'P':
        return createWithChild(
            Node::Kind::ProtocolConformanceRefInTypeModule, popProtocol());
      case 'p':
        return createWithChild(
            Node::Kind::ProtocolConformanceRefInProtocolModule, popProtocol());
      default:
        pushBack();
        pushBack();
        return demangleIdentifier();
      }

    case 'I': return demangleImplFunctionType();
    case 'K': return createNode(Node::Kind::ThrowsAnnotation);
    case 'L': return demangleLocalIdentifier();
    case 'M': return demangleMetatype();
    case 'N': return createWithChild(Node::Kind::TypeMetadata,
                                     popNode(Node::Kind::Type));
    case 'O': return demangleAnyGenericType(Node::Kind::Enum);
    case 'P': return demangleAnyGenericType(Node::Kind::Protocol);
    case 'Q': return demangleArchetype();
    case 'R': return demangleGenericRequirement();
    case 'S': return demangleStandardSubstitution();
    case 'T': return demangleThunkOrSpecialization();
    case 'V': return demangleAnyGenericType(Node::Kind::Structure);
    case 'W': return demangleWitness();
    case 'X': return demangleSpecialType();
    case 'Y': return demangleTypeAnnotation();
    case 'Z': return createWithChild(Node::Kind::Static, popNode(isEntity));
    case 'a': return demangleAnyGenericType(Node::Kind::TypeAlias);
    case 'c': return popFunctionType(Node::Kind::FunctionType);
    case 'd': return createNode(Node::Kind::VariadicMarker);
    case 'f': return demangleFunctionEntity();
    case 'g': return demangleRetroactiveConformance();
    case 'h': return createType(createWithChild(Node::Kind::Shared,
                                                popTypeAndGetChild()));
    case 'i': return demangleSubscript();
    case 'l': return demangleGenericSignature(/*hasParamCounts*/ false);
    case 'm': return createType(createWithChild(Node::Kind::Metatype,
                                                popNode(Node::Kind::Type)));
    case 'n':
      return createType(
          createWithChild(Node::Kind::Owned, popTypeAndGetChild()));
    case 'o': return demangleOperatorIdentifier();
    case 'p': return demangleProtocolListType();
    case 'q': return createType(demangleGenericParamIndex());
    case 'r': return demangleGenericSignature(/*hasParamCounts*/ true);
    case 's': return createNode(Node::Kind::Module, STDLIB_NAME);
    case 't': return popTuple();
    case 'u': return demangleGenericType();
    case 'v': return demangleVariable();
    case 'w': return demangleValueWitness();
    case 'x': return createType(getDependentGenericParamType(0, 0));
    case 'y': return createNode(Node::Kind::EmptyList);
    case 'z': return createType(createWithChild(Node::Kind::InOut,
                                                popTypeAndGetChild()));
    case '_': return createNode(Node::Kind::FirstElementMarker);
    case '.':
      // IRGen still uses '.<n>' to disambiguate partial apply thunks and
      // outlined copy functions. We treat such a suffix as "unmangled suffix".
      pushBack();
      return createNode(Node::Kind::Suffix, consumeAll());
    default:
      pushBack();
      return demangleIdentifier();
  }
}

int Demangler::demangleNatural() {
  if (!isDigit(peekChar()))
    return -1000;
  int num = 0;
  while (true) {
    char c = peekChar();
    if (!isDigit(c))
      return num;
    int newNum = (10 * num) + (c - '0');
    if (newNum < num)
      return -1000;
    num = newNum;
    nextChar();
  }
}

int Demangler::demangleIndex() {
  if (nextIf('_'))
    return 0;
  int num = demangleNatural();
  if (num >= 0 && nextIf('_'))
    return num + 1;
  return -1000;
}

NodePointer Demangler::demangleIndexAsNode() {
  int Idx = demangleIndex();
  if (Idx >= 0)
    return createNode(Node::Kind::Number, Idx);
  return nullptr;
}

NodePointer Demangler::demangleMultiSubstitutions() {
  int RepeatCount = -1;
  while (true) {
    char c = nextChar();
    if (c == 0) {
      // End of text.
      return nullptr;
    }
    if (isLowerLetter(c)) {
      // It's a substitution with an index < 26.
      NodePointer Nd = pushMultiSubstitutions(RepeatCount, c - 'a');
      if (!Nd)
        return nullptr;
      pushNode(Nd);
      RepeatCount = -1;
      // A lowercase letter indicates that there are more substitutions to
      // follow.
      continue;
    }
    if (isUpperLetter(c)) {
      // The last substitution.
      return pushMultiSubstitutions(RepeatCount, c - 'A');
    }
    if (c == '_') {
      // The previously demangled number is actually not a repeat count but
      // the large (> 26) index of a substitution. Because it's an index we
      // have to add 27 and not 26.
      unsigned Idx = RepeatCount + 27;
      if (Idx >= Substitutions.size())
        return nullptr;
      return Substitutions[Idx];
    }
    pushBack();
    // Not a letter? Then it can only be a natural number which might be the
    // repeat count or a large (> 26) substitution index.
    RepeatCount = demangleNatural();
    if (RepeatCount < 0)
      return nullptr;
  }
}

NodePointer Demangler::pushMultiSubstitutions(int RepeatCount,
                                              size_t SubstIdx) {
  if (SubstIdx >= Substitutions.size())
    return nullptr;
  if (RepeatCount > SubstitutionMerging::MaxRepeatCount)
    return nullptr;
  NodePointer Nd = Substitutions[SubstIdx];
  while (RepeatCount-- > 1) {
    pushNode(Nd);
  }
  return Nd;
}

NodePointer Demangler::createSwiftType(Node::Kind typeKind, const char *name) {
  return createType(createWithChildren(typeKind,
    createNode(Node::Kind::Module, STDLIB_NAME),
    createNode(Node::Kind::Identifier, name)));
}

NodePointer Demangler::demangleStandardSubstitution() {
  switch (char c = nextChar()) {
    case 'o':
      return createNode(Node::Kind::Module, MANGLING_MODULE_OBJC);
    case 'C':
      return createNode(Node::Kind::Module, MANGLING_MODULE_CLANG_IMPORTER);
    case 'g': {
      NodePointer OptionalTy =
        createType(createWithChildren(Node::Kind::BoundGenericEnum,
          createSwiftType(Node::Kind::Enum, "Optional"),
          createWithChild(Node::Kind::TypeList, popNode(Node::Kind::Type))));
      addSubstitution(OptionalTy);
      return OptionalTy;
    }
    default: {
      pushBack();
      int RepeatCount = demangleNatural();
      if (RepeatCount > SubstitutionMerging::MaxRepeatCount)
        return nullptr;
      bool secondLevelSubstitution = nextIf('c');
      if (NodePointer Nd = createStandardSubstitution(
              nextChar(), secondLevelSubstitution)) {
        while (RepeatCount-- > 1) {
          pushNode(Nd);
        }
        return Nd;
      }
      return nullptr;
    }
  }
}

NodePointer Demangler::createStandardSubstitution(
    char Subst, bool SecondLevel) {
#define STANDARD_TYPE(KIND, MANGLING, TYPENAME)                   \
  if (!SecondLevel && Subst == #MANGLING[0]) {                    \
    return createSwiftType(Node::Kind::KIND, #TYPENAME);          \
  }

#define STANDARD_TYPE_2(KIND, MANGLING, TYPENAME)                   \
  if (SecondLevel && Subst == #MANGLING[0]) {                    \
    return createSwiftType(Node::Kind::KIND, #TYPENAME);          \
  }

#include "swift/Demangling/StandardTypesMangling.def"
  return nullptr;
}

NodePointer Demangler::demangleIdentifier() {
  bool hasWordSubsts = false;
  bool isPunycoded = false;
  char c = peekChar();
  if (!isDigit(c))
    return nullptr;
  if (c == '0') {
    nextChar();
    if (peekChar() == '0') {
      nextChar();
      isPunycoded = true;
    } else {
      hasWordSubsts = true;
    }
  }
  CharVector Identifier;
  do {
    while (hasWordSubsts && isLetter(peekChar())) {
      char c = nextChar();
      int WordIdx = 0;
      if (isLowerLetter(c)) {
        WordIdx = c - 'a';
      } else {
        assert(isUpperLetter(c));
        WordIdx = c - 'A';
        hasWordSubsts = false;
      }
      if (WordIdx >= NumWords)
        return nullptr;
      assert(WordIdx < MaxNumWords);
      StringRef Slice = Words[WordIdx];
      Identifier.append(Slice, *this);
    }
    if (nextIf('0'))
      break;
    int numChars = demangleNatural();
    if (numChars <= 0)
      return nullptr;
    if (isPunycoded)
      nextIf('_');
    if (Pos + numChars > Text.size())
      return nullptr;
    StringRef Slice = StringRef(Text.data() + Pos, numChars);
    if (isPunycoded) {
      std::string PunycodedString;
      if (!Punycode::decodePunycodeUTF8(Slice, PunycodedString))
        return nullptr;
      Identifier.append(StringRef(PunycodedString), *this);
    } else {
      Identifier.append(Slice, *this);
      int wordStartPos = -1;
      for (int Idx = 0, End = (int)Slice.size(); Idx <= End; ++Idx) {
        char c = (Idx < End ? Slice[Idx] : 0);
        if (wordStartPos >= 0 && isWordEnd(c, Slice[Idx - 1])) {
          if (Idx - wordStartPos >= 2 && NumWords < MaxNumWords) {
            StringRef word(Slice.begin() + wordStartPos, Idx - wordStartPos);
            Words[NumWords++] = word;
          }
          wordStartPos = -1;
        }
        if (wordStartPos < 0 && isWordStart(c)) {
          wordStartPos = Idx;
        }
      }
    }
    Pos += numChars;
  } while (hasWordSubsts);

  if (Identifier.empty())
    return nullptr;
  NodePointer Ident = createNode(Node::Kind::Identifier, Identifier);
  addSubstitution(Ident);
  return Ident;
}

NodePointer Demangler::demangleOperatorIdentifier() {
  NodePointer Ident = popNode(Node::Kind::Identifier);
  if (!Ident)
    return nullptr;

  static const char op_char_table[] = "& @/= >    <*!|+?%-~   ^ .";

  CharVector OpStr;
  for (signed char c : Ident->getText()) {
    if (c < 0) {
      // Pass through Unicode characters.
      OpStr.push_back(c, *this);
      continue;
    }
    if (!isLowerLetter(c))
      return nullptr;
    char o = op_char_table[c - 'a'];
    if (o == ' ')
      return nullptr;
    OpStr.push_back(o, *this);
  }
  switch (nextChar()) {
    case 'i': return createNode(Node::Kind::InfixOperator, OpStr);
    case 'p': return createNode(Node::Kind::PrefixOperator, OpStr);
    case 'P': return createNode(Node::Kind::PostfixOperator, OpStr);
    default: return nullptr;
  }
}

NodePointer Demangler::demangleLocalIdentifier() {
  if (nextIf('L')) {
    NodePointer discriminator = popNode(Node::Kind::Identifier);
    NodePointer name = popNode(isDeclName);
    return createWithChildren(Node::Kind::PrivateDeclName, discriminator, name);
  }
  if (nextIf('l')) {
    NodePointer discriminator = popNode(Node::Kind::Identifier);
    return createWithChild(Node::Kind::PrivateDeclName, discriminator);
  }
  if ((peekChar() >= 'a' && peekChar() <= 'j') ||
      (peekChar() >= 'A' && peekChar() <= 'J')) {
    char relatedEntityKind = nextChar();
    NodePointer kindNd = createNode(Node::Kind::Identifier,
                                    StringRef(&relatedEntityKind, 1));
    NodePointer name = popNode();
    NodePointer result = createNode(Node::Kind::RelatedEntityDeclName);
    addChild(result, kindNd);
    return addChild(result, name);
  }
  NodePointer discriminator = demangleIndexAsNode();
  NodePointer name = popNode(isDeclName);
  return createWithChildren(Node::Kind::LocalDeclName, discriminator, name);
}

NodePointer Demangler::popModule() {
  if (NodePointer Ident = popNode(Node::Kind::Identifier))
    return changeKind(Ident, Node::Kind::Module);
  return popNode(Node::Kind::Module);
}

NodePointer Demangler::popContext() {
  if (NodePointer Mod = popModule())
    return Mod;

  if (NodePointer Ty = popNode(Node::Kind::Type)) {
    if (Ty->getNumChildren() != 1)
      return nullptr;
    NodePointer Child = Ty->getFirstChild();
    if (!isContext(Child->getKind()))
      return nullptr;
    return Child;
  }
  return popNode(isContext);
}

NodePointer Demangler::popTypeAndGetChild() {
  NodePointer Ty = popNode(Node::Kind::Type);
  if (!Ty || Ty->getNumChildren() != 1)
    return nullptr;
  return Ty->getFirstChild();
}

NodePointer Demangler::popTypeAndGetAnyGeneric() {
  NodePointer Child = popTypeAndGetChild();
  if (Child && isAnyGeneric(Child->getKind()))
    return Child;
  return nullptr;
}

NodePointer Demangler::demangleBuiltinType() {
  NodePointer Ty = nullptr;
  const int maxTypeSize = 4096; // a very conservative upper bound
  switch (nextChar()) {
    case 'b':
      Ty = createNode(Node::Kind::BuiltinTypeName,
                               BUILTIN_TYPE_NAME_BRIDGEOBJECT);
      break;
    case 'B':
      Ty = createNode(Node::Kind::BuiltinTypeName,
                              BUILTIN_TYPE_NAME_UNSAFEVALUEBUFFER);
      break;
    case 'e':
      Ty = createNode(Node::Kind::BuiltinTypeName,
                              BUILTIN_TYPE_NAME_EXECUTOR);
      break;
    case 'f': {
      int size = demangleIndex() - 1;
      if (size <= 0 || size > maxTypeSize)
        return nullptr;
      CharVector name;
      name.append(BUILTIN_TYPE_NAME_FLOAT, *this);
      name.append(size, *this);
      Ty = createNode(Node::Kind::BuiltinTypeName, name);
      break;
    }
    case 'i': {
      int size = demangleIndex() - 1;
      if (size <= 0 || size > maxTypeSize)
        return nullptr;
      CharVector name;
      name.append(BUILTIN_TYPE_NAME_INT, *this);
      name.append(size, *this);
      Ty = createNode(Node::Kind::BuiltinTypeName, name);
      break;
    }
    case 'I':
      Ty = createNode(Node::Kind::BuiltinTypeName,
                      BUILTIN_TYPE_NAME_INTLITERAL);
      break;
    case 'v': {
      int elts = demangleIndex() - 1;
      if (elts <= 0 || elts > maxTypeSize)
        return nullptr;
      NodePointer EltType = popTypeAndGetChild();
      if (!EltType || EltType->getKind() != Node::Kind::BuiltinTypeName ||
          !EltType->getText().startswith(BUILTIN_TYPE_NAME_PREFIX))
        return nullptr;
      CharVector name;
      name.append(BUILTIN_TYPE_NAME_VEC, *this);
      name.append(elts, *this);
      name.push_back('x', *this);
      name.append(EltType->getText().substr(BUILTIN_TYPE_NAME_PREFIX.size()),
                  *this);
      Ty = createNode(Node::Kind::BuiltinTypeName, name);
      break;
    }
    case 'O':
      Ty = createNode(Node::Kind::BuiltinTypeName,
                               BUILTIN_TYPE_NAME_UNKNOWNOBJECT);
      break;
    case 'o':
      Ty = createNode(Node::Kind::BuiltinTypeName,
                               BUILTIN_TYPE_NAME_NATIVEOBJECT);
      break;
    case 'p':
      Ty = createNode(Node::Kind::BuiltinTypeName,
                               BUILTIN_TYPE_NAME_RAWPOINTER);
      break;
    case 'j':
      Ty = createNode(Node::Kind::BuiltinTypeName,
                               BUILTIN_TYPE_NAME_JOB);
      break;
    case 'D':
      Ty = createNode(Node::Kind::BuiltinTypeName,
                               BUILTIN_TYPE_NAME_DEFAULTACTORSTORAGE);
      break;
    case 'c':
      Ty = createNode(Node::Kind::BuiltinTypeName,
                               BUILTIN_TYPE_NAME_RAWUNSAFECONTINUATION);
      break;
    case 't':
      Ty = createNode(Node::Kind::BuiltinTypeName, BUILTIN_TYPE_NAME_SILTOKEN);
      break;
    case 'w':
      Ty = createNode(Node::Kind::BuiltinTypeName,
                               BUILTIN_TYPE_NAME_WORD);
      break;
    default:
      return nullptr;
  }
  return createType(Ty);
}

NodePointer Demangler::demangleAnyGenericType(Node::Kind kind) {
  NodePointer Name = popNode(isDeclName);
  NodePointer Ctx = popContext();
  NodePointer NTy = createType(createWithChildren(kind, Ctx, Name));
  addSubstitution(NTy);
  return NTy;
}

NodePointer Demangler::demangleExtensionContext() {
  NodePointer GenSig = popNode(Node::Kind::DependentGenericSignature);
  NodePointer Module = popModule();
  NodePointer Type = popTypeAndGetAnyGeneric();
  NodePointer Ext = createWithChildren(Node::Kind::Extension, Module, Type);
  if (GenSig)
    Ext = addChild(Ext, GenSig);
  return Ext;
}

NodePointer Demangler::demanglePlainFunction() {
  NodePointer GenSig = popNode(Node::Kind::DependentGenericSignature);
  NodePointer Type = popFunctionType(Node::Kind::FunctionType);
  NodePointer LabelList = popFunctionParamLabels(Type);

  if (GenSig) {
    Type = createType(createWithChildren(Node::Kind::DependentGenericType,
                                         GenSig, Type));
  }

  auto Name = popNode(isDeclName);
  auto Ctx = popContext();

  if (LabelList)
    return createWithChildren(Node::Kind::Function, Ctx, Name, LabelList, Type);

  return createWithChildren(Node::Kind::Function, Ctx, Name, Type);
}

NodePointer Demangler::popFunctionType(Node::Kind kind, bool hasClangType) {
  NodePointer FuncType = createNode(kind);
  NodePointer ClangType = nullptr;
  if (hasClangType) {
    ClangType = demangleClangType();
  }
  addChild(FuncType, ClangType);
  addChild(FuncType, popNode(Node::Kind::GlobalActorFunctionType));
  addChild(FuncType, popNode(Node::Kind::DifferentiableFunctionType));
  addChild(FuncType, popNode(Node::Kind::ThrowsAnnotation));
  addChild(FuncType, popNode(Node::Kind::ConcurrentFunctionType));
  addChild(FuncType, popNode(Node::Kind::AsyncAnnotation));

  FuncType = addChild(FuncType, popFunctionParams(Node::Kind::ArgumentTuple));
  FuncType = addChild(FuncType, popFunctionParams(Node::Kind::ReturnType));
  return createType(FuncType);
}

NodePointer Demangler::popFunctionParams(Node::Kind kind) {
  NodePointer ParamsType = nullptr;
  if (popNode(Node::Kind::EmptyList)) {
    ParamsType = createType(createNode(Node::Kind::Tuple));
  } else {
    ParamsType = popNode(Node::Kind::Type);
  }
  return createWithChild(kind, ParamsType);
}

NodePointer Demangler::popFunctionParamLabels(NodePointer Type) {
  if (!IsOldFunctionTypeMangling && popNode(Node::Kind::EmptyList))
    return createNode(Node::Kind::LabelList);

  if (!Type || Type->getKind() != Node::Kind::Type)
    return nullptr;

  auto FuncType = Type->getFirstChild();
  if (FuncType->getKind() == Node::Kind::DependentGenericType)
    FuncType = FuncType->getChild(1)->getFirstChild();

  if (FuncType->getKind() != Node::Kind::FunctionType &&
      FuncType->getKind() != Node::Kind::NoEscapeFunctionType)
    return nullptr;

  unsigned FirstChildIdx = 0;
  if (FuncType->getChild(FirstChildIdx)->getKind()
        == Node::Kind::GlobalActorFunctionType)
    ++FirstChildIdx;
  if (FuncType->getChild(FirstChildIdx)->getKind()
        == Node::Kind::DifferentiableFunctionType)
    ++FirstChildIdx;
  if (FuncType->getChild(FirstChildIdx)->getKind()
        == Node::Kind::ThrowsAnnotation)
    ++FirstChildIdx;
  if (FuncType->getChild(FirstChildIdx)->getKind()
        == Node::Kind::ConcurrentFunctionType)
    ++FirstChildIdx;
  if (FuncType->getChild(FirstChildIdx)->getKind()
        == Node::Kind::AsyncAnnotation)
    ++FirstChildIdx;
  auto ParameterType = FuncType->getChild(FirstChildIdx);

  assert(ParameterType->getKind() == Node::Kind::ArgumentTuple);

  NodePointer ParamsType = ParameterType->getFirstChild();
  assert(ParamsType->getKind() == Node::Kind::Type);
  auto Params = ParamsType->getFirstChild();
  unsigned NumParams =
    Params->getKind() == Node::Kind::Tuple ? Params->getNumChildren() : 1;

  if (NumParams == 0)
    return nullptr;

  auto getChildIf =
      [](NodePointer Node,
         Node::Kind filterBy) -> std::pair<NodePointer, unsigned> {
    for (unsigned i = 0, n = Node->getNumChildren(); i != n; ++i) {
      auto Child = Node->getChild(i);
      if (Child->getKind() == filterBy)
        return {Child, i};
    }
    return {nullptr, 0};
  };

  auto getLabel = [&](NodePointer Params, unsigned Idx) -> NodePointer {
    // Old-style function type mangling has labels as part of the argument.
    if (IsOldFunctionTypeMangling) {
      auto Param = Params->getChild(Idx);
      auto Label = getChildIf(Param, Node::Kind::TupleElementName);

      if (Label.first) {
        Param->removeChildAt(Label.second);
        return createNodeWithAllocatedText(Node::Kind::Identifier,
                                           Label.first->getText());
      }

      return createNode(Node::Kind::FirstElementMarker);
    }

    return popNode();
  };

  auto LabelList = createNode(Node::Kind::LabelList);
  auto Tuple = ParameterType->getFirstChild()->getFirstChild();

  if (IsOldFunctionTypeMangling &&
      (!Tuple || Tuple->getKind() != Node::Kind::Tuple))
    return LabelList;

  bool hasLabels = false;
  for (unsigned i = 0; i != NumParams; ++i) {
    auto Label = getLabel(Tuple, i);

    if (!Label)
      return nullptr;

    if (Label->getKind() != Node::Kind::Identifier &&
        Label->getKind() != Node::Kind::FirstElementMarker)
      return nullptr;

    LabelList->addChild(Label, *this);
    hasLabels |= Label->getKind() != Node::Kind::FirstElementMarker;
  }

  // Old style label mangling can produce label list without
  // actual labels, we need to support that case specifically.
  if (!hasLabels)
    return createNode(Node::Kind::LabelList);

  if (!IsOldFunctionTypeMangling)
    LabelList->reverseChildren();

  return LabelList;
}

NodePointer Demangler::popTuple() {
  NodePointer Root = createNode(Node::Kind::Tuple);

  if (!popNode(Node::Kind::EmptyList)) {
    bool firstElem = false;
    do {
      firstElem = (popNode(Node::Kind::FirstElementMarker) != nullptr);
      NodePointer TupleElmt = createNode(Node::Kind::TupleElement);
      addChild(TupleElmt, popNode(Node::Kind::VariadicMarker));
      if (NodePointer Ident = popNode(Node::Kind::Identifier)) {
        TupleElmt->addChild(createNodeWithAllocatedText(
                              Node::Kind::TupleElementName, Ident->getText()),
                            *this);
      }
      NodePointer Ty = popNode(Node::Kind::Type);
      if (!Ty)
        return nullptr;
      TupleElmt->addChild(Ty, *this);
      Root->addChild(TupleElmt, *this);
    } while (!firstElem);

    Root->reverseChildren();
  }
  return createType(Root);
}

NodePointer Demangler::popTypeList() {
  NodePointer Root = createNode(Node::Kind::TypeList);

  if (!popNode(Node::Kind::EmptyList)) {
    bool firstElem = false;
    do {
      firstElem = (popNode(Node::Kind::FirstElementMarker) != nullptr);
      NodePointer Ty = popNode(Node::Kind::Type);
      if (!Ty)
        return nullptr;
      Root->addChild(Ty, *this);
    } while (!firstElem);
    
    Root->reverseChildren();
  }
  return Root;
}

NodePointer Demangler::popProtocol() {
  if (NodePointer Type = popNode(Node::Kind::Type)) {
    if (Type->getNumChildren() < 1)
      return nullptr;

    if (!isProtocolNode(Type))
      return nullptr;

    return Type;
  }
  
  if (NodePointer SymbolicRef = popNode(Node::Kind::ProtocolSymbolicReference)){
    return SymbolicRef;
  }

  NodePointer Name = popNode(isDeclName);
  NodePointer Ctx = popContext();
  NodePointer Proto = createWithChildren(Node::Kind::Protocol, Ctx, Name);
  return createType(Proto);
}

NodePointer Demangler::popAnyProtocolConformanceList() {
  NodePointer conformanceList
    = createNode(Node::Kind::AnyProtocolConformanceList);
  if (!popNode(Node::Kind::EmptyList)) {
    bool firstElem = false;
    do {
      firstElem = (popNode(Node::Kind::FirstElementMarker) != nullptr);
      NodePointer anyConformance = popAnyProtocolConformance();
      if (!anyConformance)
        return nullptr;
      conformanceList->addChild(anyConformance, *this);
    } while (!firstElem);

    conformanceList->reverseChildren();
  }
  return conformanceList;
}

NodePointer Demangler::popAnyProtocolConformance() {
  return popNode([](Node::Kind kind) {
    switch (kind) {
    case Node::Kind::ConcreteProtocolConformance:
    case Node::Kind::DependentProtocolConformanceRoot:
    case Node::Kind::DependentProtocolConformanceInherited:
    case Node::Kind::DependentProtocolConformanceAssociated:
      return true;

    default:
      return false;
    }
  });
}

NodePointer Demangler::demangleRetroactiveProtocolConformanceRef() {
  NodePointer module = popModule();
  NodePointer proto = popProtocol();
  auto protocolConformanceRef =
      createWithChildren(Node::Kind::ProtocolConformanceRefInOtherModule,
                         proto, module);
  return protocolConformanceRef;
}

NodePointer Demangler::demangleConcreteProtocolConformance() {
  NodePointer conditionalConformanceList = popAnyProtocolConformanceList();

  NodePointer conformanceRef =
      popNode(Node::Kind::ProtocolConformanceRefInTypeModule);
  if (!conformanceRef) {
    conformanceRef =
        popNode(Node::Kind::ProtocolConformanceRefInProtocolModule);
  }
  if (!conformanceRef)
    conformanceRef = demangleRetroactiveProtocolConformanceRef();

  NodePointer type = popNode(Node::Kind::Type);
  return createWithChildren(Node::Kind::ConcreteProtocolConformance,
                            type, conformanceRef, conditionalConformanceList);
}

NodePointer Demangler::popDependentProtocolConformance() {
  return popNode([](Node::Kind kind) {
    switch (kind) {
    case Node::Kind::DependentProtocolConformanceRoot:
    case Node::Kind::DependentProtocolConformanceInherited:
    case Node::Kind::DependentProtocolConformanceAssociated:
      return true;

    default:
      return false;
    }
  });
}

NodePointer Demangler::demangleDependentProtocolConformanceRoot() {
  NodePointer index = demangleDependentConformanceIndex();
  NodePointer protocol = popProtocol();
  NodePointer dependentType = popNode(Node::Kind::Type);
  return createWithChildren(Node::Kind::DependentProtocolConformanceRoot,
                            dependentType, protocol, index);
}

NodePointer Demangler::demangleDependentProtocolConformanceInherited() {
  NodePointer index = demangleDependentConformanceIndex();
  NodePointer protocol = popProtocol();
  NodePointer nested = popDependentProtocolConformance();
  return createWithChildren(Node::Kind::DependentProtocolConformanceInherited,
                            nested, protocol, index);
}

NodePointer Demangler::popDependentAssociatedConformance() {
  NodePointer protocol = popProtocol();
  NodePointer dependentType = popNode(Node::Kind::Type);
  return createWithChildren(Node::Kind::DependentAssociatedConformance,
                            dependentType, protocol);
}

NodePointer Demangler::demangleDependentProtocolConformanceAssociated() {
  NodePointer index = demangleDependentConformanceIndex();
  NodePointer associatedConformance = popDependentAssociatedConformance();
  NodePointer nested = popDependentProtocolConformance();
  return createWithChildren(Node::Kind::DependentProtocolConformanceAssociated,
                            nested, associatedConformance, index);
}

NodePointer Demangler::demangleDependentConformanceIndex() {
  int index = demangleIndex();
  // index < 0 indicates a demangling error.
  // index == 0 is ill-formed by the (originally buggy) use of this production.
  if (index <= 0) return nullptr;

  // index == 1 indicates an unknown index.
  if (index == 1) return createNode(Node::Kind::UnknownIndex);

  // Remove the index adjustment.
  return createNode(Node::Kind::Index, unsigned(index) - 2);
}

NodePointer Demangler::demangleRetroactiveConformance() {
  NodePointer index = demangleIndexAsNode();
  NodePointer conformance = popAnyProtocolConformance();
  return createWithChildren(Node::Kind::RetroactiveConformance, index, conformance);
}

bool Demangler::demangleBoundGenerics(Vector<NodePointer> &TypeListList,
                                      NodePointer &RetroactiveConformances) {
  RetroactiveConformances = nullptr;
  while (auto RetroactiveConformance =
         popNode(Node::Kind::RetroactiveConformance)) {
    if (!RetroactiveConformances)
      RetroactiveConformances = createNode(Node::Kind::TypeList);
    RetroactiveConformances->addChild(RetroactiveConformance, *this);
  }
  if (RetroactiveConformances)
    RetroactiveConformances->reverseChildren();
  
  for (;;) {
    NodePointer TList = createNode(Node::Kind::TypeList);
    TypeListList.push_back(TList, *this);
    while (NodePointer Ty = popNode(Node::Kind::Type)) {
      TList->addChild(Ty, *this);
    }
    TList->reverseChildren();
    
    if (popNode(Node::Kind::EmptyList))
      break;
    if (!popNode(Node::Kind::FirstElementMarker))
      return false;
  }
  return true;
}

NodePointer Demangler::demangleBoundGenericType() {
  NodePointer RetroactiveConformances;
  Vector<NodePointer> TypeListList(*this, 4);
  
  if (!demangleBoundGenerics(TypeListList, RetroactiveConformances))
    return nullptr;

  NodePointer Nominal = popTypeAndGetAnyGeneric();
  if (!Nominal)
    return nullptr;
  NodePointer BoundNode = demangleBoundGenericArgs(Nominal, TypeListList, 0);
  if (!BoundNode)
    return nullptr;
  addChild(BoundNode, RetroactiveConformances);
  NodePointer NTy = createType(BoundNode);
  addSubstitution(NTy);
  return NTy;
}

bool Demangle::nodeConsumesGenericArgs(Node *node) {
  switch (node->getKind()) {
    case Node::Kind::Variable:
    case Node::Kind::Subscript:
    case Node::Kind::ImplicitClosure:
    case Node::Kind::ExplicitClosure:
    case Node::Kind::DefaultArgumentInitializer:
    case Node::Kind::Initializer:
    case Node::Kind::PropertyWrapperBackingInitializer:
    case Node::Kind::PropertyWrapperInitFromProjectedValue:
      return false;
    default:
      return true;
  }
}

NodePointer Demangler::demangleBoundGenericArgs(NodePointer Nominal,
                                    const Vector<NodePointer> &TypeLists,
                                    size_t TypeListIdx) {
  // TODO: This would be a lot easier if we represented bound generic args
  // flatly in the demangling tree, since that's how they're mangled and also
  // how the runtime generally wants to consume them.
  
  if (!Nominal)
    return nullptr;

  if (TypeListIdx >= TypeLists.size())
    return nullptr;

  // 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();
         --i) {
      auto list = TypeLists[i];
      for (auto child : *list) {
        remainingTypeList->addChild(child, *this);
      }
    }
    return createWithChildren(Node::Kind::BoundGenericOtherNominalType,
                              createType(Nominal), remainingTypeList);
  }

  // Generic arguments for the outermost type come first.
  if (Nominal->getNumChildren() == 0)
    return nullptr;
  NodePointer Context = Nominal->getFirstChild();

  bool consumesGenericArgs = nodeConsumesGenericArgs(Nominal);

  NodePointer args = TypeLists[TypeListIdx];

  if (consumesGenericArgs)
    ++TypeListIdx;

  if (TypeListIdx < TypeLists.size()) {
    NodePointer BoundParent = nullptr;
    if (Context->getKind() == Node::Kind::Extension) {
      BoundParent = demangleBoundGenericArgs(Context->getChild(1), TypeLists,
                                             TypeListIdx);
      BoundParent = createWithChildren(Node::Kind::Extension,
                                       Context->getFirstChild(),
                                       BoundParent);
      if (Context->getNumChildren() == 3) {
        // Add the generic signature of the extension context.
        addChild(BoundParent, Context->getChild(2));
      }
    } else {
      BoundParent = demangleBoundGenericArgs(Context, TypeLists, TypeListIdx);
    }
    // Rebuild this type with the new parent type, which may have
    // had its generic arguments applied.
    NodePointer NewNominal = createWithChild(Nominal->getKind(), BoundParent);
    if (!NewNominal)
      return nullptr;

    // Append remaining children of the origin nominal.
    for (unsigned Idx = 1; Idx < Nominal->getNumChildren(); ++Idx) {
      addChild(NewNominal, Nominal->getChild(Idx));
    }
    Nominal = NewNominal;
  }
  if (!consumesGenericArgs)
    return Nominal;

  // If there were no arguments at this level there is nothing left
  // to do.
  if (args->getNumChildren() == 0)
    return Nominal;

  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;
  }
  return createWithChildren(kind, createType(Nominal), args);
}

NodePointer Demangler::demangleImplParamConvention(Node::Kind ConvKind) {
  const char *attr = nullptr;
  switch (nextChar()) {
    case 'i': attr = "@in"; break;
    case 'c':
      attr = "@in_constant";
      break;
    case 'l': attr = "@inout"; break;
    case 'b': attr = "@inout_aliasable"; break;
    case 'n': attr = "@in_guaranteed"; break;
    case 'x': attr = "@owned"; break;
    case 'g': attr = "@guaranteed"; break;
    case 'e': attr = "@deallocating"; break;
    case 'y': attr = "@unowned"; break;
    default:
      pushBack();
      return nullptr;
  }
  return createWithChild(ConvKind,
                         createNode(Node::Kind::ImplConvention, attr));
}

NodePointer Demangler::demangleImplResultConvention(Node::Kind ConvKind) {
  const char *attr = nullptr;
  switch (nextChar()) {
    case 'r': attr = "@out"; break;
    case 'o': attr = "@owned"; break;
    case 'd': attr = "@unowned"; break;
    case 'u': attr = "@unowned_inner_pointer"; break;
    case 'a': attr = "@autoreleased"; break;
    default:
      pushBack();
      return nullptr;
  }
  return createWithChild(ConvKind,
                         createNode(Node::Kind::ImplConvention, attr));
}

NodePointer Demangler::demangleImplParameterResultDifferentiability() {
  // Empty string represents default differentiability.
  const char *attr = "";
  if (nextIf('w'))
    attr = "@noDerivative";
  return createNode(Node::Kind::ImplParameterResultDifferentiability, attr);
}

NodePointer Demangler::demangleClangType() {
  int numChars = demangleNatural();
  if (numChars <= 0 || Pos + numChars > Text.size())
    return nullptr;
  CharVector mangledClangType;
  mangledClangType.append(StringRef(Text.data() + Pos, numChars), *this);
  Pos = Pos + numChars;
  return createNode(Node::Kind::ClangType, mangledClangType);
}

NodePointer Demangler::demangleImplFunctionType() {
  NodePointer type = createNode(Node::Kind::ImplFunctionType);

  if (nextIf('s')) {
    Vector<NodePointer> Substitutions;
    NodePointer SubstitutionRetroConformances;
    if (!demangleBoundGenerics(Substitutions, SubstitutionRetroConformances))
      return nullptr;

    NodePointer sig = popNode(Node::Kind::DependentGenericSignature);
    if (!sig)
      return nullptr;

    auto subsNode = createNode(Node::Kind::ImplPatternSubstitutions);
    subsNode->addChild(sig, *this);
    assert(Substitutions.size() == 1);
    subsNode->addChild(Substitutions[0], *this);
    if (SubstitutionRetroConformances)
      subsNode->addChild(SubstitutionRetroConformances, *this);
    type->addChild(subsNode, *this);
  }

  if (nextIf('I')) {
    Vector<NodePointer> Substitutions;
    NodePointer SubstitutionRetroConformances;
    if (!demangleBoundGenerics(Substitutions, SubstitutionRetroConformances))
      return nullptr;

    auto subsNode = createNode(Node::Kind::ImplInvocationSubstitutions);
    assert(Substitutions.size() == 1);
    subsNode->addChild(Substitutions[0], *this);
    if (SubstitutionRetroConformances)
      subsNode->addChild(SubstitutionRetroConformances, *this);
    type->addChild(subsNode, *this);
  }
  
  NodePointer GenSig = popNode(Node::Kind::DependentGenericSignature);
  if (GenSig && nextIf('P'))
    GenSig = changeKind(GenSig, Node::Kind::DependentPseudogenericSignature);

  if (nextIf('e'))
    type->addChild(createNode(Node::Kind::ImplEscaping), *this);

  switch ((MangledDifferentiabilityKind)peekChar()) {
  case MangledDifferentiabilityKind::Normal:  // 'd'
  case MangledDifferentiabilityKind::Linear:  // 'l'
  case MangledDifferentiabilityKind::Forward: // 'f'
  case MangledDifferentiabilityKind::Reverse: // 'r'
    type->addChild(
        createNode(
            Node::Kind::ImplDifferentiabilityKind, (Node::IndexType)nextChar()),
        *this);
    break;
  default:
    break;
  }

  const char *CAttr = nullptr;
  switch (nextChar()) {
    case 'y': CAttr = "@callee_unowned"; break;
    case 'g': CAttr = "@callee_guaranteed"; break;
    case 'x': CAttr = "@callee_owned"; break;
    case 't': CAttr = "@convention(thin)"; break;
    default: return nullptr;
  }
  type->addChild(createNode(Node::Kind::ImplConvention, CAttr), *this);

  const char *FConv = nullptr;
  bool hasClangType = false;
  switch (nextChar()) {
  case 'B': FConv = "block"; break;
  case 'C': FConv = "c"; break;
  case 'z': {
    switch (nextChar()) {
    case 'B': hasClangType = true; FConv = "block"; break;
    case 'C': hasClangType = true; FConv = "c"; break;
    default: pushBack(); pushBack(); break;
    }
    break;
  }
  case 'M': FConv = "method"; break;
  case 'O': FConv = "objc_method"; break;
  case 'K': FConv = "closure"; break;
  case 'W': FConv = "witness_method"; break;
  default: pushBack(); break;
  }
  if (FConv) {
    auto FAttrNode = createNode(Node::Kind::ImplFunctionConvention);
    FAttrNode->addChild(
        createNode(Node::Kind::ImplFunctionConventionName, FConv), *this);
    if (hasClangType)
      FAttrNode->addChild(demangleClangType(), *this);
    type->addChild(FAttrNode, *this);
  }

  const char *CoroAttr = nullptr;
  if (nextIf('A'))
    CoroAttr = "@yield_once";
  else if (nextIf('G'))
    CoroAttr = "@yield_many";
  if (CoroAttr)
    type->addChild(createNode(Node::Kind::ImplFunctionAttribute, CoroAttr), *this);

  if (nextIf('h')) {
    type->addChild(createNode(Node::Kind::ImplFunctionAttribute, "@Sendable"),
                   *this);
  }

  if (nextIf('H')) {
    type->addChild(createNode(Node::Kind::ImplFunctionAttribute, "@async"),
                   *this);
  }

  addChild(type, GenSig);

  int NumTypesToAdd = 0;
  while (NodePointer Param =
             demangleImplParamConvention(Node::Kind::ImplParameter)) {
    type = addChild(type, Param);
    if (NodePointer Diff = demangleImplParameterResultDifferentiability())
      Param = addChild(Param, Diff);
    ++NumTypesToAdd;
  }
  while (NodePointer Result = demangleImplResultConvention(
                                                    Node::Kind::ImplResult)) {
    type = addChild(type, Result);
    if (NodePointer Diff = demangleImplParameterResultDifferentiability())
      Result = addChild(Result, Diff);
    ++NumTypesToAdd;
  }
  while (nextIf('Y')) {
    NodePointer YieldResult =
      demangleImplParamConvention(Node::Kind::ImplYield);
    if (!YieldResult)
      return nullptr;
    type = addChild(type, YieldResult);
    ++NumTypesToAdd;
  }
  if (nextIf('z')) {
    NodePointer ErrorResult = demangleImplResultConvention(
                                                  Node::Kind::ImplErrorResult);
    if (!ErrorResult)
      return nullptr;
    type = addChild(type, ErrorResult);
    ++NumTypesToAdd;
  }
  if (!nextIf('_'))
    return nullptr;

  for (int Idx = 0; Idx < NumTypesToAdd; ++Idx) {
    NodePointer ConvTy = popNode(Node::Kind::Type);
    if (!ConvTy)
      return nullptr;
    type->getChild(type->getNumChildren() - Idx - 1)->addChild(ConvTy, *this);
  }
  
  return createType(type);
}

NodePointer Demangler::demangleMetatype() {
  switch (nextChar()) {
    case 'a':
      return createWithPoppedType(Node::Kind::TypeMetadataAccessFunction);
    case 'A':
      return createWithChild(Node::Kind::ReflectionMetadataAssocTypeDescriptor,
                             popProtocolConformance());
    case 'b':
      return createWithPoppedType(
          Node::Kind::CanonicalSpecializedGenericTypeMetadataAccessFunction);
    case 'B':
      return createWithChild(Node::Kind::ReflectionMetadataBuiltinDescriptor,
                               popNode(Node::Kind::Type));
    case 'c':
      return createWithChild(Node::Kind::ProtocolConformanceDescriptor,
                             popProtocolConformance());
    case 'C': {
      NodePointer Ty = popNode(Node::Kind::Type);
      if (!Ty || !isAnyGeneric(Ty->getChild(0)->getKind()))
        return nullptr;
      return createWithChild(Node::Kind::ReflectionMetadataSuperclassDescriptor,
                             Ty->getChild(0));
    }
    case 'D':
      return createWithPoppedType(Node::Kind::TypeMetadataDemanglingCache);
    case 'f':
      return createWithPoppedType(Node::Kind::FullTypeMetadata);
    case 'F':
      return createWithChild(Node::Kind::ReflectionMetadataFieldDescriptor,
                             popNode(Node::Kind::Type));
    case 'g':
      return createWithChild(Node::Kind::OpaqueTypeDescriptorAccessor,
                             popNode());
    case 'h':
      return createWithChild(Node::Kind::OpaqueTypeDescriptorAccessorImpl,
                             popNode());
    case 'i':
      return createWithPoppedType(Node::Kind::TypeMetadataInstantiationFunction);
    case 'I':
      return createWithPoppedType(Node::Kind::TypeMetadataInstantiationCache);
    case 'j':
      return createWithChild(Node::Kind::OpaqueTypeDescriptorAccessorKey,
                             popNode());
    case 'J':
      return createWithChild(Node::Kind::NoncanonicalSpecializedGenericTypeMetadataCache, popNode());
    case 'k':
      return createWithChild(Node::Kind::OpaqueTypeDescriptorAccessorVar,
                             popNode());
    case 'K':
      return createWithChild(Node::Kind::MetadataInstantiationCache,
                             popNode());
    case 'l':
      return createWithPoppedType(
                          Node::Kind::TypeMetadataSingletonInitializationCache);
    case 'L':
      return createWithPoppedType(Node::Kind::TypeMetadataLazyCache);
    case 'm':
      return createWithPoppedType(Node::Kind::Metaclass);
    case 'M':
      return createWithPoppedType(
          Node::Kind::CanonicalSpecializedGenericMetaclass);
    case 'n':
      return createWithPoppedType(Node::Kind::NominalTypeDescriptor);
    case 'N':
      return createWithPoppedType(
          Node::Kind::NoncanonicalSpecializedGenericTypeMetadata);
    case 'o':
      return createWithPoppedType(Node::Kind::ClassMetadataBaseOffset);
    case 'p':
      return createWithChild(Node::Kind::ProtocolDescriptor, popProtocol());
    case 'P':
      return createWithPoppedType(Node::Kind::GenericTypeMetadataPattern);
    case 'Q':
      return createWithChild(Node::Kind::OpaqueTypeDescriptor, popNode());
    case 'r':
      return createWithPoppedType(Node::Kind::TypeMetadataCompletionFunction);
    case 's':
      return createWithPoppedType(Node::Kind::ObjCResilientClassStub);
    case 'S':
      return createWithChild(Node::Kind::ProtocolSelfConformanceDescriptor,
                             popProtocol());
    case 't':
      return createWithPoppedType(Node::Kind::FullObjCResilientClassStub);
    case 'u':
      return createWithPoppedType(Node::Kind::MethodLookupFunction);
    case 'U':
      return createWithPoppedType(Node::Kind::ObjCMetadataUpdateFunction);
    case 'V':
      return createWithChild(Node::Kind::PropertyDescriptor,
                             popNode(isEntity));
    case 'X':
      return demanglePrivateContextDescriptor();
    case 'z':
      return createWithPoppedType(
          Node::Kind::CanonicalPrespecializedGenericTypeCachingOnceToken);
    default:
      return nullptr;
  }
}
  
NodePointer Demangler::demanglePrivateContextDescriptor() {
  switch (nextChar()) {
  case 'E': {
    auto Extension = popContext();
    if (!Extension)
      return nullptr;
    return createWithChild(Node::Kind::ExtensionDescriptor, Extension);
  }
  case 'M': {
    auto Module = popModule();
    if (!Module)
      return nullptr;
    return createWithChild(Node::Kind::ModuleDescriptor, Module);
  }
  case 'Y': {
    auto Discriminator = popNode();
    if (!Discriminator)
      return nullptr;
    auto Context = popContext();
    if (!Context)
      return nullptr;
    
    auto node = createNode(Node::Kind::AnonymousDescriptor);
    node->addChild(Context, *this);
    node->addChild(Discriminator, *this);
    return node;
  }
  case 'X': {
    auto Context = popContext();
    if (!Context)
      return nullptr;
    return createWithChild(Node::Kind::AnonymousDescriptor, Context);
  }
  case 'A': {
    auto path = popAssocTypePath();
    if (!path)
      return nullptr;
    auto base = popNode(Node::Kind::Type);
    if (!base)
      return nullptr;
    return createWithChildren(Node::Kind::AssociatedTypeGenericParamRef,
                              base, path);
  }
  default:
    return nullptr;
  }
}

NodePointer Demangler::demangleArchetype() {
  switch (nextChar()) {
  case 'a': {
    NodePointer Ident = popNode(Node::Kind::Identifier);
    NodePointer ArcheTy = popTypeAndGetChild();
    NodePointer AssocTy = createType(
          createWithChildren(Node::Kind::AssociatedTypeRef, ArcheTy, Ident));
    addSubstitution(AssocTy);
    return AssocTy;
  }
  case 'O': {
    auto definingContext = popContext();
    return createWithChild(Node::Kind::OpaqueReturnTypeOf, definingContext);
  }
  case 'o': {
    auto index = demangleIndex();
    Vector<NodePointer> boundGenericArgs;
    NodePointer retroactiveConformances;
    if (!demangleBoundGenerics(boundGenericArgs, retroactiveConformances))
      return nullptr;
    auto Name = popNode();
    if (!Name)
      return nullptr;
    auto opaque = createWithChildren(Node::Kind::OpaqueType, Name,
                                   createNode(Node::Kind::Index, index));
    auto boundGenerics = createNode(Node::Kind::TypeList);
    for (unsigned i = boundGenericArgs.size(); i-- > 0;)
      boundGenerics->addChild(boundGenericArgs[i], *this);
    opaque->addChild(boundGenerics, *this);
    if (retroactiveConformances)
      opaque->addChild(retroactiveConformances, *this);
    
    auto opaqueTy = createType(opaque);
    addSubstitution(opaqueTy);
    return opaqueTy;
  }
  case 'r': {
    return createType(createNode(Node::Kind::OpaqueReturnType));
  }

  case 'x': {
    NodePointer T = demangleAssociatedTypeSimple(nullptr);
    addSubstitution(T);
    return T;
  }
      
  case 'X': {
    NodePointer T = demangleAssociatedTypeCompound(nullptr);
    addSubstitution(T);
    return T;
  }

  case 'y': {
    NodePointer T = demangleAssociatedTypeSimple(demangleGenericParamIndex());
    addSubstitution(T);
    return T;
  }
  case 'Y': {
    NodePointer T = demangleAssociatedTypeCompound(
                                                 demangleGenericParamIndex());
    addSubstitution(T);
    return T;
  }

  case 'z': {
    NodePointer T = demangleAssociatedTypeSimple(
                                          getDependentGenericParamType(0, 0));
    addSubstitution(T);
    return T;
  }
  case 'Z': {
    NodePointer T = demangleAssociatedTypeCompound(
                                          getDependentGenericParamType(0, 0));
    addSubstitution(T);
    return T;
  }
  default:
    return nullptr;
  }
}

NodePointer Demangler::demangleAssociatedTypeSimple(NodePointer Base) {
  NodePointer ATName = popAssocTypeName();
  NodePointer BaseTy;
  if (Base) {
    BaseTy = createType(Base);
  } else {
    BaseTy = popNode(Node::Kind::Type);
  }
  return createType(createWithChildren(Node::Kind::DependentMemberType,
                                       BaseTy, ATName));
}

NodePointer Demangler::demangleAssociatedTypeCompound(NodePointer Base) {
  Vector<NodePointer> AssocTyNames(*this, 4);
  bool firstElem = false;
  do {
    firstElem = (popNode(Node::Kind::FirstElementMarker) != nullptr);
    NodePointer AssocTyName = popAssocTypeName();
    if (!AssocTyName)
      return nullptr;
    AssocTyNames.push_back(AssocTyName, *this);
  } while (!firstElem);
    
  NodePointer BaseTy;
  if (Base)
    BaseTy = createType(Base);
  else
    BaseTy = popNode(Node::Kind::Type);

  while (NodePointer AssocTy = AssocTyNames.pop_back_val()) {
    NodePointer depTy = createNode(Node::Kind::DependentMemberType);
    depTy = addChild(depTy, BaseTy);
    BaseTy = createType(addChild(depTy, AssocTy));
  }
  return BaseTy;
}

NodePointer Demangler::popAssocTypeName() {
  NodePointer Proto = popNode(Node::Kind::Type);
  if (Proto && !isProtocolNode(Proto))
    return nullptr;

  // If we haven't seen a protocol, check for a symbolic reference.
  if (!Proto)
    Proto = popNode(Node::Kind::ProtocolSymbolicReference);

  NodePointer Id = popNode(Node::Kind::Identifier);
  NodePointer AssocTy = createWithChild(Node::Kind::DependentAssociatedTypeRef, Id);
  addChild(AssocTy, Proto);
  return AssocTy;
}
  
NodePointer Demangler::popAssocTypePath() {
  NodePointer AssocTypePath = createNode(Node::Kind::AssocTypePath);
  bool firstElem = false;
  do {
    firstElem = (popNode(Node::Kind::FirstElementMarker) != nullptr);
    NodePointer AssocTy = popAssocTypeName();
    if (!AssocTy)
      return nullptr;
    AssocTypePath->addChild(AssocTy, *this);
  } while (!firstElem);
  AssocTypePath->reverseChildren();
  return AssocTypePath;
}

NodePointer Demangler::getDependentGenericParamType(int depth, int index) {
  if (depth < 0 || index < 0)
    return nullptr;

  auto paramTy = createNode(Node::Kind::DependentGenericParamType);
  paramTy->addChild(createNode(Node::Kind::Index, depth), *this);
  paramTy->addChild(createNode(Node::Kind::Index, index), *this);
  return paramTy;
}

NodePointer Demangler::demangleGenericParamIndex() {
  if (nextIf('d')) {
    int depth = demangleIndex() + 1;
    int index = demangleIndex();
    return getDependentGenericParamType(depth, index);
  }
  if (nextIf('z')) {
    return getDependentGenericParamType(0, 0);
  }
  return getDependentGenericParamType(0, demangleIndex() + 1);
}

NodePointer Demangler::popProtocolConformance() {
  NodePointer GenSig = popNode(Node::Kind::DependentGenericSignature);
  NodePointer Module = popModule();
  NodePointer Proto = popProtocol();
  NodePointer Type = popNode(Node::Kind::Type);
  NodePointer Ident = nullptr;
  if (!Type) {
    // Property behavior conformance
    Ident = popNode(Node::Kind::Identifier);
    Type = popNode(Node::Kind::Type);
  }
  if (GenSig) {
    Type = createType(createWithChildren(Node::Kind::DependentGenericType,
                                         GenSig, Type));
  }
  NodePointer Conf = createWithChildren(Node::Kind::ProtocolConformance,
                                        Type, Proto, Module);
  addChild(Conf, Ident);
  return Conf;
}

NodePointer Demangler::demangleThunkOrSpecialization() {
  switch (char c = nextChar()) {
    case 'c': return createWithChild(Node::Kind::CurryThunk, popNode(isEntity));
    case 'j': return createWithChild(Node::Kind::DispatchThunk, popNode(isEntity));
    case 'q': return createWithChild(Node::Kind::MethodDescriptor, popNode(isEntity));
    case 'o': return createNode(Node::Kind::ObjCAttribute);
    case 'O': return createNode(Node::Kind::NonObjCAttribute);
    case 'D': return createNode(Node::Kind::DynamicAttribute);
    case 'd': return createNode(Node::Kind::DirectMethodReferenceAttribute);
    case 'a': return createNode(Node::Kind::PartialApplyObjCForwarder);
    case 'A': return createNode(Node::Kind::PartialApplyForwarder);
    case 'm': return createNode(Node::Kind::MergedFunction);
    case 'X': return createNode(Node::Kind::DynamicallyReplaceableFunctionVar);
    case 'x': return createNode(Node::Kind::DynamicallyReplaceableFunctionKey);
    case 'I': return createNode(Node::Kind::DynamicallyReplaceableFunctionImpl);
    case 'Y':
    case 'Q': {
      NodePointer discriminator = demangleIndexAsNode();
      return createWithChild(
          c == 'Q' ? Node::Kind::AsyncAwaitResumePartialFunction :
             /*'Y'*/ Node::Kind::AsyncSuspendResumePartialFunction,
          discriminator);
    }
    case 'C': {
      NodePointer type = popNode(Node::Kind::Type);
      return createWithChild(Node::Kind::CoroutineContinuationPrototype, type);
    }
    case 'z':
    case 'Z': {
      NodePointer flagMode = demangleIndexAsNode();
      NodePointer sig = popNode(Node::Kind::DependentGenericSignature);
      NodePointer resultType = popNode(Node::Kind::Type);
      NodePointer implType = popNode(Node::Kind::Type);
      auto node = createWithChildren(c == 'z'
                                  ? Node::Kind::ObjCAsyncCompletionHandlerImpl
                                  : Node::Kind::PredefinedObjCAsyncCompletionHandlerImpl,
                                implType, resultType, flagMode);
      if (sig)
        addChild(node, sig);
      return node;
    }
    case 'V': {
      NodePointer Base = popNode(isEntity);
      NodePointer Derived = popNode(isEntity);
      return createWithChildren(Node::Kind::VTableThunk, Derived, Base);
    }
    case 'W': {
      NodePointer Entity = popNode(isEntity);
      NodePointer Conf = popProtocolConformance();
      return createWithChildren(Node::Kind::ProtocolWitness, Conf, Entity);
    }
    case 'S':
      return createWithChild(Node::Kind::ProtocolSelfConformanceWitness,
                             popNode(isEntity));
    case 'R':
    case 'r':
    case 'y': {
      Node::Kind kind;
      if (c == 'R') kind = Node::Kind::ReabstractionThunkHelper;
      else if (c == 'y') kind = Node::Kind::ReabstractionThunkHelperWithSelf;
      else kind = Node::Kind::ReabstractionThunk;
      NodePointer Thunk = createNode(kind);
      if (NodePointer GenSig = popNode(Node::Kind::DependentGenericSignature))
        addChild(Thunk, GenSig);
      if (kind == Node::Kind::ReabstractionThunkHelperWithSelf)
        addChild(Thunk, popNode(Node::Kind::Type));
      addChild(Thunk, popNode(Node::Kind::Type));
      addChild(Thunk, popNode(Node::Kind::Type));
      return Thunk;
    }
    case 'g':
      return demangleGenericSpecialization(Node::Kind::GenericSpecialization);
    case 'G':
      return demangleGenericSpecialization(Node::Kind::
                                          GenericSpecializationNotReAbstracted);
    case 'B':
      return demangleGenericSpecialization(Node::Kind::
                                      GenericSpecializationInResilienceDomain);
    case 's':
      return demangleGenericSpecialization(
          Node::Kind::GenericSpecializationPrespecialized);
    case 'i':
      return demangleGenericSpecialization(Node::Kind::InlinedGenericFunction);
    case 'p': {
      NodePointer Spec = demangleSpecAttributes(Node::Kind::
                                                GenericPartialSpecialization);
      NodePointer Param = createWithChild(Node::Kind::GenericSpecializationParam,
                                          popNode(Node::Kind::Type));
      return addChild(Spec, Param);
    }
    case'P': {
      NodePointer Spec = demangleSpecAttributes(Node::Kind::
                                  GenericPartialSpecializationNotReAbstracted);
      NodePointer Param = createWithChild(Node::Kind::GenericSpecializationParam,
                                          popNode(Node::Kind::Type));
      return addChild(Spec, Param);
    }
    case'f':
      return demangleFunctionSpecialization();
    case 'K':
    case 'k': {
      auto nodeKind = c == 'K' ? Node::Kind::KeyPathGetterThunkHelper
                               : Node::Kind::KeyPathSetterThunkHelper;

      bool isSerialized = nextIf('q');

      std::vector<NodePointer> types;
      auto node = popNode();
      if (!node || node->getKind() != Node::Kind::Type)
        return nullptr;
      do {
        types.push_back(node);
        node = popNode();
      } while (node && node->getKind() == Node::Kind::Type);
      
      NodePointer result;
      if (node) {
        if (node->getKind() == Node::Kind::DependentGenericSignature) {
          auto decl = popNode();
          if (!decl)
            return nullptr;
          result = createWithChildren(nodeKind, decl, /*sig*/ node);
        } else {
          result = createWithChild(nodeKind, /*decl*/ node);
        }
      } else {
        return nullptr;
      }
      for (auto i = types.rbegin(), e = types.rend(); i != e; ++i) {
        result->addChild(*i, *this);
      }

      if (isSerialized)
        result->addChild(createNode(Node::Kind::IsSerialized), *this);

      return result;
    }
    case 'l': {
      auto assocTypeName = popAssocTypeName();
      if (!assocTypeName)
        return nullptr;

      return createWithChild(Node::Kind::AssociatedTypeDescriptor,
                             assocTypeName);
    }
    case 'L':
      return createWithChild(Node::Kind::ProtocolRequirementsBaseDescriptor,
                             popProtocol());
    case 'M':
      return createWithChild(Node::Kind::DefaultAssociatedTypeMetadataAccessor,
                             popAssocTypeName());

    case 'n': {
      NodePointer requirementTy = popProtocol();
      NodePointer conformingType = popAssocTypePath();
      NodePointer protoTy = popNode(Node::Kind::Type);
      return createWithChildren(Node::Kind::AssociatedConformanceDescriptor,
                                protoTy, conformingType, requirementTy);
    }

    case 'N': {
      NodePointer requirementTy = popProtocol();
      auto assocTypePath = popAssocTypePath();
      NodePointer protoTy = popNode(Node::Kind::Type);
      return createWithChildren(
                            Node::Kind::DefaultAssociatedConformanceAccessor,
                            protoTy, assocTypePath, requirementTy);
    }

    case 'b': {
      NodePointer requirementTy = popProtocol();
      NodePointer protoTy = popNode(Node::Kind::Type);
      return createWithChildren(Node::Kind::BaseConformanceDescriptor,
                                protoTy, requirementTy);
    }

    case 'H':
    case 'h': {
      auto nodeKind = c == 'H' ? Node::Kind::KeyPathEqualsThunkHelper
                               : Node::Kind::KeyPathHashThunkHelper;

      bool isSerialized = nextIf('q');

      NodePointer genericSig = nullptr;
      std::vector<NodePointer> types;
      
      auto node = popNode();
      if (node) {
        if (node->getKind() == Node::Kind::DependentGenericSignature) {
          genericSig = node;
        } else if (node->getKind() == Node::Kind::Type) {
          types.push_back(node);
        } else {
          return nullptr;
        }
      } else {
        return nullptr;
      }
      
      while (auto node = popNode()) {
        if (node->getKind() != Node::Kind::Type) {
          return nullptr;
        }
        types.push_back(node);
      }
      
      NodePointer result = createNode(nodeKind);
      for (auto i = types.rbegin(), e = types.rend(); i != e; ++i) {
        result->addChild(*i, *this);
      }
      if (genericSig)
        result->addChild(genericSig, *this);

      if (isSerialized)
        result->addChild(createNode(Node::Kind::IsSerialized), *this);

      return result;
    }
    case 'v': {
      int Idx = demangleIndex();
      if (Idx < 0)
        return nullptr;
      return createNode(Node::Kind::OutlinedVariable, Idx);
    }
    case 'e': {
      std::string Params = demangleBridgedMethodParams();
      if (Params.empty())
        return nullptr;
      return createNode(Node::Kind::OutlinedBridgedMethod, Params);
    }
    case 'u': return createNode(Node::Kind::AsyncFunctionPointer);
    case 'U': {
      auto globalActor = popNode(Node::Kind::Type);
      if (!globalActor)
        return nullptr;
      
      auto reabstraction = popNode();
      if (!reabstraction)
        return nullptr;
      
      auto node = createNode(Node::Kind::ReabstractionThunkHelperWithGlobalActor);
      node->addChild(reabstraction, *this);
      node->addChild(globalActor, *this);
      return node;
    }
    case 'J':
      switch (peekChar()) {
      case 'S':
        nextChar();
        return demangleAutoDiffSubsetParametersThunk();
      case 'O':
        nextChar();
        return demangleAutoDiffSelfReorderingReabstractionThunk();
      case 'V':
        nextChar();
        return demangleAutoDiffFunctionOrSimpleThunk(
            Node::Kind::AutoDiffDerivativeVTableThunk);
      default:
        return demangleAutoDiffFunctionOrSimpleThunk(
            Node::Kind::AutoDiffFunction);
      }
    default:
      return nullptr;
  }
}

NodePointer
Demangler::demangleAutoDiffFunctionOrSimpleThunk(Node::Kind nodeKind) {
  auto result = createNode(nodeKind);
  while (auto *originalNode = popNode())
    result = addChild(result, originalNode);
  result->reverseChildren();
  auto kind = demangleAutoDiffFunctionKind();
  result = addChild(result, kind);
  result = addChild(result, demangleIndexSubset());
  if (!nextIf('p'))
    return nullptr;
  result = addChild(result, demangleIndexSubset());
  if (!nextIf('r'))
    return nullptr;
  return result;
}

NodePointer Demangler::demangleAutoDiffFunctionKind() {
  char kind = nextChar();
  if (kind != 'f' && kind != 'r' && kind != 'd' && kind != 'p')
    return nullptr;
  return createNode(Node::Kind::AutoDiffFunctionKind, kind);
}

NodePointer Demangler::demangleAutoDiffSubsetParametersThunk() {
  auto result = createNode(Node::Kind::AutoDiffSubsetParametersThunk);
  while (auto *node = popNode())
    result = addChild(result, node);
  result->reverseChildren();
  auto kind = demangleAutoDiffFunctionKind();
  result = addChild(result, kind);
  result = addChild(result, demangleIndexSubset());
  if (!nextIf('p'))
    return nullptr;
  result = addChild(result, demangleIndexSubset());
  if (!nextIf('r'))
    return nullptr;
  result = addChild(result, demangleIndexSubset());
  if (!nextIf('P'))
    return nullptr;
  return result;
}

NodePointer Demangler::demangleAutoDiffSelfReorderingReabstractionThunk() {
  auto result = createNode(
      Node::Kind::AutoDiffSelfReorderingReabstractionThunk);
  addChild(result, popNode(Node::Kind::DependentGenericSignature));
  result = addChild(result, popNode(Node::Kind::Type));
  result = addChild(result, popNode(Node::Kind::Type));
  result->reverseChildren();
  result = addChild(result, demangleAutoDiffFunctionKind());
  return result;
}

NodePointer Demangler::demangleDifferentiabilityWitness() {
  auto result = createNode(Node::Kind::DifferentiabilityWitness);
  auto optionalGenSig = popNode(Node::Kind::DependentGenericSignature);
  while (auto *node = popNode())
    result = addChild(result, node);
  result->reverseChildren();
  MangledDifferentiabilityKind kind;
  switch (auto c = nextChar()) {
  case 'f': kind = MangledDifferentiabilityKind::Forward; break;
  case 'r': kind = MangledDifferentiabilityKind::Reverse; break;
  case 'd': kind = MangledDifferentiabilityKind::Normal; break;
  case 'l': kind = MangledDifferentiabilityKind::Linear; break;
  default: return nullptr;
  }
  result = addChild(
      result, createNode(Node::Kind::Index, (Node::IndexType)kind));
  result = addChild(result, demangleIndexSubset());
  if (!nextIf('p'))
    return nullptr;
  result = addChild(result, demangleIndexSubset());
  if (!nextIf('r'))
    return nullptr;
  addChild(result, optionalGenSig);
  return result;
}

NodePointer Demangler::demangleIndexSubset() {
  std::string str;
  for (auto c = peekChar(); c == 'S' || c == 'U'; c = peekChar()) {
    str.push_back(c);
    (void)nextChar();
  }
  if (str.empty())
    return nullptr;
  return createNode(Node::Kind::IndexSubset, str);
}

NodePointer Demangler::demangleDifferentiableFunctionType() {
  MangledDifferentiabilityKind kind;
  switch (auto c = nextChar()) {
  case 'f': kind = MangledDifferentiabilityKind::Forward; break;
  case 'r': kind = MangledDifferentiabilityKind::Reverse; break;
  case 'd': kind = MangledDifferentiabilityKind::Normal; break;
  case 'l': kind = MangledDifferentiabilityKind::Linear; break;
  default: return nullptr;
  }
  return createNode(
      Node::Kind::DifferentiableFunctionType, (Node::IndexType)kind);
}

std::string Demangler::demangleBridgedMethodParams() {
  if (nextIf('_'))
    return std::string();

  std::string Str;

  auto kind = nextChar();
  switch (kind) {
  default:
    return std::string();
  case 'p': case 'a': case 'm':
    Str.push_back(kind);
  }

  while (!nextIf('_')) {
    auto c = nextChar();
    if (c != 'n' && c != 'b' && c != 'g')
      return std::string();
    Str.push_back(c);
  }
  return Str;
}

NodePointer Demangler::demangleGenericSpecialization(Node::Kind SpecKind) {
  NodePointer Spec = demangleSpecAttributes(SpecKind);
  if (!Spec)
    return nullptr;
  NodePointer TyList = popTypeList();
  if (!TyList)
    return nullptr;
  for (NodePointer Ty : *TyList) {
    Spec->addChild(createWithChild(Node::Kind::GenericSpecializationParam, Ty),
                   *this);
  }
  return Spec;
}

NodePointer Demangler::demangleFunctionSpecialization() {
  NodePointer Spec = demangleSpecAttributes(
        Node::Kind::FunctionSignatureSpecialization);
  while (Spec && !nextIf('_')) {
    Spec = addChild(Spec, demangleFuncSpecParam(Node::Kind::FunctionSignatureSpecializationParam));
  }
  if (!nextIf('n'))
    Spec = addChild(Spec, demangleFuncSpecParam(Node::Kind::FunctionSignatureSpecializationReturn));

  if (!Spec)
    return nullptr;

  // Add the required parameters in reverse order.
  for (size_t Idx = 0, Num = Spec->getNumChildren(); Idx < Num; ++Idx) {
    NodePointer Param = Spec->getChild(Num - Idx - 1);
    if (Param->getKind() != Node::Kind::FunctionSignatureSpecializationParam)
      continue;

    if (Param->getNumChildren() == 0)
      continue;
    NodePointer KindNd = Param->getFirstChild();
    assert(KindNd->getKind() ==
             Node::Kind::FunctionSignatureSpecializationParamKind);
    auto ParamKind = (FunctionSigSpecializationParamKind)KindNd->getIndex();
    switch (ParamKind) {
      case FunctionSigSpecializationParamKind::ConstantPropFunction:
      case FunctionSigSpecializationParamKind::ConstantPropGlobal:
      case FunctionSigSpecializationParamKind::ConstantPropString:
      case FunctionSigSpecializationParamKind::ClosureProp: {
        size_t FixedChildren = Param->getNumChildren();
        while (NodePointer Ty = popNode(Node::Kind::Type)) {
          if (ParamKind != FunctionSigSpecializationParamKind::ClosureProp)
            return nullptr;
          Param = addChild(Param, Ty);
        }
        NodePointer Name = popNode(Node::Kind::Identifier);
        if (!Name)
          return nullptr;
        StringRef Text = Name->getText();
        if (ParamKind ==
                FunctionSigSpecializationParamKind::ConstantPropString &&
            !Text.empty() && Text[0] == '_') {
          // A '_' escapes a leading digit or '_' of a string constant.
          Text = Text.drop_front(1);
        }
        addChild(Param, createNodeWithAllocatedText(
          Node::Kind::FunctionSignatureSpecializationParamPayload, Text));
        Param->reverseChildren(FixedChildren);
        break;
      }
      default:
        break;
    }
  }
  return Spec;
}

NodePointer Demangler::demangleFuncSpecParam(Node::Kind Kind) {
  assert(Kind == Node::Kind::FunctionSignatureSpecializationParam ||
         Kind == Node::Kind::FunctionSignatureSpecializationReturn);
  NodePointer Param = createNode(Kind);
  switch (nextChar()) {
    case 'n':
      return Param;
    case 'c':
      // Consumes an identifier and multiple type parameters.
      // The parameters will be added later.
      return addChild(Param, createNode(
        Node::Kind::FunctionSignatureSpecializationParamKind,
        uint64_t(FunctionSigSpecializationParamKind::ClosureProp)));
    case 'p': {
      switch (nextChar()) {
        case 'f':
          // Consumes an identifier parameter, which will be added later.
          return addChild(
              Param,
              createNode(Node::Kind::FunctionSignatureSpecializationParamKind,
                         Node::IndexType(FunctionSigSpecializationParamKind::
                                             ConstantPropFunction)));
        case 'g':
          // Consumes an identifier parameter, which will be added later.
          return addChild(
              Param,
              createNode(
                  Node::Kind::FunctionSignatureSpecializationParamKind,
                  Node::IndexType(
                      FunctionSigSpecializationParamKind::ConstantPropGlobal)));
        case 'i':
          return addFuncSpecParamNumber(Param,
                    FunctionSigSpecializationParamKind::ConstantPropInteger);
        case 'd':
          return addFuncSpecParamNumber(Param,
                      FunctionSigSpecializationParamKind::ConstantPropFloat);
        case 's': {
          // Consumes an identifier parameter (the string constant),
          // which will be added later.
          const char *Encoding = nullptr;
          switch (nextChar()) {
            case 'b': Encoding = "u8"; break;
            case 'w': Encoding = "u16"; break;
            case 'c': Encoding = "objc"; break;
            default: return nullptr;
          }
          addChild(Param,
                   createNode(
                       Node::Kind::FunctionSignatureSpecializationParamKind,
                       Node::IndexType(
                           swift::Demangle::FunctionSigSpecializationParamKind::
                               ConstantPropString)));
          return addChild(Param, createNode(
                  Node::Kind::FunctionSignatureSpecializationParamPayload,
                  Encoding));
        }
        default:
          return nullptr;
      }
    }
    case 'e': {
      unsigned Value =
          unsigned(FunctionSigSpecializationParamKind::ExistentialToGeneric);
      if (nextIf('D'))
        Value |= unsigned(FunctionSigSpecializationParamKind::Dead);
      if (nextIf('G'))
        Value |=
            unsigned(FunctionSigSpecializationParamKind::OwnedToGuaranteed);
      if (nextIf('O'))
        Value |=
            unsigned(FunctionSigSpecializationParamKind::GuaranteedToOwned);
      if (nextIf('X'))
        Value |= unsigned(FunctionSigSpecializationParamKind::SROA);
      return addChild(
          Param,
          createNode(Node::Kind::FunctionSignatureSpecializationParamKind,
                     Value));
    }
    case 'd': {
      unsigned Value = unsigned(FunctionSigSpecializationParamKind::Dead);
      if (nextIf('G'))
        Value |= unsigned(FunctionSigSpecializationParamKind::OwnedToGuaranteed);
      if (nextIf('O'))
        Value |=
            unsigned(FunctionSigSpecializationParamKind::GuaranteedToOwned);
      if (nextIf('X'))
        Value |= unsigned(FunctionSigSpecializationParamKind::SROA);
      return addChild(Param, createNode(
                  Node::Kind::FunctionSignatureSpecializationParamKind, Value));
    }
    case 'g': {
      unsigned Value = unsigned(FunctionSigSpecializationParamKind::
                                OwnedToGuaranteed);
      if (nextIf('X'))
        Value |= unsigned(FunctionSigSpecializationParamKind::SROA);
      return addChild(Param, createNode(
                  Node::Kind::FunctionSignatureSpecializationParamKind, Value));
    }
    case 'o': {
      unsigned Value =
          unsigned(FunctionSigSpecializationParamKind::GuaranteedToOwned);
      if (nextIf('X'))
        Value |= unsigned(FunctionSigSpecializationParamKind::SROA);
      return addChild(
          Param,
          createNode(Node::Kind::FunctionSignatureSpecializationParamKind,
                     Value));
    }
    case 'x':
      return addChild(Param, createNode(
                Node::Kind::FunctionSignatureSpecializationParamKind,
                unsigned(FunctionSigSpecializationParamKind::SROA)));
    case 'i':
      return addChild(Param, createNode(
                Node::Kind::FunctionSignatureSpecializationParamKind,
                unsigned(FunctionSigSpecializationParamKind::BoxToValue)));
    case 's':
      return addChild(Param, createNode(
                Node::Kind::FunctionSignatureSpecializationParamKind,
                unsigned(FunctionSigSpecializationParamKind::BoxToStack)));
    default:
      return nullptr;
  }
}

NodePointer Demangler::addFuncSpecParamNumber(NodePointer Param,
                                    FunctionSigSpecializationParamKind Kind) {
  Param->addChild(createNode(
        Node::Kind::FunctionSignatureSpecializationParamKind, unsigned(Kind)),
        *this);
  CharVector Str;
  while (isDigit(peekChar())) {
    Str.push_back(nextChar(), *this);
  }
  if (Str.empty())
    return nullptr;
  return addChild(Param, createNode(
     Node::Kind::FunctionSignatureSpecializationParamPayload, Str));
}

NodePointer Demangler::demangleSpecAttributes(Node::Kind SpecKind) {
  bool isSerialized = nextIf('q');

  int PassID = (int)nextChar() - '0';
  if (PassID < 0 || PassID > 9)
    return nullptr;

  NodePointer SpecNd = createNode(SpecKind);
  if (isSerialized)
    SpecNd->addChild(createNode(Node::Kind::IsSerialized),
                     *this);

  SpecNd->addChild(createNode(Node::Kind::SpecializationPassID, PassID),
                   *this);
  return SpecNd;
}

NodePointer Demangler::demangleWitness() {
  switch (char c = nextChar()) {
    case 'C':
      return createWithChild(Node::Kind::EnumCase,
                             popNode(isEntity));
    case 'V':
      return createWithChild(Node::Kind::ValueWitnessTable,
                             popNode(Node::Kind::Type));
    case 'v': {
      unsigned Directness;
      switch (nextChar()) {
        case 'd': Directness = unsigned(Directness::Direct); break;
        case 'i': Directness = unsigned(Directness::Indirect); break;
        default: return nullptr;
      }
      return createWithChildren(Node::Kind::FieldOffset,
                        createNode(Node::Kind::Directness, Directness),
                        popNode(isEntity));
    }
    case 'S':
      return createWithChild(Node::Kind::ProtocolSelfConformanceWitnessTable,
                             popProtocol());
    case 'P':
      return createWithChild(Node::Kind::ProtocolWitnessTable,
                             popProtocolConformance());
    case 'p':
      return createWithChild(Node::Kind::ProtocolWitnessTablePattern,
                             popProtocolConformance());
    case 'G':
      return createWithChild(Node::Kind::GenericProtocolWitnessTable,
                             popProtocolConformance());
    case 'I':
      return createWithChild(
                  Node::Kind::GenericProtocolWitnessTableInstantiationFunction,
                  popProtocolConformance());

    case 'r':
      return createWithChild(Node::Kind::ResilientProtocolWitnessTable,
                             popProtocolConformance());

    case 'l': {
      NodePointer Conf = popProtocolConformance();
      NodePointer Type = popNode(Node::Kind::Type);
      return createWithChildren(Node::Kind::LazyProtocolWitnessTableAccessor,
                                Type, Conf);
    }
    case 'L': {
      NodePointer Conf = popProtocolConformance();
      NodePointer Type = popNode(Node::Kind::Type);
      return createWithChildren(
               Node::Kind::LazyProtocolWitnessTableCacheVariable, Type, Conf);
    }
    case 'a':
      return createWithChild(Node::Kind::ProtocolWitnessTableAccessor,
                             popProtocolConformance());
    case 't': {
      NodePointer Name = popNode(isDeclName);
      NodePointer Conf = popProtocolConformance();
      return createWithChildren(Node::Kind::AssociatedTypeMetadataAccessor,
                                Conf, Name);
    }
    case 'T': {
      NodePointer ProtoTy = popNode(Node::Kind::Type);
      NodePointer ConformingType = popAssocTypePath();
      NodePointer Conf = popProtocolConformance();
      return createWithChildren(Node::Kind::AssociatedTypeWitnessTableAccessor,
                                Conf, ConformingType, ProtoTy);
    }
    case 'b': {
      NodePointer ProtoTy = popNode(Node::Kind::Type);
      NodePointer Conf = popProtocolConformance();
      return createWithChildren(Node::Kind::BaseWitnessTableAccessor,
                                Conf, ProtoTy);
    }
    case 'O': {
      switch (nextChar()) {
      case 'y': {
        if (auto sig = popNode(Node::Kind::DependentGenericSignature))
          return createWithChildren(Node::Kind::OutlinedCopy,
                                    popNode(Node::Kind::Type), sig);
        return createWithChild(Node::Kind::OutlinedCopy,
                               popNode(Node::Kind::Type));
      }
      case 'e': {
        if (auto sig = popNode(Node::Kind::DependentGenericSignature))
          return createWithChildren(Node::Kind::OutlinedConsume,
                                    popNode(Node::Kind::Type), sig);
        return createWithChild(Node::Kind::OutlinedConsume,
                               popNode(Node::Kind::Type));
      }
      case 'r': {
        if (auto sig = popNode(Node::Kind::DependentGenericSignature))
          return createWithChildren(Node::Kind::OutlinedRetain,
                                    popNode(Node::Kind::Type), sig);
        return createWithChild(Node::Kind::OutlinedRetain,
                               popNode(Node::Kind::Type));
      }
      case 's': {
        if (auto sig = popNode(Node::Kind::DependentGenericSignature))
          return createWithChildren(Node::Kind::OutlinedRelease,
                                    popNode(Node::Kind::Type), sig);
        return createWithChild(Node::Kind::OutlinedRelease,
                               popNode(Node::Kind::Type));
      }
      case 'b': {
        if (auto sig = popNode(Node::Kind::DependentGenericSignature))
          return createWithChildren(Node::Kind::OutlinedInitializeWithTake,
                                    popNode(Node::Kind::Type), sig);
        return createWithChild(Node::Kind::OutlinedInitializeWithTake,
                               popNode(Node::Kind::Type));
      }
      case 'c': {
        if (auto sig = popNode(Node::Kind::DependentGenericSignature))
          return createWithChildren(Node::Kind::OutlinedInitializeWithCopy,
                                    popNode(Node::Kind::Type), sig);
        return createWithChild(Node::Kind::OutlinedInitializeWithCopy,
                               popNode(Node::Kind::Type));
      }
      case 'd': {
        if (auto sig = popNode(Node::Kind::DependentGenericSignature))
          return createWithChildren(Node::Kind::OutlinedAssignWithTake,
                                    popNode(Node::Kind::Type), sig);
        return createWithChild(Node::Kind::OutlinedAssignWithTake,
                               popNode(Node::Kind::Type));
      }
      case 'f': {
        if (auto sig = popNode(Node::Kind::DependentGenericSignature))
          return createWithChildren(Node::Kind::OutlinedAssignWithCopy,
                                    popNode(Node::Kind::Type), sig);
        return createWithChild(Node::Kind::OutlinedAssignWithCopy,
                               popNode(Node::Kind::Type));
      }
      case 'h': {
        if (auto sig = popNode(Node::Kind::DependentGenericSignature))
          return createWithChildren(Node::Kind::OutlinedDestroy,
                                    popNode(Node::Kind::Type), sig);
        return createWithChild(Node::Kind::OutlinedDestroy,
                               popNode(Node::Kind::Type));
      }
      default:
        return nullptr;
      }
    }
    case 'Z':
    case 'z': {
      auto declList = createNode(Node::Kind::GlobalVariableOnceDeclList);
      std::vector<NodePointer> vars;
      while (auto sig = popNode(Node::Kind::FirstElementMarker)) {
        auto identifier = popNode(isDeclName);
        if (!identifier)
          return nullptr;
        vars.push_back(identifier);
      }
      for (auto i = vars.rbegin(); i != vars.rend(); ++i) {
        declList->addChild(*i, *this);
      }
      
      auto context = popContext();
      if (!context)
        return nullptr;
      Node::Kind kind = c == 'Z'
        ? Node::Kind::GlobalVariableOnceFunction
        : Node::Kind::GlobalVariableOnceToken;
      return createWithChildren(kind,
                                context,
                                declList);
    }
    case 'J':
      return demangleDifferentiabilityWitness();
    default:
      return nullptr;
  }
}

NodePointer Demangler::demangleSpecialType() {
  switch (auto specialChar = nextChar()) {
    case 'E':
      return popFunctionType(Node::Kind::NoEscapeFunctionType);
    case 'A':
      return popFunctionType(Node::Kind::EscapingAutoClosureType);
    case 'f':
      return popFunctionType(Node::Kind::ThinFunctionType);
    case 'K':
      return popFunctionType(Node::Kind::AutoClosureType);
    case 'U':
      return popFunctionType(Node::Kind::UncurriedFunctionType);
    case 'L':
      return popFunctionType(Node::Kind::EscapingObjCBlock);
    case 'B':
      return popFunctionType(Node::Kind::ObjCBlock);
    case 'C':
      return popFunctionType(Node::Kind::CFunctionPointer);
    case 'z':
      switch (auto cchar = nextChar()) {
      case 'B':
        return popFunctionType(Node::Kind::ObjCBlock, true);
      case 'C':
        return popFunctionType(Node::Kind::CFunctionPointer, true);
      default:
        return nullptr;
      }
    case 'o':
      return createType(createWithChild(Node::Kind::Unowned,
                                        popNode(Node::Kind::Type)));
    case 'u':
      return createType(createWithChild(Node::Kind::Unmanaged,
                                        popNode(Node::Kind::Type)));
    case 'w':
      return createType(createWithChild(Node::Kind::Weak,
                                        popNode(Node::Kind::Type)));
    case 'b':
      return createType(createWithChild(Node::Kind::SILBoxType,
                                        popNode(Node::Kind::Type)));
    case 'D':
      return createType(createWithChild(Node::Kind::DynamicSelf,
                                        popNode(Node::Kind::Type)));
    case 'M': {
      NodePointer MTR = demangleMetatypeRepresentation();
      NodePointer Type = popNode(Node::Kind::Type);
      return createType(createWithChildren(Node::Kind::Metatype, MTR, Type));
    }
    case 'm': {
      NodePointer MTR = demangleMetatypeRepresentation();
      NodePointer Type = popNode(Node::Kind::Type);
      return createType(createWithChildren(Node::Kind::ExistentialMetatype,
                                           MTR, Type));
    }
    case 'p':
      return createType(createWithChild(Node::Kind::ExistentialMetatype,
                                        popNode(Node::Kind::Type)));
    case 'c': {
      NodePointer Superclass = popNode(Node::Kind::Type);
      NodePointer Protocols = demangleProtocolList();
      return createType(createWithChildren(Node::Kind::ProtocolListWithClass,
                                           Protocols, Superclass));
    }
    case 'l': {
      NodePointer Protocols = demangleProtocolList();
      return createType(createWithChild(Node::Kind::ProtocolListWithAnyObject,
                                        Protocols));
    }
    case 'X':
    case 'x': {
      // SIL box types.
      NodePointer signature = nullptr, genericArgs = nullptr;
      if (specialChar == 'X') {
        signature = popNode(Node::Kind::DependentGenericSignature);
        if (!signature)
          return nullptr;
        genericArgs = popTypeList();
        if (!genericArgs)
          return nullptr;
      }
      
      auto fieldTypes = popTypeList();
      if (!fieldTypes)
        return nullptr;
      // Build layout.
      auto layout = createNode(Node::Kind::SILBoxLayout);
      for (unsigned i = 0, e = fieldTypes->getNumChildren(); i < e; ++i) {
        auto fieldType = fieldTypes->getChild(i);
        assert(fieldType->getKind() == Node::Kind::Type);
        bool isMutable = false;
        // 'inout' typelist mangling is used to represent mutable fields.
        if (fieldType->getChild(0)->getKind() == Node::Kind::InOut) {
          isMutable = true;
          fieldType = createType(fieldType->getChild(0)->getChild(0));
        }
        auto field = createNode(isMutable
                                         ? Node::Kind::SILBoxMutableField
                                         : Node::Kind::SILBoxImmutableField);
        field->addChild(fieldType, *this);
        layout->addChild(field, *this);
      }
      auto boxTy = createNode(Node::Kind::SILBoxTypeWithLayout);
      boxTy->addChild(layout, *this);
      if (signature) {
        boxTy->addChild(signature, *this);
        assert(genericArgs);
        boxTy->addChild(genericArgs, *this);
      }
      return createType(boxTy);
    }
    case 'Y':
      return demangleAnyGenericType(Node::Kind::OtherNominalType);
    case 'Z': {
      auto types = popTypeList();
      auto name = popNode(Node::Kind::Identifier);
      auto parent = popContext();
      auto anon = createNode(Node::Kind::AnonymousContext);
      anon = addChild(anon, name);
      anon = addChild(anon, parent);
      anon = addChild(anon, types);
      return anon;
    }
    case 'e':
      return createType(createNode(Node::Kind::ErrorType));
    case 'S':
      // Sugared type for debugger.
      switch (nextChar()) {
      case 'q':
        return createType(createWithChild(Node::Kind::SugaredOptional,
                                          popNode(Node::Kind::Type)));
      case 'a':
        return createType(createWithChild(Node::Kind::SugaredArray,
                                          popNode(Node::Kind::Type)));
      case 'D': {
        NodePointer value = popNode(Node::Kind::Type);
        NodePointer key = popNode(Node::Kind::Type);
        return createType(createWithChildren(Node::Kind::SugaredDictionary,
                                             key, value));
      }
      case 'p':
        return createType(createWithChild(Node::Kind::SugaredParen,
                                          popNode(Node::Kind::Type)));
      default:
        return nullptr;
      }
    default:
      return nullptr;
  }
}

NodePointer Demangler::demangleMetatypeRepresentation() {
  switch (nextChar()) {
    case 't':
      return createNode(Node::Kind::MetatypeRepresentation, "@thin");
    case 'T':
      return createNode(Node::Kind::MetatypeRepresentation, "@thick");
    case 'o':
      return createNode(Node::Kind::MetatypeRepresentation,
                                 "@objc_metatype");
    default:
      return nullptr;
  }
}

NodePointer Demangler::demangleAccessor(NodePointer ChildNode) {
  Node::Kind Kind;
  switch (nextChar()) {
    case 'm': Kind = Node::Kind::MaterializeForSet; break;
    case 's': Kind = Node::Kind::Setter; break;
    case 'g': Kind = Node::Kind::Getter; break;
    case 'G': Kind = Node::Kind::GlobalGetter; break;
    case 'w': Kind = Node::Kind::WillSet; break;
    case 'W': Kind = Node::Kind::DidSet; break;
    case 'r': Kind = Node::Kind::ReadAccessor; break;
    case 'M': Kind = Node::Kind::ModifyAccessor; break;
    case 'a':
      switch (nextChar()) {
        case 'O': Kind = Node::Kind::OwningMutableAddressor; break;
        case 'o': Kind = Node::Kind::NativeOwningMutableAddressor; break;
        case 'P': Kind = Node::Kind::NativePinningMutableAddressor; break;
        case 'u': Kind = Node::Kind::UnsafeMutableAddressor; break;
        default: return nullptr;
      }
      break;
    case 'l':
      switch (nextChar()) {
        case 'O': Kind = Node::Kind::OwningAddressor; break;
        case 'o': Kind = Node::Kind::NativeOwningAddressor; break;
        case 'p': Kind = Node::Kind::NativePinningAddressor; break;
        case 'u': Kind = Node::Kind::UnsafeAddressor; break;
        default: return nullptr;
      }
      break;
    case 'p': // Pseudo-accessor referring to the variable/subscript itself
      return ChildNode;
    default: return nullptr;
  }
  NodePointer Entity = createWithChild(Kind, ChildNode);
  return Entity;
}

NodePointer Demangler::demangleFunctionEntity() {
  enum {
    None,
    TypeAndMaybePrivateName,
    TypeAndIndex,
    Index
  } Args;

  Node::Kind Kind = Node::Kind::EmptyList;
  switch (nextChar()) {
    case 'D': Args = None; Kind = Node::Kind::Deallocator; break;
    case 'd': Args = None; Kind = Node::Kind::Destructor; break;
    case 'E': Args = None; Kind = Node::Kind::IVarDestroyer; break;
    case 'e': Args = None; Kind = Node::Kind::IVarInitializer; break;
    case 'i': Args = None; Kind = Node::Kind::Initializer; break;
    case 'C':
      Args = TypeAndMaybePrivateName; Kind = Node::Kind::Allocator; break;
    case 'c':
      Args = TypeAndMaybePrivateName; Kind = Node::Kind::Constructor; break;
    case 'U': Args = TypeAndIndex; Kind = Node::Kind::ExplicitClosure; break;
    case 'u': Args = TypeAndIndex; Kind = Node::Kind::ImplicitClosure; break;
    case 'A': Args = Index; Kind = Node::Kind::DefaultArgumentInitializer; break;
    case 'p': return demangleEntity(Node::Kind::GenericTypeParamDecl);
    case 'P':
      Args = None;
      Kind = Node::Kind::PropertyWrapperBackingInitializer;
      break;
    case 'W':
      Args = None;
      Kind = Node::Kind::PropertyWrapperInitFromProjectedValue;
      break;
    default: return nullptr;
  }

  NodePointer NameOrIndex = nullptr, ParamType = nullptr, LabelList = nullptr;
  switch (Args) {
    case None:
      break;
    case TypeAndMaybePrivateName:
      NameOrIndex = popNode(Node::Kind::PrivateDeclName);
      ParamType = popNode(Node::Kind::Type);
      LabelList = popFunctionParamLabels(ParamType);
      break;
    case TypeAndIndex:
      NameOrIndex = demangleIndexAsNode();
      ParamType = popNode(Node::Kind::Type);
      break;
    case Index:
      NameOrIndex = demangleIndexAsNode();
      break;
  }
  NodePointer Entity = createWithChild(Kind, popContext());
  switch (Args) {
    case None:
      break;
    case Index:
      Entity = addChild(Entity, NameOrIndex);
      break;
    case TypeAndMaybePrivateName:
      addChild(Entity, LabelList);
      Entity = addChild(Entity, ParamType);
      addChild(Entity, NameOrIndex);
      break;
    case TypeAndIndex:
      Entity = addChild(Entity, NameOrIndex);
      Entity = addChild(Entity, ParamType);
      break;
  }
  return Entity;
}

NodePointer Demangler::demangleEntity(Node::Kind Kind) {
  NodePointer Type = popNode(Node::Kind::Type);
  NodePointer LabelList = popFunctionParamLabels(Type);
  NodePointer Name = popNode(isDeclName);
  NodePointer Context = popContext();
  return LabelList ? createWithChildren(Kind, Context, Name, LabelList, Type)
                   : createWithChildren(Kind, Context, Name, Type);
}

NodePointer Demangler::demangleVariable() {
  NodePointer Variable = demangleEntity(Node::Kind::Variable);
  return demangleAccessor(Variable);
}

NodePointer Demangler::demangleSubscript() {
  NodePointer PrivateName = popNode(Node::Kind::PrivateDeclName);
  NodePointer Type = popNode(Node::Kind::Type);
  NodePointer LabelList = popFunctionParamLabels(Type);
  NodePointer Context = popContext();

  NodePointer Subscript = createNode(Node::Kind::Subscript);
  Subscript = addChild(Subscript, Context);
  addChild(Subscript, LabelList);
  Subscript = addChild(Subscript, Type);
  addChild(Subscript, PrivateName);

  return demangleAccessor(Subscript);
}

NodePointer Demangler::demangleProtocolList() {
  NodePointer TypeList = createNode(Node::Kind::TypeList);
  NodePointer ProtoList = createWithChild(Node::Kind::ProtocolList, TypeList);
  if (!popNode(Node::Kind::EmptyList)) {
    bool firstElem = false;
    do {
      firstElem = (popNode(Node::Kind::FirstElementMarker) != nullptr);
      NodePointer Proto = popProtocol();
      if (!Proto)
        return nullptr;
      TypeList->addChild(Proto, *this);
    } while (!firstElem);

    TypeList->reverseChildren();
  }
  return ProtoList;
}

NodePointer Demangler::demangleProtocolListType() {
  NodePointer ProtoList = demangleProtocolList();
  return createType(ProtoList);
}

NodePointer Demangler::demangleGenericSignature(bool hasParamCounts) {
  NodePointer Sig = createNode(Node::Kind::DependentGenericSignature);
  if (hasParamCounts) {
    while (!nextIf('l')) {
      int count = 0;
      if (!nextIf('z'))
        count = demangleIndex() + 1;
      if (count < 0)
        return nullptr;
      Sig->addChild(createNode(Node::Kind::DependentGenericParamCount,
                                        count), *this);
    }
  } else {
    Sig->addChild(createNode(Node::Kind::DependentGenericParamCount, 1),
                  *this);
  }
  size_t NumCounts = Sig->getNumChildren();
  while (NodePointer Req = popNode(isRequirement)) {
    Sig->addChild(Req, *this);
  }
  Sig->reverseChildren(NumCounts);
  return Sig;
}

NodePointer Demangler::demangleGenericRequirement() {
  
  enum { Generic, Assoc, CompoundAssoc, Substitution } TypeKind;
  enum { Protocol, BaseClass, SameType, Layout } ConstraintKind;
  
  switch (nextChar()) {
    case 'c': ConstraintKind = BaseClass; TypeKind = Assoc; break;
    case 'C': ConstraintKind = BaseClass; TypeKind = CompoundAssoc; break;
    case 'b': ConstraintKind = BaseClass; TypeKind = Generic; break;
    case 'B': ConstraintKind = BaseClass; TypeKind = Substitution; break;
    case 't': ConstraintKind = SameType; TypeKind = Assoc; break;
    case 'T': ConstraintKind = SameType; TypeKind = CompoundAssoc; break;
    case 's': ConstraintKind = SameType; TypeKind = Generic; break;
    case 'S': ConstraintKind = SameType; TypeKind = Substitution; break;
    case 'm': ConstraintKind = Layout; TypeKind = Assoc; break;
    case 'M': ConstraintKind = Layout; TypeKind = CompoundAssoc; break;
    case 'l': ConstraintKind = Layout; TypeKind = Generic; break;
    case 'L': ConstraintKind = Layout; TypeKind = Substitution; break;
    case 'p': ConstraintKind = Protocol; TypeKind = Assoc; break;
    case 'P': ConstraintKind = Protocol; TypeKind = CompoundAssoc; break;
    case 'Q': ConstraintKind = Protocol; TypeKind = Substitution; break;
    default:  ConstraintKind = Protocol; TypeKind = Generic; pushBack(); break;
  }

  NodePointer ConstrTy = nullptr;

  switch (TypeKind) {
  case Generic:
    ConstrTy = createType(demangleGenericParamIndex());
    break;
  case Assoc:
    ConstrTy = demangleAssociatedTypeSimple(demangleGenericParamIndex());
    addSubstitution(ConstrTy);
    break;
  case CompoundAssoc:
    ConstrTy = demangleAssociatedTypeCompound(demangleGenericParamIndex());
    addSubstitution(ConstrTy);
    break;
  case Substitution:
    ConstrTy = popNode(Node::Kind::Type);
    break;
  }

  switch (ConstraintKind) {
  case Protocol:
    return createWithChildren(
        Node::Kind::DependentGenericConformanceRequirement, ConstrTy,
        popProtocol());
  case BaseClass:
    return createWithChildren(
        Node::Kind::DependentGenericConformanceRequirement, ConstrTy,
        popNode(Node::Kind::Type));
  case SameType:
    return createWithChildren(Node::Kind::DependentGenericSameTypeRequirement,
                              ConstrTy, popNode(Node::Kind::Type));
  case Layout: {
    auto c = nextChar();
    NodePointer size = nullptr;
    NodePointer alignment = nullptr;
    const char *name = nullptr;
    if (c == 'U') {
      name = "U";
    } else if (c == 'R') {
      name = "R";
    } else if (c == 'N') {
      name = "N";
    } else if (c == 'C') {
      name = "C";
    } else if (c == 'D') {
      name = "D";
    } else if (c == 'T') {
      name = "T";
    } else if (c == 'E') {
      size = demangleIndexAsNode();
      if (!size)
        return nullptr;
      alignment = demangleIndexAsNode();
      name = "E";
    } else if (c == 'e') {
      size = demangleIndexAsNode();
      if (!size)
        return nullptr;
      name = "e";
    } else if (c == 'M') {
      size = demangleIndexAsNode();
      if (!size)
        return nullptr;
      alignment = demangleIndexAsNode();
      name = "M";
    } else if (c == 'm') {
      size = demangleIndexAsNode();
      if (!size)
        return nullptr;
      name = "m";
    } else {
      // Unknown layout constraint.
      return nullptr;
    }

    auto NameNode = createNode(Node::Kind::Identifier, name);
    auto LayoutRequirement = createWithChildren(
        Node::Kind::DependentGenericLayoutRequirement, ConstrTy, NameNode);
    if (size)
      addChild(LayoutRequirement, size);
    if (alignment)
      addChild(LayoutRequirement, alignment);
    return LayoutRequirement;
  }
  }
  return nullptr;
}

NodePointer Demangler::demangleGenericType() {
  NodePointer GenSig = popNode(Node::Kind::DependentGenericSignature);
  NodePointer Ty = popNode(Node::Kind::Type);
  return createType(createWithChildren(Node::Kind::DependentGenericType,
                                       GenSig, Ty));
}

static int decodeValueWitnessKind(StringRef CodeStr) {
#define VALUE_WITNESS(MANGLING, NAME) \
  if (CodeStr == #MANGLING) return (int)ValueWitnessKind::NAME;
#include "swift/Demangling/ValueWitnessMangling.def"
  return -1;
}

NodePointer Demangler::demangleValueWitness() {
  char Code[2];
  Code[0] = nextChar();
  Code[1] = nextChar();
  int Kind = decodeValueWitnessKind(StringRef(Code, 2));
  if (Kind < 0)
    return nullptr;
  NodePointer VW = createNode(Node::Kind::ValueWitness);
  addChild(VW, createNode(Node::Kind::Index, unsigned(Kind)));
  return addChild(VW, popNode(Node::Kind::Type));
}
