//===--- Remangler.cpp - Swift re-mangling from a demangling tree ---------===// // // 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 the remangler, which turns a demangling parse // tree back into a mangled string. This is useful for tools which // want to extract subtrees from mangled strings. // //===----------------------------------------------------------------------===// #include "swift/Demangling/Demangler.h" #include "swift/Demangling/Punycode.h" #include "swift/Demangling/ManglingUtils.h" #include "swift/Demangling/ManglingMacros.h" #include "swift/AST/Ownership.h" #include "swift/Strings.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "RemanglerBase.h" #include #include using namespace swift; using namespace Demangle; using namespace Mangle; [[noreturn]] static void unreachable(const char *Message) { fprintf(stderr, "fatal error: %s\n", Message); std::abort(); } static char getCharOfNodeText(Node *node, unsigned idx) { switch (node->getKind()) { case Node::Kind::InfixOperator: case Node::Kind::PrefixOperator: case Node::Kind::PostfixOperator: return Mangle::translateOperatorChar(node->getText()[idx]); default: return node->getText()[idx]; } } bool SubstitutionEntry::identifierEquals(Node *lhs, Node *rhs) { unsigned length = lhs->getText().size(); if (rhs->getText().size() != length) return false; // The fast path. if (lhs->getKind() == rhs->getKind()) return lhs->getText() == rhs->getText(); // The slow path. for (unsigned i = 0; i < length; ++i) { if (getCharOfNodeText(lhs, i) != getCharOfNodeText(rhs, i)) return false; } return true; } void SubstitutionEntry::deepHash(Node *node) { if (treatAsIdentifier) { combineHash((size_t) Node::Kind::Identifier); assert(node->hasText()); switch (node->getKind()) { case Node::Kind::InfixOperator: case Node::Kind::PrefixOperator: case Node::Kind::PostfixOperator: for (char c : node->getText()) { combineHash((unsigned char)translateOperatorChar(c)); } return; default: break; } } else { combineHash((size_t) node->getKind()); } if (node->hasIndex()) { combineHash(node->getIndex()); } else if (node->hasText()) { for (char c : node->getText()) { combineHash((unsigned char) c); } } for (Node *child : *node) { deepHash(child); } } bool SubstitutionEntry::deepEquals(Node *lhs, Node *rhs) const { if (lhs->getKind() != rhs->getKind()) return false; if (lhs->hasIndex()) { if (!rhs->hasIndex()) return false; if (lhs->getIndex() != rhs->getIndex()) return false; } else if (lhs->hasText()) { if (!rhs->hasText()) return false; if (lhs->getText() != rhs->getText()) return false; } else if (rhs->hasIndex() || rhs->hasText()) { return false; } if (lhs->getNumChildren() != rhs->getNumChildren()) return false; for (auto li = lhs->begin(), ri = rhs->begin(), le = lhs->end(); li != le; ++li, ++ri) { if (!deepEquals(*li, *ri)) return false; } return true; } // Find a substitution and return its index. // Returns -1 if no substitution is found. int RemanglerBase::findSubstitution(const SubstitutionEntry &entry) { // First search in InlineSubstitutions. SubstitutionEntry *result = std::find(InlineSubstitutions, InlineSubstitutions + NumInlineSubsts, entry); if (result != InlineSubstitutions + NumInlineSubsts) return result - InlineSubstitutions; // Then search in OverflowSubstitutions. auto it = OverflowSubstitutions.find(entry); if (it == OverflowSubstitutions.end()) return -1; return it->second; } void RemanglerBase::addSubstitution(const SubstitutionEntry &entry) { assert(findSubstitution(entry) < 0); if (NumInlineSubsts < InlineSubstCapacity) { // There is still free space in NumInlineSubsts. assert(OverflowSubstitutions.empty()); InlineSubstitutions[NumInlineSubsts++] = entry; return; } // We have to add the entry to OverflowSubstitutions. unsigned Idx = OverflowSubstitutions.size() + InlineSubstCapacity; auto result = OverflowSubstitutions.insert({entry, Idx}); assert(result.second); (void) result; } namespace { class Remangler : public RemanglerBase { template friend void Mangle::mangleIdentifier(Mangler &M, StringRef ident); friend class Mangle::SubstitutionMerging; const bool UsePunycode = true; Vector Words; Vector SubstWordsInIdent; static const size_t MaxNumWords = 26; SubstitutionMerging SubstMerging; // A callback for resolving symbolic references. SymbolicResolver Resolver; void addSubstWordsInIdent(const WordReplacement &repl) { SubstWordsInIdent.push_back(repl, Factory); } void addWord(const SubstitutionWord &word) { Words.push_back(word, Factory); } template friend void mangleIdentifier(Mangler &M, StringRef ident); class EntityContext { bool AsContext = false; public: class ManglingContextRAII { EntityContext &Ctx; bool SavedValue; public: ManglingContextRAII(EntityContext &ctx) : Ctx(ctx), SavedValue(ctx.AsContext) { ctx.AsContext = true; } ~ManglingContextRAII() { Ctx.AsContext = SavedValue; } }; }; Node *getSingleChild(Node *node) { assert(node->getNumChildren() == 1); return node->getFirstChild(); } Node *getSingleChild(Node *node, Node::Kind kind) { Node *Child = getSingleChild(node); assert(Child->getKind() == kind); return Child; } Node *skipType(Node *node) { if (node->getKind() == Node::Kind::Type) return getSingleChild(node); return node; } Node *getChildOfType(Node *node) { assert(node->getKind() == Node::Kind::Type); return getSingleChild(node); } void mangleIndex(Node::IndexType value) { if (value == 0) { Buffer << '_'; } else { Buffer << (value - 1) << '_'; } } void mangleDependentConformanceIndex(Node *node); void mangleChildNodes(Node *node) { mangleNodes(node->begin(), node->end()); } void mangleChildNodesReversed(Node *node) { for (size_t Idx = 0, Num = node->getNumChildren(); Idx < Num; ++Idx) { mangleChildNode(node, Num - Idx - 1); } } void mangleListSeparator(bool &isFirstListItem) { if (isFirstListItem) { Buffer << '_'; isFirstListItem = false; } } void mangleEndOfList(bool isFirstListItem) { if (isFirstListItem) Buffer << 'y'; } void mangleNodes(Node::iterator i, Node::iterator e) { for (; i != e; ++i) { mangle(*i); } } void mangleSingleChildNode(Node *node) { assert(node->getNumChildren() == 1); mangle(*node->begin()); } void mangleChildNode(Node *node, unsigned index) { assert(index < node->getNumChildren()); mangle(node->begin()[index]); } void manglePureProtocol(Node *Proto) { Proto = skipType(Proto); if (mangleStandardSubstitution(Proto)) return; mangleChildNodes(Proto); } void mangleProtocolList(Node *protocols, Node *superclass, bool hasExplicitAnyObject); bool trySubstitution(Node *node, SubstitutionEntry &entry, bool treatAsIdentifier = false); void mangleIdentifierImpl(Node *node, bool isOperator); bool mangleStandardSubstitution(Node *node); void mangleDependentGenericParamIndex(Node *node, const char *nonZeroPrefix = "", char zeroOp = 'z'); std::pair mangleConstrainedType(Node *node); void mangleFunctionSignature(Node *FuncType) { mangleChildNodesReversed(FuncType); } void mangleAnyNominalType(Node *node); void mangleAnyGenericType(Node *node, StringRef TypeOp); void mangleGenericArgs(Node *node, char &Separator, bool fullSubstitutionMap=false); void mangleAnyConstructor(Node *node, char kindOp); void mangleAbstractStorage(Node *node, StringRef accessorCode); void mangleAnyProtocolConformance(Node *node); void mangleKeyPathThunkHelper(Node *node, StringRef op); #define NODE(ID) \ void mangle##ID(Node *node); #define CONTEXT_NODE(ID) \ void mangle##ID(Node *node); \ // void mangle##ID(Node *node, EntityContext &ctx); #include "swift/Demangling/DemangleNodes.def" public: Remangler(SymbolicResolver Resolver, NodeFactory &Factory) : RemanglerBase(Factory), Resolver(Resolver) { } void mangle(Node *node) { switch (node->getKind()) { #define NODE(ID) case Node::Kind::ID: return mangle##ID(node); #include "swift/Demangling/DemangleNodes.def" } unreachable("bad demangling tree node"); } }; bool Remangler::trySubstitution(Node *node, SubstitutionEntry &entry, bool treatAsIdentifier) { if (mangleStandardSubstitution(node)) return true; // Go ahead and initialize the substitution entry. entry.setNode(node, treatAsIdentifier); int Idx = findSubstitution(entry); if (Idx < 0) return false; if (Idx >= 26) { Buffer << 'A'; mangleIndex(Idx - 26); return true; } char Subst = Idx + 'A'; if (!SubstMerging.tryMergeSubst(*this, Subst, /*isStandardSubst*/ false)) { Buffer << 'A' << Subst; } return true; } void Remangler::mangleIdentifierImpl(Node *node, bool isOperator) { SubstitutionEntry entry; if (trySubstitution(node, entry, /*treatAsIdentifier*/ true)) return; if (isOperator) { Mangle::mangleIdentifier(*this, Mangle::translateOperator(node->getText())); } else { Mangle::mangleIdentifier(*this, node->getText()); } addSubstitution(entry); } bool Remangler::mangleStandardSubstitution(Node *node) { if (node->getKind() != Node::Kind::Structure && node->getKind() != Node::Kind::Enum && node->getKind() != Node::Kind::Protocol) return false; Node *context = node->getFirstChild(); if (context->getKind() != Node::Kind::Module || context->getText() != STDLIB_NAME) return false; // Ignore private stdlib names if (node->getChild(1)->getKind() != Node::Kind::Identifier) return false; if (char Subst = getStandardTypeSubst(node->getChild(1)->getText())) { if (!SubstMerging.tryMergeSubst(*this, Subst, /*isStandardSubst*/ true)) { Buffer << 'S' << Subst; } return true; } return false; } void Remangler::mangleDependentGenericParamIndex(Node *node, const char *nonZeroPrefix, char zeroOp) { auto depth = node->getChild(0)->getIndex(); auto index = node->getChild(1)->getIndex(); if (depth != 0) { Buffer << nonZeroPrefix << 'd'; mangleIndex(depth - 1); mangleIndex(index); return; } if (index != 0) { Buffer << nonZeroPrefix; mangleIndex(index - 1); return; } // depth == index == 0 Buffer << zeroOp; } std::pair Remangler::mangleConstrainedType(Node *node) { if (node->getKind() == Node::Kind::Type) node = getChildOfType(node); SubstitutionEntry entry; if (trySubstitution(node, entry)) return {-1, nullptr}; Vector Chain; while (node->getKind() == Node::Kind::DependentMemberType) { Chain.push_back(node->getChild(1), Factory); node = getChildOfType(node->getFirstChild()); } if (node->getKind() != Node::Kind::DependentGenericParamType) { mangle(node); node = nullptr; } const char *ListSeparator = (Chain.size() > 1 ? "_" : ""); for (unsigned i = 1, n = Chain.size(); i <= n; ++i) { Node *DepAssocTyRef = Chain[n - i]; mangle(DepAssocTyRef); Buffer << ListSeparator; ListSeparator = ""; } if (!Chain.empty()) addSubstitution(entry); return {(int)Chain.size(), node}; } void Remangler::mangleAnyGenericType(Node *node, StringRef TypeOp) { SubstitutionEntry entry; if (trySubstitution(node, entry)) return; mangleChildNodes(node); Buffer << TypeOp; addSubstitution(entry); } void Remangler::mangleAnyNominalType(Node *node) { if (isSpecialized(node)) { SubstitutionEntry entry; if (trySubstitution(node, entry)) return; NodePointer unboundType = getUnspecialized(node, Factory); mangleAnyNominalType(unboundType); char Separator = 'y'; mangleGenericArgs(node, Separator); if (node->getNumChildren() == 3) { // Retroactive conformances. auto listNode = node->getChild(2); for (size_t Idx = 0, Num = listNode->getNumChildren(); Idx < Num; ++Idx) { mangle(listNode->getChild(Idx)); } } Buffer << 'G'; addSubstitution(entry); return; } switch (node->getKind()) { case Node::Kind::Structure: return mangleAnyGenericType(node, "V"); case Node::Kind::Enum: return mangleAnyGenericType(node, "O"); case Node::Kind::Class: return mangleAnyGenericType(node, "C"); case Node::Kind::OtherNominalType: return mangleAnyGenericType(node, "XY"); case Node::Kind::TypeAlias: return mangleAnyGenericType(node, "a"); default: unreachable("bad nominal type kind"); } } void Remangler::mangleGenericArgs(Node *node, char &Separator, bool fullSubstitutionMap) { switch (node->getKind()) { case Node::Kind::Protocol: // A protocol cannot be the parent of a nominal type, so this case should // never be hit by valid swift code. But the indexer might generate a URL // from invalid swift code, which has a bound generic inside a protocol. // The ASTMangler treats a protocol like any other nominal type in this // case, so we also support it in the remangler. case Node::Kind::Structure: case Node::Kind::Enum: case Node::Kind::Class: case Node::Kind::TypeAlias: if (node->getKind() == Node::Kind::TypeAlias) fullSubstitutionMap = true; mangleGenericArgs(node->getChild(0), Separator, fullSubstitutionMap); Buffer << Separator; Separator = '_'; break; case Node::Kind::Function: case Node::Kind::Getter: case Node::Kind::Setter: case Node::Kind::WillSet: case Node::Kind::DidSet: case Node::Kind::ReadAccessor: case Node::Kind::ModifyAccessor: case Node::Kind::UnsafeAddressor: case Node::Kind::UnsafeMutableAddressor: case Node::Kind::Allocator: case Node::Kind::Constructor: case Node::Kind::Destructor: case Node::Kind::Variable: case Node::Kind::Subscript: case Node::Kind::ExplicitClosure: case Node::Kind::ImplicitClosure: case Node::Kind::DefaultArgumentInitializer: case Node::Kind::Initializer: case Node::Kind::PropertyWrapperBackingInitializer: if (!fullSubstitutionMap) break; mangleGenericArgs(node->getChild(0), Separator, fullSubstitutionMap); if (Demangle::nodeConsumesGenericArgs(node)) { Buffer << Separator; Separator = '_'; } break; case Node::Kind::BoundGenericOtherNominalType: case Node::Kind::BoundGenericStructure: case Node::Kind::BoundGenericEnum: case Node::Kind::BoundGenericClass: case Node::Kind::BoundGenericProtocol: case Node::Kind::BoundGenericTypeAlias: { if (node->getKind() == Node::Kind::BoundGenericTypeAlias) fullSubstitutionMap = true; NodePointer unboundType = node->getChild(0); assert(unboundType->getKind() == Node::Kind::Type); NodePointer nominalType = unboundType->getChild(0); NodePointer parentOrModule = nominalType->getChild(0); mangleGenericArgs(parentOrModule, Separator, fullSubstitutionMap); Buffer << Separator; Separator = '_'; mangleChildNodes(node->getChild(1)); break; } case Node::Kind::BoundGenericFunction: { fullSubstitutionMap = true; NodePointer unboundFunction = node->getChild(0); assert(unboundFunction->getKind() == Node::Kind::Function || unboundFunction->getKind() == Node::Kind::Constructor); NodePointer parentOrModule = unboundFunction->getChild(0); mangleGenericArgs(parentOrModule, Separator, fullSubstitutionMap); Buffer << Separator; Separator = '_'; mangleChildNodes(node->getChild(1)); break; } case Node::Kind::Extension: mangleGenericArgs(node->getChild(1), Separator, fullSubstitutionMap); break; default: break; } } void Remangler::mangleAbstractStorage(Node *node, StringRef accessorCode) { mangleChildNodes(node); switch (node->getKind()) { case Node::Kind::Subscript: Buffer << "i"; break; case Node::Kind::Variable: Buffer << "v"; break; default: unreachable("Not a storage node"); } Buffer << accessorCode; } void Remangler::mangleAllocator(Node *node) { mangleAnyConstructor(node, 'C'); } void Remangler::mangleArgumentTuple(Node *node) { Node *Child = skipType(getSingleChild(node)); if (Child->getKind() == Node::Kind::Tuple && Child->getNumChildren() == 0) { Buffer << 'y'; return; } mangle(Child); } void Remangler::mangleAssociatedType(Node *node) { unreachable("unsupported node"); } void Remangler::mangleAssociatedTypeRef(Node *node) { SubstitutionEntry entry; if (trySubstitution(node, entry)) return; mangleChildNodes(node); Buffer << "Qa"; addSubstitution(entry); } void Remangler::mangleAssociatedTypeDescriptor(Node *node) { mangleChildNodes(node); Buffer << "Tl"; } void Remangler::mangleAssociatedConformanceDescriptor(Node *node) { mangle(node->getChild(0)); mangle(node->getChild(1)); manglePureProtocol(node->getChild(2)); Buffer << "Tn"; } void Remangler::mangleDefaultAssociatedConformanceAccessor(Node *node) { mangle(node->getChild(0)); mangle(node->getChild(1)); manglePureProtocol(node->getChild(2)); Buffer << "TN"; } void Remangler::mangleBaseConformanceDescriptor(Node *node) { mangle(node->getChild(0)); manglePureProtocol(node->getChild(1)); Buffer << "Tb"; } void Remangler::mangleAssociatedTypeMetadataAccessor(Node *node) { mangleChildNodes(node); // protocol conformance, identifier Buffer << "Wt"; } void Remangler::mangleDefaultAssociatedTypeMetadataAccessor(Node *node) { mangleChildNodes(node); // protocol conformance, identifier Buffer << "TM"; } void Remangler::mangleAssociatedTypeWitnessTableAccessor(Node *node) { mangleChildNodes(node); // protocol conformance, type, protocol Buffer << "WT"; } void Remangler::mangleBaseWitnessTableAccessor(Node *node) { mangleChildNodes(node); // protocol conformance, protocol Buffer << "Wb"; } void Remangler::mangleAutoClosureType(Node *node) { mangleChildNodesReversed(node); // argument tuple, result type Buffer << "XK"; } void Remangler::mangleEscapingAutoClosureType(Node *node) { mangleChildNodesReversed(node); // argument tuple, result type Buffer << "XA"; } void Remangler::mangleNoEscapeFunctionType(Node *node) { mangleChildNodesReversed(node); // argument tuple, result type Buffer << "XE"; } void Remangler::mangleBoundGenericClass(Node *node) { mangleAnyNominalType(node); } void Remangler::mangleBoundGenericEnum(Node *node) { Node *Enum = node->getChild(0)->getChild(0); assert(Enum->getKind() == Node::Kind::Enum); Node *Mod = Enum->getChild(0); Node *Id = Enum->getChild(1); if (Mod->getKind() == Node::Kind::Module && Mod->getText() == STDLIB_NAME && Id->getKind() == Node::Kind::Identifier && Id->getText() == "Optional") { SubstitutionEntry entry; if (trySubstitution(node, entry)) return; mangleSingleChildNode(node->getChild(1)); Buffer << "Sg"; addSubstitution(entry); return; } mangleAnyNominalType(node); } void Remangler::mangleBoundGenericStructure(Node *node) { mangleAnyNominalType(node); } void Remangler::mangleBoundGenericOtherNominalType(Node *node) { mangleAnyNominalType(node); } void Remangler::mangleBoundGenericProtocol(Node *node) { mangleAnyNominalType(node); } void Remangler::mangleBoundGenericTypeAlias(Node *node) { mangleAnyNominalType(node); } void Remangler::mangleBoundGenericFunction(Node *node) { SubstitutionEntry entry; if (trySubstitution(node, entry)) return; NodePointer unboundFunction = getUnspecialized(node, Factory); mangleFunction(unboundFunction); char Separator = 'y'; mangleGenericArgs(node, Separator); Buffer << 'G'; addSubstitution(entry); } void Remangler::mangleBuiltinTypeName(Node *node) { Buffer << 'B'; StringRef text = node->getText(); if (text == BUILTIN_TYPE_NAME_BRIDGEOBJECT) { Buffer << 'b'; } else if (text == BUILTIN_TYPE_NAME_UNSAFEVALUEBUFFER) { Buffer << 'B'; } else if (text == BUILTIN_TYPE_NAME_UNKNOWNOBJECT) { Buffer << 'O'; } else if (text == BUILTIN_TYPE_NAME_NATIVEOBJECT) { Buffer << 'o'; } else if (text == BUILTIN_TYPE_NAME_RAWPOINTER) { Buffer << 'p'; } else if (text == BUILTIN_TYPE_NAME_SILTOKEN) { Buffer << 't'; } else if (text == BUILTIN_TYPE_NAME_INTLITERAL) { Buffer << 'I'; } else if (text == BUILTIN_TYPE_NAME_WORD) { Buffer << 'w'; } else if (text.consume_front(BUILTIN_TYPE_NAME_INT)) { Buffer << 'i' << text << '_'; } else if (text.consume_front(BUILTIN_TYPE_NAME_FLOAT)) { Buffer << 'f' << text << '_'; } else if (text.consume_front(BUILTIN_TYPE_NAME_VEC)) { // Avoid using StringRef::split because its definition is not // provided in the header so that it requires linking with libSupport.a. size_t splitIdx = text.find('x'); auto element = text.substr(splitIdx).substr(1); if (element == "RawPointer") { Buffer << 'p'; } else if (element.consume_front("FPIEEE")) { Buffer << 'f' << element << '_'; } else if (element.consume_front("Int")) { Buffer << 'i' << element << '_'; } else { unreachable("unexpected builtin vector type"); } Buffer << "Bv" << text.substr(0, splitIdx) << '_'; } else { unreachable("unexpected builtin type"); } } void Remangler::mangleCFunctionPointer(Node *node) { mangleChildNodesReversed(node); // argument tuple, result type Buffer << "XC"; } void Remangler::mangleClass(Node *node) { mangleAnyNominalType(node); } void Remangler::mangleAnyConstructor(Node *node, char kindOp) { mangleChildNodes(node); Buffer << "f" << kindOp; } void Remangler::mangleConstructor(Node *node) { mangleAnyConstructor(node, 'c'); } void Remangler::mangleCoroutineContinuationPrototype(Node *node) { mangleChildNodes(node); Buffer << "TC"; } void Remangler::mangleDeallocator(Node *node) { mangleChildNodes(node); Buffer << "fD"; } void Remangler::mangleDeclContext(Node *node) { mangleSingleChildNode(node); } void Remangler::mangleDefaultArgumentInitializer(Node *node) { mangleChildNode(node, 0); Buffer << "fA"; mangleChildNode(node, 1); } void Remangler::mangleDependentAssociatedTypeRef(Node *node) { mangleIdentifier(node->getFirstChild()); if (node->getNumChildren() > 1) mangleChildNode(node, 1); } void Remangler::mangleDependentGenericConformanceRequirement(Node *node) { Node *ProtoOrClass = node->getChild(1); if (ProtoOrClass->getFirstChild()->getKind() == Node::Kind::Protocol) { manglePureProtocol(ProtoOrClass); auto NumMembersAndParamIdx = mangleConstrainedType(node->getChild(0)); assert(NumMembersAndParamIdx.first < 0 || NumMembersAndParamIdx.second); switch (NumMembersAndParamIdx.first) { case -1: Buffer << "RQ"; return; // substitution case 0: Buffer << "R"; break; case 1: Buffer << "Rp"; break; default: Buffer << "RP"; break; } mangleDependentGenericParamIndex(NumMembersAndParamIdx.second); return; } mangle(ProtoOrClass); auto NumMembersAndParamIdx = mangleConstrainedType(node->getChild(0)); assert(NumMembersAndParamIdx.first < 0 || NumMembersAndParamIdx.second); switch (NumMembersAndParamIdx.first) { case -1: Buffer << "RB"; return; // substitution case 0: Buffer << "Rb"; break; case 1: Buffer << "Rc"; break; default: Buffer << "RC"; break; } mangleDependentGenericParamIndex(NumMembersAndParamIdx.second); return; } void Remangler::mangleDependentGenericParamCount(Node *node) { unreachable("handled inline in DependentGenericSignature"); } void Remangler::mangleDependentGenericParamType(Node *node) { if (node->getChild(0)->getIndex() == 0 && node->getChild(1)->getIndex() == 0) { Buffer << 'x'; return; } Buffer << 'q'; mangleDependentGenericParamIndex(node); } void Remangler::mangleDependentGenericSameTypeRequirement(Node *node) { mangleChildNode(node, 1); auto NumMembersAndParamIdx = mangleConstrainedType(node->getChild(0)); assert(NumMembersAndParamIdx.first < 0 || NumMembersAndParamIdx.second); switch (NumMembersAndParamIdx.first) { case -1: Buffer << "RS"; return; // substitution case 0: Buffer << "Rs"; break; case 1: Buffer << "Rt"; break; default: Buffer << "RT"; break; } mangleDependentGenericParamIndex(NumMembersAndParamIdx.second); } void Remangler::mangleDependentGenericLayoutRequirement(Node *node) { auto NumMembersAndParamIdx = mangleConstrainedType(node->getChild(0)); assert(NumMembersAndParamIdx.first < 0 || NumMembersAndParamIdx.second); switch (NumMembersAndParamIdx.first) { case -1: Buffer << "RL"; break; // substitution case 0: Buffer << "Rl"; break; case 1: Buffer << "Rm"; break; default: Buffer << "RM"; break; } // If not a substitution, mangle the dependent generic param index. if (NumMembersAndParamIdx.first != -1) mangleDependentGenericParamIndex(NumMembersAndParamIdx.second); assert(node->getChild(1)->getKind() == Node::Kind::Identifier); assert(node->getChild(1)->getText().size() == 1); Buffer << node->getChild(1)->getText()[0]; if (node->getNumChildren() >=3) mangleChildNode(node, 2); if (node->getNumChildren() >=4) mangleChildNode(node, 3); } void Remangler::mangleDependentGenericSignature(Node *node) { size_t ParamCountEnd = 0; for (size_t Idx = 0, Num = node->getNumChildren(); Idx < Num; Idx++) { Node *Child = node->getChild(Idx); if (Child->getKind() == Node::Kind::DependentGenericParamCount) { ParamCountEnd = Idx + 1; } else { // requirement mangleChildNode(node, Idx); } } // If there's only one generic param, mangle nothing. if (ParamCountEnd == 1 && node->getChild(0)->getIndex() == 1) { Buffer << 'l'; return; } // Remangle generic params. Buffer << 'r'; for (size_t Idx = 0; Idx < ParamCountEnd; ++Idx) { Node *Count = node->getChild(Idx); if (Count->getIndex() > 0) { mangleIndex(Count->getIndex() - 1); } else { Buffer << 'z'; } } Buffer << 'l'; } void Remangler::mangleDependentGenericType(Node *node) { mangleChildNodesReversed(node); // type, generic signature Buffer << 'u'; } void Remangler::mangleDependentMemberType(Node *node) { auto NumMembersAndParamIdx = mangleConstrainedType(node); switch (NumMembersAndParamIdx.first) { case -1: break; // substitution case 0: unreachable("wrong dependent member type"); case 1: Buffer << 'Q'; if (auto dependentBase = NumMembersAndParamIdx.second) { mangleDependentGenericParamIndex(dependentBase, "y", 'z'); } else { Buffer << 'x'; } break; default: Buffer << 'Q'; if (auto dependentBase = NumMembersAndParamIdx.second) { mangleDependentGenericParamIndex(dependentBase, "Y", 'Z'); } else { Buffer << 'X'; } break; } } void Remangler::mangleDependentPseudogenericSignature(Node *node) { unreachable("handled inline"); } void Remangler::mangleDestructor(Node *node) { mangleChildNodes(node); Buffer << "fd"; } void Remangler::mangleDidSet(Node *node) { mangleAbstractStorage(node->getFirstChild(), "W"); } void Remangler::mangleDirectness(Node *node) { if (node->getIndex() == unsigned(Directness::Direct)) { Buffer << 'd'; } else { assert(node->getIndex() == unsigned(Directness::Indirect)); Buffer << 'i'; } } void Remangler::mangleDynamicAttribute(Node *node) { Buffer << "TD"; } void Remangler::mangleDirectMethodReferenceAttribute(Node *node) { Buffer << "Td"; } void Remangler::mangleDynamicSelf(Node *node) { mangleSingleChildNode(node); // type Buffer << "XD"; } void Remangler::mangleEnum(Node *node) { mangleAnyNominalType(node); } void Remangler::mangleErrorType(Node *node) { Buffer << "Xe"; } void Remangler::mangleExistentialMetatype(Node *node) { if (node->getFirstChild()->getKind() == Node::Kind::MetatypeRepresentation) { mangleChildNode(node, 1); Buffer << "Xm"; mangleChildNode(node, 0); } else { mangleSingleChildNode(node); Buffer << "Xp"; } } void Remangler::mangleExplicitClosure(Node *node) { mangleChildNode(node, 0); // context mangleChildNode(node, 2); // type Buffer << "fU"; mangleChildNode(node, 1); // index } void Remangler::mangleExtension(Node *node) { mangleChildNode(node, 1); mangleChildNode(node, 0); if (node->getNumChildren() == 3) mangleChildNode(node, 2); // generic signature Buffer << 'E'; } void Remangler::mangleAnonymousContext(Node *node) { mangleChildNode(node, 1); mangleChildNode(node, 0); if (node->getNumChildren() >= 3) mangleTypeList(node->getChild(2)); Buffer << "XZ"; } void Remangler::mangleFieldOffset(Node *node) { mangleChildNode(node, 1); // variable Buffer << "Wv"; mangleChildNode(node, 0); // directness } void Remangler::mangleEnumCase(Node *node) { mangleSingleChildNode(node); // enum case Buffer << "WC"; } void Remangler::mangleFullTypeMetadata(Node *node) { mangleSingleChildNode(node); Buffer << "Mf"; } void Remangler::mangleFunction(Node *node) { mangleChildNode(node, 0); // context mangleChildNode(node, 1); // name bool hasLabels = node->getChild(2)->getKind() == Node::Kind::LabelList; Node *FuncType = getSingleChild(node->getChild(hasLabels ? 3 : 2)); if (hasLabels) mangleChildNode(node, 2); // parameter labels if (FuncType->getKind() == Node::Kind::DependentGenericType) { mangleFunctionSignature(getSingleChild(FuncType->getChild(1))); mangleChildNode(FuncType, 0); // generic signature } else { mangleFunctionSignature(FuncType); } Buffer << "F"; } void Remangler::mangleFunctionSignatureSpecialization(Node *node) { for (NodePointer Param : *node) { if (Param->getKind() == Node::Kind::FunctionSignatureSpecializationParam && Param->getNumChildren() > 0) { Node *KindNd = Param->getChild(0); switch (FunctionSigSpecializationParamKind(KindNd->getIndex())) { case FunctionSigSpecializationParamKind::ConstantPropFunction: case FunctionSigSpecializationParamKind::ConstantPropGlobal: mangleIdentifier(Param->getChild(1)); break; case FunctionSigSpecializationParamKind::ConstantPropString: { NodePointer TextNd = Param->getChild(2); StringRef Text = TextNd->getText(); if (!Text.empty() && (isDigit(Text[0]) || Text[0] == '_')) { std::string Buffer = "_"; Buffer.append(Text.data(), Text.size()); TextNd = Factory.createNode(Node::Kind::Identifier, Buffer); } mangleIdentifier(TextNd); break; } case FunctionSigSpecializationParamKind::ClosureProp: mangleIdentifier(Param->getChild(1)); for (unsigned i = 2, e = Param->getNumChildren(); i != e; ++i) { mangleType(Param->getChild(i)); } break; default: break; } } } Buffer << "Tf"; bool returnValMangled = false; for (NodePointer Child : *node) { if (Child->getKind() == Node::Kind::FunctionSignatureSpecializationReturn) { Buffer << '_'; returnValMangled = true; } mangle(Child); if (Child->getKind() == Node::Kind::SpecializationPassID && node->hasIndex()) { Buffer << node->getIndex(); } } if (!returnValMangled) Buffer << "_n"; } void Remangler::mangleFunctionSignatureSpecializationReturn(Node *node) { mangleFunctionSignatureSpecializationParam(node); } void Remangler::mangleFunctionSignatureSpecializationParam(Node *node) { if (!node->hasChildren()) { Buffer << 'n'; return; } // The first child is always a kind that specifies the type of param that we // have. Node *KindNd = node->getChild(0); unsigned kindValue = KindNd->getIndex(); auto kind = FunctionSigSpecializationParamKind(kindValue); switch (kind) { case FunctionSigSpecializationParamKind::ConstantPropFunction: Buffer << "pf"; return; case FunctionSigSpecializationParamKind::ConstantPropGlobal: Buffer << "pg"; return; case FunctionSigSpecializationParamKind::ConstantPropInteger: Buffer << "pi" << node->getChild(1)->getText(); return; case FunctionSigSpecializationParamKind::ConstantPropFloat: Buffer << "pd" << node->getChild(1)->getText(); return; case FunctionSigSpecializationParamKind::ConstantPropString: { Buffer << "ps"; StringRef encodingStr = node->getChild(1)->getText(); if (encodingStr == "u8") { Buffer << 'b'; } else if (encodingStr == "u16") { Buffer << 'w'; } else if (encodingStr == "objc") { Buffer << 'c'; } else { unreachable("Unknown encoding"); } return; } case FunctionSigSpecializationParamKind::ClosureProp: Buffer << 'c'; return; case FunctionSigSpecializationParamKind::BoxToValue: Buffer << 'i'; return; case FunctionSigSpecializationParamKind::BoxToStack: Buffer << 's'; return; case FunctionSigSpecializationParamKind::SROA: Buffer << 'x'; return; default: if (kindValue & unsigned( FunctionSigSpecializationParamKind::ExistentialToGeneric)) { Buffer << 'e'; if (kindValue & unsigned(FunctionSigSpecializationParamKind::Dead)) Buffer << 'D'; if (kindValue & unsigned(FunctionSigSpecializationParamKind::OwnedToGuaranteed)) Buffer << 'G'; if (kindValue & unsigned(FunctionSigSpecializationParamKind::GuaranteedToOwned)) Buffer << 'O'; } else if (kindValue & unsigned(FunctionSigSpecializationParamKind::Dead)) { Buffer << 'd'; if (kindValue & unsigned(FunctionSigSpecializationParamKind::OwnedToGuaranteed)) Buffer << 'G'; if (kindValue & unsigned(FunctionSigSpecializationParamKind::GuaranteedToOwned)) Buffer << 'O'; } else if (kindValue & unsigned(FunctionSigSpecializationParamKind::OwnedToGuaranteed)) { Buffer << 'g'; } else if (kindValue & unsigned( FunctionSigSpecializationParamKind::GuaranteedToOwned)) { Buffer << 'o'; } if (kindValue & unsigned(FunctionSigSpecializationParamKind::SROA)) Buffer << 'X'; return; } } void Remangler::mangleFunctionSignatureSpecializationParamKind(Node *node) { unreachable("handled inline"); } void Remangler::mangleFunctionSignatureSpecializationParamPayload(Node *node) { unreachable("handled inline"); } void Remangler::mangleFunctionType(Node *node) { mangleFunctionSignature(node); Buffer << 'c'; } void Remangler::mangleGenericProtocolWitnessTable(Node *node) { mangleSingleChildNode(node); Buffer << "WG"; } void Remangler::mangleGenericProtocolWitnessTableInstantiationFunction(Node *node) { mangleSingleChildNode(node); Buffer << "WI"; } void Remangler::mangleResilientProtocolWitnessTable(Node *node) { mangleSingleChildNode(node); Buffer << "Wr"; } void Remangler::mangleGenericPartialSpecialization(Node *node) { for (NodePointer Child : *node) { if (Child->getKind() == Node::Kind::GenericSpecializationParam) { mangleChildNode(Child, 0); break; } } Buffer << (node->getKind() == Node::Kind::GenericPartialSpecializationNotReAbstracted ? "TP" : "Tp"); for (NodePointer Child : *node) { if (Child->getKind() != Node::Kind::GenericSpecializationParam) mangle(Child); } } void Remangler::mangleGenericPartialSpecializationNotReAbstracted(Node *node) { mangleGenericPartialSpecialization(node); } void Remangler::mangleGenericSpecialization(Node *node) { bool FirstParam = true; for (NodePointer Child : *node) { if (Child->getKind() == Node::Kind::GenericSpecializationParam) { mangleChildNode(Child, 0); mangleListSeparator(FirstParam); } } assert(!FirstParam && "generic specialization with no substitutions"); switch (node->getKind()) { case Node::Kind::GenericSpecialization: Buffer << "Tg"; break; case Node::Kind::GenericSpecializationNotReAbstracted: Buffer << "TG"; break; case Node::Kind::InlinedGenericFunction: Buffer << "Ti"; break; default: unreachable("unsupported node"); } for (NodePointer Child : *node) { if (Child->getKind() != Node::Kind::GenericSpecializationParam) mangle(Child); } } void Remangler::mangleGenericSpecializationNotReAbstracted(Node *node) { mangleGenericSpecialization(node); } void Remangler::mangleInlinedGenericFunction(Node *node) { mangleGenericSpecialization(node); } void Remangler::mangleGenericSpecializationParam(Node *node) { unreachable("handled inline"); } void Remangler::mangleGenericTypeMetadataPattern(Node *node) { mangleSingleChildNode(node); Buffer << "MP"; } void Remangler::mangleGenericTypeParamDecl(Node *node) { mangleChildNodes(node); Buffer << "fp"; } void Remangler::mangleGetter(Node *node) { mangleAbstractStorage(node->getFirstChild(), "g"); } void Remangler::mangleGlobal(Node *node) { Buffer << MANGLING_PREFIX_STR; bool mangleInReverseOrder = false; for (auto Iter = node->begin(), End = node->end(); Iter != End; ++Iter) { Node *Child = *Iter; switch (Child->getKind()) { case Node::Kind::FunctionSignatureSpecialization: case Node::Kind::GenericSpecialization: case Node::Kind::GenericSpecializationNotReAbstracted: case Node::Kind::InlinedGenericFunction: case Node::Kind::GenericPartialSpecialization: case Node::Kind::GenericPartialSpecializationNotReAbstracted: case Node::Kind::OutlinedBridgedMethod: case Node::Kind::OutlinedVariable: case Node::Kind::ObjCAttribute: case Node::Kind::NonObjCAttribute: case Node::Kind::DynamicAttribute: case Node::Kind::VTableAttribute: case Node::Kind::DirectMethodReferenceAttribute: case Node::Kind::MergedFunction: case Node::Kind::DynamicallyReplaceableFunctionKey: case Node::Kind::DynamicallyReplaceableFunctionImpl: case Node::Kind::DynamicallyReplaceableFunctionVar: mangleInReverseOrder = true; break; default: mangle(Child); if (mangleInReverseOrder) { auto ReverseIter = Iter; while (ReverseIter != node->begin()) { --ReverseIter; mangle(*ReverseIter); } mangleInReverseOrder = false; } break; } } } void Remangler::mangleGlobalGetter(Node *node) { mangleAbstractStorage(node->getFirstChild(), "G"); } void Remangler::mangleIdentifier(Node *node) { mangleIdentifierImpl(node, /*isOperator*/ false); } void Remangler::mangleIndex(Node *node) { unreachable("handled inline"); } void Remangler::mangleUnknownIndex(Node *node) { unreachable("handled inline"); } void Remangler::mangleIVarInitializer(Node *node) { mangleSingleChildNode(node); Buffer << "fe"; } void Remangler::mangleIVarDestroyer(Node *node) { mangleSingleChildNode(node); Buffer << "fE"; } void Remangler::mangleImplEscaping(Node *node) { Buffer << 'e'; } void Remangler::mangleImplConvention(Node *node) { char ConvCh = llvm::StringSwitch(node->getText()) .Case("@callee_unowned", 'y') .Case("@callee_guaranteed", 'g') .Case("@callee_owned", 'x') .Default(0); assert(ConvCh && "invalid impl callee convention"); Buffer << ConvCh; } void Remangler::mangleImplFunctionAttribute(Node *node) { unreachable("handled inline"); } void Remangler::mangleImplSubstitutions(Node *node) { unreachable("handled inline"); } void Remangler::mangleImplImpliedSubstitutions(Node *node) { unreachable("handled inline"); } void Remangler::mangleImplFunctionType(Node *node) { const char *PseudoGeneric = ""; Node *GenSig = nullptr; Node *GenSubs = nullptr; bool isImplied; for (NodePointer Child : *node) { switch (auto kind = Child->getKind()) { case Node::Kind::ImplParameter: case Node::Kind::ImplResult: case Node::Kind::ImplErrorResult: mangleChildNode(Child, 1); break; case Node::Kind::DependentPseudogenericSignature: PseudoGeneric = "P"; LLVM_FALLTHROUGH; case Node::Kind::DependentGenericSignature: GenSig = Child; break; case Node::Kind::ImplSubstitutions: case Node::Kind::ImplImpliedSubstitutions: GenSubs = Child; isImplied = kind == Node::Kind::ImplImpliedSubstitutions; break; default: break; } } if (GenSig) mangle(GenSig); if (GenSubs) { Buffer << 'y'; mangleChildNodes(GenSubs->getChild(0)); if (GenSubs->getNumChildren() >= 2) mangleRetroactiveConformance(GenSubs->getChild(1)); } Buffer << 'I'; if (GenSubs) { Buffer << 's'; if (!isImplied) Buffer << 'i'; } Buffer << PseudoGeneric; for (NodePointer Child : *node) { switch (Child->getKind()) { case Node::Kind::ImplEscaping: Buffer << 'e'; break; case Node::Kind::ImplConvention: { char ConvCh = llvm::StringSwitch(Child->getText()) .Case("@callee_unowned", 'y') .Case("@callee_guaranteed", 'g') .Case("@callee_owned", 'x') .Case("@convention(thin)", 't') .Default(0); assert(ConvCh && "invalid impl callee convention"); Buffer << ConvCh; break; } case Node::Kind::ImplFunctionAttribute: { char FuncAttr = llvm::StringSwitch(Child->getText()) .Case("@convention(block)", 'B') .Case("@convention(c)", 'C') .Case("@convention(method)", 'M') .Case("@convention(objc_method)", 'O') .Case("@convention(closure)", 'K') .Case("@convention(witness_method)", 'W') .Default(0); assert(FuncAttr && "invalid impl function attribute"); Buffer << FuncAttr; break; } case Node::Kind::ImplParameter: { char ConvCh = llvm::StringSwitch(Child->getFirstChild()->getText()) .Case("@in", 'i') .Case("@inout", 'l') .Case("@inout_aliasable", 'b') .Case("@in_guaranteed", 'n') .Case("@in_constant", 'c') .Case("@owned", 'x') .Case("@guaranteed", 'g') .Case("@deallocating", 'e') .Case("@unowned", 'y') .Default(0); assert(ConvCh && "invalid impl parameter convention"); Buffer << ConvCh; break; } case Node::Kind::ImplErrorResult: Buffer << 'z'; LLVM_FALLTHROUGH; case Node::Kind::ImplResult: { char ConvCh = llvm::StringSwitch(Child->getFirstChild()->getText()) .Case("@out", 'r') .Case("@owned", 'o') .Case("@unowned", 'd') .Case("@unowned_inner_pointer", 'u') .Case("@autoreleased", 'a') .Default(0); assert(ConvCh && "invalid impl parameter convention"); Buffer << ConvCh; break; } default: break; } } Buffer << '_'; } void Remangler::mangleImplicitClosure(Node *node) { mangleChildNode(node, 0); // context mangleChildNode(node, 2); // type Buffer << "fu"; mangleChildNode(node, 1); // index } void Remangler::mangleImplParameter(Node *node) { unreachable("handled inline"); } void Remangler::mangleImplResult(Node *node) { unreachable("handled inline"); } void Remangler::mangleImplErrorResult(Node *node) { unreachable("handled inline"); } void Remangler::mangleInOut(Node *node) { mangleSingleChildNode(node); Buffer << 'z'; } void Remangler::mangleShared(Node *node) { mangleSingleChildNode(node); Buffer << 'h'; } void Remangler::mangleOwned(Node *node) { mangleSingleChildNode(node); Buffer << 'n'; } void Remangler::mangleInfixOperator(Node *node) { mangleIdentifierImpl(node, /*isOperator*/ true); Buffer << "oi"; } void Remangler::mangleInitializer(Node *node) { mangleChildNodes(node); Buffer << "fi"; } void Remangler::manglePropertyWrapperBackingInitializer(Node *node) { mangleChildNodes(node); Buffer << "fP"; } void Remangler::mangleLazyProtocolWitnessTableAccessor(Node *node) { mangleChildNodes(node); Buffer << "Wl"; } void Remangler::mangleLazyProtocolWitnessTableCacheVariable(Node *node) { mangleChildNodes(node); Buffer << "WL"; } void Remangler::mangleLocalDeclName(Node *node) { mangleChildNode(node, 1); // identifier Buffer << 'L'; mangleChildNode(node, 0); // index } void Remangler::mangleMaterializeForSet(Node *node) { mangleAbstractStorage(node->getFirstChild(), "m"); } void Remangler::mangleMetatype(Node *node) { if (node->getFirstChild()->getKind() == Node::Kind::MetatypeRepresentation) { mangleChildNode(node, 1); Buffer << "XM"; mangleChildNode(node, 0); } else { mangleSingleChildNode(node); Buffer << 'm'; } } void Remangler::mangleMetatypeRepresentation(Node *node) { if (node->getText() == "@thin") { Buffer << 't'; } else if (node->getText() == "@thick") { Buffer << 'T'; } else if (node->getText() == "@objc_metatype") { Buffer << 'o'; } else { unreachable("wrong metatype representation"); } } void Remangler::mangleMetaclass(Node *node) { mangleChildNodes(node); Buffer << "Mm"; } void Remangler::mangleModifyAccessor(Node *node) { mangleAbstractStorage(node->getFirstChild(), "M"); } void Remangler::mangleModule(Node *node) { if (node->getText() == STDLIB_NAME) { Buffer << 's'; } else if (node->getText() == MANGLING_MODULE_OBJC) { Buffer << "So"; } else if (node->getText() == MANGLING_MODULE_CLANG_IMPORTER) { Buffer << "SC"; } else { mangleIdentifier(node); } } void Remangler::mangleNativeOwningAddressor(Node *node) { mangleAbstractStorage(node->getFirstChild(), "lo"); } void Remangler::mangleNativeOwningMutableAddressor(Node *node) { mangleAbstractStorage(node->getFirstChild(), "ao"); } void Remangler::mangleNativePinningAddressor(Node *node) { mangleAbstractStorage(node->getFirstChild(), "lp"); } void Remangler::mangleNativePinningMutableAddressor(Node *node) { mangleAbstractStorage(node->getFirstChild(), "aP"); } void Remangler::mangleClassMetadataBaseOffset(Node *node) { mangleSingleChildNode(node); Buffer << "Mo"; } void Remangler::mangleNominalTypeDescriptor(Node *node) { mangleSingleChildNode(node); Buffer << "Mn"; } void Remangler::mangleOpaqueTypeDescriptor(Node *node) { mangleSingleChildNode(node); Buffer << "MQ"; } void Remangler::mangleOpaqueTypeDescriptorAccessor(Node *node) { mangleSingleChildNode(node); Buffer << "Mg"; } void Remangler::mangleOpaqueTypeDescriptorAccessorImpl(Node *node) { mangleSingleChildNode(node); Buffer << "Mh"; } void Remangler::mangleOpaqueTypeDescriptorAccessorKey(Node *node) { mangleSingleChildNode(node); Buffer << "Mj"; } void Remangler::mangleOpaqueTypeDescriptorAccessorVar(Node *node) { mangleSingleChildNode(node); Buffer << "Mk"; } void Remangler::manglePropertyDescriptor(Node *node) { mangleSingleChildNode(node); Buffer << "MV"; } void Remangler::mangleNonObjCAttribute(Node *node) { Buffer << "TO"; } void Remangler::mangleTuple(Node *node) { mangleTypeList(node); Buffer << 't'; } void Remangler::mangleNumber(Node *node) { mangleIndex(node->getIndex()); } void Remangler::mangleObjCAttribute(Node *node) { Buffer << "To"; } void Remangler::mangleObjCBlock(Node *node) { mangleChildNodesReversed(node); Buffer << "XB"; } void Remangler::mangleEscapingObjCBlock(Node *node) { mangleChildNodesReversed(node); Buffer << "XL"; } void Remangler::mangleOwningAddressor(Node *node) { mangleAbstractStorage(node->getFirstChild(), "lO"); } void Remangler::mangleOwningMutableAddressor(Node *node) { mangleAbstractStorage(node->getFirstChild(), "aO"); } void Remangler::manglePartialApplyForwarder(Node *node) { mangleChildNodesReversed(node); Buffer << "TA"; } void Remangler::manglePartialApplyObjCForwarder(Node *node) { mangleChildNodesReversed(node); Buffer << "Ta"; } void Remangler::mangleMergedFunction(Node *node) { Buffer << "Tm"; } void Remangler::mangleDynamicallyReplaceableFunctionImpl(Node *node) { Buffer << "TI"; } void Remangler::mangleDynamicallyReplaceableFunctionKey(Node *node) { Buffer << "Tx"; } void Remangler::mangleDynamicallyReplaceableFunctionVar(Node *node) { Buffer << "TX"; } void Remangler::manglePostfixOperator(Node *node) { mangleIdentifierImpl(node, /*isOperator*/ true); Buffer << "oP"; } void Remangler::manglePrefixOperator(Node *node) { mangleIdentifierImpl(node, /*isOperator*/ true); Buffer << "op"; } void Remangler::manglePrivateDeclName(Node *node) { mangleChildNodesReversed(node); Buffer << (node->getNumChildren() == 1 ? "Ll" : "LL"); } void Remangler::mangleProtocol(Node *node) { mangleAnyGenericType(node, "P"); } void Remangler::mangleRetroactiveConformance(Node *node) { mangleAnyProtocolConformance(node->getChild(1)); Buffer << 'g'; mangleIndex(node->getChild(0)->getIndex()); } void Remangler::mangleProtocolConformance(Node *node) { Node *Ty = getChildOfType(node->getChild(0)); Node *GenSig = nullptr; if (Ty->getKind() == Node::Kind::DependentGenericType) { GenSig = Ty->getFirstChild(); Ty = Ty->getChild(1); } mangle(Ty); if (node->getNumChildren() == 4) mangleChildNode(node, 3); manglePureProtocol(node->getChild(1)); mangleChildNode(node, 2); if (GenSig) mangle(GenSig); } void Remangler::mangleProtocolConformanceRefInTypeModule(Node *node) { manglePureProtocol(node->getChild(0)); Buffer << "HP"; } void Remangler::mangleProtocolConformanceRefInProtocolModule(Node *node) { manglePureProtocol(node->getChild(0)); Buffer << "Hp"; } void Remangler::mangleProtocolConformanceRefInOtherModule(Node *node) { manglePureProtocol(node->getChild(0)); mangleChildNode(node, 1); } void Remangler::mangleConcreteProtocolConformance(Node *node) { mangleType(node->getChild(0)); mangle(node->getChild(1)); if (node->getNumChildren() > 2) mangleAnyProtocolConformanceList(node->getChild(2)); else Buffer << "y"; Buffer << "HC"; } void Remangler::mangleDependentProtocolConformanceRoot(Node *node) { mangleType(node->getChild(0)); manglePureProtocol(node->getChild(1)); Buffer << "HD"; mangleDependentConformanceIndex(node->getChild(2)); } void Remangler::mangleDependentProtocolConformanceInherited(Node *node) { mangleAnyProtocolConformance(node->getChild(0)); manglePureProtocol(node->getChild(1)); Buffer << "HI"; mangleDependentConformanceIndex(node->getChild(2)); } void Remangler::mangleDependentAssociatedConformance(Node *node) { mangleType(node->getChild(0)); manglePureProtocol(node->getChild(1)); } void Remangler::mangleDependentProtocolConformanceAssociated(Node *node) { mangleAnyProtocolConformance(node->getChild(0)); mangleDependentAssociatedConformance(node->getChild(1)); Buffer << "HA"; mangleDependentConformanceIndex(node->getChild(2)); } void Remangler::mangleDependentConformanceIndex(Node *node) { assert(node->getKind() == Node::Kind::Index || node->getKind() == Node::Kind::UnknownIndex); assert(node->hasIndex() == (node->getKind() == Node::Kind::Index)); mangleIndex(node->hasIndex() ? node->getIndex() + 2 : 1); } void Remangler::mangleAnyProtocolConformance(Node *node) { switch (node->getKind()) { case Node::Kind::ConcreteProtocolConformance: return mangleConcreteProtocolConformance(node); case Node::Kind::DependentProtocolConformanceRoot: return mangleDependentProtocolConformanceRoot(node); case Node::Kind::DependentProtocolConformanceInherited: return mangleDependentProtocolConformanceInherited(node); case Node::Kind::DependentProtocolConformanceAssociated: return mangleDependentProtocolConformanceAssociated(node); default: break; } } void Remangler::mangleAnyProtocolConformanceList(Node *node) { bool firstElem = true; for (NodePointer child : *node) { mangleAnyProtocolConformance(child); mangleListSeparator(firstElem); } mangleEndOfList(firstElem); } void Remangler::mangleProtocolDescriptor(Node *node) { manglePureProtocol(getSingleChild(node)); Buffer << "Mp"; } void Remangler::mangleProtocolRequirementsBaseDescriptor(Node *node) { manglePureProtocol(getSingleChild(node)); Buffer << "TL"; } void Remangler::mangleProtocolSelfConformanceDescriptor(Node *node) { manglePureProtocol(node->getChild(0)); Buffer << "MS"; } void Remangler::mangleProtocolConformanceDescriptor(Node *node) { mangleProtocolConformance(node->getChild(0)); Buffer << "Mc"; } void Remangler::mangleProtocolList(Node *node, Node *superclass, bool hasExplicitAnyObject) { auto *protocols = getSingleChild(node, Node::Kind::TypeList); bool FirstElem = true; for (NodePointer Child : *protocols) { manglePureProtocol(Child); mangleListSeparator(FirstElem); } mangleEndOfList(FirstElem); if (superclass) { mangleType(superclass); Buffer << "Xc"; return; } else if (hasExplicitAnyObject) { Buffer << "Xl"; return; } Buffer << 'p'; } void Remangler::mangleProtocolList(Node *node) { mangleProtocolList(node, nullptr, false); } void Remangler::mangleProtocolListWithClass(Node *node) { mangleProtocolList(node->getChild(0), node->getChild(1), false); } void Remangler::mangleProtocolListWithAnyObject(Node *node) { mangleProtocolList(node->getChild(0), nullptr, true); } void Remangler::mangleProtocolSelfConformanceWitness(Node *node) { mangleSingleChildNode(node); Buffer << "TS"; } void Remangler::mangleProtocolWitness(Node *node) { mangleChildNodes(node); Buffer << "TW"; } void Remangler::mangleProtocolSelfConformanceWitnessTable(Node *node) { manglePureProtocol(node->getChild(0)); Buffer << "WS"; } void Remangler::mangleProtocolWitnessTable(Node *node) { mangleSingleChildNode(node); Buffer << "WP"; } void Remangler::mangleProtocolWitnessTablePattern(Node *node) { mangleSingleChildNode(node); Buffer << "Wp"; } void Remangler::mangleProtocolWitnessTableAccessor(Node *node) { mangleSingleChildNode(node); Buffer << "Wa"; } void Remangler::mangleReabstractionThunk(Node *node) { mangleChildNodesReversed(node); Buffer << "Tr"; } void Remangler::mangleReabstractionThunkHelper(Node *node) { mangleChildNodesReversed(node); Buffer << "TR"; } void Remangler::mangleReabstractionThunkHelperWithSelf(Node *node) { mangleChildNodesReversed(node); Buffer << "Ty"; } void Remangler::mangleReadAccessor(Node *node) { mangleAbstractStorage(node->getFirstChild(), "r"); } void Remangler::mangleKeyPathThunkHelper(Node *node, StringRef op) { for (NodePointer Child : *node) if (Child->getKind() != Node::Kind::IsSerialized) mangle(Child); Buffer << op; for (NodePointer Child : *node) if (Child->getKind() == Node::Kind::IsSerialized) mangle(Child); } void Remangler::mangleKeyPathGetterThunkHelper(Node *node) { mangleKeyPathThunkHelper(node, "TK"); } void Remangler::mangleKeyPathSetterThunkHelper(Node *node) { mangleKeyPathThunkHelper(node, "Tk"); } void Remangler::mangleKeyPathEqualsThunkHelper(Node *node) { mangleKeyPathThunkHelper(node, "TH"); } void Remangler::mangleKeyPathHashThunkHelper(Node *node) { mangleKeyPathThunkHelper(node, "Th"); } void Remangler::mangleReturnType(Node *node) { mangleArgumentTuple(node); } void Remangler::mangleRelatedEntityDeclName(Node *node) { mangleChildNode(node, 1); NodePointer kindNode = node->getFirstChild(); if (kindNode->getText().size() != 1) unreachable("cannot handle multi-byte related entities"); Buffer << "L" << kindNode->getText(); } void Remangler::mangleSILBoxType(Node *node) { mangleSingleChildNode(node); Buffer << "Xb"; } void Remangler::mangleSetter(Node *node) { mangleAbstractStorage(node->getFirstChild(), "s"); } void Remangler::mangleSpecializationPassID(Node *node) { Buffer << node->getIndex(); } void Remangler::mangleIsSerialized(Node *node) { Buffer << 'q'; } void Remangler::mangleStatic(Node *node) { mangleSingleChildNode(node); Buffer << 'Z'; } void Remangler::mangleOtherNominalType(Node *node) { mangleAnyNominalType(node); } void Remangler::mangleStructure(Node *node) { mangleAnyNominalType(node); } void Remangler::mangleSubscript(Node *node) { mangleAbstractStorage(node, "p"); } void Remangler::mangleSuffix(Node *node) { // Just add the suffix back on. Buffer << node->getText(); } void Remangler::mangleThinFunctionType(Node *node) { mangleFunctionSignature(node); Buffer << "Xf"; } void Remangler::mangleTupleElement(Node *node) { mangleChildNodesReversed(node); // tuple type, element name? } void Remangler::mangleTupleElementName(Node *node) { mangleIdentifier(node); } void Remangler::mangleType(Node *node) { mangleSingleChildNode(node); } void Remangler::mangleTypeAlias(Node *node) { mangleAnyNominalType(node); } void Remangler::mangleTypeList(Node *node) { bool FirstElem = true; for (size_t Idx = 0, Num = node->getNumChildren(); Idx < Num; ++Idx) { mangleChildNode(node, Idx); mangleListSeparator(FirstElem); } mangleEndOfList(FirstElem); } void Remangler::mangleLabelList(Node *node) { if (node->getNumChildren() == 0) Buffer << 'y'; else mangleChildNodes(node); } void Remangler::mangleTypeMangling(Node *node) { mangleChildNodes(node); Buffer << 'D'; } void Remangler::mangleTypeMetadata(Node *node) { mangleSingleChildNode(node); Buffer << "N"; } void Remangler::mangleTypeMetadataAccessFunction(Node *node) { mangleSingleChildNode(node); Buffer << "Ma"; } void Remangler::mangleTypeMetadataInstantiationCache(Node *node) { mangleSingleChildNode(node); Buffer << "MI"; } void Remangler::mangleTypeMetadataInstantiationFunction(Node *node) { mangleSingleChildNode(node); Buffer << "Mi"; } void Remangler::mangleTypeMetadataSingletonInitializationCache(Node *node) { mangleSingleChildNode(node); Buffer << "Ml"; } void Remangler::mangleTypeMetadataCompletionFunction(Node *node) { mangleSingleChildNode(node); Buffer << "Mr"; } void Remangler::mangleTypeMetadataDemanglingCache(Node *node) { mangleChildNodes(node); Buffer << "MD"; } void Remangler::mangleTypeMetadataLazyCache(Node *node) { mangleChildNodes(node); Buffer << "ML"; } void Remangler::mangleUncurriedFunctionType(Node *node) { mangleFunctionSignature(node); // Mangle as regular function type (there is no "uncurried function type" // in the new mangling scheme). Buffer << 'c'; } void Remangler::mangleUnsafeAddressor(Node *node) { mangleAbstractStorage(node->getFirstChild(), "lu"); } void Remangler::mangleUnsafeMutableAddressor(Node *node) { mangleAbstractStorage(node->getFirstChild(), "au"); } void Remangler::mangleValueWitness(Node *node) { mangleChildNode(node, 1); // type const char *Code = nullptr; switch (ValueWitnessKind(node->getFirstChild()->getIndex())) { #define VALUE_WITNESS(MANGLING, NAME) \ case ValueWitnessKind::NAME: Code = #MANGLING; break; #include "swift/Demangling/ValueWitnessMangling.def" } Buffer << 'w' << Code; } void Remangler::mangleValueWitnessTable(Node *node) { mangleSingleChildNode(node); Buffer << "WV"; } void Remangler::mangleVariable(Node *node) { mangleAbstractStorage(node, "p"); } void Remangler::mangleVTableAttribute(Node *node) { unreachable("Old-fashioned vtable thunk in new mangling format"); } void Remangler::mangleVTableThunk(Node *node) { mangleChildNodes(node); Buffer << "TV"; } #define REF_STORAGE(Name, ...) \ void Remangler::mangle##Name(Node *node) { \ mangleSingleChildNode(node); \ Buffer << manglingOf(ReferenceOwnership::Name); \ } #include "swift/AST/ReferenceStorage.def" void Remangler::mangleWillSet(Node *node) { mangleAbstractStorage(node->getFirstChild(), "w"); } void Remangler::mangleReflectionMetadataBuiltinDescriptor(Node *node) { mangleSingleChildNode(node); Buffer << "MB"; } void Remangler::mangleReflectionMetadataFieldDescriptor(Node *node) { mangleSingleChildNode(node); Buffer << "MF"; } void Remangler::mangleReflectionMetadataAssocTypeDescriptor(Node *node) { mangleSingleChildNode(node); // protocol-conformance Buffer << "MA"; } void Remangler::mangleReflectionMetadataSuperclassDescriptor(Node *node) { mangleSingleChildNode(node); // protocol-conformance Buffer << "MC"; } void Remangler::mangleCurryThunk(Node *node) { mangleSingleChildNode(node); Buffer << "Tc"; } void Remangler::mangleDispatchThunk(Node *node) { mangleSingleChildNode(node); Buffer << "Tj"; } void Remangler::mangleMethodDescriptor(Node *node) { mangleSingleChildNode(node); Buffer << "Tq"; } void Remangler::mangleMethodLookupFunction(Node *node) { mangleSingleChildNode(node); Buffer << "Mu"; } void Remangler::mangleObjCMetadataUpdateFunction(Node *node) { mangleSingleChildNode(node); Buffer << "MU"; } void Remangler::mangleObjCResilientClassStub(Node *node) { mangleSingleChildNode(node); Buffer << "Ms"; } void Remangler::mangleFullObjCResilientClassStub(Node *node) { mangleSingleChildNode(node); Buffer << "Mt"; } void Remangler::mangleThrowsAnnotation(Node *node) { Buffer << 'K'; } void Remangler::mangleEmptyList(Node *node) { Buffer << 'y'; } void Remangler::mangleFirstElementMarker(Node *node) { Buffer << '_'; } void Remangler::mangleVariadicMarker(Node *node) { Buffer << 'd'; } void Remangler::mangleOutlinedCopy(Node *node) { mangleChildNodes(node); Buffer << "WOy"; } void Remangler::mangleOutlinedConsume(Node *node) { mangleChildNodes(node); Buffer << "WOe"; } void Remangler::mangleOutlinedRetain(Node *node) { mangleChildNodes(node); Buffer << "WOr"; } void Remangler::mangleOutlinedRelease(Node *node) { mangleChildNodes(node); Buffer << "WOs"; } void Remangler::mangleOutlinedInitializeWithTake(Node *node) { mangleChildNodes(node); Buffer << "WOb"; } void Remangler::mangleOutlinedInitializeWithCopy(Node *node) { mangleChildNodes(node); Buffer << "WOc"; } void Remangler::mangleOutlinedAssignWithTake(Node *node) { mangleChildNodes(node); Buffer << "WOd"; } void Remangler::mangleOutlinedAssignWithCopy(Node *node) { mangleChildNodes(node); Buffer << "WOf"; } void Remangler::mangleOutlinedDestroy(Node *node) { mangleChildNodes(node); Buffer << "WOh"; } void Remangler::mangleOutlinedVariable(Node *node) { Buffer << "Tv"; mangleIndex(node->getIndex()); } void Remangler::mangleOutlinedBridgedMethod(Node *node) { Buffer << "Te"; Buffer << node->getText(); Buffer << "_"; } void Remangler::mangleSILBoxTypeWithLayout(Node *node) { assert(node->getNumChildren() == 1 || node->getNumChildren() == 3); assert(node->getChild(0)->getKind() == Node::Kind::SILBoxLayout); auto layout = node->getChild(0); auto layoutTypeList = Factory.createNode(Node::Kind::TypeList); for (unsigned i = 0, e = layout->getNumChildren(); i < e; ++i) { assert(layout->getChild(i)->getKind() == Node::Kind::SILBoxImmutableField || layout->getChild(i)->getKind() == Node::Kind::SILBoxMutableField); auto field = layout->getChild(i); assert(field->getNumChildren() == 1 && field->getChild(0)->getKind() == Node::Kind::Type); auto fieldType = field->getChild(0); // 'inout' mangling is used to represent mutable fields. if (field->getKind() == Node::Kind::SILBoxMutableField) { auto inout = Factory.createNode(Node::Kind::InOut); inout->addChild(fieldType->getChild(0), Factory); fieldType = Factory.createNode(Node::Kind::Type); fieldType->addChild(inout, Factory); } layoutTypeList->addChild(fieldType, Factory); } mangleTypeList(layoutTypeList); if (node->getNumChildren() == 3) { auto signature = node->getChild(1); auto genericArgs = node->getChild(2); assert(signature->getKind() == Node::Kind::DependentGenericSignature); assert(genericArgs->getKind() == Node::Kind::TypeList); mangleTypeList(genericArgs); mangleDependentGenericSignature(signature); Buffer << "XX"; } else { Buffer << "Xx"; } } void Remangler::mangleSILBoxLayout(Node *node) { unreachable("should be part of SILBoxTypeWithLayout"); } void Remangler::mangleSILBoxMutableField(Node *node) { unreachable("should be part of SILBoxTypeWithLayout"); } void Remangler::mangleSILBoxImmutableField(Node *node) { unreachable("should be part of SILBoxTypeWithLayout"); } void Remangler::mangleAssocTypePath(Node *node) { bool FirstElem = true; for (NodePointer Child : *node) { mangle(Child); mangleListSeparator(FirstElem); } } void Remangler::mangleModuleDescriptor(Node *node) { mangle(node->getChild(0)); Buffer << "MXM"; } void Remangler::mangleExtensionDescriptor(Node *node) { mangle(node->getChild(0)); Buffer << "MXE"; } void Remangler::mangleAnonymousDescriptor(Node *node) { mangle(node->getChild(0)); if (node->getNumChildren() == 1) { Buffer << "MXX"; } else { mangleIdentifier(node->getChild(1)); Buffer << "MXY"; } } void Remangler::mangleAssociatedTypeGenericParamRef(Node *node) { mangleType(node->getChild(0)); mangleAssocTypePath(node->getChild(1)); Buffer << "MXA"; } void Remangler::mangleTypeSymbolicReference(Node *node) { return mangle(Resolver(SymbolicReferenceKind::Context, (const void *)node->getIndex())); } void Remangler::mangleProtocolSymbolicReference(Node *node) { return mangle(Resolver(SymbolicReferenceKind::Context, (const void *)node->getIndex())); } void Remangler::mangleOpaqueTypeDescriptorSymbolicReference(Node *node) { return mangle(Resolver(SymbolicReferenceKind::Context, (const void *)node->getIndex())); } void Remangler::mangleSugaredOptional(Node *node) { mangleType(node->getChild(0)); Buffer << "XSq"; } void Remangler::mangleSugaredArray(Node *node) { mangleType(node->getChild(0)); Buffer << "XSa"; } void Remangler::mangleSugaredDictionary(Node *node) { mangleType(node->getChild(0)); mangleType(node->getChild(1)); Buffer << "XSD"; } void Remangler::mangleSugaredParen(Node *node) { mangleType(node->getChild(0)); Buffer << "XSp"; } void Remangler::mangleOpaqueReturnType(Node *node) { Buffer << "Qr"; } void Remangler::mangleOpaqueReturnTypeOf(Node *node) { mangle(node->getChild(0)); Buffer << "QO"; } void Remangler::mangleOpaqueType(Node *node) { SubstitutionEntry entry; if (trySubstitution(node, entry)) return; mangle(node->getChild(0)); auto boundGenerics = node->getChild(2); for (unsigned i = 0; i < boundGenerics->getNumChildren(); ++i) { Buffer << (i == 0 ? 'y' : '_'); mangleChildNodes(boundGenerics->getChild(i)); } if (node->getNumChildren() >= 4) { auto retroactiveConformances = node->getChild(3); for (unsigned i = 0; i < retroactiveConformances->getNumChildren(); ++i) { mangle(retroactiveConformances->getChild(i)); } } Buffer << "Qo"; mangleIndex(node->getChild(1)->getIndex()); addSubstitution(entry); } void Remangler::mangleAccessorFunctionReference(Node *node) { unreachable("can't remangle"); } } // anonymous namespace /// The top-level interface to the remangler. std::string Demangle::mangleNode(NodePointer node) { return mangleNode(node, [](SymbolicReferenceKind, const void *) -> NodePointer { unreachable("should not try to mangle a symbolic reference; " "resolve it to a non-symbolic demangling tree instead"); }); } std::string Demangle::mangleNode(NodePointer node, SymbolicResolver resolver) { if (!node) return ""; NodeFactory Factory; Remangler remangler(resolver, Factory); remangler.mangle(node); return remangler.str(); } llvm::StringRef Demangle::mangleNode(NodePointer node, SymbolicResolver resolver, NodeFactory &Factory) { if (!node) return StringRef(); Remangler remangler(resolver, Factory); remangler.mangle(node); return remangler.getBufferStr(); } bool Demangle::isSpecialized(Node *node) { switch (node->getKind()) { case Node::Kind::BoundGenericStructure: case Node::Kind::BoundGenericEnum: case Node::Kind::BoundGenericClass: case Node::Kind::BoundGenericOtherNominalType: case Node::Kind::BoundGenericTypeAlias: case Node::Kind::BoundGenericProtocol: case Node::Kind::BoundGenericFunction: return true; case Node::Kind::Structure: case Node::Kind::Enum: case Node::Kind::Class: case Node::Kind::TypeAlias: case Node::Kind::OtherNominalType: case Node::Kind::Protocol: case Node::Kind::Function: case Node::Kind::Allocator: case Node::Kind::Constructor: case Node::Kind::Destructor: case Node::Kind::Variable: case Node::Kind::Subscript: case Node::Kind::ExplicitClosure: case Node::Kind::ImplicitClosure: case Node::Kind::Initializer: case Node::Kind::PropertyWrapperBackingInitializer: case Node::Kind::DefaultArgumentInitializer: case Node::Kind::Getter: case Node::Kind::Setter: case Node::Kind::WillSet: case Node::Kind::DidSet: case Node::Kind::ReadAccessor: case Node::Kind::ModifyAccessor: case Node::Kind::UnsafeAddressor: case Node::Kind::UnsafeMutableAddressor: return isSpecialized(node->getChild(0)); case Node::Kind::Extension: return isSpecialized(node->getChild(1)); default: return false; } } NodePointer Demangle::getUnspecialized(Node *node, NodeFactory &Factory) { unsigned NumToCopy = 2; switch (node->getKind()) { case Node::Kind::Function: case Node::Kind::Getter: case Node::Kind::Setter: case Node::Kind::WillSet: case Node::Kind::DidSet: case Node::Kind::ReadAccessor: case Node::Kind::ModifyAccessor: case Node::Kind::UnsafeAddressor: case Node::Kind::UnsafeMutableAddressor: case Node::Kind::Allocator: case Node::Kind::Constructor: case Node::Kind::Destructor: case Node::Kind::Variable: case Node::Kind::Subscript: case Node::Kind::ExplicitClosure: case Node::Kind::ImplicitClosure: case Node::Kind::Initializer: case Node::Kind::PropertyWrapperBackingInitializer: case Node::Kind::DefaultArgumentInitializer: NumToCopy = node->getNumChildren(); LLVM_FALLTHROUGH; case Node::Kind::Structure: case Node::Kind::Enum: case Node::Kind::Class: case Node::Kind::TypeAlias: case Node::Kind::OtherNominalType: { NodePointer result = Factory.createNode(node->getKind()); NodePointer parentOrModule = node->getChild(0); if (isSpecialized(parentOrModule)) parentOrModule = getUnspecialized(parentOrModule, Factory); result->addChild(parentOrModule, Factory); for (unsigned Idx = 1; Idx < NumToCopy; ++Idx) { result->addChild(node->getChild(Idx), Factory); } return result; } case Node::Kind::BoundGenericStructure: case Node::Kind::BoundGenericEnum: case Node::Kind::BoundGenericClass: case Node::Kind::BoundGenericProtocol: case Node::Kind::BoundGenericOtherNominalType: case Node::Kind::BoundGenericTypeAlias: { NodePointer unboundType = node->getChild(0); assert(unboundType->getKind() == Node::Kind::Type); NodePointer nominalType = unboundType->getChild(0); if (isSpecialized(nominalType)) return getUnspecialized(nominalType, Factory); return nominalType; } case Node::Kind::BoundGenericFunction: { NodePointer unboundFunction = node->getChild(0); assert(unboundFunction->getKind() == Node::Kind::Function || unboundFunction->getKind() == Node::Kind::Constructor); if (isSpecialized(unboundFunction)) return getUnspecialized(unboundFunction, Factory); return unboundFunction; } case Node::Kind::Extension: { NodePointer parent = node->getChild(1); if (!isSpecialized(parent)) return node; NodePointer result = Factory.createNode(Node::Kind::Extension); result->addChild(node->getFirstChild(), Factory); result->addChild(getUnspecialized(parent, Factory), Factory); if (node->getNumChildren() == 3) { // Add the generic signature of the extension. result->addChild(node->getChild(2), Factory); } return result; } default: unreachable("bad nominal type kind"); } }