mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This new format more efficiently represents existing information, while more accurately encoding important information about nested generic contexts with same-type and layout constraints that need to be evaluated at runtime. It's also designed with an eye to forward- and backward-compatible expansion for ABI stability with future Swift versions.
623 lines
22 KiB
C++
623 lines
22 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/Basic/Range.h"
|
|
#include "swift/Runtime/Metadata.h"
|
|
#include "swift/Strings.h"
|
|
#include "Private.h"
|
|
|
|
#include <vector>
|
|
|
|
#if SWIFT_OBJC_INTEROP
|
|
#include <objc/runtime.h>
|
|
#endif
|
|
|
|
using namespace swift;
|
|
|
|
// FIXME: This stuff should be merged with the existing logic in
|
|
// include/swift/Reflection/TypeRefBuilder.h as part of the rewrite
|
|
// to change stdlib reflection over to using remote mirrors.
|
|
|
|
Demangle::NodePointer
|
|
swift::_swift_buildDemanglingForMetadata(const Metadata *type,
|
|
Demangle::Demangler &Dem);
|
|
|
|
static Demangle::NodePointer
|
|
_buildDemanglerForBuiltinType(const Metadata *type, Demangle::Demangler &Dem) {
|
|
#define BUILTIN_TYPE(Symbol, Name) \
|
|
if (type == &METADATA_SYM(Symbol).base) \
|
|
return Dem.createNode(Node::Kind::BuiltinTypeName, Name);
|
|
#include "swift/Runtime/BuiltinTypes.def"
|
|
return nullptr;
|
|
}
|
|
|
|
/// Build a demangled type tree for a nominal type.
|
|
static Demangle::NodePointer
|
|
_buildDemanglingForNominalType(const Metadata *type, Demangle::Demangler &Dem) {
|
|
using namespace Demangle;
|
|
|
|
// Get the context descriptor from the type metadata.
|
|
const TypeContextDescriptor *description;
|
|
|
|
switch (type->getKind()) {
|
|
case MetadataKind::Class: {
|
|
auto classType = static_cast<const ClassMetadata *>(type);
|
|
#if SWIFT_OBJC_INTEROP
|
|
// Peek through artificial subclasses.
|
|
while (classType->isTypeMetadata() && classType->isArtificialSubclass())
|
|
classType = classType->SuperClass;
|
|
#endif
|
|
description = classType->getDescription();
|
|
break;
|
|
}
|
|
case MetadataKind::Enum:
|
|
case MetadataKind::Optional: {
|
|
auto enumType = static_cast<const EnumMetadata *>(type);
|
|
description = enumType->Description;
|
|
break;
|
|
}
|
|
case MetadataKind::Struct: {
|
|
auto structType = static_cast<const StructMetadata *>(type);
|
|
description = structType->Description;
|
|
break;
|
|
}
|
|
default:
|
|
return nullptr;
|
|
}
|
|
|
|
// Demangle the generic arguments.
|
|
std::vector<NodePointer> demangledGenerics;
|
|
bool concretizedGenerics = false;
|
|
if (auto generics = description->getGenericContext()) {
|
|
auto genericArgs = description->getGenericArguments(type);
|
|
for (auto param : generics->getGenericParams()) {
|
|
switch (param.getKind()) {
|
|
case GenericParamKind::Type:
|
|
// We don't know about type parameters with extra arguments.
|
|
if (param.hasExtraArgument()) {
|
|
genericArgs += param.hasExtraArgument() + param.hasKeyArgument();
|
|
goto unknown_param;
|
|
}
|
|
|
|
// The type should have a key argument unless it's been same-typed to
|
|
// another type.
|
|
if (param.hasKeyArgument()) {
|
|
auto paramType = *genericArgs++;
|
|
auto paramDemangling =
|
|
_swift_buildDemanglingForMetadata(paramType, Dem);
|
|
if (!paramDemangling)
|
|
return nullptr;
|
|
demangledGenerics.push_back(paramDemangling);
|
|
} else {
|
|
// Leave a gap for us to fill in by looking at same type info.
|
|
demangledGenerics.push_back(nullptr);
|
|
concretizedGenerics = true;
|
|
}
|
|
break;
|
|
|
|
unknown_param:
|
|
default: {
|
|
// We don't know about this kind of parameter. Create a placeholder
|
|
// mangling.
|
|
// ABI TODO: Mangle some kind of unique "unknown parameter"
|
|
// representation here.
|
|
auto placeholder = Dem.createNode(Node::Kind::Tuple);
|
|
auto emptyList = Dem.createNode(Node::Kind::TypeList);
|
|
placeholder->addChild(emptyList, Dem);
|
|
auto type = Dem.createNode(Node::Kind::Type);
|
|
type->addChild(placeholder, Dem);
|
|
demangledGenerics.push_back(type);
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we have concretized generic arguments, check for same type
|
|
// requirements to get the argument values.
|
|
// ABI TODO
|
|
}
|
|
unsigned usedDemangledGenerics = 0;
|
|
|
|
// Walk up the context tree.
|
|
std::vector<const ContextDescriptor *> descriptorPath;
|
|
{
|
|
const ContextDescriptor *parent = description;
|
|
while (parent) {
|
|
descriptorPath.push_back(parent);
|
|
parent = parent->Parent;
|
|
}
|
|
}
|
|
|
|
// Build a demangling tree from the context path.
|
|
NodePointer node = nullptr;
|
|
|
|
auto getGenericArgsTypeListForContext =
|
|
[&](const ContextDescriptor *context) -> NodePointer {
|
|
// ABI TODO: As a hack to maintain existing broken behavior,
|
|
// if there were any generic arguments eliminated by same type
|
|
// constraints, we don't mangle any of them into intermediate contexts,
|
|
// and pile all of the non-concrete arguments into the innermost context.
|
|
if (concretizedGenerics)
|
|
return nullptr;
|
|
|
|
auto generics = context->getGenericContext();
|
|
if (!generics)
|
|
return nullptr;
|
|
|
|
auto numParams = generics->getGenericContextHeader().NumParams;
|
|
if (numParams <= usedDemangledGenerics)
|
|
return nullptr;
|
|
|
|
auto genericArgsList = Dem.createNode(Node::Kind::TypeList);
|
|
for (unsigned e = generics->getGenericContextHeader().NumParams;
|
|
usedDemangledGenerics < e;
|
|
++usedDemangledGenerics) {
|
|
genericArgsList->addChild(demangledGenerics[usedDemangledGenerics],
|
|
Dem);
|
|
}
|
|
return genericArgsList;
|
|
};
|
|
|
|
auto innermostComponent = descriptorPath.front();
|
|
for (auto component : reversed(descriptorPath)) {
|
|
switch (auto kind = component->getKind()) {
|
|
case ContextDescriptorKind::Module: {
|
|
assert(node == nullptr && "module should be top level");
|
|
auto name = llvm::cast<ModuleContextDescriptor>(component)->Name.get();
|
|
node = Dem.createNode(Node::Kind::Module, name);
|
|
break;
|
|
}
|
|
|
|
case ContextDescriptorKind::Extension: {
|
|
auto extension = llvm::cast<ExtensionContextDescriptor>(component);
|
|
// Demangle the extension self type.
|
|
auto selfType = Dem.demangleType(extension->ExtendedContext.get());
|
|
assert(selfType->getKind() == Node::Kind::Type);
|
|
selfType = selfType->getChild(0);
|
|
|
|
// Substitute in the generic arguments.
|
|
// TODO: This kludge only kinda works if there are no same-type
|
|
// constraints. We'd need to handle those correctly everywhere else too
|
|
// though.
|
|
auto genericArgsList = getGenericArgsTypeListForContext(component);
|
|
|
|
if (selfType->getKind() == Node::Kind::BoundGenericEnum
|
|
|| selfType->getKind() == Node::Kind::BoundGenericStructure
|
|
|| selfType->getKind() == Node::Kind::BoundGenericClass
|
|
|| selfType->getKind() == Node::Kind::BoundGenericOtherNominalType) {
|
|
if (genericArgsList) {
|
|
auto substSelfType = Dem.createNode(selfType->getKind());
|
|
substSelfType->addChild(selfType->getChild(0), Dem);
|
|
substSelfType->addChild(genericArgsList, Dem);
|
|
selfType = substSelfType;
|
|
} else {
|
|
// TODO: Use the unsubstituted type if we can't handle the
|
|
// substitutions yet.
|
|
selfType = selfType->getChild(0)->getChild(0);
|
|
}
|
|
}
|
|
|
|
auto extNode = Dem.createNode(Node::Kind::Extension);
|
|
extNode->addChild(node, Dem);
|
|
extNode->addChild(selfType, Dem);
|
|
|
|
// TODO: Turn the generic signature into a demangling as the third
|
|
// generic argument.
|
|
|
|
node = extNode;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
// Form a type context demangling for type contexts.
|
|
if (auto type = llvm::dyn_cast<TypeContextDescriptor>(component)) {
|
|
auto name = type->Name.get();
|
|
Node::Kind nodeKind;
|
|
Node::Kind genericNodeKind;
|
|
switch (kind) {
|
|
case ContextDescriptorKind::Class:
|
|
nodeKind = Node::Kind::Class;
|
|
genericNodeKind = Node::Kind::BoundGenericClass;
|
|
break;
|
|
case ContextDescriptorKind::Struct:
|
|
nodeKind = Node::Kind::Structure;
|
|
genericNodeKind = Node::Kind::BoundGenericStructure;
|
|
break;
|
|
case ContextDescriptorKind::Enum:
|
|
nodeKind = Node::Kind::Enum;
|
|
genericNodeKind = Node::Kind::BoundGenericEnum;
|
|
break;
|
|
default:
|
|
// We don't know about this kind of type. Use an "other type" mangling
|
|
// for it.
|
|
nodeKind = Node::Kind::OtherNominalType;
|
|
genericNodeKind = Node::Kind::BoundGenericOtherNominalType;
|
|
break;
|
|
}
|
|
|
|
// Override the node kind if this is a Clang-imported type so we give it
|
|
// a stable mangling.
|
|
auto typeFlags = type->Flags.getKindSpecificFlags();
|
|
if (typeFlags & (uint16_t)TypeContextDescriptorFlags::IsCTag) {
|
|
nodeKind = Node::Kind::Structure;
|
|
} else if (typeFlags & (uint16_t)TypeContextDescriptorFlags::IsCTypedef) {
|
|
nodeKind = Node::Kind::TypeAlias;
|
|
}
|
|
|
|
auto typeNode = Dem.createNode(nodeKind);
|
|
typeNode->addChild(node, Dem);
|
|
auto identifier = Dem.createNode(Node::Kind::Identifier, name);
|
|
typeNode->addChild(identifier, Dem);
|
|
node = typeNode;
|
|
|
|
// Apply generic arguments if the context is generic.
|
|
if (auto genericArgsList = getGenericArgsTypeListForContext(component)){
|
|
auto unspecializedType = Dem.createNode(Node::Kind::Type);
|
|
unspecializedType->addChild(node, Dem);
|
|
|
|
auto genericNode = Dem.createNode(genericNodeKind);
|
|
genericNode->addChild(unspecializedType, Dem);
|
|
genericNode->addChild(genericArgsList, Dem);
|
|
node = genericNode;
|
|
}
|
|
|
|
// ABI TODO: If there were concretized generic arguments, just pile
|
|
// all the non-concretized generic arguments into the innermost context.
|
|
if (concretizedGenerics && component == innermostComponent) {
|
|
auto unspecializedType = Dem.createNode(Node::Kind::Type);
|
|
unspecializedType->addChild(node, Dem);
|
|
|
|
auto genericTypeList = Dem.createNode(Node::Kind::TypeList);
|
|
for (auto arg : demangledGenerics) {
|
|
if (!arg) continue;
|
|
genericTypeList->addChild(arg, Dem);
|
|
}
|
|
|
|
if (genericTypeList->getNumChildren() > 0) {
|
|
auto genericNode = Dem.createNode(genericNodeKind);
|
|
genericNode->addChild(unspecializedType, Dem);
|
|
genericNode->addChild(genericTypeList, Dem);
|
|
node = genericNode;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// This runtime doesn't understand this context, or it's a context with
|
|
// no richer runtime information available about it (such as an anonymous
|
|
// context). Use an unstable mangling to represent the context by its
|
|
// pointer identity.
|
|
// ABI TODO: extensions fall into this path, but they shouldn't. we
|
|
// should try to demangle them accurately.
|
|
char addressBuf[sizeof(void*) * 2 + 2 + 1];
|
|
snprintf(addressBuf, sizeof(addressBuf), "0x%" PRIxPTR, (uintptr_t)component);
|
|
|
|
auto anonNode = Dem.createNode(Node::Kind::AnonymousContext);
|
|
CharVector addressStr;
|
|
addressStr.append(addressBuf, Dem);
|
|
auto name = Dem.createNode(Node::Kind::Identifier, addressStr);
|
|
anonNode->addChild(name, Dem);
|
|
anonNode->addChild(node, Dem);
|
|
|
|
// Collect generic arguments if the context is generic.
|
|
auto genericArgsList = getGenericArgsTypeListForContext(component);
|
|
if (!genericArgsList)
|
|
genericArgsList = Dem.createNode(Node::Kind::TypeList);
|
|
anonNode->addChild(genericArgsList, Dem);
|
|
|
|
node = anonNode;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Wrap the final result in a top-level Type node.
|
|
auto top = Dem.createNode(Node::Kind::Type);
|
|
top->addChild(node, Dem);
|
|
return top;
|
|
}
|
|
|
|
// Build a demangled type tree for a type.
|
|
Demangle::NodePointer
|
|
swift::_swift_buildDemanglingForMetadata(const Metadata *type,
|
|
Demangle::Demangler &Dem) {
|
|
using namespace Demangle;
|
|
|
|
switch (type->getKind()) {
|
|
case MetadataKind::Class:
|
|
case MetadataKind::Enum:
|
|
case MetadataKind::Optional:
|
|
case MetadataKind::Struct:
|
|
return _buildDemanglingForNominalType(type, Dem);
|
|
case MetadataKind::ObjCClassWrapper: {
|
|
#if SWIFT_OBJC_INTEROP
|
|
auto objcWrapper = static_cast<const ObjCClassWrapperMetadata *>(type);
|
|
const char *className = class_getName(objcWrapper->getObjCClassObject());
|
|
|
|
auto module = Dem.createNode(Node::Kind::Module, MANGLING_MODULE_OBJC);
|
|
auto node = Dem.createNode(Node::Kind::Class);
|
|
node->addChild(module, Dem);
|
|
node->addChild(Dem.createNode(Node::Kind::Identifier,
|
|
llvm::StringRef(className)), Dem);
|
|
|
|
return node;
|
|
#else
|
|
assert(false && "no ObjC interop");
|
|
return nullptr;
|
|
#endif
|
|
}
|
|
case MetadataKind::ForeignClass: {
|
|
auto foreign = static_cast<const ForeignClassMetadata *>(type);
|
|
return Dem.demangleType(foreign->getName());
|
|
}
|
|
case MetadataKind::Existential: {
|
|
auto exis = static_cast<const ExistentialTypeMetadata *>(type);
|
|
|
|
std::vector<const ProtocolDescriptor *> protocols;
|
|
protocols.reserve(exis->Protocols.NumProtocols);
|
|
for (unsigned i = 0, e = exis->Protocols.NumProtocols; i < e; ++i)
|
|
protocols.push_back(exis->Protocols[i]);
|
|
|
|
auto type_list = Dem.createNode(Node::Kind::TypeList);
|
|
auto proto_list = Dem.createNode(Node::Kind::ProtocolList);
|
|
proto_list->addChild(type_list, Dem);
|
|
|
|
// The protocol descriptors should be pre-sorted since the compiler will
|
|
// only ever make a swift_getExistentialTypeMetadata invocation using
|
|
// its canonical ordering of protocols.
|
|
|
|
for (auto *protocol : protocols) {
|
|
// The protocol name is mangled as a type symbol, with the _Tt prefix.
|
|
StringRef ProtoName(protocol->Name);
|
|
NodePointer protocolNode = Dem.demangleSymbol(ProtoName);
|
|
|
|
// ObjC protocol names aren't mangled.
|
|
if (!protocolNode) {
|
|
auto module = Dem.createNode(Node::Kind::Module,
|
|
MANGLING_MODULE_OBJC);
|
|
auto node = Dem.createNode(Node::Kind::Protocol);
|
|
node->addChild(module, Dem);
|
|
node->addChild(Dem.createNode(Node::Kind::Identifier,
|
|
llvm::StringRef(protocol->Name)), Dem);
|
|
auto typeNode = Dem.createNode(Node::Kind::Type);
|
|
typeNode->addChild(node, Dem);
|
|
type_list->addChild(typeNode, Dem);
|
|
continue;
|
|
}
|
|
|
|
// Dig out the protocol node.
|
|
// Global -> (Protocol|TypeMangling)
|
|
protocolNode = protocolNode->getChild(0);
|
|
if (protocolNode->getKind() == Node::Kind::TypeMangling) {
|
|
protocolNode = protocolNode->getChild(0); // TypeMangling -> Type
|
|
protocolNode = protocolNode->getChild(0); // Type -> ProtocolList
|
|
protocolNode = protocolNode->getChild(0); // ProtocolList -> TypeList
|
|
protocolNode = protocolNode->getChild(0); // TypeList -> Type
|
|
|
|
assert(protocolNode->getKind() == Node::Kind::Type);
|
|
assert(protocolNode->getChild(0)->getKind() == Node::Kind::Protocol);
|
|
} else {
|
|
assert(protocolNode->getKind() == Node::Kind::Protocol);
|
|
}
|
|
|
|
type_list->addChild(protocolNode, Dem);
|
|
}
|
|
|
|
if (auto superclass = exis->getSuperclassConstraint()) {
|
|
// If there is a superclass constraint, we mangle it specially.
|
|
auto result = Dem.createNode(Node::Kind::ProtocolListWithClass);
|
|
auto superclassNode = _swift_buildDemanglingForMetadata(superclass, Dem);
|
|
|
|
result->addChild(proto_list, Dem);
|
|
result->addChild(superclassNode, Dem);
|
|
return result;
|
|
}
|
|
|
|
if (exis->isClassBounded()) {
|
|
// Check if the class constraint is implied by any of our
|
|
// protocols.
|
|
bool requiresClassImplicit = false;
|
|
|
|
for (auto *protocol : protocols) {
|
|
if (protocol->Flags.getClassConstraint()
|
|
== ProtocolClassConstraint::Class)
|
|
requiresClassImplicit = true;
|
|
}
|
|
|
|
// If it was implied, we don't do anything special.
|
|
if (requiresClassImplicit)
|
|
return proto_list;
|
|
|
|
// If the existential type has an explicit AnyObject constraint,
|
|
// we must mangle it as such.
|
|
auto result = Dem.createNode(Node::Kind::ProtocolListWithAnyObject);
|
|
result->addChild(proto_list, Dem);
|
|
return result;
|
|
}
|
|
|
|
// Just a simple composition of protocols.
|
|
return proto_list;
|
|
}
|
|
case MetadataKind::ExistentialMetatype: {
|
|
auto metatype = static_cast<const ExistentialMetatypeMetadata *>(type);
|
|
auto instance = _swift_buildDemanglingForMetadata(metatype->InstanceType,
|
|
Dem);
|
|
auto node = Dem.createNode(Node::Kind::ExistentialMetatype);
|
|
node->addChild(instance, Dem);
|
|
return node;
|
|
}
|
|
case MetadataKind::Function: {
|
|
auto func = static_cast<const FunctionTypeMetadata *>(type);
|
|
|
|
Node::Kind kind;
|
|
switch (func->getConvention()) {
|
|
case FunctionMetadataConvention::Swift:
|
|
kind = Node::Kind::FunctionType;
|
|
break;
|
|
case FunctionMetadataConvention::Block:
|
|
kind = Node::Kind::ObjCBlock;
|
|
break;
|
|
case FunctionMetadataConvention::CFunctionPointer:
|
|
kind = Node::Kind::CFunctionPointer;
|
|
break;
|
|
case FunctionMetadataConvention::Thin:
|
|
kind = Node::Kind::ThinFunctionType;
|
|
break;
|
|
}
|
|
|
|
std::vector<std::pair<NodePointer, bool>> inputs;
|
|
for (unsigned i = 0, e = func->getNumParameters(); i < e; ++i) {
|
|
auto param = func->getParameter(i);
|
|
auto flags = func->getParameterFlags(i);
|
|
auto input = _swift_buildDemanglingForMetadata(param, Dem);
|
|
|
|
if (flags.isInOut()) {
|
|
NodePointer inout = Dem.createNode(Node::Kind::InOut);
|
|
inout->addChild(input, Dem);
|
|
input = inout;
|
|
} else if (flags.isShared()) {
|
|
NodePointer shared = Dem.createNode(Node::Kind::Shared);
|
|
shared->addChild(input, Dem);
|
|
input = shared;
|
|
}
|
|
|
|
inputs.push_back({input, flags.isVariadic()});
|
|
}
|
|
|
|
NodePointer totalInput = nullptr;
|
|
switch (inputs.size()) {
|
|
case 1: {
|
|
auto &singleParam = inputs.front();
|
|
if (!singleParam.second) {
|
|
totalInput = singleParam.first;
|
|
break;
|
|
}
|
|
|
|
// If single parameter has a variadic marker it
|
|
// requires a tuple wrapper.
|
|
LLVM_FALLTHROUGH;
|
|
}
|
|
|
|
// This covers both none and multiple parameters.
|
|
default:
|
|
auto tuple = Dem.createNode(Node::Kind::Tuple);
|
|
for (auto &input : inputs) {
|
|
NodePointer eltType;
|
|
bool isVariadic;
|
|
std::tie(eltType, isVariadic) = input;
|
|
|
|
// Tuple element := variadic-marker label? type
|
|
auto tupleElt = Dem.createNode(Node::Kind::TupleElement);
|
|
|
|
if (isVariadic)
|
|
tupleElt->addChild(Dem.createNode(Node::Kind::VariadicMarker), Dem);
|
|
|
|
if (eltType->getKind() == Node::Kind::Type) {
|
|
tupleElt->addChild(eltType, Dem);
|
|
} else {
|
|
auto type = Dem.createNode(Node::Kind::Type);
|
|
type->addChild(eltType, Dem);
|
|
tupleElt->addChild(type, Dem);
|
|
}
|
|
|
|
tuple->addChild(tupleElt, Dem);
|
|
}
|
|
totalInput = tuple;
|
|
break;
|
|
}
|
|
|
|
NodePointer parameters = Dem.createNode(Node::Kind::ArgumentTuple);
|
|
NodePointer paramType = Dem.createNode(Node::Kind::Type);
|
|
|
|
paramType->addChild(totalInput, Dem);
|
|
parameters->addChild(paramType, Dem);
|
|
|
|
NodePointer resultTy = _swift_buildDemanglingForMetadata(func->ResultType,
|
|
Dem);
|
|
NodePointer result = Dem.createNode(Node::Kind::ReturnType);
|
|
result->addChild(resultTy, Dem);
|
|
|
|
auto funcNode = Dem.createNode(kind);
|
|
if (func->throws())
|
|
funcNode->addChild(Dem.createNode(Node::Kind::ThrowsAnnotation), Dem);
|
|
funcNode->addChild(parameters, Dem);
|
|
funcNode->addChild(result, Dem);
|
|
return funcNode;
|
|
}
|
|
case MetadataKind::Metatype: {
|
|
auto metatype = static_cast<const MetatypeMetadata *>(type);
|
|
auto instance = _swift_buildDemanglingForMetadata(metatype->InstanceType,
|
|
Dem);
|
|
auto typeNode = Dem.createNode(Node::Kind::Type);
|
|
typeNode->addChild(instance, Dem);
|
|
auto node = Dem.createNode(Node::Kind::Metatype);
|
|
node->addChild(typeNode, Dem);
|
|
return node;
|
|
}
|
|
case MetadataKind::Tuple: {
|
|
auto tuple = static_cast<const TupleTypeMetadata *>(type);
|
|
const char *labels = tuple->Labels;
|
|
auto tupleNode = Dem.createNode(Node::Kind::Tuple);
|
|
for (unsigned i = 0, e = tuple->NumElements; i < e; ++i) {
|
|
auto elt = Dem.createNode(Node::Kind::TupleElement);
|
|
|
|
// Add a label child if applicable:
|
|
if (labels) {
|
|
// Look for the next space in the labels string.
|
|
if (const char *space = strchr(labels, ' ')) {
|
|
// If there is one, and the label isn't empty, add a label child.
|
|
if (labels != space) {
|
|
auto eltName =
|
|
Dem.createNode(Node::Kind::TupleElementName,
|
|
llvm::StringRef(labels, space - labels));
|
|
elt->addChild(eltName, Dem);
|
|
}
|
|
|
|
// Skip past the space.
|
|
labels = space + 1;
|
|
}
|
|
}
|
|
|
|
// Add the element type child.
|
|
auto eltType =
|
|
_swift_buildDemanglingForMetadata(tuple->getElement(i).Type, Dem);
|
|
|
|
if (eltType->getKind() == Node::Kind::Type) {
|
|
elt->addChild(eltType, Dem);
|
|
} else {
|
|
auto type = Dem.createNode(Node::Kind::Type);
|
|
type->addChild(eltType, Dem);
|
|
elt->addChild(type, Dem);
|
|
}
|
|
|
|
// Add the completed element to the tuple.
|
|
tupleNode->addChild(elt, Dem);
|
|
}
|
|
return tupleNode;
|
|
}
|
|
case MetadataKind::Opaque: {
|
|
if (auto builtinType = _buildDemanglerForBuiltinType(type, Dem))
|
|
return builtinType;
|
|
|
|
// FIXME: Some opaque types do have manglings, but we don't have enough info
|
|
// to figure them out.
|
|
break;
|
|
}
|
|
case MetadataKind::HeapLocalVariable:
|
|
case MetadataKind::HeapGenericLocalVariable:
|
|
case MetadataKind::ErrorObject:
|
|
break;
|
|
}
|
|
// Not a type.
|
|
return nullptr;
|
|
}
|