//===--- NodePrinter.cpp - Swift Demangling Node Printer ------------------===// // // 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 node printer for demangle node trees. // //===----------------------------------------------------------------------===// #include "swift/AST/Ownership.h" #include "swift/Basic/STLExtras.h" #include "swift/Demangling/Demangle.h" #include "swift/Strings.h" #include #include #include #include using namespace swift; using namespace Demangle; using llvm::StringRef; DemanglerPrinter &DemanglerPrinter::operator<<(unsigned long long n) & { char buffer[32]; snprintf(buffer, sizeof(buffer), "%llu", n); Stream.append(buffer); return *this; } DemanglerPrinter &DemanglerPrinter::writeHex(unsigned long long n) & { char buffer[32]; snprintf(buffer, sizeof(buffer), "%llX", n); Stream.append(buffer); return *this; } DemanglerPrinter &DemanglerPrinter::operator<<(long long n) & { char buffer[32]; snprintf(buffer, sizeof(buffer), "%lld",n); Stream.append(buffer); return *this; } #if SWIFT_STDLIB_HAS_TYPE_PRINTING [[noreturn]] static void printer_unreachable(const char *Message) { fprintf(stderr, "fatal error: %s\n", Message); std::abort(); } std::string Demangle::genericParameterName(uint64_t depth, uint64_t index) { DemanglerPrinter name; do { name << (char)('A' + (index % 26)); index /= 26; } while (index); if (depth != 0) name << depth; return std::move(name).str(); } namespace { struct QuotedString { std::string Value; explicit QuotedString(std::string Value) : Value(Value) {} }; static DemanglerPrinter &operator<<(DemanglerPrinter &printer, const QuotedString &QS) { printer << '"'; for (auto C : QS.Value) { switch (C) { case '\\': printer << "\\\\"; break; case '\t': printer << "\\t"; break; case '\n': printer << "\\n"; break; case '\r': printer << "\\r"; break; case '"': printer << "\\\""; break; case '\0': printer << "\\0"; break; default: auto c = static_cast(C); // Other control or high-bit characters should get escaped. if (c < 0x20 || c >= 0x7F) { static const char Hexdigit[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; printer << "\\x" << Hexdigit[c >> 4] << Hexdigit[c & 0xF]; } else { printer << (char)c; } break; } } printer << '"'; return printer; } static StringRef toString(Directness d) { switch (d) { case Directness::Direct: return "direct"; case Directness::Indirect: return "indirect"; } printer_unreachable("bad directness"); } static StringRef toString(ValueWitnessKind k) { switch (k) { case ValueWitnessKind::AllocateBuffer: return "allocateBuffer"; case ValueWitnessKind::AssignWithCopy: return "assignWithCopy"; case ValueWitnessKind::AssignWithTake: return "assignWithTake"; case ValueWitnessKind::DeallocateBuffer: return "deallocateBuffer"; case ValueWitnessKind::Destroy: return "destroy"; case ValueWitnessKind::DestroyBuffer: return "destroyBuffer"; case ValueWitnessKind::InitializeBufferWithCopyOfBuffer: return "initializeBufferWithCopyOfBuffer"; case ValueWitnessKind::InitializeBufferWithCopy: return "initializeBufferWithCopy"; case ValueWitnessKind::InitializeWithCopy: return "initializeWithCopy"; case ValueWitnessKind::InitializeBufferWithTake: return "initializeBufferWithTake"; case ValueWitnessKind::InitializeWithTake: return "initializeWithTake"; case ValueWitnessKind::ProjectBuffer: return "projectBuffer"; case ValueWitnessKind::InitializeBufferWithTakeOfBuffer: return "initializeBufferWithTakeOfBuffer"; case ValueWitnessKind::DestroyArray: return "destroyArray"; case ValueWitnessKind::InitializeArrayWithCopy: return "initializeArrayWithCopy"; case ValueWitnessKind::InitializeArrayWithTakeFrontToBack: return "initializeArrayWithTakeFrontToBack"; case ValueWitnessKind::InitializeArrayWithTakeBackToFront: return "initializeArrayWithTakeBackToFront"; case ValueWitnessKind::StoreExtraInhabitant: return "storeExtraInhabitant"; case ValueWitnessKind::GetExtraInhabitantIndex: return "getExtraInhabitantIndex"; case ValueWitnessKind::GetEnumTag: return "getEnumTag"; case ValueWitnessKind::DestructiveProjectEnumData: return "destructiveProjectEnumData"; case ValueWitnessKind::DestructiveInjectEnumTag: return "destructiveInjectEnumTag"; case ValueWitnessKind::GetEnumTagSinglePayload: return "getEnumTagSinglePayload"; case ValueWitnessKind::StoreEnumTagSinglePayload: return "storeEnumTagSinglePayload"; } printer_unreachable("bad value witness kind"); } class NodePrinter { private: DemanglerPrinter Printer; DemangleOptions Options; bool SpecializationPrefixPrinted = false; bool isValid = true; public: NodePrinter(DemangleOptions options) : Options(options) {} std::string printRoot(NodePointer root) { isValid = true; print(root, 0); if (isValid) return std::move(Printer).str(); return ""; } private: static const unsigned MaxDepth = 768; /// Called when the node tree in valid. /// /// The demangler already catches most error cases and mostly produces valid /// node trees. But some cases are difficult to catch in the demangler and /// instead the NodePrinter bails. void setInvalid() { isValid = false; } void printChildren(Node::iterator begin, Node::iterator end, unsigned depth, const char *sep = nullptr) { for (; begin != end;) { print(*begin, depth + 1); ++begin; if (sep && begin != end) Printer << sep; } } void printChildren(NodePointer Node, unsigned depth, const char *sep = nullptr) { if (!Node) return; Node::iterator begin = Node->begin(), end = Node->end(); printChildren(begin, end, depth, sep); } NodePointer getFirstChildOfKind(NodePointer Node, Node::Kind kind) { if (!Node) return nullptr; for (NodePointer child : *Node) { if (child && child->getKind() == kind) return child; } return nullptr; } void printBoundGenericNoSugar(NodePointer Node, unsigned depth) { if (Node->getNumChildren() < 2) return; NodePointer typelist = Node->getChild(1); print(Node->getChild(0), depth + 1); Printer << "<"; printChildren(typelist, depth, ", "); Printer << ">"; } void printOptionalIndex(NodePointer node) { assert(node->getKind() == Node::Kind::Index || node->getKind() == Node::Kind::UnknownIndex); if (node->hasIndex()) Printer << "#" << node->getIndex() << " "; } static bool isSwiftModule(NodePointer node) { return (node->getKind() == Node::Kind::Module && node->getText() == STDLIB_NAME); } bool printContext(NodePointer Context) { if (!Options.QualifyEntities) return false; if (Context->getKind() == Node::Kind::Module) { if (Context->getText() == swift::STDLIB_NAME) return Options.DisplayStdlibModule; if (Context->getText() == swift::MANGLING_MODULE_OBJC) return Options.DisplayObjCModule; if (Context->getText() == Options.HidingCurrentModule) return false; if (Context->getText().starts_with(LLDB_EXPRESSIONS_MODULE_NAME_PREFIX)) return Options.DisplayDebuggerGeneratedModule; } return true; } static bool isIdentifier(NodePointer node, StringRef desired) { return (node->getKind() == Node::Kind::Identifier && node->getText() == desired); } enum class SugarType { None, Optional, ImplicitlyUnwrappedOptional, Array, Dictionary }; enum class TypePrinting { NoType, WithColon, FunctionStyle }; /// Determine whether this is a "simple" type, from the type-simple /// production. bool isSimpleType(NodePointer Node) { switch (Node->getKind()) { case Node::Kind::AssociatedType: case Node::Kind::AssociatedTypeRef: case Node::Kind::BoundGenericClass: case Node::Kind::BoundGenericEnum: case Node::Kind::BoundGenericStructure: case Node::Kind::BoundGenericProtocol: case Node::Kind::BoundGenericOtherNominalType: case Node::Kind::BoundGenericTypeAlias: case Node::Kind::BoundGenericFunction: case Node::Kind::BuiltinTypeName: case Node::Kind::BuiltinTupleType: case Node::Kind::BuiltinFixedArray: case Node::Kind::Class: case Node::Kind::DependentGenericType: case Node::Kind::DependentMemberType: case Node::Kind::DependentGenericParamType: case Node::Kind::DynamicSelf: case Node::Kind::Enum: case Node::Kind::ErrorType: case Node::Kind::ExistentialMetatype: case Node::Kind::Metatype: case Node::Kind::MetatypeRepresentation: case Node::Kind::Module: case Node::Kind::Tuple: case Node::Kind::Pack: case Node::Kind::SILPackDirect: case Node::Kind::SILPackIndirect: case Node::Kind::ConstrainedExistentialRequirementList: case Node::Kind::ConstrainedExistentialSelf: case Node::Kind::Protocol: case Node::Kind::ProtocolSymbolicReference: case Node::Kind::ReturnType: case Node::Kind::SILBoxType: case Node::Kind::SILBoxTypeWithLayout: case Node::Kind::Structure: case Node::Kind::OtherNominalType: case Node::Kind::TupleElementName: case Node::Kind::TypeAlias: case Node::Kind::TypeList: case Node::Kind::LabelList: case Node::Kind::TypeSymbolicReference: case Node::Kind::SugaredOptional: case Node::Kind::SugaredArray: case Node::Kind::SugaredDictionary: case Node::Kind::SugaredParen: case Node::Kind::Integer: case Node::Kind::NegativeInteger: return true; case Node::Kind::Type: return isSimpleType(Node->getChild(0)); case Node::Kind::ProtocolList: return Node->getChild(0)->getNumChildren() <= 1; case Node::Kind::ProtocolListWithAnyObject: return Node->getChild(0)->getChild(0)->getNumChildren() == 0; case Node::Kind::ConstrainedExistential: case Node::Kind::PackElement: case Node::Kind::PackElementLevel: case Node::Kind::PackExpansion: case Node::Kind::ProtocolListWithClass: case Node::Kind::AccessorAttachedMacroExpansion: case Node::Kind::AccessorFunctionReference: case Node::Kind::Allocator: case Node::Kind::ArgumentTuple: case Node::Kind::AssociatedConformanceDescriptor: case Node::Kind::AssociatedTypeDescriptor: case Node::Kind::AssociatedTypeMetadataAccessor: case Node::Kind::AssociatedTypeWitnessTableAccessor: case Node::Kind::AsyncRemoved: case Node::Kind::AutoClosureType: case Node::Kind::BaseConformanceDescriptor: case Node::Kind::BaseWitnessTableAccessor: case Node::Kind::BodyAttachedMacroExpansion: case Node::Kind::ClangType: case Node::Kind::ClassMetadataBaseOffset: case Node::Kind::CFunctionPointer: case Node::Kind::ConformanceAttachedMacroExpansion: case Node::Kind::Constructor: case Node::Kind::CoroutineContinuationPrototype: case Node::Kind::CurryThunk: case Node::Kind::SILThunkIdentity: case Node::Kind::SILThunkHopToMainActorIfNeeded: case Node::Kind::DispatchThunk: case Node::Kind::Deallocator: case Node::Kind::IsolatedDeallocator: case Node::Kind::DeclContext: case Node::Kind::DefaultArgumentInitializer: case Node::Kind::DefaultAssociatedTypeMetadataAccessor: case Node::Kind::DefaultAssociatedConformanceAccessor: case Node::Kind::DependentAssociatedTypeRef: case Node::Kind::DependentGenericSignature: case Node::Kind::DependentGenericParamPackMarker: case Node::Kind::DependentGenericParamCount: case Node::Kind::DependentGenericConformanceRequirement: case Node::Kind::DependentGenericLayoutRequirement: case Node::Kind::DependentGenericSameTypeRequirement: case Node::Kind::DependentGenericSameShapeRequirement: case Node::Kind::DependentPseudogenericSignature: case Node::Kind::Destructor: case Node::Kind::DidSet: case Node::Kind::DirectMethodReferenceAttribute: case Node::Kind::Directness: case Node::Kind::DynamicAttribute: case Node::Kind::EscapingAutoClosureType: case Node::Kind::EscapingObjCBlock: case Node::Kind::NoEscapeFunctionType: case Node::Kind::ExplicitClosure: case Node::Kind::Extension: case Node::Kind::ExtensionAttachedMacroExpansion: case Node::Kind::EnumCase: case Node::Kind::FieldOffset: case Node::Kind::FreestandingMacroExpansion: case Node::Kind::FullObjCResilientClassStub: case Node::Kind::FullTypeMetadata: case Node::Kind::Function: case Node::Kind::FunctionSignatureSpecialization: case Node::Kind::FunctionSignatureSpecializationParam: case Node::Kind::FunctionSignatureSpecializationReturn: case Node::Kind::FunctionSignatureSpecializationParamKind: case Node::Kind::FunctionSignatureSpecializationParamPayload: case Node::Kind::FunctionType: case Node::Kind::GenericProtocolWitnessTable: case Node::Kind::GenericProtocolWitnessTableInstantiationFunction: case Node::Kind::GenericPartialSpecialization: case Node::Kind::GenericPartialSpecializationNotReAbstracted: case Node::Kind::GenericSpecialization: case Node::Kind::GenericSpecializationNotReAbstracted: case Node::Kind::GenericSpecializationInResilienceDomain: case Node::Kind::GenericSpecializationParam: case Node::Kind::GenericSpecializationPrespecialized: case Node::Kind::InlinedGenericFunction: case Node::Kind::GenericTypeMetadataPattern: case Node::Kind::Getter: case Node::Kind::Global: case Node::Kind::GlobalGetter: case Node::Kind::Identifier: case Node::Kind::Index: case Node::Kind::InitAccessor: case Node::Kind::IVarInitializer: case Node::Kind::IVarDestroyer: case Node::Kind::ImplDifferentiabilityKind: case Node::Kind::ImplEscaping: case Node::Kind::ImplErasedIsolation: case Node::Kind::ImplSendingResult: case Node::Kind::ImplConvention: case Node::Kind::ImplParameterResultDifferentiability: case Node::Kind::ImplParameterSending: case Node::Kind::ImplFunctionAttribute: case Node::Kind::ImplFunctionConvention: case Node::Kind::ImplFunctionConventionName: case Node::Kind::ImplFunctionType: case Node::Kind::ImplCoroutineKind: case Node::Kind::ImplInvocationSubstitutions: case Node::Kind::ImplPatternSubstitutions: case Node::Kind::ImplicitClosure: case Node::Kind::ImplParameter: case Node::Kind::ImplResult: case Node::Kind::ImplYield: case Node::Kind::ImplErrorResult: case Node::Kind::InOut: case Node::Kind::InfixOperator: case Node::Kind::Initializer: case Node::Kind::Isolated: case Node::Kind::Sending: case Node::Kind::CompileTimeConst: case Node::Kind::PropertyWrapperBackingInitializer: case Node::Kind::PropertyWrapperInitFromProjectedValue: case Node::Kind::KeyPathGetterThunkHelper: case Node::Kind::KeyPathSetterThunkHelper: case Node::Kind::KeyPathEqualsThunkHelper: case Node::Kind::KeyPathHashThunkHelper: case Node::Kind::LazyProtocolWitnessTableAccessor: case Node::Kind::LazyProtocolWitnessTableCacheVariable: case Node::Kind::LocalDeclName: case Node::Kind::Macro: case Node::Kind::MacroExpansionLoc: case Node::Kind::MacroExpansionUniqueName: case Node::Kind::MaterializeForSet: case Node::Kind::MemberAttributeAttachedMacroExpansion: case Node::Kind::MemberAttachedMacroExpansion: case Node::Kind::MergedFunction: case Node::Kind::Metaclass: case Node::Kind::MethodDescriptor: case Node::Kind::MethodLookupFunction: case Node::Kind::ModifyAccessor: case Node::Kind::Modify2Accessor: case Node::Kind::NativeOwningAddressor: case Node::Kind::NativeOwningMutableAddressor: case Node::Kind::NativePinningAddressor: case Node::Kind::NativePinningMutableAddressor: case Node::Kind::NominalTypeDescriptor: case Node::Kind::NominalTypeDescriptorRecord: case Node::Kind::NonObjCAttribute: case Node::Kind::Number: case Node::Kind::ObjCAsyncCompletionHandlerImpl: case Node::Kind::ObjCAttribute: case Node::Kind::ObjCBlock: case Node::Kind::ObjCMetadataUpdateFunction: case Node::Kind::ObjCResilientClassStub: case Node::Kind::OpaqueTypeDescriptor: case Node::Kind::OpaqueTypeDescriptorRecord: case Node::Kind::OpaqueTypeDescriptorAccessor: case Node::Kind::OpaqueTypeDescriptorAccessorImpl: case Node::Kind::OpaqueTypeDescriptorAccessorKey: case Node::Kind::OpaqueTypeDescriptorAccessorVar: case Node::Kind::Owned: case Node::Kind::OwningAddressor: case Node::Kind::OwningMutableAddressor: case Node::Kind::PartialApplyForwarder: case Node::Kind::PartialApplyObjCForwarder: case Node::Kind::PeerAttachedMacroExpansion: case Node::Kind::PostfixOperator: case Node::Kind::PreambleAttachedMacroExpansion: case Node::Kind::PredefinedObjCAsyncCompletionHandlerImpl: case Node::Kind::PrefixOperator: case Node::Kind::PrivateDeclName: case Node::Kind::PropertyDescriptor: case Node::Kind::ProtocolConformance: case Node::Kind::ProtocolConformanceDescriptor: case Node::Kind::ProtocolConformanceDescriptorRecord: case Node::Kind::MetadataInstantiationCache: case Node::Kind::ProtocolDescriptor: case Node::Kind::ProtocolDescriptorRecord: case Node::Kind::ProtocolRequirementsBaseDescriptor: case Node::Kind::ProtocolSelfConformanceDescriptor: case Node::Kind::ProtocolSelfConformanceWitness: case Node::Kind::ProtocolSelfConformanceWitnessTable: case Node::Kind::ProtocolWitness: case Node::Kind::ProtocolWitnessTable: case Node::Kind::ProtocolWitnessTableAccessor: case Node::Kind::ProtocolWitnessTablePattern: case Node::Kind::ReabstractionThunk: case Node::Kind::ReabstractionThunkHelper: case Node::Kind::ReabstractionThunkHelperWithSelf: case Node::Kind::ReabstractionThunkHelperWithGlobalActor: case Node::Kind::ReadAccessor: case Node::Kind::Read2Accessor: case Node::Kind::RelatedEntityDeclName: case Node::Kind::RetroactiveConformance: case Node::Kind::Setter: case Node::Kind::Shared: case Node::Kind::SILBoxLayout: case Node::Kind::SILBoxMutableField: case Node::Kind::SILBoxImmutableField: case Node::Kind::IsSerialized: case Node::Kind::DroppedArgument: case Node::Kind::SpecializationPassID: case Node::Kind::Static: case Node::Kind::Subscript: case Node::Kind::Suffix: case Node::Kind::ThinFunctionType: case Node::Kind::TupleElement: case Node::Kind::TypeMangling: case Node::Kind::TypeMetadata: case Node::Kind::TypeMetadataAccessFunction: case Node::Kind::TypeMetadataCompletionFunction: case Node::Kind::TypeMetadataInstantiationCache: case Node::Kind::TypeMetadataInstantiationFunction: case Node::Kind::TypeMetadataSingletonInitializationCache: case Node::Kind::TypeMetadataDemanglingCache: case Node::Kind::TypeMetadataLazyCache: case Node::Kind::UncurriedFunctionType: #define REF_STORAGE(Name, ...) \ case Node::Kind::Name: #include "swift/AST/ReferenceStorage.def" case Node::Kind::UnknownIndex: case Node::Kind::UnsafeAddressor: case Node::Kind::UnsafeMutableAddressor: case Node::Kind::ValueWitness: case Node::Kind::ValueWitnessTable: case Node::Kind::Variable: case Node::Kind::VTableAttribute: case Node::Kind::VTableThunk: case Node::Kind::WillSet: case Node::Kind::ReflectionMetadataBuiltinDescriptor: case Node::Kind::ReflectionMetadataFieldDescriptor: case Node::Kind::ReflectionMetadataAssocTypeDescriptor: case Node::Kind::ReflectionMetadataSuperclassDescriptor: case Node::Kind::ResilientProtocolWitnessTable: case Node::Kind::GenericTypeParamDecl: case Node::Kind::ConcurrentFunctionType: case Node::Kind::DifferentiableFunctionType: case Node::Kind::GlobalActorFunctionType: case Node::Kind::IsolatedAnyFunctionType: case Node::Kind::SendingResultFunctionType: case Node::Kind::AsyncAnnotation: case Node::Kind::ThrowsAnnotation: case Node::Kind::TypedThrowsAnnotation: case Node::Kind::EmptyList: case Node::Kind::FirstElementMarker: case Node::Kind::VariadicMarker: case Node::Kind::OutlinedBridgedMethod: case Node::Kind::OutlinedCopy: case Node::Kind::OutlinedConsume: case Node::Kind::OutlinedRetain: case Node::Kind::OutlinedRelease: case Node::Kind::OutlinedInitializeWithTake: case Node::Kind::OutlinedInitializeWithCopy: case Node::Kind::OutlinedAssignWithTake: case Node::Kind::OutlinedAssignWithCopy: case Node::Kind::OutlinedDestroy: case Node::Kind::OutlinedInitializeWithCopyNoValueWitness: case Node::Kind::OutlinedAssignWithTakeNoValueWitness: case Node::Kind::OutlinedAssignWithCopyNoValueWitness: case Node::Kind::OutlinedDestroyNoValueWitness: case Node::Kind::OutlinedEnumTagStore: case Node::Kind::OutlinedEnumGetTag: case Node::Kind::OutlinedEnumProjectDataForLoad: case Node::Kind::OutlinedVariable: case Node::Kind::OutlinedReadOnlyObject: case Node::Kind::AssocTypePath: case Node::Kind::ModuleDescriptor: case Node::Kind::AnonymousDescriptor: case Node::Kind::AssociatedTypeGenericParamRef: case Node::Kind::ExtensionDescriptor: case Node::Kind::AnonymousContext: case Node::Kind::AnyProtocolConformanceList: case Node::Kind::ConcreteProtocolConformance: case Node::Kind::PackProtocolConformance: case Node::Kind::DependentAssociatedConformance: case Node::Kind::DependentProtocolConformanceAssociated: case Node::Kind::DependentProtocolConformanceInherited: case Node::Kind::DependentProtocolConformanceRoot: case Node::Kind::ProtocolConformanceRefInTypeModule: case Node::Kind::ProtocolConformanceRefInProtocolModule: case Node::Kind::ProtocolConformanceRefInOtherModule: case Node::Kind::DistributedThunk: case Node::Kind::DistributedAccessor: case Node::Kind::DynamicallyReplaceableFunctionKey: case Node::Kind::DynamicallyReplaceableFunctionImpl: case Node::Kind::DynamicallyReplaceableFunctionVar: case Node::Kind::OpaqueType: case Node::Kind::OpaqueTypeDescriptorSymbolicReference: case Node::Kind::OpaqueReturnType: case Node::Kind::OpaqueReturnTypeIndex: case Node::Kind::OpaqueReturnTypeParent: case Node::Kind::OpaqueReturnTypeOf: case Node::Kind::CanonicalSpecializedGenericMetaclass: case Node::Kind::CanonicalSpecializedGenericTypeMetadataAccessFunction: case Node::Kind::NoncanonicalSpecializedGenericTypeMetadata: case Node::Kind::NoncanonicalSpecializedGenericTypeMetadataCache: case Node::Kind::GlobalVariableOnceDeclList: case Node::Kind::GlobalVariableOnceFunction: case Node::Kind::GlobalVariableOnceToken: case Node::Kind::CanonicalPrespecializedGenericTypeCachingOnceToken: case Node::Kind::AsyncFunctionPointer: case Node::Kind::AutoDiffFunction: case Node::Kind::AutoDiffDerivativeVTableThunk: case Node::Kind::AutoDiffSelfReorderingReabstractionThunk: case Node::Kind::AutoDiffSubsetParametersThunk: case Node::Kind::AutoDiffFunctionKind: case Node::Kind::DifferentiabilityWitness: case Node::Kind::NoDerivative: case Node::Kind::IndexSubset: case Node::Kind::AsyncAwaitResumePartialFunction: case Node::Kind::AsyncSuspendResumePartialFunction: case Node::Kind::AccessibleFunctionRecord: case Node::Kind::BackDeploymentThunk: case Node::Kind::BackDeploymentFallback: case Node::Kind::ExtendedExistentialTypeShape: case Node::Kind::Uniquable: case Node::Kind::UniqueExtendedExistentialTypeShapeSymbolicReference: case Node::Kind::NonUniqueExtendedExistentialTypeShapeSymbolicReference: case Node::Kind::SymbolicExtendedExistentialType: case Node::Kind::HasSymbolQuery: case Node::Kind::ObjectiveCProtocolSymbolicReference: case Node::Kind::DependentGenericInverseConformanceRequirement: case Node::Kind::DependentGenericParamValueMarker: return false; } printer_unreachable("bad node kind"); } void printWithParens(NodePointer type, unsigned depth) { bool needs_parens = !isSimpleType(type); if (needs_parens) Printer << "("; print(type, depth + 1); if (needs_parens) Printer << ")"; } SugarType findSugar(NodePointer Node) { if (Node->getNumChildren() == 1 && Node->getKind() == Node::Kind::Type) return findSugar(Node->getChild(0)); if (Node->getNumChildren() != 2) return SugarType::None; if (Node->getKind() != Node::Kind::BoundGenericEnum && Node->getKind() != Node::Kind::BoundGenericStructure) return SugarType::None; auto unboundType = Node->getChild(0)->getChild(0); // drill through Type auto typeArgs = Node->getChild(1); if (Node->getKind() == Node::Kind::BoundGenericEnum) { // Swift.Optional if (isIdentifier(unboundType->getChild(1), "Optional") && typeArgs->getNumChildren() == 1 && isSwiftModule(unboundType->getChild(0))) { return SugarType::Optional; } // Swift.ImplicitlyUnwrappedOptional if (isIdentifier(unboundType->getChild(1), "ImplicitlyUnwrappedOptional") && typeArgs->getNumChildren() == 1 && isSwiftModule(unboundType->getChild(0))) { return SugarType::ImplicitlyUnwrappedOptional; } return SugarType::None; } assert(Node->getKind() == Node::Kind::BoundGenericStructure); // Array if (isIdentifier(unboundType->getChild(1), "Array") && typeArgs->getNumChildren() == 1 && isSwiftModule(unboundType->getChild(0))) { return SugarType::Array; } // Dictionary if (isIdentifier(unboundType->getChild(1), "Dictionary") && typeArgs->getNumChildren() == 2 && isSwiftModule(unboundType->getChild(0))) { return SugarType::Dictionary; } return SugarType::None; } void printBoundGeneric(NodePointer Node, unsigned depth) { if (Node->getNumChildren() < 2) return; if (Node->getNumChildren() != 2) { printBoundGenericNoSugar(Node, depth); return; } if (!Options.SynthesizeSugarOnTypes || Node->getKind() == Node::Kind::BoundGenericClass) { // no sugar here printBoundGenericNoSugar(Node, depth); return; } // Print the conforming type for a "bound" protocol node "as" the protocol // type. if (Node->getKind() == Node::Kind::BoundGenericProtocol) { printChildren(Node->getChild(1), depth); Printer << " as "; print(Node->getChild(0), depth + 1); return; } SugarType sugarType = findSugar(Node); switch (sugarType) { case SugarType::None: printBoundGenericNoSugar(Node, depth); break; case SugarType::Optional: case SugarType::ImplicitlyUnwrappedOptional: { NodePointer type = Node->getChild(1)->getChild(0); printWithParens(type, depth); Printer << (sugarType == SugarType::Optional ? "?" : "!"); break; } case SugarType::Array: { NodePointer type = Node->getChild(1)->getChild(0); Printer << "["; print(type, depth + 1); Printer << "]"; break; } case SugarType::Dictionary: { NodePointer keyType = Node->getChild(1)->getChild(0); NodePointer valueType = Node->getChild(1)->getChild(1); Printer << "["; print(keyType, depth + 1); Printer << " : "; print(valueType, depth + 1); Printer << "]"; break; } } } NodePointer getChildIf(NodePointer Node, Node::Kind Kind) { auto result = std::find_if(Node->begin(), Node->end(), [&](NodePointer child) { return child->getKind() == Kind; }); return result != Node->end() ? *result : nullptr; } void printFunctionParameters(NodePointer LabelList, NodePointer ParameterType, unsigned depth, bool showTypes) { if (ParameterType->getKind() != Node::Kind::ArgumentTuple) { setInvalid(); return; } NodePointer Parameters = ParameterType->getFirstChild(); assert(Parameters->getKind() == Node::Kind::Type); Parameters = Parameters->getFirstChild(); if (Parameters->getKind() != Node::Kind::Tuple) { // only a single not-named parameter if (showTypes) { Printer << '('; print(Parameters, depth + 1); Printer << ')'; } else { Printer << "(_:)"; } return; } auto getLabelFor = [&](NodePointer Param, unsigned Index) -> std::string { auto Label = LabelList->getChild(Index); assert(Label && (Label->getKind() == Node::Kind::Identifier || Label->getKind() == Node::Kind::FirstElementMarker)); return Label->getKind() == Node::Kind::Identifier ? Label->getText().str() : "_"; }; unsigned ParamIndex = 0; bool hasLabels = LabelList && LabelList->getNumChildren() > 0; Printer << '('; llvm::interleave( Parameters->begin(), Parameters->end(), [&](NodePointer Param) { assert(Param->getKind() == Node::Kind::TupleElement); if (hasLabels) { Printer << getLabelFor(Param, ParamIndex) << ':'; } else if (!showTypes) { if (auto Label = getChildIf(Param, Node::Kind::TupleElementName)) Printer << Label->getText() << ":"; else Printer << "_:"; } if (hasLabels && showTypes) Printer << ' '; ++ParamIndex; if (showTypes) print(Param, depth + 1); }, [&]() { Printer << (showTypes ? ", " : ""); }); Printer << ')'; } void printFunctionType(NodePointer LabelList, NodePointer node, unsigned depth) { if (node->getNumChildren() < 2) { setInvalid(); return; } auto printConventionWithMangledCType = [this, node, depth](const char *convention) { Printer << "@convention(" << convention; if (node->getFirstChild()->getKind() == Node::Kind::ClangType) { Printer << ", mangledCType: \""; print(node->getFirstChild(), depth + 1); Printer << '"'; } Printer << ") "; }; switch (node->getKind()) { case Node::Kind::FunctionType: case Node::Kind::UncurriedFunctionType: case Node::Kind::NoEscapeFunctionType: break; case Node::Kind::AutoClosureType: case Node::Kind::EscapingAutoClosureType: Printer << "@autoclosure "; break; case Node::Kind::ThinFunctionType: Printer << "@convention(thin) "; break; case Node::Kind::CFunctionPointer: printConventionWithMangledCType("c"); break; case Node::Kind::EscapingObjCBlock: Printer << "@escaping "; LLVM_FALLTHROUGH; case Node::Kind::ObjCBlock: printConventionWithMangledCType("block"); break; default: assert(false && "Unhandled function type in printFunctionType!"); } unsigned argIndex = node->getNumChildren() - 2; unsigned startIndex = 0; bool isSendable = false, isAsync = false, hasSendingResult = false; auto diffKind = MangledDifferentiabilityKind::NonDifferentiable; if (node->getChild(startIndex)->getKind() == Node::Kind::ClangType) { // handled earlier ++startIndex; } // Be sure to check for function signature components in the same // order that they're added by the demangler, which is the reverse // of the order that they appear in the mangling grammar. if (node->getChild(startIndex)->getKind() == Node::Kind::SendingResultFunctionType) { ++startIndex; hasSendingResult = true; } // function-isolation; note that these can't actually both appear. if (node->getChild(startIndex)->getKind() == Node::Kind::IsolatedAnyFunctionType) { print(node->getChild(startIndex), depth + 1); ++startIndex; } if (node->getChild(startIndex)->getKind() == Node::Kind::GlobalActorFunctionType) { print(node->getChild(startIndex), depth + 1); ++startIndex; } if (node->getChild(startIndex)->getKind() == Node::Kind::DifferentiableFunctionType) { diffKind = (MangledDifferentiabilityKind)node->getChild(startIndex)->getIndex(); ++startIndex; } Node *thrownErrorNode = nullptr; if (node->getChild(startIndex)->getKind() == Node::Kind::ThrowsAnnotation || node->getChild(startIndex)->getKind() == Node::Kind::TypedThrowsAnnotation) { thrownErrorNode = node->getChild(startIndex); ++startIndex; } if (node->getChild(startIndex)->getKind() == Node::Kind::ConcurrentFunctionType) { ++startIndex; isSendable = true; } if (node->getChild(startIndex)->getKind() == Node::Kind::AsyncAnnotation) { ++startIndex; isAsync = true; } switch (diffKind) { case MangledDifferentiabilityKind::Forward: Printer << "@differentiable(_forward) "; break; case MangledDifferentiabilityKind::Reverse: Printer << "@differentiable(reverse) "; break; case MangledDifferentiabilityKind::Linear: Printer << "@differentiable(_linear) "; break; case MangledDifferentiabilityKind::Normal: Printer << "@differentiable "; break; case MangledDifferentiabilityKind::NonDifferentiable: break; } if (isSendable) Printer << "@Sendable "; printFunctionParameters(LabelList, node->getChild(argIndex), depth, Options.ShowFunctionArgumentTypes); if (!Options.ShowFunctionArgumentTypes) return; if (isAsync) Printer << " async"; if (thrownErrorNode) { print(thrownErrorNode, depth + 1); } Printer << " -> "; if (hasSendingResult) Printer << "sending "; print(node->getChild(argIndex + 1), depth + 1); } void printImplFunctionType(NodePointer fn, unsigned depth) { NodePointer patternSubs = nullptr; NodePointer invocationSubs = nullptr; NodePointer sendingResult = nullptr; enum State { Attrs, Inputs, Results } curState = Attrs; auto transitionTo = [&](State newState) { assert(newState >= curState); for (; curState != newState; curState = State(curState + 1)) { switch (curState) { case Attrs: if (patternSubs) { Printer << "@substituted "; print(patternSubs->getChild(0), depth + 1); Printer << ' '; } Printer << '('; continue; case Inputs: Printer << ") -> "; if (sendingResult) { print(sendingResult, depth + 1); Printer << " "; } Printer << "("; continue; case Results: printer_unreachable("no state after Results"); } printer_unreachable("bad state"); } }; for (auto &child : *fn) { if (child->getKind() == Node::Kind::ImplParameter) { if (curState == Inputs) Printer << ", "; transitionTo(Inputs); print(child, depth + 1); } else if (child->getKind() == Node::Kind::ImplResult || child->getKind() == Node::Kind::ImplYield || child->getKind() == Node::Kind::ImplErrorResult) { if (curState == Results) Printer << ", "; transitionTo(Results); print(child, depth + 1); } else if (child->getKind() == Node::Kind::ImplPatternSubstitutions) { patternSubs = child; } else if (child->getKind() == Node::Kind::ImplInvocationSubstitutions) { invocationSubs = child; } else if (child->getKind() == Node::Kind::ImplSendingResult) { sendingResult = child; } else { assert(curState == Attrs); print(child, depth + 1); Printer << ' '; } } transitionTo(Results); Printer << ')'; if (patternSubs) { Printer << " for <"; printChildren(patternSubs->getChild(1), depth); Printer << '>'; } if (invocationSubs) { Printer << " for <"; printChildren(invocationSubs->getChild(0), depth); Printer << '>'; } } void printGenericSignature(NodePointer Node, unsigned depth) { Printer << '<'; unsigned numChildren = Node->getNumChildren(); unsigned numGenericParams = 0; for (; numGenericParams < numChildren; ++numGenericParams) { if (Node->getChild(numGenericParams)->getKind() != Node::Kind::DependentGenericParamCount) { break; } } unsigned firstRequirement = numGenericParams; for (; firstRequirement < numChildren; ++firstRequirement) { auto child = Node->getChild(firstRequirement); if (child->getKind() == Node::Kind::Type) child = child->getChild(0); if (child->getKind() != Node::Kind::DependentGenericParamPackMarker && child->getKind() != Node::Kind::DependentGenericParamValueMarker) { break; } } auto isGenericParamPack = [&](unsigned depth, unsigned index) { for (unsigned i = numGenericParams; i < firstRequirement; ++i) { auto child = Node->getChild(i); if (child->getKind() != Node::Kind::DependentGenericParamPackMarker) continue; child = child->getChild(0); if (child->getKind() != Node::Kind::Type) continue; child = child->getChild(0); if (child->getKind() != Node::Kind::DependentGenericParamType) continue; if (index == child->getChild(0)->getIndex() && depth == child->getChild(1)->getIndex()) { return true; } } return false; }; auto isGenericParamValue = [&](unsigned depth, unsigned index) { for (unsigned i = numGenericParams; i < firstRequirement; ++i) { auto child = Node->getChild(i); if (child->getKind() != Node::Kind::DependentGenericParamValueMarker) continue; child = child->getChild(0); if (child->getKind() != Node::Kind::Type) continue; auto param = child->getChild(0); auto type = child->getChild(1); if (param->getKind() != Node::Kind::DependentGenericParamType) continue; if (index == param->getChild(0)->getIndex() && depth == param->getChild(1)->getIndex()) { return std::make_pair(true, type); } } return std::make_pair(false, NodePointer()); }; unsigned gpDepth = 0; for (; gpDepth < numGenericParams; ++gpDepth) { if (gpDepth != 0) Printer << "><"; unsigned count = Node->getChild(gpDepth)->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 important for malformed // symbols where count can be really huge. if (index >= 128) { Printer << "..."; break; } if (isGenericParamPack(gpDepth, index)) Printer << "each "; auto value = isGenericParamValue(gpDepth, index); if (value.first) Printer << "let "; // FIXME: Depth won't match when a generic signature applies to a // method in generic type context. Printer << Options.GenericParameterName(gpDepth, index); if (value.second) { Printer << ": "; print(value.second, depth + 1); } } } if (firstRequirement != numChildren) { if (Options.DisplayWhereClauses) { Printer << " where "; for (unsigned i = firstRequirement; i < numChildren; ++i) { if (i > firstRequirement) Printer << ", "; print(Node->getChild(i), depth + 1); } } } Printer << '>'; } void printFunctionSigSpecializationParams(NodePointer Node, unsigned depth); void printSpecializationPrefix(NodePointer node, StringRef Description, unsigned depth, StringRef ParamPrefix = StringRef()); /// The main big print function. NodePointer print(NodePointer Node, unsigned depth, bool asPrefixContext = false); NodePointer printAbstractStorage(NodePointer Node, unsigned depth, bool asPrefixContent, StringRef ExtraName); /// Utility function to print entities. /// /// \param Entity The entity node to print /// \param depth The depth in the print() call tree. /// \param asPrefixContext Should the entity printed as a context which as a /// prefix to another entity, e.g. the Abc in Abc.def() /// \param TypePr How should the type of the entity be printed, if at all. /// E.g. with a colon for properties or as a function type. /// \param hasName Does the entity has a name, e.g. a function in contrast to /// an initializer. /// \param ExtraName An extra name added to the entity name (if any). /// \param ExtraIndex An extra index added to the entity name (if any), /// e.g. closure #1 /// \param OverwriteName If non-empty, print this name instead of the one /// provided by the node. Gets printed even if hasName is false. /// \return If a non-null node is returned it's a context which must be /// printed in postfix-form after the entity: " in ". NodePointer printEntity(NodePointer Entity, unsigned depth, bool asPrefixContext, TypePrinting TypePr, bool hasName, StringRef ExtraName = "", int ExtraIndex = -1, StringRef OverwriteName = ""); /// Print the type of an entity. /// /// \param Entity The entity. /// \param type The type of the entity. /// \param genericFunctionTypeList If not null, the generic argument types /// which is printed in the generic signature. /// \param depth The depth in the print() call tree. void printEntityType(NodePointer Entity, NodePointer type, NodePointer genericFunctionTypeList, unsigned depth); }; } // end anonymous namespace static bool isExistentialType(NodePointer node) { return (node->getKind() == Node::Kind::ExistentialMetatype || node->getKind() == Node::Kind::ProtocolList || node->getKind() == Node::Kind::ProtocolListWithClass || node->getKind() == Node::Kind::ProtocolListWithAnyObject); } /// Print the relevant parameters and return the new index. void NodePrinter::printFunctionSigSpecializationParams(NodePointer Node, unsigned depth) { unsigned Idx = 0; unsigned End = Node->getNumChildren(); while (Idx < End) { NodePointer firstChild = Node->getChild(Idx); unsigned V = firstChild->getIndex(); auto K = FunctionSigSpecializationParamKind(V); switch (K) { case FunctionSigSpecializationParamKind::BoxToValue: case FunctionSigSpecializationParamKind::BoxToStack: case FunctionSigSpecializationParamKind::InOutToOut: print(Node->getChild(Idx++), depth + 1); break; case FunctionSigSpecializationParamKind::ConstantPropFunction: case FunctionSigSpecializationParamKind::ConstantPropGlobal: { Printer << "["; print(Node->getChild(Idx++), depth + 1); Printer << " : "; const auto &text = Node->getChild(Idx++)->getText(); std::string demangledName = demangleSymbolAsString(text); if (demangledName.empty()) { Printer << text; } else { Printer << demangledName; } Printer << "]"; break; } case FunctionSigSpecializationParamKind::ConstantPropInteger: case FunctionSigSpecializationParamKind::ConstantPropFloat: Printer << "["; print(Node->getChild(Idx++), depth + 1); Printer << " : "; print(Node->getChild(Idx++), depth + 1); Printer << "]"; break; case FunctionSigSpecializationParamKind::ConstantPropString: Printer << "["; print(Node->getChild(Idx++), depth + 1); Printer << " : "; print(Node->getChild(Idx++), depth + 1); Printer << "'"; print(Node->getChild(Idx++), depth + 1); Printer << "'"; Printer << "]"; break; case FunctionSigSpecializationParamKind::ConstantPropKeyPath: Printer << "["; print(Node->getChild(Idx++), depth + 1); Printer << " : "; print(Node->getChild(Idx++), depth + 1); Printer << "<"; print(Node->getChild(Idx++), depth + 1); Printer << ","; print(Node->getChild(Idx++), depth + 1); Printer << ">]"; break; case FunctionSigSpecializationParamKind::ClosureProp: Printer << "["; print(Node->getChild(Idx++), depth + 1); Printer << " : "; print(Node->getChild(Idx++), depth + 1); Printer << ", Argument Types : ["; for (unsigned e = Node->getNumChildren(); Idx < e;) { NodePointer child = Node->getChild(Idx); // Until we no longer have a type node, keep demangling. if (child->getKind() != Node::Kind::Type) break; print(child, depth + 1); ++Idx; // If we are not done, print the ", ". if (Idx < e && Node->getChild(Idx)->hasText()) Printer << ", "; } Printer << "]"; break; default: assert( ((V & unsigned(FunctionSigSpecializationParamKind::OwnedToGuaranteed)) || (V & unsigned(FunctionSigSpecializationParamKind::GuaranteedToOwned)) || (V & unsigned(FunctionSigSpecializationParamKind::SROA)) || (V & unsigned(FunctionSigSpecializationParamKind::Dead))|| (V & unsigned( FunctionSigSpecializationParamKind::ExistentialToGeneric))) && "Invalid OptionSet"); print(Node->getChild(Idx++), depth + 1); } } } void NodePrinter::printSpecializationPrefix(NodePointer node, StringRef Description, unsigned depth, StringRef ParamPrefix) { if (!Options.DisplayGenericSpecializations) { if (!SpecializationPrefixPrinted) { Printer << "specialized "; SpecializationPrefixPrinted = true; } return; } Printer << Description << " <"; const char *Separator = ""; int argNum = 0; for (NodePointer child : *node) { switch (child->getKind()) { case Node::Kind::SpecializationPassID: case Node::Kind::DroppedArgument: // We skip those nodes since it does not contain any // information that is useful to our users. break; case Node::Kind::IsSerialized: Printer << Separator; Separator = ", "; print(child, depth + 1); break; default: // Ignore empty specializations. if (child->hasChildren()) { Printer << Separator << ParamPrefix; Separator = ", "; switch (child->getKind()) { case Node::Kind::FunctionSignatureSpecializationParam: Printer << "Arg[" << argNum << "] = "; printFunctionSigSpecializationParams(child, depth); break; case Node::Kind::FunctionSignatureSpecializationReturn: Printer << "Return = "; printFunctionSigSpecializationParams(child, depth); break; default: print(child, depth + 1); } } ++argNum; break; } } Printer << "> of "; } static bool isClassType(NodePointer Node) { return Node->getKind() == Node::Kind::Class; } static bool needSpaceBeforeType(NodePointer Type) { switch (Type->getKind()) { case Node::Kind::Type: return needSpaceBeforeType(Type->getFirstChild()); case Node::Kind::FunctionType: case Node::Kind::NoEscapeFunctionType: case Node::Kind::UncurriedFunctionType: case Node::Kind::DependentGenericType: return false; default: return true; } } /// Determine whether to print an entity's type. static bool shouldShowEntityType(Node::Kind EntityKind, const DemangleOptions &Options) { switch (EntityKind) { case Node::Kind::ExplicitClosure: case Node::Kind::ImplicitClosure: /// The signature of a closure (its `Type` node) can optionally be omitted. /// Unlike functions which can have overloads, the signature of a closure is /// not needed to be uniquely identified. A closure is uniquely identified /// by its index and parent. Omitting the signature improves the readability /// when long type names are in use. return Options.ShowClosureSignature; default: return true; } } NodePointer NodePrinter::print(NodePointer Node, unsigned depth, bool asPrefixContext) { if (depth > NodePrinter::MaxDepth) { Printer << "<>"; return nullptr; } if (!Node) { Printer << ""; return nullptr; } switch (auto kind = Node->getKind()) { case Node::Kind::Static: Printer << "static "; print(Node->getChild(0), depth + 1); return nullptr; case Node::Kind::AsyncRemoved: Printer << "async demotion of "; 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::SILThunkIdentity: Printer << "identity thunk of "; print(Node->getChild(0), depth + 1); return nullptr; case Node::Kind::SILThunkHopToMainActorIfNeeded: Printer << "hop to main actor 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: case Node::Kind::OutlinedInitializeWithCopyNoValueWitness: Printer << "outlined init with copy of "; print(Node->getChild(0), depth + 1); return nullptr; case Node::Kind::OutlinedAssignWithTake: case Node::Kind::OutlinedAssignWithTakeNoValueWitness: Printer << "outlined assign with take of "; print(Node->getChild(0), depth + 1); return nullptr; case Node::Kind::OutlinedAssignWithCopy: case Node::Kind::OutlinedAssignWithCopyNoValueWitness: Printer << "outlined assign with copy of "; print(Node->getChild(0), depth + 1); return nullptr; case Node::Kind::OutlinedDestroy: case Node::Kind::OutlinedDestroyNoValueWitness: Printer << "outlined destroy of "; print(Node->getChild(0), depth + 1); return nullptr; case Node::Kind::OutlinedEnumProjectDataForLoad: Printer << "outlined enum project data for load of "; print(Node->getChild(0), depth + 1); return nullptr; case Node::Kind::OutlinedEnumTagStore: Printer << "outlined enum tag store of "; print(Node->getChild(0), depth + 1); return nullptr; case Node::Kind::OutlinedEnumGetTag: Printer << "outlined enum get tag of "; print(Node->getChild(0), depth + 1); return nullptr; case Node::Kind::OutlinedVariable: Printer << "outlined variable #" << Node->getIndex() << " of "; return nullptr; case Node::Kind::OutlinedReadOnlyObject: Printer << "outlined read-only object #" << 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::Macro: return printEntity(Node, depth, asPrefixContext, Node->getNumChildren() == 3? TypePrinting::WithColon : TypePrinting::FunctionStyle, /*hasName*/ true); #define FREESTANDING_MACRO_ROLE(Name, Description) #define ATTACHED_MACRO_ROLE(Name, Description, MangledChar) \ case Node::Kind::Name##AttachedMacroExpansion: \ return printEntity(Node, depth, asPrefixContext, \ TypePrinting::NoType, /*hasName*/true, \ (Description " macro @" + \ nodeToString(Node->getChild(2)) + " expansion #"), \ (int)Node->getChild(3)->getIndex() + 1); #include "swift/Basic/MacroRoles.def" case Node::Kind::FreestandingMacroExpansion: return printEntity(Node, depth, asPrefixContext, TypePrinting::NoType, /*hasName*/true, "freestanding macro expansion #", (int)Node->getChild(2)->getIndex() + 1); case Node::Kind::MacroExpansionLoc: if (Node->getNumChildren() > 0) { Printer << "module "; print(Node->getChild(0), depth + 1); } if (Node->getNumChildren() > 1) { Printer << " file "; print(Node->getChild(1), depth + 1); } if (Node->getNumChildren() > 2) { Printer << " line "; print(Node->getChild(2), depth + 1); } if (Node->getNumChildren() > 3) { Printer << " column "; print(Node->getChild(3), depth + 1); } return nullptr; case Node::Kind::MacroExpansionUniqueName: return printEntity(Node, depth, asPrefixContext, TypePrinting::NoType, /*hasName*/true, "unique name #", (int)Node->getChild(2)->getIndex() + 1); 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::Pack: { Printer << "Pack{"; printChildren(Node, depth, ", "); Printer << "}"; return nullptr; } case Node::Kind::SILPackDirect: case Node::Kind::SILPackIndirect: { Printer << (kind == Node::Kind::SILPackDirect ? "@direct" : "@indirect"); Printer << " Pack{"; printChildren(Node, depth, ", "); Printer << "}"; return nullptr; } case Node::Kind::PackExpansion: { Printer << "repeat "; print(Node->getChild(0), depth + 1); return nullptr; } case Node::Kind::PackElement: { Printer << "/* level: " << Node->getChild(1)->getIndex() << " */ "; Printer << "each "; print(Node->getChild(0), depth + 1); return nullptr; } case Node::Kind::PackElementLevel: printer_unreachable("should be handled in Node::Kind::PackElement"); case Node::Kind::ReturnType: if (Node->getNumChildren() == 0) Printer << Node->getText(); else { 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::Sending: Printer << "sending "; 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::DroppedArgument: Printer << "param" << Node->getIndex() << "-removed"; 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::ConstantPropKeyPath: Printer << "Constant Propagated KeyPath"; 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::BuiltinTupleType: Printer << "Builtin.TheTupleType"; return nullptr; case Node::Kind::BuiltinFixedArray: Printer << "Builtin.FixedArray<"; print(Node->getChild(0), depth + 1); Printer << ", "; print(Node->getChild(1), depth + 1); Printer << ">"; 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 "; } 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::BackDeploymentThunk: if (!Options.ShortenThunk) { Printer << "back deployment thunk for "; } return nullptr; case Node::Kind::BackDeploymentFallback: Printer << "back deployment fallback 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::ConstrainedExistential: { Printer << "any "; print(Node->getChild(0), depth + 1); Printer << "<"; print(Node->getChild(1), depth + 1); Printer << ">"; return nullptr; } case Node::Kind::ConstrainedExistentialRequirementList: { printChildren(Node, depth, ", "); 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::ConstrainedExistentialSelf: Printer << "Self"; 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::Read2Accessor: return printAbstractStorage(Node->getFirstChild(), depth, asPrefixContext, "read2"); case Node::Kind::ModifyAccessor: return printAbstractStorage(Node->getFirstChild(), depth, asPrefixContext, "modify"); case Node::Kind::Modify2Accessor: return printAbstractStorage(Node->getFirstChild(), depth, asPrefixContext, "modify2"); case Node::Kind::InitAccessor: return printAbstractStorage(Node->getFirstChild(), depth, asPrefixContext, "init"); 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::IsolatedDeallocator: return printEntity(Node, depth, asPrefixContext, TypePrinting::NoType, /*hasName*/ false, isClassType(Node->getChild(0)) ? "__isolated_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::ImplErasedIsolation: Printer << "@isolated(any)"; return nullptr; case Node::Kind::ImplCoroutineKind: // Skip if text is empty. if (Node->getText().empty()) return nullptr; // Otherwise, print with leading @. Printer << '@' << Node->getText(); return nullptr; case Node::Kind::ImplSendingResult: Printer << "sending"; 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::ImplParameterSending: // 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 differentiability and sending if it exists. if (Node->getNumChildren() == 4) { print(Node->getChild(1), depth + 1); print(Node->getChild(2), 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 << ""; return nullptr; case Node::Kind::DependentPseudogenericSignature: case Node::Kind::DependentGenericSignature: { printGenericSignature(Node, depth); return nullptr; } case Node::Kind::DependentGenericParamCount: case Node::Kind::DependentGenericParamPackMarker: case Node::Kind::DependentGenericParamValueMarker: 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::DependentGenericInverseConformanceRequirement: { NodePointer type = Node->getChild(0); print(type, depth + 1); Printer << ": ~"; switch (Node->getChild(1)->getIndex()) { #define INVERTIBLE_PROTOCOL(Name, Bit) \ case Bit: Printer << "Swift." << #Name; break; #include "swift/ABI/InvertibleProtocols.def" default: Printer << "Swift.getChild(1)->getIndex() << ">"; break; } 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::DependentGenericSameShapeRequirement: { NodePointer fst = Node->getChild(0); NodePointer snd = Node->getChild(1); print(fst, depth + 1); Printer << ".shape == "; print(snd, depth + 1); Printer << ".shape"; 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::IsolatedAnyFunctionType: Printer << "@isolated(any) "; return nullptr; case Node::Kind::SendingResultFunctionType: Printer << "sending "; return nullptr; case Node::Kind::AsyncAnnotation: Printer << " async"; return nullptr; case Node::Kind::ThrowsAnnotation: Printer << " throws"; return nullptr; case Node::Kind::TypedThrowsAnnotation: Printer << " throws("; if (Node->getNumChildren() == 1) print(Node->getChild(0), depth + 1); Printer << ")"; 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: if (Node->getNumChildren() > 0) { Printer << "("; for (unsigned i = 0; i < Node->getNumChildren(); ++i) { if (i > 0) Printer << ", "; print(Node->getChild(i), depth + 1); } Printer << ")"; } return nullptr; case Node::Kind::ConcreteProtocolConformance: Printer << "concrete protocol conformance "; if (Node->hasIndex()) Printer << "#" << Node->getIndex() << " "; print(Node->getChild(0), depth + 1); Printer << " to "; print(Node->getChild(1), depth + 1); if (Node->getNumChildren() > 2 && Node->getChild(2)->getNumChildren() > 0) { Printer << " with conditional requirements: "; print(Node->getChild(2), depth + 1); } return nullptr; case Node::Kind::PackProtocolConformance: Printer << "pack protocol conformance "; 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); Printer << " to "; 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); Printer << " to "; 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); Printer << " to "; 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: Printer << "some"; return nullptr; case Node::Kind::OpaqueReturnTypeOf: 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 << " "; 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; case Node::Kind::Uniquable: Printer << "uniquable "; print(Node->getChild(0), depth + 1); return nullptr; case Node::Kind::ExtendedExistentialTypeShape: { // Printing the requirement signature is pretty useless if we // don't print `where` clauses. auto savedDisplayWhereClauses = Options.DisplayWhereClauses; Options.DisplayWhereClauses = true; NodePointer genSig = nullptr, type = nullptr; if (Node->getNumChildren() == 2) { genSig = Node->getChild(1); type = Node->getChild(2); } else { type = Node->getChild(1); } Printer << "existential shape for "; if (genSig) { print(genSig, depth + 1); Printer << " "; } Printer << "any "; print(type, depth + 1); Options.DisplayWhereClauses = savedDisplayWhereClauses; return nullptr; } case Node::Kind::UniqueExtendedExistentialTypeShapeSymbolicReference: Printer << "unique existential shape symbolic reference 0x"; Printer.writeHex(Node->getIndex()); return nullptr; case Node::Kind::NonUniqueExtendedExistentialTypeShapeSymbolicReference: Printer << "non-unique existential shape symbolic reference 0x"; Printer.writeHex(Node->getIndex()); return nullptr; case Node::Kind::ObjectiveCProtocolSymbolicReference: Printer << "objective-c protocol symbolic reference 0x"; Printer.writeHex(Node->getIndex()); return nullptr; case Node::Kind::SymbolicExtendedExistentialType: { auto shape = Node->getChild(0); bool isUnique = (shape->getKind() == Node::Kind::UniqueExtendedExistentialTypeShapeSymbolicReference); Printer << "symbolic existential type (" << (isUnique ? "" : "non-") << "unique) 0x"; Printer.writeHex(shape->getIndex()); Printer << " <"; print(Node->getChild(1), depth + 1); if (Node->getNumChildren() > 2) { Printer << ", "; print(Node->getChild(2), depth + 1); } Printer << ">"; return nullptr; } case Node::Kind::HasSymbolQuery: Printer << "#_hasSymbol query for "; return nullptr; case Node::Kind::OpaqueReturnTypeIndex: case Node::Kind::OpaqueReturnTypeParent: return nullptr; case Node::Kind::Integer: Printer << Node->getIndex(); return nullptr; case Node::Kind::NegativeInteger: { intptr_t signedValue = Node->getIndex(); Printer << signedValue; return nullptr; } } printer_unreachable("bad node kind!"); } NodePointer NodePrinter::printAbstractStorage(NodePointer Node, unsigned depth, bool asPrefixContent, StringRef ExtraName) { switch (Node->getKind()) { case Node::Kind::Variable: return printEntity(Node, depth, asPrefixContent, TypePrinting::WithColon, /*hasName*/ true, ExtraName); case Node::Kind::Subscript: return printEntity(Node, depth, asPrefixContent, TypePrinting::WithColon, /*hasName*/ false, ExtraName, /*ExtraIndex*/ -1, "subscript"); default: printer_unreachable("Not an abstract storage node"); } } NodePointer NodePrinter::printEntity(NodePointer Entity, unsigned depth, bool asPrefixContext, TypePrinting TypePr, bool hasName, StringRef ExtraName, int ExtraIndex, StringRef OverwriteName) { NodePointer genericFunctionTypeList = nullptr; if (Entity->getKind() == Node::Kind::BoundGenericFunction) { genericFunctionTypeList = Entity->getChild(1); Entity = Entity->getFirstChild(); } // Either we print the context in prefix form "." or in // suffix form " in ". bool MultiWordName = ExtraName.contains(' '); // Also a local name (e.g. Mystruct #1) does not look good if its context is // printed in prefix form. bool LocalName = hasName && Entity->getChild(1)->getKind() == Node::Kind::LocalDeclName; if (LocalName && Options.DisplayLocalNameContexts) MultiWordName = true; if (asPrefixContext && (TypePr != TypePrinting::NoType || MultiWordName)) { // If the context has a type to be printed, we can't use the prefix form. return Entity; } NodePointer PostfixContext = nullptr; NodePointer Context = Entity->getChild(0); if (printContext(Context)) { if (MultiWordName) { // If the name contains some spaces we don't print the context now but // later in suffix form. PostfixContext = Context; } else { size_t CurrentPos = Printer.getStringRef().size(); PostfixContext = print(Context, depth + 1, /*asPrefixContext*/ true); // Was the context printed as prefix? if (Printer.getStringRef().size() != CurrentPos) Printer << '.'; } } if (hasName || !OverwriteName.empty()) { if (!ExtraName.empty() && MultiWordName) { Printer << ExtraName; if (ExtraIndex >= 0) Printer << ExtraIndex; Printer << " of "; ExtraName = ""; ExtraIndex = -1; } size_t CurrentPos = Printer.getStringRef().size(); if (!OverwriteName.empty()) { Printer << OverwriteName; } else { auto Name = Entity->getChild(1); if (Name->getKind() != Node::Kind::PrivateDeclName) print(Name, depth + 1); if (auto PrivateName = getChildIf(Entity, Node::Kind::PrivateDeclName)) print(PrivateName, depth + 1); } if (Printer.getStringRef().size() != CurrentPos && !ExtraName.empty()) Printer << '.'; } if (!ExtraName.empty()) { Printer << ExtraName; if (ExtraIndex >= 0) Printer << ExtraIndex; } if (TypePr != TypePrinting::NoType) { NodePointer type = getChildIf(Entity, Node::Kind::Type); assert(type && "malformed entity"); if (!type) { setInvalid(); return nullptr; } type = type->getChild(0); if (TypePr == TypePrinting::FunctionStyle) { // We expect to see a function type here, but if we don't, use the colon. NodePointer t = type; while (t->getKind() == Node::Kind::DependentGenericType) t = t->getChild(1)->getChild(0); if (t->getKind() != Node::Kind::FunctionType && t->getKind() != Node::Kind::NoEscapeFunctionType && t->getKind() != Node::Kind::UncurriedFunctionType && t->getKind() != Node::Kind::CFunctionPointer && t->getKind() != Node::Kind::ThinFunctionType) { TypePr = TypePrinting::WithColon; } } if (TypePr == TypePrinting::WithColon) { if (Options.DisplayEntityTypes) { Printer << " : "; printEntityType(Entity, type, genericFunctionTypeList, depth); } } else if (shouldShowEntityType(Entity->getKind(), Options)) { assert(TypePr == TypePrinting::FunctionStyle); if (MultiWordName || needSpaceBeforeType(type)) Printer << ' '; printEntityType(Entity, type, genericFunctionTypeList, depth); } } if (!asPrefixContext && PostfixContext && (!LocalName || Options.DisplayLocalNameContexts)) { // Print any left over context which couldn't be printed in prefix form. if (Entity->getKind() == Node::Kind::DefaultArgumentInitializer || Entity->getKind() == Node::Kind::Initializer || Entity->getKind() == Node::Kind::PropertyWrapperBackingInitializer || Entity->getKind() == Node::Kind::PropertyWrapperInitFromProjectedValue) { Printer << " of "; } else { Printer << " in "; } print(PostfixContext, depth + 1); PostfixContext = nullptr; } return PostfixContext; } void NodePrinter::printEntityType(NodePointer Entity, NodePointer type, NodePointer genericFunctionTypeList, unsigned depth) { NodePointer labelList = getChildIf(Entity, Node::Kind::LabelList); if (labelList || genericFunctionTypeList) { if (genericFunctionTypeList) { Printer << "<"; printChildren(genericFunctionTypeList, depth, ", "); Printer << ">"; } if (type->getKind() == Node::Kind::DependentGenericType) { if (!genericFunctionTypeList) print(type->getChild(0), depth + 1); // generic signature auto dependentType = type->getChild(1); if (needSpaceBeforeType(dependentType)) Printer << ' '; type = dependentType->getFirstChild(); } printFunctionType(labelList, type, depth); } else { print(type, depth + 1); } } NodePointer matchSequenceOfKinds(NodePointer start, std::vector> pattern) { if (start != nullptr) { NodePointer current = start; size_t idx = 0; while (idx < pattern.size()) { std::tuple next = pattern[idx]; idx += 1; NodePointer nextChild = current->getChild(std::get<1>(next)); if (nextChild != nullptr && nextChild->getKind() == std::get<0>(next)) { current = nextChild; } else { return nullptr; } } if (idx == pattern.size()) { return current; } else { return nullptr; } } else { return nullptr; } } std::string Demangle::keyPathSourceString(const char *MangledName, size_t MangledNameLength) { std::string invalid = ""; std::string unlabelledArg = "_: "; Context ctx; NodePointer root = ctx.demangleSymbolAsNode(StringRef(MangledName, MangledNameLength)); if (!root) return invalid; if (root->getNumChildren() >= 1) { NodePointer firstChild = root->getChild(0); if (firstChild->getKind() == Node::Kind::KeyPathGetterThunkHelper) { NodePointer child = firstChild->getChild(0); switch (child->getKind()) { case Node::Kind::Subscript: { std::string subscriptText = "subscript("; std::vector argumentTypeNames; auto getArgumentTypeName = [&argumentTypeNames](size_t i) { if (i < argumentTypeNames.size()) return argumentTypeNames[i]; return std::string(""); }; auto getArgumentNodeName = [](NodePointer node) { if (node->getKind() == Node::Kind::Identifier) { return std::string(node->getText()); } if (node->getKind() == Node::Kind::LocalDeclName) { auto text = node->getChild(1)->getText(); auto index = node->getChild(0)->getIndex() + 1; return std::string(text) + " #" + std::to_string(index); } return std::string(""); }; // Multiple arguments case NodePointer argList = matchSequenceOfKinds( child, { std::make_pair(Node::Kind::Type, 2), std::make_pair(Node::Kind::FunctionType, 0), std::make_pair(Node::Kind::ArgumentTuple, 0), std::make_pair(Node::Kind::Type, 0), std::make_pair(Node::Kind::Tuple, 0), }); if (argList != nullptr) { size_t numArgumentTypes = argList->getNumChildren(); size_t idx = 0; while (idx < numArgumentTypes) { NodePointer argumentType = argList->getChild(idx); idx += 1; if (argumentType->getKind() == Node::Kind::TupleElement) { argumentType = argumentType->getChild(0)->getChild(0)->getChild(1); argumentTypeNames.push_back(getArgumentNodeName(argumentType)); continue; } argumentTypeNames.push_back(""); } } else { // Case where there is a single argument argList = matchSequenceOfKinds( child, { std::make_pair(Node::Kind::Type, 2), std::make_pair(Node::Kind::FunctionType, 0), std::make_pair(Node::Kind::ArgumentTuple, 0), std::make_pair(Node::Kind::Type, 0), }); if (argList != nullptr) { argumentTypeNames.push_back( getArgumentNodeName(argList->getChild(0)->getChild(1))); } } child = child->getChild(1); size_t idx = 0; // There is an argument label: if (child != nullptr) { if (child->getKind() == Node::Kind::LabelList) { size_t numChildren = child->getNumChildren(); if (numChildren == 0) { subscriptText += unlabelledArg + getArgumentTypeName(0); } else { while (idx < numChildren) { Node *argChild = child->getChild(idx); idx += 1; if (argChild->getKind() == Node::Kind::Identifier) { subscriptText += std::string(argChild->getText()) + ": " + getArgumentTypeName(idx - 1); if (idx != numChildren) { subscriptText += ", "; } } else if (argChild->getKind() == Node::Kind::FirstElementMarker || argChild->getKind() == Node::Kind::VariadicMarker) { subscriptText += unlabelledArg + getArgumentTypeName(idx - 1); } } } } } else { subscriptText += unlabelledArg + getArgumentTypeName(0); } return subscriptText + ")"; } case Node::Kind::Variable: { child = child->getChild(1); if (child == nullptr) { return invalid; } if (child->getKind() == Node::Kind::PrivateDeclName) { child = child->getChild(1); if (child == nullptr) { return invalid; } if (child->getKind() == Node::Kind::Identifier) { return std::string(child->getText()); } } else if (child->getKind() == Node::Kind::Identifier) { return std::string(child->getText()); } break; } default: return invalid; } } } return invalid; } std::string Demangle::nodeToString(NodePointer root, const DemangleOptions &options) { if (!root) return ""; return NodePrinter(options).printRoot(root); } #endif