NodePointer NodePrinter::print()

in lib/Demangling/NodePrinter.cpp [1161:2939]


NodePointer NodePrinter::print(NodePointer Node, unsigned depth,
                               bool asPrefixContext) {
  if (depth > NodePrinter::MaxDepth) {
    Printer << "<<too complex>>";
    return nullptr;
  }

  if (!Node) {
    Printer << "<null node pointer>";
    return nullptr;
  }

  switch (auto kind = Node->getKind()) {
  case Node::Kind::Static:
    Printer << "static ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::CurryThunk:
    Printer << "curry thunk of ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::DispatchThunk:
    Printer << "dispatch thunk of ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::MethodDescriptor:
    Printer << "method descriptor for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::MethodLookupFunction:
    Printer << "method lookup function for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::ObjCMetadataUpdateFunction:
    Printer << "ObjC metadata update function for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::ObjCResilientClassStub:
    Printer << "ObjC resilient class stub for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::FullObjCResilientClassStub:
    Printer << "full ObjC resilient class stub for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::OutlinedBridgedMethod:
    Printer << "outlined bridged method (" << Node->getText() << ") of ";
    return nullptr;
  case Node::Kind::OutlinedCopy:
    Printer << "outlined copy of ";
    print(Node->getChild(0), depth + 1);
    if (Node->getNumChildren() > 1)
      print(Node->getChild(1), depth + 1);
    return nullptr;
  case Node::Kind::OutlinedConsume:
    Printer << "outlined consume of ";
    print(Node->getChild(0), depth + 1);
    if (Node->getNumChildren() > 1)
      print(Node->getChild(1), depth + 1);
    return nullptr;
  case Node::Kind::OutlinedRetain:
    Printer << "outlined retain of ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::OutlinedRelease:
    Printer << "outlined release of ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::OutlinedInitializeWithTake:
    Printer << "outlined init with take of ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::OutlinedInitializeWithCopy:
    Printer << "outlined init with copy of ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::OutlinedAssignWithTake:
    Printer << "outlined assign with take of ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::OutlinedAssignWithCopy:
    Printer << "outlined assign with copy of ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::OutlinedDestroy:
    Printer << "outlined destroy of ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::OutlinedVariable:
    Printer << "outlined variable #" << Node->getIndex() << " of ";
    return nullptr;
  case Node::Kind::Directness:
    Printer << toString(Directness(Node->getIndex())) << " ";
    return nullptr;
  case Node::Kind::AnonymousContext:
    if (Options.QualifyEntities && Options.DisplayExtensionContexts) {
      print(Node->getChild(1), depth + 1);
      Printer << ".(unknown context at ";
      print(Node->getChild(0), depth + 1);
      Printer << ")";
      if (Node->getNumChildren() >= 3 &&
          Node->getChild(2)->getNumChildren() > 0) {
        Printer << '<';
        print(Node->getChild(2), depth + 1);
        Printer << '>';
      }
    }
    return nullptr;
  case Node::Kind::Extension:
    assert((Node->getNumChildren() == 2 || Node->getNumChildren() == 3)
           && "Extension expects 2 or 3 children.");
    if (Options.QualifyEntities && Options.DisplayExtensionContexts) {
      Printer << "(extension in ";
      // Print the module where extension is defined.
      print(Node->getChild(0), depth + 1, true);
      Printer << "):";
    }
    print(Node->getChild(1), depth + 1);
    if (Node->getNumChildren() == 3) {
      // Currently the runtime does not mangle the generic signature.
      // This is an open to-do in swift::_buildDemanglingForContext().
      if (!Options.PrintForTypeName)
        print(Node->getChild(2), depth + 1);
    }
    return nullptr;
  case Node::Kind::Variable:
    return printEntity(Node, depth, asPrefixContext, TypePrinting::WithColon,
                       /*hasName*/ true);
  case Node::Kind::Function:
  case Node::Kind::BoundGenericFunction:
    return printEntity(Node, depth, asPrefixContext,
                       TypePrinting::FunctionStyle,
                       /*hasName*/ true);
  case Node::Kind::Subscript:
    return printEntity(
        Node, depth, asPrefixContext, TypePrinting::FunctionStyle,
        /*hasName*/ false, /*ExtraName*/ "", /*ExtraIndex*/ -1, "subscript");
  case Node::Kind::GenericTypeParamDecl:
    return printEntity(Node, depth, asPrefixContext, TypePrinting::NoType,
                       /*hasName*/ true);
  case Node::Kind::ExplicitClosure:
    return printEntity(
        Node, depth, asPrefixContext,
        Options.ShowFunctionArgumentTypes ? TypePrinting::FunctionStyle
                                          : TypePrinting::NoType,
        /*hasName*/ false, "closure #", (int)Node->getChild(1)->getIndex() + 1);
  case Node::Kind::ImplicitClosure:
    return printEntity(Node, depth, asPrefixContext,
                       Options.ShowFunctionArgumentTypes
                           ? TypePrinting::FunctionStyle
                           : TypePrinting::NoType,
                       /*hasName*/ false, "implicit closure #",
                       (int)Node->getChild(1)->getIndex() + 1);
  case Node::Kind::Global:
    printChildren(Node, depth);
    return nullptr;
  case Node::Kind::Suffix:
    if (Options.DisplayUnmangledSuffix) {
      Printer << " with unmangled suffix "
              << QuotedString(Node->getText().str());
    }
    return nullptr;
  case Node::Kind::Initializer:
    return printEntity(Node, depth, asPrefixContext, TypePrinting::NoType,
                       /*hasName*/ false, "variable initialization expression");
  case Node::Kind::PropertyWrapperBackingInitializer:
    return printEntity(Node, depth, asPrefixContext, TypePrinting::NoType,
                       /*hasName*/ false,
                       "property wrapper backing initializer");
  case Node::Kind::PropertyWrapperInitFromProjectedValue:
    return printEntity(Node, depth, asPrefixContext, TypePrinting::NoType,
                       /*hasName*/ false,
                       "property wrapper init from projected value");
  case Node::Kind::DefaultArgumentInitializer:
    return printEntity(Node, depth, asPrefixContext, TypePrinting::NoType,
                       /*hasName*/ false, "default argument ",
                       (int)Node->getChild(1)->getIndex());
  case Node::Kind::DeclContext:
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::Type:
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::TypeMangling:
    if (Node->getChild(0)->getKind() == Node::Kind::LabelList) {
      printFunctionType(Node->getChild(0), Node->getChild(1)->getFirstChild(),
                        depth);
    } else {
      print(Node->getChild(0), depth + 1);
    }
    return nullptr;
  case Node::Kind::Class:
  case Node::Kind::Structure:
  case Node::Kind::Enum:
  case Node::Kind::Protocol:
  case Node::Kind::TypeAlias:
  case Node::Kind::OtherNominalType:
    return printEntity(Node, depth, asPrefixContext, TypePrinting::NoType,
                       /*hasName*/ true);
  case Node::Kind::LocalDeclName:
    print(Node->getChild(1), depth + 1);
    if (Options.DisplayLocalNameContexts)
      Printer << " #" << (Node->getChild(0)->getIndex() + 1);
    return nullptr;
  case Node::Kind::PrivateDeclName:
    if (Node->getNumChildren() > 1) {
      if (Options.ShowPrivateDiscriminators)
        Printer << '(';

      print(Node->getChild(1), depth + 1);

      if (Options.ShowPrivateDiscriminators)
        Printer << " in " << Node->getChild(0)->getText() << ')';
    } else {
      if (Options.ShowPrivateDiscriminators) {
        Printer << "(in " << Node->getChild(0)->getText() << ')';
      }
    }
    return nullptr;
  case Node::Kind::RelatedEntityDeclName:
    Printer << "related decl '" << Node->getFirstChild()->getText() << "' for ";
    print(Node->getChild(1), depth + 1);
    return nullptr;
  case Node::Kind::Module:
    if (Options.DisplayModuleNames)
      Printer << Node->getText();
    return nullptr;
  case Node::Kind::Identifier:
    Printer << Node->getText();
    return nullptr;
  case Node::Kind::Index:
    Printer << Node->getIndex();
    return nullptr;
  case Node::Kind::UnknownIndex:
    Printer << "unknown index";
    return nullptr;
  case Node::Kind::FunctionType:
  case Node::Kind::UncurriedFunctionType:
  case Node::Kind::NoEscapeFunctionType:
  case Node::Kind::AutoClosureType:
  case Node::Kind::EscapingAutoClosureType:
  case Node::Kind::ThinFunctionType:
  case Node::Kind::CFunctionPointer:
  case Node::Kind::ObjCBlock:
  case Node::Kind::EscapingObjCBlock:
    printFunctionType(nullptr, Node, depth);
    return nullptr;
  case Node::Kind::ClangType:
    Printer << Node->getText();
    return nullptr;
  case Node::Kind::ArgumentTuple:
    printFunctionParameters(nullptr, Node, depth,
                            Options.ShowFunctionArgumentTypes);
    return nullptr;
  case Node::Kind::Tuple: {
    Printer << "(";
    printChildren(Node, depth, ", ");
    Printer << ")";
    return nullptr;
  }
  case Node::Kind::TupleElement: {
    if (auto Label = getChildIf(Node, Node::Kind::TupleElementName))
      Printer << Label->getText() << ": ";

    auto Type = getChildIf(Node, Node::Kind::Type);
    assert(Type && "malformed Node::Kind::TupleElement");

    print(Type, depth + 1);

    if (getChildIf(Node, Node::Kind::VariadicMarker))
      Printer << "...";
    return nullptr;
  }
  case Node::Kind::TupleElementName:
    Printer << Node->getText() << ": ";
    return nullptr;
  case Node::Kind::ReturnType:
    if (Node->getNumChildren() == 0)
      Printer << " -> " << Node->getText();
    else {
      Printer << " -> ";
      printChildren(Node, depth);
    }
    return nullptr;
  case Node::Kind::RetroactiveConformance:
    if (Node->getNumChildren() != 2)
      return nullptr;

    Printer << "retroactive @ ";
    print(Node->getChild(0), depth + 1);
    print(Node->getChild(1), depth + 1);
    return nullptr;
#define REF_STORAGE(Name, ...)                                                 \
  case Node::Kind::Name:                                                       \
    Printer << keywordOf(ReferenceOwnership::Name) << " ";                     \
    print(Node->getChild(0), depth + 1);                                       \
    return nullptr;
#include "swift/AST/ReferenceStorage.def"
  case Node::Kind::InOut:
    Printer << "inout ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::Isolated:
    Printer << "isolated ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::CompileTimeConst:
    Printer << "_const ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::Shared:
    Printer << "__shared ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::Owned:
    Printer << "__owned ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::NoDerivative:
    Printer << "@noDerivative ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::NonObjCAttribute:
    Printer << "@nonobjc ";
    return nullptr;
  case Node::Kind::ObjCAttribute:
    Printer << "@objc ";
    return nullptr;
  case Node::Kind::DirectMethodReferenceAttribute:
    Printer << "super ";
    return nullptr;
  case Node::Kind::DynamicAttribute:
    Printer << "dynamic ";
    return nullptr;
  case Node::Kind::VTableAttribute:
    Printer << "override ";
    return nullptr;
  case Node::Kind::FunctionSignatureSpecialization:
    printSpecializationPrefix(Node, "function signature specialization", depth);
    return nullptr;
  case Node::Kind::GenericPartialSpecialization:
    printSpecializationPrefix(Node, "generic partial specialization", depth,
                              "Signature = ");
    return nullptr;
  case Node::Kind::GenericPartialSpecializationNotReAbstracted:
    printSpecializationPrefix(Node,
                              "generic not-reabstracted partial specialization",
                              depth, "Signature = ");
    return nullptr;
  case Node::Kind::GenericSpecialization:
  case Node::Kind::GenericSpecializationInResilienceDomain:
    printSpecializationPrefix(Node, "generic specialization", depth);
    return nullptr;
  case Node::Kind::GenericSpecializationPrespecialized:
    printSpecializationPrefix(Node, "generic pre-specialization", depth);
    return nullptr;
  case Node::Kind::GenericSpecializationNotReAbstracted:
    printSpecializationPrefix(Node, "generic not re-abstracted specialization",
                              depth);
    return nullptr;
  case Node::Kind::InlinedGenericFunction:
    printSpecializationPrefix(Node, "inlined generic function", depth);
    return nullptr;
  case Node::Kind::IsSerialized:
    Printer << "serialized";
    return nullptr;
  case Node::Kind::GenericSpecializationParam:
    print(Node->getChild(0), depth + 1);
    for (unsigned i = 1, e = Node->getNumChildren(); i < e; ++i) {
      if (i == 1)
        Printer << " with ";
      else
        Printer << " and ";
      print(Node->getChild(i), depth + 1);
    }
    return nullptr;
  case Node::Kind::FunctionSignatureSpecializationReturn:
  case Node::Kind::FunctionSignatureSpecializationParam:
    printer_unreachable("should be handled in printSpecializationPrefix");
  case Node::Kind::FunctionSignatureSpecializationParamPayload: {
    std::string demangledName = demangleSymbolAsString(Node->getText());
    if (demangledName.empty()) {
      Printer << Node->getText();
    } else {
      Printer << demangledName;
    }
    return nullptr;
  }
  case Node::Kind::FunctionSignatureSpecializationParamKind: {
    uint64_t raw = Node->getIndex();

    bool printedOptionSet = false;
    if (raw &
        uint64_t(FunctionSigSpecializationParamKind::ExistentialToGeneric)) {
      printedOptionSet = true;
      Printer << "Existential To Protocol Constrained Generic";
    }

    if (raw & uint64_t(FunctionSigSpecializationParamKind::Dead)) {
      if (printedOptionSet)
        Printer << " and ";
      printedOptionSet = true;
      Printer << "Dead";
    }
    if (raw & uint64_t(FunctionSigSpecializationParamKind::OwnedToGuaranteed)) {
      if (printedOptionSet)
        Printer << " and ";
      printedOptionSet = true;
      Printer << "Owned To Guaranteed";
    }

    if (raw & uint64_t(FunctionSigSpecializationParamKind::GuaranteedToOwned)) {
      if (printedOptionSet)
        Printer << " and ";
      printedOptionSet = true;
      Printer << "Guaranteed To Owned";
    }

    if (raw & uint64_t(FunctionSigSpecializationParamKind::SROA)) {
      if (printedOptionSet)
        Printer << " and ";
      Printer << "Exploded";
      return nullptr;
    }

    if (printedOptionSet)
      return nullptr;

    switch (FunctionSigSpecializationParamKind(raw)) {
    case FunctionSigSpecializationParamKind::BoxToValue:
      Printer << "Value Promoted from Box";
      return nullptr;
    case FunctionSigSpecializationParamKind::BoxToStack:
      Printer << "Stack Promoted from Box";
      return nullptr;
    case FunctionSigSpecializationParamKind::InOutToOut:
      Printer << "InOut Converted to Out";
      return nullptr;
    case FunctionSigSpecializationParamKind::ConstantPropFunction:
      Printer << "Constant Propagated Function";
      return nullptr;
    case FunctionSigSpecializationParamKind::ConstantPropGlobal:
      Printer << "Constant Propagated Global";
      return nullptr;
    case FunctionSigSpecializationParamKind::ConstantPropInteger:
      Printer << "Constant Propagated Integer";
      return nullptr;
    case FunctionSigSpecializationParamKind::ConstantPropFloat:
      Printer << "Constant Propagated Float";
      return nullptr;
    case FunctionSigSpecializationParamKind::ConstantPropString:
      Printer << "Constant Propagated String";
      return nullptr;
    case FunctionSigSpecializationParamKind::ClosureProp:
      Printer << "Closure Propagated";
      return nullptr;
    case FunctionSigSpecializationParamKind::ExistentialToGeneric:
    case FunctionSigSpecializationParamKind::Dead:
    case FunctionSigSpecializationParamKind::OwnedToGuaranteed:
    case FunctionSigSpecializationParamKind::GuaranteedToOwned:
    case FunctionSigSpecializationParamKind::SROA:
      printer_unreachable("option sets should have been handled earlier");
    }
    return nullptr;
  }
  case Node::Kind::SpecializationPassID:
    Printer << Node->getIndex();
    return nullptr;
  case Node::Kind::BuiltinTypeName:
    Printer << Node->getText();
    return nullptr;
  case Node::Kind::Number:
    Printer << Node->getIndex();
    return nullptr;
  case Node::Kind::InfixOperator:
    Printer << Node->getText() << " infix";
    return nullptr;
  case Node::Kind::PrefixOperator:
    Printer << Node->getText() << " prefix";
    return nullptr;
  case Node::Kind::PostfixOperator:
    Printer << Node->getText() << " postfix";
    return nullptr;
  case Node::Kind::LazyProtocolWitnessTableAccessor:
    Printer << "lazy protocol witness table accessor for type ";
    print(Node->getChild(0), depth + 1);
    Printer << " and conformance ";
    print(Node->getChild(1), depth + 1);
    return nullptr;
  case Node::Kind::LazyProtocolWitnessTableCacheVariable:
    Printer << "lazy protocol witness table cache variable for type ";
    print(Node->getChild(0), depth + 1);
    Printer << " and conformance ";
    print(Node->getChild(1), depth + 1);
    return nullptr;
  case Node::Kind::ProtocolSelfConformanceWitnessTable:
    Printer << "protocol self-conformance witness table for ";
    print(Node->getFirstChild(), depth + 1);
    return nullptr;
  case Node::Kind::ProtocolWitnessTableAccessor:
    Printer << "protocol witness table accessor for ";
    print(Node->getFirstChild(), depth + 1);
    return nullptr;
  case Node::Kind::ProtocolWitnessTable:
    Printer << "protocol witness table for ";
    print(Node->getFirstChild(), depth + 1);
    return nullptr;
  case Node::Kind::ProtocolWitnessTablePattern:
    Printer << "protocol witness table pattern for ";
    print(Node->getFirstChild(), depth + 1);
    return nullptr;
  case Node::Kind::GenericProtocolWitnessTable:
    Printer << "generic protocol witness table for ";
    print(Node->getFirstChild(), depth + 1);
    return nullptr;
  case Node::Kind::GenericProtocolWitnessTableInstantiationFunction:
    Printer << "instantiation function for generic protocol witness table for ";
    print(Node->getFirstChild(), depth + 1);
    return nullptr;
  case Node::Kind::ResilientProtocolWitnessTable:
    Printer << "resilient protocol witness table for ";
    print(Node->getFirstChild(), depth + 1);
    return nullptr;
  case Node::Kind::VTableThunk: {
    Printer << "vtable thunk for ";
    print(Node->getChild(1), depth + 1);
    Printer << " dispatching to ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  }
  case Node::Kind::ProtocolSelfConformanceWitness: {
    Printer << "protocol self-conformance witness for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  }
  case Node::Kind::ProtocolWitness: {
    Printer << "protocol witness for ";
    print(Node->getChild(1), depth + 1);
    Printer << " in conformance ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  }
  case Node::Kind::PartialApplyForwarder:
    if (Options.ShortenPartialApply)
      Printer << "partial apply";
    else
      Printer << "partial apply forwarder";

    if (Node->hasChildren()) {
      Printer << " for ";
      printChildren(Node, depth);
    }
    return nullptr;
  case Node::Kind::PartialApplyObjCForwarder:
    if (Options.ShortenPartialApply)
      Printer << "partial apply";
    else
      Printer << "partial apply ObjC forwarder";

    if (Node->hasChildren()) {
      Printer << " for ";
      printChildren(Node, depth);
    }
    return nullptr;
  case Node::Kind::KeyPathGetterThunkHelper:
  case Node::Kind::KeyPathSetterThunkHelper:
    if (Node->getKind() == Node::Kind::KeyPathGetterThunkHelper)
      Printer << "key path getter for ";
    else
      Printer << "key path setter for ";

    print(Node->getChild(0), depth + 1);
    Printer << " : ";
    for (unsigned index = 1; index < Node->getNumChildren(); ++index) {
      auto Child = Node->getChild(index);
      if (Child->getKind() == Node::Kind::IsSerialized)
        Printer << ", ";
      print(Child, depth + 1);
    }
    return nullptr;
  case Node::Kind::KeyPathEqualsThunkHelper:
  case Node::Kind::KeyPathHashThunkHelper: {
    Printer << "key path index "
         << (Node->getKind() == Node::Kind::KeyPathEqualsThunkHelper
               ? "equality" : "hash")
         << " operator for ";

    unsigned lastChildIndex = Node->getNumChildren();
    auto lastChild = Node->getChild(lastChildIndex - 1);
    if (lastChild->getKind() == Node::Kind::IsSerialized) {
      --lastChildIndex;
      lastChild = Node->getChild(lastChildIndex - 1);
    }

    if (lastChild->getKind() == Node::Kind::DependentGenericSignature) {
      print(lastChild, depth + 1);
      --lastChildIndex;
    }

    Printer << "(";
    for (unsigned i = 0; i < lastChildIndex; ++i) {
      if (i != 0)
        Printer << ", ";
      print(Node->getChild(i), depth + 1);
    }
    Printer << ")";
    return nullptr;
  }
  case Node::Kind::FieldOffset: {
    print(Node->getChild(0), depth + 1); // directness
    Printer << "field offset for ";
    auto entity = Node->getChild(1);
    print(entity, depth + 1, /*asContext*/ false);
    return nullptr;
  }
  case Node::Kind::EnumCase: {
    Printer << "enum case for ";
    auto entity = Node->getChild(0);
    print(entity, depth + 1, /*asContext*/ false);
    return nullptr;
  }
  case Node::Kind::ReabstractionThunk:
  case Node::Kind::ReabstractionThunkHelper: {
    if (Options.ShortenThunk) {
      Printer << "thunk for ";
      print(Node->getChild(Node->getNumChildren() - 1), depth + 1);
      return nullptr;
    }
    Printer << "reabstraction thunk ";
    if (Node->getKind() == Node::Kind::ReabstractionThunkHelper)
      Printer << "helper ";
    unsigned idx = 0;
    if (Node->getNumChildren() == 3) {
      auto generics = Node->getChild(0);
      idx = 1;
      print(generics, depth + 1);
      Printer << " ";
    }
    Printer << "from ";
    print(Node->getChild(idx + 1), depth + 1);
    Printer << " to ";
    print(Node->getChild(idx), depth + 1);
    return nullptr;
  }
  case Node::Kind::ReabstractionThunkHelperWithGlobalActor: {
    print(Node->getChild(0), depth + 1);
    Printer << " with global actor constraint ";
    print(Node->getChild(1), depth + 1);
    return nullptr;
  }
  case Node::Kind::ReabstractionThunkHelperWithSelf: {
    Printer << "reabstraction thunk ";
    unsigned idx = 0;
    if (Node->getNumChildren() == 4) {
      auto generics = Node->getChild(0);
      idx = 1;
      print(generics, depth + 1);
      Printer << " ";
    }
    Printer << "from ";
    print(Node->getChild(idx + 2), depth + 1);
    Printer << " to ";
    print(Node->getChild(idx + 1), depth + 1);
    Printer << " self ";
    print(Node->getChild(idx), depth + 1);
    return nullptr;
  }
  case Node::Kind::AutoDiffFunction:
  case Node::Kind::AutoDiffDerivativeVTableThunk: {
    unsigned prefixEndIndex = 0;
    while (prefixEndIndex != Node->getNumChildren() &&
           Node->getChild(prefixEndIndex)->getKind()
              != Node::Kind::AutoDiffFunctionKind)
      ++prefixEndIndex;
    auto funcKind = Node->getChild(prefixEndIndex);
    auto paramIndices = Node->getChild(prefixEndIndex + 1);
    auto resultIndices = Node->getChild(prefixEndIndex + 2);
    if (kind == Node::Kind::AutoDiffDerivativeVTableThunk)
      Printer << "vtable thunk for ";
    print(funcKind, depth + 1);
    Printer << " of ";
    NodePointer optionalGenSig = nullptr;
    for (unsigned i = 0; i < prefixEndIndex; ++i) {
      // The last node may be a generic signature. If so, print it later.
      if (i == prefixEndIndex - 1 &&
          Node->getChild(i)->getKind()
              == Node::Kind::DependentGenericSignature) {
        optionalGenSig = Node->getChild(i);
        break;
      }
      print(Node->getChild(i), depth + 1);
    }
    if (Options.ShortenThunk)
      return nullptr;
    Printer << " with respect to parameters ";
    print(paramIndices, depth + 1);
    Printer << " and results ";
    print(resultIndices, depth + 1);
    if (optionalGenSig && Options.DisplayWhereClauses) {
      Printer << " with ";
      print(optionalGenSig, depth + 1);
    }
    return nullptr;
  }
  case Node::Kind::AutoDiffSelfReorderingReabstractionThunk: {
    Printer << "autodiff self-reordering reabstraction thunk ";
    auto childIt = Node->begin();
    auto fromType = *childIt++;
    auto toType = *childIt++;
    if (Options.ShortenThunk) {
      Printer << "for ";
      print(fromType, depth + 1);
      return nullptr;
    }
    NodePointer optionalGenSig =
        (*childIt)->getKind() == Node::Kind::DependentGenericSignature
            ? *childIt++ : nullptr;
    Printer << "for ";
    print(*childIt++, depth + 1); // kind
    if (optionalGenSig) {
      print(optionalGenSig, depth + 1);
      Printer << ' ';
    }
    Printer << " from ";
    print(fromType, depth + 1);
    Printer << " to ";
    print(toType, depth + 1);
    return nullptr;
  }
  case Node::Kind::AutoDiffSubsetParametersThunk: {
    Printer << "autodiff subset parameters thunk for ";
    auto currentIndex = Node->getNumChildren() - 1;
    auto toParamIndices = Node->getChild(currentIndex--);
    auto resultIndices = Node->getChild(currentIndex--);
    auto paramIndices = Node->getChild(currentIndex--);
    auto kind = Node->getChild(currentIndex--);
    print(kind, depth + 1);
    Printer << " from ";
    // Print the "from" thing.
    if (currentIndex == 0) {
      print(Node->getFirstChild(), depth + 1); // the "from" type
    } else {
      for (unsigned i = 0; i < currentIndex; ++i) // the "from" global
        print(Node->getChild(i), depth + 1);
    }
    if (Options.ShortenThunk)
      return nullptr;
    Printer << " with respect to parameters ";
    print(paramIndices, depth + 1);
    Printer << " and results ";
    print(resultIndices, depth + 1);
    Printer << " to parameters ";
    print(toParamIndices, depth + 1);
    if (currentIndex > 0) {
      Printer << " of type ";
      print(Node->getChild(currentIndex), depth + 1); // "to" type
    }
    return nullptr;
  }
  case Node::Kind::AutoDiffFunctionKind: {
    auto kind = (AutoDiffFunctionKind)Node->getIndex();
    switch (kind) {
    case AutoDiffFunctionKind::JVP:
      Printer << "forward-mode derivative";
      break;
    case AutoDiffFunctionKind::VJP:
      Printer << "reverse-mode derivative";
      break;
    case AutoDiffFunctionKind::Differential:
      Printer << "differential";
      break;
    case AutoDiffFunctionKind::Pullback:
      Printer << "pullback";
      break;
    }
    return nullptr;
  }
  case Node::Kind::DifferentiabilityWitness: {
    auto kindNodeIndex = Node->getNumChildren() - (
        Node->getLastChild()->getKind() == Node::Kind::DependentGenericSignature
            ? 4 : 3);
    auto kind =
        (MangledDifferentiabilityKind)Node->getChild(kindNodeIndex)->getIndex();
    switch (kind) {
    case MangledDifferentiabilityKind::Forward:
      Printer << "forward-mode";
      break;
    case MangledDifferentiabilityKind::Reverse:
      Printer << "reverse-mode";
      break;
    case MangledDifferentiabilityKind::Normal:
      Printer << "normal";
      break;
    case MangledDifferentiabilityKind::Linear:
      Printer << "linear";
      break;
    case MangledDifferentiabilityKind::NonDifferentiable:
      assert(false && "Impossible case");
    }
    Printer << " differentiability witness for ";
    unsigned idx = 0;
    for (auto numChildren = Node->getNumChildren();
         idx < numChildren &&
             Node->getChild(idx)->getKind() != Node::Kind::Index; ++idx)
      print(Node->getChild(idx), depth + 1);
    ++idx; // kind (handled earlier)
    Printer << " with respect to parameters ";
    print(Node->getChild(idx++), depth + 1); // parameter indices
    Printer << " and results ";
    print(Node->getChild(idx++), depth + 1);
    if (idx < Node->getNumChildren()) {
      auto *genSig = Node->getChild(idx);
      assert(genSig->getKind() == Node::Kind::DependentGenericSignature);
      Printer << " with ";
      print(genSig, depth + 1);
    }
    return nullptr;
  }
  case Node::Kind::IndexSubset: {
    Printer << '{';
        auto text = Node->getText();
    bool printedAnyIndex = false;
    for (unsigned i = 0, n = text.size(); i < n; ++i) {
      if (text[i] != 'S') {
        assert(text[i] == 'U');
        continue;
      }
      if (printedAnyIndex)
        Printer << ", ";
      Printer << i;
      printedAnyIndex = true;
    }
    Printer << '}';
    return nullptr;
  }
  case Node::Kind::MergedFunction:
    if (!Options.ShortenThunk) {
      Printer << "merged ";
    }
    return nullptr;
  case Node::Kind::TypeSymbolicReference:
    Printer << "type symbolic reference 0x";
    Printer.writeHex(Node->getIndex());
    return nullptr;
  case Node::Kind::OpaqueTypeDescriptorSymbolicReference:
    Printer << "opaque type symbolic reference 0x";
    Printer.writeHex(Node->getIndex());
    return nullptr;
  case Node::Kind::DistributedThunk:
    if (!Options.ShortenThunk) {
      Printer << "distributed thunk for ";
    }
    return nullptr;
  case Node::Kind::DistributedAccessor:
    if (!Options.ShortenThunk) {
      Printer << "distributed accessor for ";
    }
    return nullptr;
  case Node::Kind::AccessibleFunctionRecord:
    if (!Options.ShortenThunk) {
      Printer << "accessible function runtime record for ";
    }
    return nullptr;
  case Node::Kind::DynamicallyReplaceableFunctionKey:
    if (!Options.ShortenThunk) {
      Printer << "dynamically replaceable key for ";
    }
    return nullptr;
  case Node::Kind::DynamicallyReplaceableFunctionImpl:
    if (!Options.ShortenThunk) {
      Printer << "dynamically replaceable thunk for ";
    }
    return nullptr;
  case Node::Kind::DynamicallyReplaceableFunctionVar:
    if (!Options.ShortenThunk) {
      Printer << "dynamically replaceable variable for ";
    }
    return nullptr;
  case Node::Kind::ProtocolSymbolicReference:
    Printer << "protocol symbolic reference 0x";
    Printer.writeHex(Node->getIndex());
    return nullptr;
  case Node::Kind::GenericTypeMetadataPattern:
    Printer << "generic type metadata pattern for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::Metaclass:
    Printer << "metaclass for ";
    print(Node->getFirstChild(), depth + 1);
    return nullptr;
  case Node::Kind::ProtocolSelfConformanceDescriptor:
    Printer << "protocol self-conformance descriptor for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::ProtocolConformanceDescriptor:
    Printer << "protocol conformance descriptor for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::ProtocolConformanceDescriptorRecord:
    Printer << "protocol conformance descriptor runtime record for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::ProtocolDescriptor:
    Printer << "protocol descriptor for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::ProtocolDescriptorRecord:
    Printer << "protocol descriptor runtime record for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::ProtocolRequirementsBaseDescriptor:
    Printer << "protocol requirements base descriptor for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::FullTypeMetadata:
    Printer << "full type metadata for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::TypeMetadata:
    Printer << "type metadata for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::TypeMetadataAccessFunction:
    Printer << "type metadata accessor for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::TypeMetadataInstantiationCache:
    Printer << "type metadata instantiation cache for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::TypeMetadataInstantiationFunction:
    Printer << "type metadata instantiation function for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::TypeMetadataSingletonInitializationCache:
    Printer << "type metadata singleton initialization cache for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::TypeMetadataCompletionFunction:
    Printer << "type metadata completion function for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::TypeMetadataDemanglingCache:
    Printer << "demangling cache variable for type metadata for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::TypeMetadataLazyCache:
    Printer << "lazy cache variable for type metadata for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::AssociatedConformanceDescriptor:
    Printer << "associated conformance descriptor for ";
    print(Node->getChild(0), depth + 1);
    Printer << ".";
    print(Node->getChild(1), depth + 1);
    Printer << ": ";
    print(Node->getChild(2), depth + 1);
    return nullptr;
  case Node::Kind::DefaultAssociatedConformanceAccessor:
    Printer << "default associated conformance accessor for ";
    print(Node->getChild(0), depth + 1);
    Printer << ".";
    print(Node->getChild(1), depth + 1);
    Printer << ": ";
    print(Node->getChild(2), depth + 1);
    return nullptr;
  case Node::Kind::AssociatedTypeDescriptor:
    Printer << "associated type descriptor for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::AssociatedTypeMetadataAccessor:
    Printer << "associated type metadata accessor for ";
    print(Node->getChild(1), depth + 1);
    Printer << " in ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::BaseConformanceDescriptor:
    Printer << "base conformance descriptor for ";
    print(Node->getChild(0), depth + 1);
    Printer << ": ";
    print(Node->getChild(1), depth + 1);
    return nullptr;
  case Node::Kind::DefaultAssociatedTypeMetadataAccessor:
    Printer << "default associated type metadata accessor for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::AssociatedTypeWitnessTableAccessor:
    Printer << "associated type witness table accessor for ";
    print(Node->getChild(1), depth + 1);
    Printer << " : ";
    print(Node->getChild(2), depth + 1);
    Printer << " in ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::BaseWitnessTableAccessor:
    Printer << "base witness table accessor for ";
    print(Node->getChild(1), depth + 1);
    Printer << " in ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::ClassMetadataBaseOffset:
    Printer << "class metadata base offset for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::PropertyDescriptor:
    Printer << "property descriptor for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::NominalTypeDescriptor:
    Printer << "nominal type descriptor for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::NominalTypeDescriptorRecord:
    Printer << "nominal type descriptor runtime record for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::OpaqueTypeDescriptor:
    Printer << "opaque type descriptor for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::OpaqueTypeDescriptorRecord:
    Printer << "opaque type descriptor runtime record for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::OpaqueTypeDescriptorAccessor:
    Printer << "opaque type descriptor accessor for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::OpaqueTypeDescriptorAccessorImpl:
    Printer << "opaque type descriptor accessor impl for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::OpaqueTypeDescriptorAccessorKey:
    Printer << "opaque type descriptor accessor key for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::OpaqueTypeDescriptorAccessorVar:
    Printer << "opaque type descriptor accessor var for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::CoroutineContinuationPrototype:
    Printer << "coroutine continuation prototype for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::ValueWitness:
    Printer << toString(ValueWitnessKind(Node->getFirstChild()->getIndex()));
    if (Options.ShortenValueWitness) Printer << " for ";
    else Printer << " value witness for ";
    print(Node->getChild(1), depth + 1);
    return nullptr;
  case Node::Kind::ValueWitnessTable:
    Printer << "value witness table for ";
    print(Node->getFirstChild(), depth + 1);
    return nullptr;
  case Node::Kind::BoundGenericClass:
  case Node::Kind::BoundGenericStructure:
  case Node::Kind::BoundGenericEnum:
  case Node::Kind::BoundGenericProtocol:
  case Node::Kind::BoundGenericOtherNominalType:
  case Node::Kind::BoundGenericTypeAlias:
    printBoundGeneric(Node, depth);
    return nullptr;
  case Node::Kind::DynamicSelf:
    Printer << "Self";
    return nullptr;
  case Node::Kind::SILBoxType: {
    Printer << "@box ";
    NodePointer type = Node->getChild(0);
    print(type, depth + 1);
    return nullptr;
  }
  case Node::Kind::Metatype: {
    unsigned Idx = 0;
    if (Node->getNumChildren() == 2) {
      NodePointer repr = Node->getChild(Idx);
      print(repr, depth + 1);
      Printer << " ";
      ++Idx;
    }
    NodePointer type = Node->getChild(Idx)->getChild(0);
    printWithParens(type, depth);
    if (isExistentialType(type)) {
      Printer << ".Protocol";
    } else {
      Printer << ".Type";
    }
    return nullptr;
  }
  case Node::Kind::ExistentialMetatype: {
    unsigned Idx = 0;
    if (Node->getNumChildren() == 2) {
      NodePointer repr = Node->getChild(Idx);
      print(repr, depth + 1);
      Printer << " ";
      ++Idx;
    }

    NodePointer type = Node->getChild(Idx);
    print(type, depth + 1);
    Printer << ".Type";
    return nullptr;
  }
  case Node::Kind::MetatypeRepresentation: {
    Printer << Node->getText();
    return nullptr;
  }
  case Node::Kind::AssociatedTypeRef:
    print(Node->getChild(0), depth + 1);
    Printer << '.' << Node->getChild(1)->getText();
    return nullptr;
  case Node::Kind::ProtocolList: {
    NodePointer type_list = Node->getChild(0);
    if (!type_list)
      return nullptr;
    if (type_list->getNumChildren() == 0)
      Printer << "Any";
    else
      printChildren(type_list, depth, " & ");
    return nullptr;
  }
  case Node::Kind::ProtocolListWithClass: {
    if (Node->getNumChildren() < 2)
      return nullptr;
    NodePointer protocols = Node->getChild(0);
    NodePointer superclass = Node->getChild(1);
    print(superclass, depth + 1);
    Printer << " & ";
    if (protocols->getNumChildren() < 1)
      return nullptr;
    NodePointer type_list = protocols->getChild(0);
    printChildren(type_list, depth, " & ");
    return nullptr;
  }
  case Node::Kind::ProtocolListWithAnyObject: {
    if (Node->getNumChildren() < 1)
      return nullptr;
    NodePointer protocols = Node->getChild(0);
    if (protocols->getNumChildren() < 1)
      return nullptr;
    NodePointer type_list = protocols->getChild(0);
    if (type_list->getNumChildren() > 0) {
      printChildren(type_list, depth, " & ");
      Printer << " & ";
    }
    if (Options.QualifyEntities && Options.DisplayStdlibModule)
      Printer << swift::STDLIB_NAME << ".";
    Printer << "AnyObject";
    return nullptr;
  }
  case Node::Kind::AssociatedType:
    // Don't print for now.
    return nullptr;
  case Node::Kind::OwningAddressor:
    return printAbstractStorage(Node->getFirstChild(), depth, asPrefixContext,
                                "owningAddressor");
  case Node::Kind::OwningMutableAddressor:
    return printAbstractStorage(Node->getFirstChild(), depth, asPrefixContext,
                                "owningMutableAddressor");
  case Node::Kind::NativeOwningAddressor:
    return printAbstractStorage(Node->getFirstChild(), depth, asPrefixContext,
                                "nativeOwningAddressor");
  case Node::Kind::NativeOwningMutableAddressor:
    return printAbstractStorage(Node->getFirstChild(), depth, asPrefixContext,
                                "nativeOwningMutableAddressor");
  case Node::Kind::NativePinningAddressor:
    return printAbstractStorage(Node->getFirstChild(), depth, asPrefixContext,
                                "nativePinningAddressor");
  case Node::Kind::NativePinningMutableAddressor:
    return printAbstractStorage(Node->getFirstChild(), depth, asPrefixContext,
                                "nativePinningMutableAddressor");
  case Node::Kind::UnsafeAddressor:
    return printAbstractStorage(Node->getFirstChild(), depth, asPrefixContext,
                                "unsafeAddressor");
  case Node::Kind::UnsafeMutableAddressor:
    return printAbstractStorage(Node->getFirstChild(), depth, asPrefixContext,
                                "unsafeMutableAddressor");
  case Node::Kind::GlobalGetter:
    return printAbstractStorage(Node->getFirstChild(), depth, asPrefixContext,
                                "getter");
  case Node::Kind::Getter:
    return printAbstractStorage(Node->getFirstChild(), depth, asPrefixContext,
                                "getter");
  case Node::Kind::Setter:
    return printAbstractStorage(Node->getFirstChild(), depth, asPrefixContext,
                                "setter");
  case Node::Kind::MaterializeForSet:
    return printAbstractStorage(Node->getFirstChild(), depth, asPrefixContext,
                                "materializeForSet");
  case Node::Kind::WillSet:
    return printAbstractStorage(Node->getFirstChild(), depth, asPrefixContext,
                                "willset");
  case Node::Kind::DidSet:
    return printAbstractStorage(Node->getFirstChild(), depth, asPrefixContext,
                                "didset");
  case Node::Kind::ReadAccessor:
    return printAbstractStorage(Node->getFirstChild(), depth, asPrefixContext,
                                "read");
  case Node::Kind::ModifyAccessor:
    return printAbstractStorage(Node->getFirstChild(), depth, asPrefixContext,
                                "modify");
  case Node::Kind::Allocator:
    return printEntity(
        Node, depth, asPrefixContext, TypePrinting::FunctionStyle,
        /*hasName*/ false,
        isClassType(Node->getChild(0)) ? "__allocating_init" : "init");
  case Node::Kind::Constructor:
    return printEntity(Node, depth, asPrefixContext,
                       TypePrinting::FunctionStyle,
                       /*hasName*/ Node->getNumChildren() > 2, "init");
  case Node::Kind::Destructor:
    return printEntity(Node, depth, asPrefixContext, TypePrinting::NoType,
                       /*hasName*/ false, "deinit");
  case Node::Kind::Deallocator:
    return printEntity(Node, depth, asPrefixContext, TypePrinting::NoType,
                       /*hasName*/ false,
                       isClassType(Node->getChild(0)) ? "__deallocating_deinit"
                                                      : "deinit");
  case Node::Kind::IVarInitializer:
    return printEntity(Node, depth, asPrefixContext, TypePrinting::NoType,
                       /*hasName*/ false, "__ivar_initializer");
  case Node::Kind::IVarDestroyer:
    return printEntity(Node, depth, asPrefixContext, TypePrinting::NoType,
                       /*hasName*/ false, "__ivar_destroyer");
  case Node::Kind::ProtocolConformance: {
    NodePointer child0 = Node->getChild(0);
    NodePointer child1 = Node->getChild(1);
    NodePointer child2 = Node->getChild(2);
    if (Node->getNumChildren() == 4) {
      // TODO: check if this is correct
      Printer << "property behavior storage of ";
      print(child2, depth + 1);
      Printer << " in ";
      print(child0, depth + 1);
      Printer << " : ";
      print(child1, depth + 1);
    } else {
      print(child0, depth + 1);
      if (Options.DisplayProtocolConformances) {
        Printer << " : ";
        print(child1, depth + 1);
        Printer << " in ";
        print(child2, depth + 1);
      }
    }
    return nullptr;
  }
  case Node::Kind::TypeList:
    printChildren(Node, depth);
    return nullptr;
  case Node::Kind::LabelList:
    return nullptr;
  case Node::Kind::ImplDifferentiabilityKind:
    Printer << "@differentiable";
    switch ((MangledDifferentiabilityKind)Node->getIndex()) {
    case MangledDifferentiabilityKind::Normal:
      break;
    case MangledDifferentiabilityKind::Linear:
      Printer << "(_linear)";
      break;
    case MangledDifferentiabilityKind::Forward:
      Printer << "(_forward)";
      break;
    case MangledDifferentiabilityKind::Reverse:
      Printer << "(reverse)";
      break;
    case MangledDifferentiabilityKind::NonDifferentiable:
      assert(false && "Impossible case 'NonDifferentiable'");
    }
    return nullptr;
  case Node::Kind::ImplEscaping:
    Printer << "@escaping";
    return nullptr;
  case Node::Kind::ImplConvention:
    Printer << Node->getText();
    return nullptr;
  case Node::Kind::ImplParameterResultDifferentiability:
    // Skip if text is empty.
    if (Node->getText().empty())
      return nullptr;
    // Otherwise, print with trailing space.
    Printer << Node->getText() << ' ';
    return nullptr;
  case Node::Kind::ImplFunctionAttribute:
    Printer << Node->getText();
    return nullptr;
  case Node::Kind::ImplFunctionConvention:
    Printer << "@convention(";
    switch (Node->getNumChildren()) {
    case 1:
      Printer << Node->getChild(0)->getText();
      break;
    case 2:
      Printer << Node->getChild(0)->getText() << ", mangledCType: \"";
      print(Node->getChild(1), depth + 1);
      Printer << '"';
      break;
    default:
      assert(false && "Unexpected numChildren for ImplFunctionConvention");
    }
    Printer << ')';
    return nullptr;
  case Node::Kind::ImplFunctionConventionName:
    assert(false && "Already handled in ImplFunctionConvention");
    return nullptr;
  case Node::Kind::ImplErrorResult:
    Printer << "@error ";
    printChildren(Node, depth, " ");
    return nullptr;
  case Node::Kind::ImplYield:
    Printer << "@yields ";
    printChildren(Node, depth, " ");
    return nullptr;
  case Node::Kind::ImplParameter:
  case Node::Kind::ImplResult:
    // Children: `convention, differentiability?, type`
    // Print convention.
    print(Node->getChild(0), depth + 1);
    Printer << " ";
    // Print differentiability, if it exists.
    if (Node->getNumChildren() == 3)
      print(Node->getChild(1), depth + 1);
    // Print type.
    print(Node->getLastChild(), depth + 1);
    return nullptr;
  case Node::Kind::ImplFunctionType:
    printImplFunctionType(Node, depth);
    return nullptr;
  case Node::Kind::ImplInvocationSubstitutions:
    Printer << "for <";
    printChildren(Node->getChild(0), depth, ", ");
    Printer << '>';
    return nullptr;
  case Node::Kind::ImplPatternSubstitutions:
    Printer << "@substituted ";
    print(Node->getChild(0), depth + 1);
    Printer << " for <";
    printChildren(Node->getChild(1), depth, ", ");
    Printer << '>';
    return nullptr;
  case Node::Kind::ErrorType:
    Printer << "<ERROR TYPE>";
    return nullptr;
      
  case Node::Kind::DependentPseudogenericSignature:
  case Node::Kind::DependentGenericSignature: {
    Printer << '<';
    
    unsigned depth = 0;
    unsigned numChildren = Node->getNumChildren();
    for (;
         depth < numChildren
           && Node->getChild(depth)->getKind()
               == Node::Kind::DependentGenericParamCount;
         ++depth) {
      if (depth != 0)
        Printer << "><";
      
      unsigned count = Node->getChild(depth)->getIndex();
      for (unsigned index = 0; index < count; ++index) {
        if (index != 0)
          Printer << ", ";
        // Limit the number of printed generic parameters. In practice this
        // it will never be exceeded. The limit is only imporant for malformed
        // symbols where count can be really huge.
        if (index >= 128) {
          Printer << "...";
          break;
        }
        // FIXME: Depth won't match when a generic signature applies to a
        // method in generic type context.
        Printer << Options.GenericParameterName(depth, index);
      }
    }
    
    if (depth != numChildren) {
      if (Options.DisplayWhereClauses) {
        Printer << " where ";
        for (unsigned i = depth; i < numChildren; ++i) {
          if (i > depth)
            Printer << ", ";
          print(Node->getChild(i), depth + 1);
        }
      }
    }
    Printer << '>';
    return nullptr;
  }
  case Node::Kind::DependentGenericParamCount:
    printer_unreachable("should be printed as a child of a "
                        "DependentGenericSignature");
  case Node::Kind::DependentGenericConformanceRequirement: {
    NodePointer type = Node->getChild(0);
    NodePointer reqt = Node->getChild(1);
    print(type, depth + 1);
    Printer << ": ";
    print(reqt, depth + 1);
    return nullptr;
  }
  case Node::Kind::DependentGenericLayoutRequirement: {
    NodePointer type = Node->getChild(0);
    NodePointer layout = Node->getChild(1);
    print(type, depth + 1);
    Printer << ": ";
    assert(layout->getKind() == Node::Kind::Identifier);
    assert(layout->getText().size() == 1);
    char c = layout->getText()[0];
    StringRef name;
    if (c == 'U') {
      name = "_UnknownLayout";
    } else if (c == 'R') {
      name = "_RefCountedObject";
    } else if (c == 'N') {
      name = "_NativeRefCountedObject";
    } else if (c == 'C') {
      name = "AnyObject";
    } else if (c == 'D') {
      name = "_NativeClass";
    } else if (c == 'T') {
      name = "_Trivial";
    } else if (c == 'E' || c == 'e') {
      name = "_Trivial";
    } else if (c == 'M' || c == 'm') {
      name = "_TrivialAtMost";
    }
    Printer << name;
    if (Node->getNumChildren() > 2) {
      Printer << "(";
      print(Node->getChild(2), depth + 1);
      if (Node->getNumChildren() > 3) {
        Printer << ", ";
        print(Node->getChild(3), depth + 1);
      }
      Printer << ")";
    }
    return nullptr;
  }
  case Node::Kind::DependentGenericSameTypeRequirement: {
    NodePointer fst = Node->getChild(0);
    NodePointer snd = Node->getChild(1);

    print(fst, depth + 1);
    Printer << " == ";
    print(snd, depth + 1);
    return nullptr;
  }
  case Node::Kind::DependentGenericParamType: {
    unsigned index = Node->getChild(1)->getIndex();
    unsigned depth = Node->getChild(0)->getIndex();
    Printer << Options.GenericParameterName(depth, index);
    return nullptr;
  }
  case Node::Kind::DependentGenericType: {
    NodePointer sig = Node->getChild(0);
    NodePointer depTy = Node->getChild(1);
    print(sig, depth + 1);
    if (needSpaceBeforeType(depTy))
      Printer << ' ';
    print(depTy, depth + 1);
    return nullptr;
  }
  case Node::Kind::DependentMemberType: {
    NodePointer base = Node->getChild(0);
    print(base, depth + 1);
    Printer << '.';
    NodePointer assocTy = Node->getChild(1);
    print(assocTy, depth + 1);
    return nullptr;
  }
  case Node::Kind::DependentAssociatedTypeRef: {
    if (Node->getNumChildren() > 1) {
      print(Node->getChild(1), depth + 1);
      Printer << '.';
    }
    print(Node->getChild(0), depth + 1);
    return nullptr;
  }
  case Node::Kind::ReflectionMetadataBuiltinDescriptor:
    Printer << "reflection metadata builtin descriptor ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::ReflectionMetadataFieldDescriptor:
    Printer << "reflection metadata field descriptor ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::ReflectionMetadataAssocTypeDescriptor:
    Printer << "reflection metadata associated type descriptor ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::ReflectionMetadataSuperclassDescriptor:
    Printer << "reflection metadata superclass descriptor ";
    print(Node->getChild(0), depth + 1);
    return nullptr;

  case Node::Kind::ConcurrentFunctionType:
    Printer << "@Sendable ";
    return nullptr;
  case Node::Kind::DifferentiableFunctionType: {
    Printer << "@differentiable";
    auto kind = (MangledDifferentiabilityKind)Node->getIndex();
    switch (kind) {
    case MangledDifferentiabilityKind::Forward:
      Printer << "(_forward)";
      break;
    case MangledDifferentiabilityKind::Reverse:
      Printer << "(reverse)";
      break;
    case MangledDifferentiabilityKind::Linear:
      Printer << "(_linear)";
      break;
    case MangledDifferentiabilityKind::Normal:
      break;
    case MangledDifferentiabilityKind::NonDifferentiable:
      assert(false && "Unexpected case NonDifferentiable");
    }
    Printer << ' ';
    return nullptr;
  }
  case Node::Kind::GlobalActorFunctionType: {
    if (Node->getNumChildren() > 0) {
      Printer << '@';
      print(Node->getChild(0), depth + 1);
      Printer << ' ';
    }
    return nullptr;
  }
  case Node::Kind::AsyncAnnotation:
    Printer << " async ";
    return nullptr;
  case Node::Kind::ThrowsAnnotation:
    Printer << " throws ";
    return nullptr;
  case Node::Kind::EmptyList:
    Printer << " empty-list ";
    return nullptr;
  case Node::Kind::FirstElementMarker:
    Printer << " first-element-marker ";
    return nullptr;
  case Node::Kind::VariadicMarker:
    Printer << " variadic-marker ";
    return nullptr;
  case Node::Kind::SILBoxTypeWithLayout: {
    assert(Node->getNumChildren() == 1 || Node->getNumChildren() == 3);
    NodePointer layout = Node->getChild(0);
    assert(layout->getKind() == Node::Kind::SILBoxLayout);
    NodePointer signature, genericArgs = nullptr;
    if (Node->getNumChildren() == 3) {
      signature = Node->getChild(1);
      assert(signature->getKind() == Node::Kind::DependentGenericSignature);
      genericArgs = Node->getChild(2);
      assert(genericArgs->getKind() == Node::Kind::TypeList);

      print(signature, depth + 1);
      Printer << ' ';
    }
    print(layout, depth + 1);
    if (genericArgs) {
      Printer << " <";
      for (unsigned i = 0, e = genericArgs->getNumChildren(); i < e; ++i) {
        if (i > 0)
          Printer << ", ";
        print(genericArgs->getChild(i), depth + 1);
      }
      Printer << '>';
    }
    return nullptr;
  }
  case Node::Kind::SILBoxLayout:
    Printer << '{';
    for (unsigned i = 0; i < Node->getNumChildren(); ++i) {
      if (i > 0)
        Printer << ',';
      Printer << ' ';
      print(Node->getChild(i), depth + 1);
    }
    Printer << " }";
    return nullptr;
  case Node::Kind::SILBoxImmutableField:
  case Node::Kind::SILBoxMutableField:
    Printer << (Node->getKind() == Node::Kind::SILBoxImmutableField
      ? "let "
      : "var ");
    assert(Node->getNumChildren() == 1
           && Node->getChild(0)->getKind() == Node::Kind::Type);
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::AssocTypePath:
    printChildren(Node->begin(), Node->end(), depth, ".");
    return nullptr;
  case Node::Kind::ModuleDescriptor:
    Printer << "module descriptor ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::AnonymousDescriptor:
    Printer << "anonymous descriptor ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::ExtensionDescriptor:
    Printer << "extension descriptor ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::AssociatedTypeGenericParamRef:
    Printer << "generic parameter reference for associated type ";
    printChildren(Node, depth);
    return nullptr;
  case Node::Kind::AnyProtocolConformanceList:
    printChildren(Node, depth);
    return nullptr;
  case Node::Kind::ConcreteProtocolConformance:
    Printer << "concrete protocol conformance ";
    if (Node->hasIndex())
      Printer << "#" << Node->getIndex() << " ";
    printChildren(Node, depth);
    return nullptr;
  case Node::Kind::DependentAssociatedConformance:
    Printer << "dependent associated conformance ";
    printChildren(Node, depth);
    return nullptr;
  case Node::Kind::DependentProtocolConformanceAssociated:
    Printer << "dependent associated protocol conformance ";
    printOptionalIndex(Node->getChild(2));
    print(Node->getChild(0), depth + 1);
    print(Node->getChild(1), depth + 1);
    return nullptr;
  case Node::Kind::DependentProtocolConformanceInherited:
    Printer << "dependent inherited protocol conformance ";
    printOptionalIndex(Node->getChild(2));
    print(Node->getChild(0), depth + 1);
    print(Node->getChild(1), depth + 1);
    return nullptr;
  case Node::Kind::DependentProtocolConformanceRoot:
    Printer << "dependent root protocol conformance ";
    printOptionalIndex(Node->getChild(2));
    print(Node->getChild(0), depth + 1);
    print(Node->getChild(1), depth + 1);
    return nullptr;
  case Node::Kind::ProtocolConformanceRefInTypeModule:
    Printer << "protocol conformance ref (type's module) ";
    printChildren(Node, depth);
    return nullptr;
  case Node::Kind::ProtocolConformanceRefInProtocolModule:
    Printer << "protocol conformance ref (protocol's module) ";
    printChildren(Node, depth);
    return nullptr;
  case Node::Kind::ProtocolConformanceRefInOtherModule:
    Printer << "protocol conformance ref (retroactive) ";
    printChildren(Node, depth);
    return nullptr;
  case Node::Kind::SugaredOptional:
    printWithParens(Node->getChild(0), depth);
    Printer << "?";
    return nullptr;
  case Node::Kind::SugaredArray:
    Printer << "[";
    print(Node->getChild(0), depth + 1);
    Printer << "]";
    return nullptr;
  case Node::Kind::SugaredDictionary:
    Printer << "[";
    print(Node->getChild(0), depth + 1);
    Printer << " : ";
    print(Node->getChild(1), depth + 1);
    Printer << "]";
    return nullptr;
  case Node::Kind::SugaredParen:
    Printer << "(";
    print(Node->getChild(0), depth + 1);
    Printer << ")";
    return nullptr;
  case Node::Kind::OpaqueReturnType:
  case Node::Kind::OpaqueReturnTypeIndexed:
    Printer << "some";
    return nullptr;
  case Node::Kind::OpaqueReturnTypeOf:
    Printer << "<<opaque return type of ";
    printChildren(Node, depth);
    Printer << ">>";
    return nullptr;
  case Node::Kind::OpaqueType:
    print(Node->getChild(0), depth + 1);
    Printer << '.';
    print(Node->getChild(1), depth + 1);
    return nullptr;
  case Node::Kind::AccessorFunctionReference:
    Printer << "accessor function at " << Node->getIndex();
    return nullptr;
  case Node::Kind::CanonicalSpecializedGenericMetaclass:
    Printer << "specialized generic metaclass for ";
    print(Node->getFirstChild(), depth + 1);
    return nullptr;
  case Node::Kind::CanonicalSpecializedGenericTypeMetadataAccessFunction:
    Printer << "canonical specialized generic type metadata accessor for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::MetadataInstantiationCache:
    Printer << "metadata instantiation cache for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::NoncanonicalSpecializedGenericTypeMetadata:
    Printer << "noncanonical specialized generic type metadata for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::NoncanonicalSpecializedGenericTypeMetadataCache:
    Printer << "cache variable for noncanonical specialized generic type metadata for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::GlobalVariableOnceToken:
  case Node::Kind::GlobalVariableOnceFunction:
    Printer << (kind == Node::Kind::GlobalVariableOnceToken
                  ? "one-time initialization token for "
                  : "one-time initialization function for ");
    printContext(Node->getChild(0));
    print(Node->getChild(1), depth + 1);
    return nullptr;
  case Node::Kind::GlobalVariableOnceDeclList:
    if (Node->getNumChildren() == 1) {
      print(Node->getChild(0), depth + 1);
    } else {
      Printer << '(';
      for (unsigned i = 0, e = Node->getNumChildren(); i < e; ++i) {
        if (i != 0) {
          Printer << ", ";
        }
        print(Node->getChild(i), depth + 1);
      }
      Printer << ')';
    }
    return nullptr;
  case Node::Kind::PredefinedObjCAsyncCompletionHandlerImpl:
    Printer << "predefined ";
    LLVM_FALLTHROUGH;
  case Node::Kind::ObjCAsyncCompletionHandlerImpl:
    Printer << "@objc completion handler block implementation for ";
    if (Node->getNumChildren() >= 4)
      print(Node->getChild(3), depth + 1);
    print(Node->getChild(0), depth + 1);
    Printer << " with result type ";
    print(Node->getChild(1), depth + 1);
    switch (Node->getChild(2)->getIndex()) {
    case 0:
      break;
    case 1:
      Printer << " nonzero on error";
      break;
    case 2:
      Printer << " zero on error";
      break;
    default:
      Printer << " <invalid error flag>";
      break;
    }
    return nullptr;
  case Node::Kind::CanonicalPrespecializedGenericTypeCachingOnceToken:
    Printer << "flag for loading of canonical specialized generic type "
               "metadata for ";
    print(Node->getChild(0), depth + 1);
    return nullptr;
  case Node::Kind::AsyncFunctionPointer:
    Printer << "async function pointer to ";
    return nullptr;
  case Node::Kind::AsyncAwaitResumePartialFunction:
    if (Options.ShowAsyncResumePartial) {
      Printer << "(";
      print(Node->getChild(0), depth + 1);
      Printer << ")";
      Printer << " await resume partial function for ";
    }
    return nullptr;
  case Node::Kind::AsyncSuspendResumePartialFunction:
    if (Options.ShowAsyncResumePartial) {
      Printer << "(";
      print(Node->getChild(0), depth + 1);
      Printer << ")";
      Printer << " suspend resume partial function for ";
    }
    return nullptr;
  }

  printer_unreachable("bad node kind!");
}