//===--- ASTMangler.cpp - Swift AST symbol mangling -----------------------===// // // 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 declaration name mangling in Swift. // //===----------------------------------------------------------------------===// #include "swift/AST/ASTMangler.h" #include "swift/AST/ASTContext.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/Initializer.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" #include "swift/AST/ProtocolConformance.h" #include "swift/Demangling/ManglingUtils.h" #include "swift/Strings.h" #include "clang/Basic/CharInfo.h" #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/CommandLine.h" using namespace swift; using namespace swift::Mangle; std::string ASTMangler::mangleClosureEntity(const AbstractClosureExpr *closure, SymbolKind SKind) { beginMangling(); appendClosureEntity(closure); appendSymbolKind(SKind); return finalize(); } std::string ASTMangler::mangleEntity(const ValueDecl *decl, bool isCurried, SymbolKind SKind) { beginMangling(); appendEntity(decl); if (isCurried) appendOperator("Tc"); appendSymbolKind(SKind); return finalize(); } std::string ASTMangler::mangleDestructorEntity(const DestructorDecl *decl, bool isDeallocating, SymbolKind SKind) { beginMangling(); appendDestructorEntity(decl, isDeallocating); appendSymbolKind(SKind); return finalize(); } std::string ASTMangler::mangleConstructorEntity(const ConstructorDecl *ctor, bool isAllocating, bool isCurried, SymbolKind SKind) { beginMangling(); appendConstructorEntity(ctor, isAllocating); if (isCurried) appendOperator("Tc"); appendSymbolKind(SKind); return finalize(); } std::string ASTMangler::mangleIVarInitDestroyEntity(const ClassDecl *decl, bool isDestroyer, SymbolKind SKind) { beginMangling(); appendContext(decl); appendOperator(isDestroyer ? "fE" : "fe"); appendSymbolKind(SKind); return finalize(); } std::string ASTMangler::mangleAccessorEntity(AccessorKind kind, AddressorKind addressorKind, const ValueDecl *decl, bool isStatic, SymbolKind SKind) { beginMangling(); appendAccessorEntity(kind, addressorKind, decl, isStatic); appendSymbolKind(SKind); return finalize(); } std::string ASTMangler::mangleGlobalGetterEntity(const ValueDecl *decl, SymbolKind SKind) { beginMangling(); appendEntity(decl, "fG", false); appendSymbolKind(SKind); return finalize(); } std::string ASTMangler::mangleDefaultArgumentEntity(const DeclContext *func, unsigned index, SymbolKind SKind) { beginMangling(); appendDefaultArgumentEntity(func, index); appendSymbolKind(SKind); return finalize(); } std::string ASTMangler::mangleInitializerEntity(const VarDecl *var, SymbolKind SKind) { beginMangling(); appendInitializerEntity(var); appendSymbolKind(SKind); return finalize(); } std::string ASTMangler::mangleNominalType(const NominalTypeDecl *decl) { beginMangling(); appendAnyGenericType(decl); return finalize(); } std::string ASTMangler::mangleVTableThunk(const FuncDecl *Base, const FuncDecl *Derived) { beginMangling(); appendEntity(Derived); appendEntity(Base); appendOperator("TV"); return finalize(); } std::string ASTMangler::mangleConstructorVTableThunk( const ConstructorDecl *Base, const ConstructorDecl *Derived, bool isAllocating) { beginMangling(); appendConstructorEntity(Derived, isAllocating); appendConstructorEntity(Base, isAllocating); appendOperator("TV"); return finalize(); } std::string ASTMangler::mangleWitnessTable(const NormalProtocolConformance *C) { beginMangling(); appendProtocolConformance(C); appendOperator("WP"); return finalize(); } std::string ASTMangler::mangleWitnessThunk(const ProtocolConformance *Conformance, const ValueDecl *Requirement) { beginMangling(); // Concrete witness thunks get a special mangling. if (Conformance) appendProtocolConformance(Conformance); if (auto ctor = dyn_cast(Requirement)) { appendConstructorEntity(ctor, /*isAllocating=*/true); } else { assert(isa(Requirement) && "expected function"); appendEntity(cast(Requirement)); } if (Conformance) appendOperator("TW"); return finalize(); } std::string ASTMangler::mangleClosureWitnessThunk( const ProtocolConformance *Conformance, const AbstractClosureExpr *Closure) { beginMangling(); appendProtocolConformance(Conformance); appendClosureEntity(Closure); appendOperator("TW"); return finalize(); } std::string ASTMangler::mangleBehaviorInitThunk(const VarDecl *decl) { auto topLevelContext = decl->getDeclContext()->getModuleScopeContext(); auto fileUnit = cast(topLevelContext); Identifier discriminator = fileUnit->getDiscriminatorForPrivateValue(decl); assert(!discriminator.empty()); assert(!isNonAscii(discriminator.str()) && "discriminator contains non-ASCII characters"); assert(!clang::isDigit(discriminator.str().front()) && "not a valid identifier"); appendContextOf(decl); appendIdentifier(decl->getName().str()); appendIdentifier(discriminator.str()); appendOperator("TB"); return finalize(); } std::string ASTMangler::mangleGlobalVariableFull(const VarDecl *decl) { // As a special case, Clang functions and globals don't get mangled at all. // FIXME: When we can import C++, use Clang's mangler. if (auto clangDecl = dyn_cast_or_null(decl->getClangDecl())) { if (auto asmLabel = clangDecl->getAttr()) { Buffer << '\01' << asmLabel->getLabel(); } else { Buffer << clangDecl->getName(); } return finalize(); } beginMangling(); appendEntity(decl); return finalize(); } std::string ASTMangler::mangleKeyPathGetterThunkHelper(const VarDecl *property) { beginMangling(); appendEntity(property); appendOperator("TK"); return finalize(); } std::string ASTMangler::mangleKeyPathSetterThunkHelper(const VarDecl *property) { beginMangling(); appendEntity(property); appendOperator("Tk"); return finalize(); } std::string ASTMangler::mangleGlobalInit(const VarDecl *decl, int counter, bool isInitFunc) { auto topLevelContext = decl->getDeclContext()->getModuleScopeContext(); auto fileUnit = cast(topLevelContext); Identifier discriminator = fileUnit->getDiscriminatorForPrivateValue(decl); assert(!discriminator.empty()); assert(!isNonAscii(discriminator.str()) && "discriminator contains non-ASCII characters"); assert(!clang::isDigit(discriminator.str().front()) && "not a valid identifier"); Buffer << "globalinit_"; appendIdentifier(discriminator.str()); Buffer << (isInitFunc ? "_func" : "_token"); Buffer << counter; return finalize(); } std::string ASTMangler::mangleReabstractionThunkHelper( CanSILFunctionType ThunkType, Type FromType, Type ToType, ModuleDecl *Module) { Mod = Module; GenericSignature *GenSig = ThunkType->getGenericSignature(); if (GenSig) CurGenericSignature = GenSig->getCanonicalSignature(); beginMangling(); appendType(FromType); appendType(ToType); if (GenSig) appendGenericSignature(GenSig); // TODO: mangle ThunkType->isPseudogeneric() appendOperator("TR"); return finalize(); } std::string ASTMangler::mangleTypeForDebugger(Type Ty, const DeclContext *DC, GenericEnvironment *GE) { GenericEnv = GE; DWARFMangling = true; beginMangling(); if (DC) bindGenericParameters(DC); DeclCtx = DC; appendType(Ty); appendOperator("D"); return finalize(); } std::string ASTMangler::mangleDeclType(const ValueDecl *decl) { DWARFMangling = true; beginMangling(); appendDeclType(decl); appendOperator("D"); return finalize(); } static bool isPrivate(const NominalTypeDecl *Nominal) { return Nominal->hasAccessibility() && Nominal->getFormalAccess() <= Accessibility::FilePrivate; } std::string ASTMangler::mangleObjCRuntimeName(const NominalTypeDecl *Nominal) { DeclContext *Ctx = Nominal->getDeclContext(); if (Ctx->isModuleScopeContext() && !isPrivate(Nominal)) { // Use the old mangling for non-private top-level classes and protocols. // This is what the ObjC runtime needs to demangle. // TODO: Use new mangling scheme as soon as the ObjC runtime // can demangle it. // // Don't use word-substitutions and punycode encoding. MaxNumWords = 0; UsePunycode = false; UseSubstitutions = false; Buffer << "_Tt"; bool isProto = false; if (isa(Nominal)) { Buffer << 'C'; } else { isProto = true; assert(isa(Nominal)); Buffer << 'P'; } appendModule(Ctx->getParentModule()); appendIdentifier(Nominal->getName().str()); if (isProto) Buffer << '_'; return finalize(); } // For all other cases, we can use the new mangling. beginMangling(); appendAnyGenericType(Nominal); return finalize(); } std::string ASTMangler::mangleTypeAsContextUSR(const NominalTypeDecl *type) { llvm::SaveAndRestore allowUnnamedRAII(AllowNamelessEntities, true); appendContext(type); return finalize(); } std::string ASTMangler::mangleDeclAsUSR(const ValueDecl *Decl, StringRef USRPrefix) { llvm::SaveAndRestore allowUnnamedRAII(AllowNamelessEntities, true); Buffer << USRPrefix; bindGenericParameters(Decl->getDeclContext()); if (auto Ctor = dyn_cast(Decl)) { appendConstructorEntity(Ctor, /*isAllocating=*/false); } else if (auto Dtor = dyn_cast(Decl)) { appendDestructorEntity(Dtor, /*isDeallocating=*/false); } else if (auto GTD = dyn_cast(Decl)) { appendAnyGenericType(GTD); } else if (isa(Decl)) { appendContextOf(Decl); appendDeclName(Decl); } else { appendEntity(Decl); } // We have a custom prefix, so finalize() won't verify for us. Do it manually. verify(Storage.str().drop_front(USRPrefix.size())); return finalize(); } std::string ASTMangler::mangleAccessorEntityAsUSR(AccessorKind kind, AddressorKind addressorKind, const ValueDecl *decl, StringRef USRPrefix) { llvm::SaveAndRestore allowUnnamedRAII(AllowNamelessEntities, true); Buffer << USRPrefix; appendAccessorEntity(kind, addressorKind, decl, /*isStatic*/ false); // We have a custom prefix, so finalize() won't verify for us. Do it manually. verify(Storage.str().drop_front(USRPrefix.size())); return finalize(); } void ASTMangler::appendSymbolKind(SymbolKind SKind) { switch (SKind) { case SymbolKind::Default: return; case SymbolKind::DynamicThunk: return appendOperator("TD"); case SymbolKind::SwiftAsObjCThunk: return appendOperator("To"); case SymbolKind::ObjCAsSwiftThunk: return appendOperator("TO"); case SymbolKind::DirectMethodReferenceThunk: return appendOperator("Td"); } } /// Returns true if one of the ancestor DeclContexts of \p D is either marked /// private or is a local context. static bool isInPrivateOrLocalContext(const ValueDecl *D) { const DeclContext *DC = D->getDeclContext(); if (!DC->isTypeContext()) { assert((DC->isModuleScopeContext() || DC->isLocalContext()) && "unexpected context kind"); return DC->isLocalContext(); } auto declaredType = DC->getDeclaredTypeOfContext(); if (!declaredType || declaredType->hasError()) return false; auto *nominal = declaredType->getAnyNominal(); if (nominal->getFormalAccess() <= Accessibility::FilePrivate) return true; return isInPrivateOrLocalContext(nominal); } static bool getUnnamedParamIndex(const ParameterList *ParamList, const ParamDecl *D, unsigned &UnnamedIndex) { for (auto Param : *ParamList) { if (!Param->hasName()) { if (Param == D) return true; ++UnnamedIndex; } } return false; } static unsigned getUnnamedParamIndex(const ParamDecl *D) { if (auto SD = dyn_cast(D->getDeclContext())) { unsigned UnnamedIndex = 0; auto *ParamList = SD->getIndices(); if (getUnnamedParamIndex(ParamList, D, UnnamedIndex)) return UnnamedIndex; llvm_unreachable("param not found"); } ArrayRef ParamLists; if (auto AFD = dyn_cast(D->getDeclContext())) { ParamLists = AFD->getParameterLists(); } else { auto ACE = cast(D->getDeclContext()); ParamLists = ACE->getParameterLists(); } unsigned UnnamedIndex = 0; for (auto ParamList : ParamLists) { if (getUnnamedParamIndex(ParamList, D, UnnamedIndex)) return UnnamedIndex; } llvm_unreachable("param not found"); } void ASTMangler::appendDeclName(const ValueDecl *decl) { if (decl->isOperator()) { appendIdentifier(translateOperator(decl->getName().str())); switch (decl->getAttrs().getUnaryOperatorKind()) { case UnaryOperatorKind::Prefix: appendOperator("op"); break; case UnaryOperatorKind::Postfix: appendOperator("oP"); break; case UnaryOperatorKind::None: appendOperator("oi"); break; } } else if (decl->hasName()) { appendIdentifier(decl->getName().str()); } else { assert(AllowNamelessEntities && "attempt to mangle unnamed decl"); // Fall back to an unlikely name, so that we still generate a valid // mangled name. appendIdentifier("_"); } if (decl->getDeclContext()->isLocalContext()) { if (auto *paramDecl = dyn_cast(decl)) { if (!decl->hasName()) { // Mangle unnamed params with their ordering. return appendOperator("L", Index(getUnnamedParamIndex(paramDecl))); } } // Mangle local declarations with a numeric discriminator. return appendOperator("L", Index(decl->getLocalDiscriminator())); } if (decl->hasAccessibility() && decl->getFormalAccess() <= Accessibility::FilePrivate && !isInPrivateOrLocalContext(decl)) { // Mangle non-local private declarations with a textual discriminator // based on their enclosing file. // The first is a discriminator string unique to the decl's // original source file. auto topLevelContext = decl->getDeclContext()->getModuleScopeContext(); auto fileUnit = cast(topLevelContext); Identifier discriminator = fileUnit->getDiscriminatorForPrivateValue(decl); assert(!discriminator.empty()); assert(!isNonAscii(discriminator.str()) && "discriminator contains non-ASCII characters"); (void)&isNonAscii; assert(!clang::isDigit(discriminator.str().front()) && "not a valid identifier"); appendIdentifier(discriminator.str()); return appendOperator("LL"); } } static const char *getMetatypeRepresentationOp(MetatypeRepresentation Rep) { switch (Rep) { case MetatypeRepresentation::Thin: return "t"; case MetatypeRepresentation::Thick: return "T"; case MetatypeRepresentation::ObjC: return "o"; } llvm_unreachable("Unhandled MetatypeRepresentation in switch."); } static bool isStdlibType(const TypeDecl *decl) { DeclContext *dc = decl->getDeclContext(); return dc->isModuleScopeContext() && dc->getParentModule()->isStdlibModule(); } /// Mangle a type into the buffer. /// void ASTMangler::appendType(Type type) { assert((DWARFMangling || type->isCanonical()) && "expecting canonical types when not mangling for the debugger"); TypeBase *tybase = type.getPointer(); switch (type->getKind()) { case TypeKind::TypeVariable: llvm_unreachable("mangling type variable"); case TypeKind::Module: llvm_unreachable("Cannot mangle module type yet"); case TypeKind::Error: case TypeKind::Unresolved: appendOperator("Xe"); return; // We don't care about these types being a bit verbose because we // don't expect them to come up that often in API names. case TypeKind::BuiltinFloat: switch (cast(tybase)->getFPKind()) { case BuiltinFloatType::IEEE16: appendOperator("Bf16_"); return; case BuiltinFloatType::IEEE32: appendOperator("Bf32_"); return; case BuiltinFloatType::IEEE64: appendOperator("Bf64_"); return; case BuiltinFloatType::IEEE80: appendOperator("Bf80_"); return; case BuiltinFloatType::IEEE128: appendOperator("Bf128_"); return; case BuiltinFloatType::PPC128: llvm_unreachable("ppc128 not supported"); } llvm_unreachable("bad floating-point kind"); case TypeKind::BuiltinInteger: { auto width = cast(tybase)->getWidth(); if (width.isFixedWidth()) appendOperator("Bi", Index(width.getFixedWidth() + 1)); else if (width.isPointerWidth()) appendOperator("Bw"); else llvm_unreachable("impossible width value"); return; } case TypeKind::BuiltinRawPointer: return appendOperator("Bp"); case TypeKind::BuiltinNativeObject: return appendOperator("Bo"); case TypeKind::BuiltinBridgeObject: return appendOperator("Bb"); case TypeKind::BuiltinUnknownObject: return appendOperator("BO"); case TypeKind::BuiltinUnsafeValueBuffer: return appendOperator("BB"); case TypeKind::BuiltinVector: appendType(cast(tybase)->getElementType()); return appendOperator("Bv", cast(tybase)->getNumElements()); case TypeKind::NameAlias: { assert(DWARFMangling && "sugared types are only legal for the debugger"); auto NameAliasTy = cast(tybase); TypeAliasDecl *decl = NameAliasTy->getDecl(); if (decl->getModuleContext() == decl->getASTContext().TheBuiltinModule) { // It's not possible to mangle the context of the builtin module. return appendType(NameAliasTy->getSinglyDesugaredType()); } // For the DWARF output we want to mangle the type alias + context, // unless the type alias references a builtin type. return appendAnyGenericType(decl); } case TypeKind::Paren: return appendSugaredType(type); case TypeKind::ArraySlice: /* fallthrough */ case TypeKind::Optional: return appendSugaredType(type); case TypeKind::Dictionary: return appendSugaredType(type); case TypeKind::ImplicitlyUnwrappedOptional: { assert(DWARFMangling && "sugared types are only legal for the debugger"); auto *IUO = cast(tybase); auto implDecl = tybase->getASTContext().getImplicitlyUnwrappedOptionalDecl(); auto GenTy = BoundGenericType::get(implDecl, Type(), IUO->getBaseType()); return appendType(GenTy); } case TypeKind::ExistentialMetatype: { ExistentialMetatypeType *EMT = cast(tybase); appendType(EMT->getInstanceType()); if (EMT->hasRepresentation()) { appendOperator("Xm", getMetatypeRepresentationOp(EMT->getRepresentation())); } else { appendOperator("Xp"); } return; } case TypeKind::Metatype: { MetatypeType *MT = cast(tybase); appendType(MT->getInstanceType()); if (MT->hasRepresentation()) { appendOperator("XM", getMetatypeRepresentationOp(MT->getRepresentation())); } else { appendOperator("m"); } return; } case TypeKind::LValue: llvm_unreachable("@lvalue types should not occur in function interfaces"); case TypeKind::InOut: appendType(cast(tybase)->getObjectType()); return appendOperator("z"); case TypeKind::UnmanagedStorage: appendType(cast(tybase)->getReferentType()); return appendOperator("Xu"); case TypeKind::UnownedStorage: appendType(cast(tybase)->getReferentType()); return appendOperator("Xo"); case TypeKind::WeakStorage: appendType(cast(tybase)->getReferentType()); return appendOperator("Xw"); case TypeKind::Tuple: appendTypeList(type); return appendOperator("t"); case TypeKind::Protocol: { bool First = true; appendProtocolName(cast(tybase)->getDecl()); appendListSeparator(First); return appendOperator("p"); } case TypeKind::ProtocolComposition: { // We mangle ProtocolType and ProtocolCompositionType using the // same production: bool First = true; auto layout = type->getExistentialLayout(); for (Type protoTy : layout.getProtocols()) { appendProtocolName(protoTy->castTo()->getDecl()); appendListSeparator(First); } if (First) appendOperator("y"); if (layout.superclass) { appendType(layout.superclass); return appendOperator("Xc"); } else if (layout.requiresClass & !layout.requiresClassImplied) { return appendOperator("Xl"); } return appendOperator("p"); } case TypeKind::UnboundGeneric: case TypeKind::Class: case TypeKind::Enum: case TypeKind::Struct: case TypeKind::BoundGenericClass: case TypeKind::BoundGenericEnum: case TypeKind::BoundGenericStruct: if (type->isSpecialized()) { // Try to mangle the entire name as a substitution. if (tryMangleSubstitution(type.getPointer())) return; NominalTypeDecl *NDecl = type->getAnyNominal(); if (isStdlibType(NDecl) && NDecl->getName().str() == "Optional") { auto GenArgs = type->castTo()->getGenericArgs(); assert(GenArgs.size() == 1); appendType(GenArgs[0]); appendOperator("Sg"); } else { appendAnyGenericType(NDecl); bool isFirstArgList = true; appendBoundGenericArgs(type, isFirstArgList); appendOperator("G"); } addSubstitution(type.getPointer()); return; } appendAnyGenericType(tybase->getAnyNominal()); return; case TypeKind::SILFunction: return appendImplFunctionType(cast(tybase)); // type ::= archetype case TypeKind::Archetype: { auto *archetype = cast(tybase); assert(DWARFMangling && "Cannot mangle free-standing archetypes"); // Mangle the associated type of a parent archetype. if (auto parent = archetype->getParent()) { assert(archetype->getAssocType() && "child archetype has no associated type?!"); if (tryMangleSubstitution(archetype)) return; appendType(parent); appendIdentifier(archetype->getName().str()); appendOperator("Qa"); addSubstitution(archetype); return; } // archetype ::= 'Q' # archetype with depth=0, index=N // archetype ::= 'Qd' # archetype with depth=M+1, index=N // Mangle generic parameter archetypes. // Find the archetype information. const DeclContext *DC = DeclCtx; auto GTPT = GenericEnvironment::mapTypeOutOfContext(GenericEnv, archetype) ->castTo(); // The DWARF output created by Swift is intentionally flat, // therefore archetypes are emitted with their DeclContext if // they appear at the top level of a type. DWARFMangling = false; while (DC && DC->isGenericContext()) { if (DC->isInnermostContextGeneric() && DC->getGenericParamsOfContext()->getDepth() == GTPT->getDepth()) break; DC = DC->getParent(); } assert(DC && "no decl context for archetype found"); if (!DC) return; appendContext(DC); DWARFMangling = true; return appendOperator("Qq", Index(GTPT->getIndex())); } case TypeKind::DynamicSelf: { auto dynamicSelf = cast(tybase); if (dynamicSelf->getSelfType()->getAnyNominal()) { appendType(dynamicSelf->getSelfType()); return appendOperator("XD"); } return appendType(dynamicSelf->getSelfType()); } case TypeKind::GenericFunction: { auto genFunc = cast(tybase); appendFunctionType(genFunc, /*forceSingleParam*/ false); appendGenericSignature(genFunc->getGenericSignature()); appendOperator("u"); return; } case TypeKind::GenericTypeParam: { auto paramTy = cast(tybase); // A special mangling for the very first generic parameter. This shows up // frequently because it corresponds to 'Self' in protocol requirement // generic signatures. if (paramTy->getDepth() == 0 && paramTy->getIndex() == 0) return appendOperator("x"); return appendOpWithGenericParamIndex("q", paramTy); } case TypeKind::DependentMember: { auto *DepTy = cast(tybase); if (tryMangleSubstitution(DepTy)) return; bool isAssocTypeAtDepth = false; if (GenericTypeParamType *gpBase = appendAssocType(DepTy, isAssocTypeAtDepth)) { if (gpBase->getDepth() == 0 && gpBase->getIndex() == 0) { appendOperator(isAssocTypeAtDepth ? "QZ" : "Qz"); } else { appendOpWithGenericParamIndex(isAssocTypeAtDepth ? "QY" : "Qy", gpBase); } } else { // Dependent members of non-generic-param types are not canonical, but // we may still want to mangle them for debugging or indexing purposes. appendType(DepTy->getBase()); appendAssociatedTypeName(DepTy); appendOperator("qa"); } addSubstitution(DepTy); return; } case TypeKind::Function: appendFunctionType(cast(tybase), /*forceSingleParam*/ false); return; case TypeKind::SILBox: { auto box = cast(tybase); auto layout = box->getLayout(); SmallVector fieldsList; for (auto &field : layout->getFields()) { auto fieldTy = field.getLoweredType(); // Use the `inout` mangling to represent a mutable field. if (field.isMutable()) fieldTy = CanInOutType::get(fieldTy); fieldsList.push_back(TupleTypeElt(fieldTy)); } appendTypeList(TupleType::get(fieldsList, tybase->getASTContext()) ->getCanonicalType()); if (auto sig = layout->getGenericSignature()) { fieldsList.clear(); for (auto &arg : box->getGenericArgs()) { fieldsList.push_back(TupleTypeElt(arg.getReplacement())); } appendTypeList(TupleType::get(fieldsList, tybase->getASTContext()) ->getCanonicalType()); appendGenericSignature(sig); appendOperator("XX"); } else { appendOperator("Xx"); } return; } case TypeKind::SILBlockStorage: llvm_unreachable("should never be mangled"); } llvm_unreachable("bad type kind"); } GenericTypeParamType *ASTMangler::appendAssocType(DependentMemberType *DepTy, bool &isAssocTypeAtDepth) { auto base = DepTy->getBase()->getCanonicalType(); // 't_0_0.Member' if (auto gpBase = dyn_cast(base)) { appendAssociatedTypeName(DepTy); isAssocTypeAtDepth = false; return gpBase; } // 't_0_0.Member.Member...' SmallVector path; path.push_back(DepTy); while (auto dmBase = dyn_cast(base)) { path.push_back(dmBase); base = dmBase.getBase(); } if (auto gpRoot = dyn_cast(base)) { bool first = true; for (auto *member : reversed(path)) { appendAssociatedTypeName(member); appendListSeparator(first); } isAssocTypeAtDepth = true; return gpRoot; } return nullptr; } void ASTMangler::appendOpWithGenericParamIndex(StringRef Op, const GenericTypeParamType *paramTy) { llvm::SmallVector OpBuf(Op.begin(), Op.end()); if (paramTy->getDepth() > 0) { OpBuf.push_back('d'); return appendOperator(StringRef(OpBuf.data(), OpBuf.size()), Index(paramTy->getDepth() - 1), Index(paramTy->getIndex())); } if (paramTy->getIndex() == 0) { OpBuf.push_back('z'); return appendOperator(StringRef(OpBuf.data(), OpBuf.size())); } appendOperator(Op, Index(paramTy->getIndex() - 1)); } /// Bind the generic parameters from the given signature. void ASTMangler::bindGenericParameters(CanGenericSignature sig) { if (sig) CurGenericSignature = sig; } /// Bind the generic parameters from the given context and its parents. void ASTMangler::bindGenericParameters(const DeclContext *DC) { if (auto sig = DC->getGenericSignatureOfContext()) bindGenericParameters(sig->getCanonicalSignature()); } void ASTMangler::appendBoundGenericArgs(Type type, bool &isFirstArgList) { BoundGenericType *boundType = nullptr; if (auto *unboundType = type->getAs()) { if (Type parent = unboundType->getParent()) appendBoundGenericArgs(parent, isFirstArgList); } else if (auto *nominalType = type->getAs()) { if (Type parent = nominalType->getParent()) appendBoundGenericArgs(parent, isFirstArgList); } else { boundType = type->castTo(); if (Type parent = boundType->getParent()) appendBoundGenericArgs(parent, isFirstArgList); } if (isFirstArgList) { appendOperator("y"); isFirstArgList = false; } else { appendOperator("_"); } if (boundType) { for (Type arg : boundType->getGenericArgs()) { appendType(arg); } } } static char getParamConvention(ParameterConvention conv) { // @in and @out are mangled the same because they're put in // different places. switch (conv) { case ParameterConvention::Indirect_In: return 'i'; case ParameterConvention::Indirect_Inout: return 'l'; case ParameterConvention::Indirect_InoutAliasable: return 'b'; case ParameterConvention::Indirect_In_Guaranteed: return 'n'; case ParameterConvention::Direct_Owned: return 'x'; case ParameterConvention::Direct_Unowned: return 'y'; case ParameterConvention::Direct_Guaranteed: return 'g'; } llvm_unreachable("bad parameter convention"); }; static char getResultConvention(ResultConvention conv) { switch (conv) { case ResultConvention::Indirect: return 'r'; case ResultConvention::Owned: return 'o'; case ResultConvention::Unowned: return 'd'; case ResultConvention::UnownedInnerPointer: return 'u'; case ResultConvention::Autoreleased: return 'a'; } llvm_unreachable("bad result convention"); }; void ASTMangler::appendImplFunctionType(SILFunctionType *fn) { llvm::SmallVector OpArgs; if (fn->isPolymorphic() && fn->isPseudogeneric()) OpArgs.push_back('P'); // if (fn->getExtInfo().hasContext()) { OpArgs.push_back(getParamConvention(fn->getCalleeConvention())); } else { OpArgs.push_back('t'); } switch (fn->getRepresentation()) { case SILFunctionTypeRepresentation::Thick: case SILFunctionTypeRepresentation::Thin: break; case SILFunctionTypeRepresentation::Block: OpArgs.push_back('B'); break; case SILFunctionTypeRepresentation::CFunctionPointer: OpArgs.push_back('C'); break; case SILFunctionTypeRepresentation::ObjCMethod: OpArgs.push_back('O'); break; case SILFunctionTypeRepresentation::Method: OpArgs.push_back('M'); break; case SILFunctionTypeRepresentation::Closure: OpArgs.push_back('K'); break; case SILFunctionTypeRepresentation::WitnessMethod: OpArgs.push_back('W'); break; } // Mangle the parameters. for (auto param : fn->getParameters()) { OpArgs.push_back(getParamConvention(param.getConvention())); appendType(param.getType()); } // Mangle the results. for (auto result : fn->getResults()) { OpArgs.push_back(getResultConvention(result.getConvention())); appendType(result.getType()); } // Mangle the error result if present. if (fn->hasErrorResult()) { auto error = fn->getErrorResult(); OpArgs.push_back('z'); OpArgs.push_back(getResultConvention(error.getConvention())); appendType(error.getType()); } if (fn->isPolymorphic()) appendGenericSignature(fn->getGenericSignature()); OpArgs.push_back('_'); appendOperator("I", StringRef(OpArgs.data(), OpArgs.size())); } /// Mangle the context of the given declaration as a . void ASTMangler::appendContextOf(const ValueDecl *decl) { // Declarations provided by a C module have a special context // mangling. // known-context ::= 'So' // // Also handle top-level imported declarations that don't have corresponding // Clang decls. Check getKind() directly to avoid a layering dependency. // known-context ::= 'SC' if (auto file = dyn_cast(decl->getDeclContext())) { if (file->getKind() == FileUnitKind::ClangModule) { // FIXME: Import-as-member Clang decls should appear under 'So' as well, // rather than under their current parent. if (decl->getClangDecl()) return appendOperator("So"); return appendOperator("SC"); } } // Just mangle the decl's DC. appendContext(decl->getDeclContext()); } namespace { class FindFirstVariable : public PatternVisitor { public: VarDecl *visitNamedPattern(NamedPattern *P) { return P->getDecl(); } VarDecl *visitTuplePattern(TuplePattern *P) { for (auto &elt : P->getElements()) { VarDecl *var = visit(elt.getPattern()); if (var) return var; } return nullptr; } VarDecl *visitParenPattern(ParenPattern *P) { return visit(P->getSubPattern()); } VarDecl *visitVarPattern(VarPattern *P) { return visit(P->getSubPattern()); } VarDecl *visitTypedPattern(TypedPattern *P) { return visit(P->getSubPattern()); } VarDecl *visitAnyPattern(AnyPattern *P) { return nullptr; } // Refutable patterns shouldn't ever come up. #define REFUTABLE_PATTERN(ID, BASE) \ VarDecl *visit##ID##Pattern(ID##Pattern *P) { \ llvm_unreachable("shouldn't be visiting a refutable pattern here!"); \ } #define PATTERN(ID, BASE) #include "swift/AST/PatternNodes.def" }; } // end anonymous namespace /// Find the first identifier bound by the given binding. This /// assumes that field and global-variable bindings always bind at /// least one name, which is probably a reasonable assumption but may /// not be adequately enforced. static Optional findFirstVariable(PatternBindingDecl *binding) { for (auto entry : binding->getPatternList()) { auto var = FindFirstVariable().visit(entry.getPattern()); if (var) return var; } // Pattern-binding bound without variables exists in erroneous code, e.g. // during code completion. return None; } void ASTMangler::appendContext(const DeclContext *ctx) { switch (ctx->getContextKind()) { case DeclContextKind::Module: return appendModule(cast(ctx)); case DeclContextKind::FileUnit: assert(!isa(ctx) && "mangling member of builtin module!"); appendContext(ctx->getParent()); return; case DeclContextKind::SerializedLocal: { auto local = cast(ctx); switch (local->getLocalDeclContextKind()) { case LocalDeclContextKind::AbstractClosure: appendClosureEntity(cast(local)); return; case LocalDeclContextKind::DefaultArgumentInitializer: { auto argInit = cast(local); appendDefaultArgumentEntity(ctx->getParent(), argInit->getIndex()); return; } case LocalDeclContextKind::PatternBindingInitializer: { auto patternInit = cast(local); if (auto var = findFirstVariable(patternInit->getBinding())) { appendInitializerEntity(var.getValue()); } else { // This is incorrect in that it does not produce a /unique/ mangling, // but it will at least produce a /valid/ mangling. appendContext(ctx->getParent()); } return; } case LocalDeclContextKind::TopLevelCodeDecl: return appendContext(local->getParent()); } } case DeclContextKind::GenericTypeDecl: appendAnyGenericType(cast(ctx)); return; case DeclContextKind::ExtensionDecl: { auto ExtD = cast(ctx); auto ExtTy = ExtD->getExtendedType(); // Recover from erroneous extension. if (ExtTy.isNull() || ExtTy->hasError()) return appendContext(ExtD->getDeclContext()); auto decl = ExtTy->getAnyNominal(); assert(decl && "extension of non-nominal type?"); // Mangle the module name if: // - the extension is defined in a different module from the actual nominal // type decl, // - the extension is constrained, or // - the extension is to a protocol. // FIXME: In a world where protocol extensions are dynamically dispatched, // "extension is to a protocol" would no longer be a reason to use the // extension mangling, because an extension method implementation could be // resiliently moved into the original protocol itself. if (ExtD->getParentModule() != decl->getParentModule() || ExtD->isConstrainedExtension() || ExtD->getDeclaredInterfaceType()->isExistentialType()) { auto sig = ExtD->getGenericSignature(); // If the extension is constrained, mangle the generic signature that // constrains it. appendAnyGenericType(decl); appendModule(ExtD->getParentModule()); if (sig && ExtD->isConstrainedExtension()) { Mod = ExtD->getModuleContext(); appendGenericSignature(sig); } return appendOperator("E"); } return appendAnyGenericType(decl); } case DeclContextKind::AbstractClosureExpr: return appendClosureEntity(cast(ctx)); case DeclContextKind::AbstractFunctionDecl: { auto fn = cast(ctx); // Constructors and destructors as contexts are always mangled // using the non-(de)allocating variants. if (auto ctor = dyn_cast(fn)) { return appendConstructorEntity(ctor, /*allocating*/ false); } if (auto dtor = dyn_cast(fn)) return appendDestructorEntity(dtor, /*deallocating*/ false); return appendEntity(fn); } case DeclContextKind::SubscriptDecl: // FIXME: We may need to do something here if subscripts contain any symbols // exposed with linkage names, or if/when they get generic parameters. return appendContext(ctx->getParent()); case DeclContextKind::Initializer: switch (cast(ctx)->getInitializerKind()) { case InitializerKind::DefaultArgument: { auto argInit = cast(ctx); return appendDefaultArgumentEntity(ctx->getParent(), argInit->getIndex()); } case InitializerKind::PatternBinding: { auto patternInit = cast(ctx); if (auto var = findFirstVariable(patternInit->getBinding())) { appendInitializerEntity(var.getValue()); } else { // This is incorrect in that it does not produce a /unique/ mangling, // but it will at least produce a /valid/ mangling. appendContext(ctx->getParent()); } return; } } llvm_unreachable("bad initializer kind"); case DeclContextKind::TopLevelCodeDecl: // Mangle the containing module context. return appendContext(ctx->getParent()); } llvm_unreachable("bad decl context"); } void ASTMangler::appendModule(const ModuleDecl *module) { assert(!module->getParent() && "cannot mangle nested modules!"); // Try the special 'swift' substitution. if (module->isStdlibModule()) return appendOperator("s"); StringRef ModName = module->getName().str(); if (ModName == MANGLING_MODULE_OBJC) return appendOperator("So"); if (ModName == MANGLING_MODULE_CLANG_IMPORTER) return appendOperator("SC"); appendIdentifier(ModName); } /// Mangle the name of a protocol as a substitution candidate. void ASTMangler::appendProtocolName(const ProtocolDecl *protocol) { appendContextOf(protocol); appendDeclName(protocol); } void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl) { // Check for certain standard types. if (tryAppendStandardSubstitution(decl)) return; // For generic types, this uses the unbound type. Type key; if (auto *alias = dyn_cast(decl)) { if (alias->isGeneric()) key = alias->getUnboundGenericType(); else key = alias->getDeclaredInterfaceType(); } else { key = cast(decl)->getDeclaredType(); } // Try to mangle the entire name as a substitution. if (tryMangleSubstitution(key.getPointer())) return; appendContextOf(decl); appendDeclName(decl); switch (decl->getKind()) { default: llvm_unreachable("not a nominal type"); case DeclKind::TypeAlias: appendOperator("a"); break; case DeclKind::Protocol: appendOperator("P"); break; case DeclKind::Class: appendOperator("C"); break; case DeclKind::Enum: appendOperator("O"); break; case DeclKind::Struct: appendOperator("V"); break; } addSubstitution(key.getPointer()); } void ASTMangler::appendFunctionType(AnyFunctionType *fn, bool forceSingleParam) { assert((DWARFMangling || fn->isCanonical()) && "expecting canonical types when not mangling for the debugger"); appendFunctionSignature(fn, forceSingleParam); // Note that we do not currently use thin representations in the AST // for the types of function decls. This may need to change at some // point, in which case the uncurry logic can probably migrate to that // case. // // It would have been cleverer if we'd used 'f' for thin functions // and something else for uncurried functions, but oh well. // // Or maybe we can change the mangling at the same time we make // changes to better support thin functions. switch (fn->getRepresentation()) { case AnyFunctionType::Representation::Block: return appendOperator("XB"); case AnyFunctionType::Representation::Thin: return appendOperator("Xf"); case AnyFunctionType::Representation::Swift: if (fn->isAutoClosure()) return appendOperator("XK"); return appendOperator("c"); case AnyFunctionType::Representation::CFunctionPointer: return appendOperator("XC"); } } void ASTMangler::appendFunctionSignature(AnyFunctionType *fn, bool forceSingleParam) { appendParams(fn->getResult(), /*forceSingleParam*/ false); appendParams(fn->getInput(), forceSingleParam); if (fn->throws()) appendOperator("K"); } void ASTMangler::appendParams(Type ParamsTy, bool forceSingleParam) { if (TupleType *Tuple = ParamsTy->getAs()) { if (Tuple->getNumElements() == 0) { if (forceSingleParam) { // A tuple containing a single empty tuple. appendOperator("y"); appendOperator("t"); appendListSeparator(); appendOperator("t"); } else { appendOperator("y"); } return; } if (forceSingleParam && Tuple->getNumElements() > 1) { appendType(ParamsTy); appendListSeparator(); appendOperator("t"); return; } } appendType(ParamsTy); } void ASTMangler::appendTypeList(Type listTy) { if (TupleType *tuple = listTy->getAs()) { if (tuple->getNumElements() == 0) return appendOperator("y"); bool firstField = true; for (auto &field : tuple->getElements()) { appendType(field.getType()); if (field.hasName()) appendIdentifier(field.getName().str()); if (field.isVararg()) appendOperator("d"); appendListSeparator(firstField); } } else { appendType(listTy); appendListSeparator(); } } void ASTMangler::appendGenericSignature(const GenericSignature *sig) { auto canSig = sig->getCanonicalSignature(); CurGenericSignature = canSig; appendGenericSignatureParts(canSig->getGenericParams(), 0, canSig->getRequirements()); } void ASTMangler::appendRequirement(const Requirement &reqt) { Type FirstTy = reqt.getFirstType()->getCanonicalType(); switch (reqt.getKind()) { case RequirementKind::Layout: { } break; case RequirementKind::Conformance: { Type SecondTy = reqt.getSecondType(); appendProtocolName(SecondTy->castTo()->getDecl()); } break; case RequirementKind::Superclass: case RequirementKind::SameType: { Type SecondTy = reqt.getSecondType(); appendType(SecondTy->getCanonicalType()); } break; } if (auto *DT = FirstTy->getAs()) { bool isAssocTypeAtDepth = false; if (tryMangleSubstitution(DT)) { switch (reqt.getKind()) { case RequirementKind::Conformance: return appendOperator("RQ"); case RequirementKind::Layout: appendOperator("RL"); appendOpParamForLayoutConstraint(reqt.getLayoutConstraint()); return; case RequirementKind::Superclass: return appendOperator("RB"); case RequirementKind::SameType: return appendOperator("RS"); } llvm_unreachable("bad requirement type"); } GenericTypeParamType *gpBase = appendAssocType(DT, isAssocTypeAtDepth); addSubstitution(DT); assert(gpBase); switch (reqt.getKind()) { case RequirementKind::Conformance: return appendOpWithGenericParamIndex(isAssocTypeAtDepth ? "RP" : "Rp", gpBase); case RequirementKind::Layout: appendOpWithGenericParamIndex(isAssocTypeAtDepth ? "RM" : "Rm", gpBase); appendOpParamForLayoutConstraint(reqt.getLayoutConstraint()); return; case RequirementKind::Superclass: return appendOpWithGenericParamIndex(isAssocTypeAtDepth ? "RC" : "Rc", gpBase); case RequirementKind::SameType: return appendOpWithGenericParamIndex(isAssocTypeAtDepth ? "RT" : "Rt", gpBase); } llvm_unreachable("bad requirement type"); } GenericTypeParamType *gpBase = FirstTy->castTo(); switch (reqt.getKind()) { case RequirementKind::Conformance: return appendOpWithGenericParamIndex("R", gpBase); case RequirementKind::Layout: appendOpWithGenericParamIndex("Rl", gpBase); appendOpParamForLayoutConstraint(reqt.getLayoutConstraint()); return; case RequirementKind::Superclass: return appendOpWithGenericParamIndex("Rb", gpBase); case RequirementKind::SameType: return appendOpWithGenericParamIndex("Rs", gpBase); } llvm_unreachable("bad requirement type"); } void ASTMangler::appendGenericSignatureParts( ArrayRef params, unsigned initialParamDepth, ArrayRef requirements) { // Mangle the requirements. for (const Requirement &reqt : requirements) { appendRequirement(reqt); } if (params.size() == 1 && params[0]->getDepth() == initialParamDepth) return appendOperator("l"); llvm::SmallVector OpStorage; llvm::raw_svector_ostream OpBuffer(OpStorage); // Mangle the number of parameters. unsigned depth = 0; unsigned count = 0; // Since it's unlikely (but not impossible) to have zero generic parameters // at a depth, encode indexes starting from 1, and use a special mangling // for zero. auto mangleGenericParamCount = [&](unsigned depth, unsigned count) { if (depth < initialParamDepth) return; if (count == 0) OpBuffer << 'z'; else OpBuffer << Index(count - 1); }; // As a special case, mangle nothing if there's a single generic parameter // at the initial depth. for (auto param : params) { if (param->getDepth() != depth) { assert(param->getDepth() > depth && "generic params not ordered"); while (depth < param->getDepth()) { mangleGenericParamCount(depth, count); ++depth; count = 0; } } assert(param->getIndex() == count && "generic params not ordered"); ++count; } mangleGenericParamCount(depth, count); OpBuffer << 'l'; appendOperator("r", StringRef(OpStorage.data(), OpStorage.size())); } void ASTMangler::appendAssociatedTypeName(DependentMemberType *dmt) { auto assocTy = dmt->getAssocType(); // If the base type is known to have a single protocol conformance // in the current generic context, then we don't need to disambiguate the // associated type name by protocol. // This can result in getting the same mangled string for different // DependentMemberTypes. This is not a problem but re-mangling might do more // aggressive substitutions, which means that the re-mangled name may differ // from the original mangled name. // FIXME: We ought to be able to get to the generic signature from a // dependent type, but can't yet. Shouldn't need this side channel. appendIdentifier(assocTy->getName().str()); if (!OptimizeProtocolNames || !CurGenericSignature || !Mod || CurGenericSignature->getConformsTo(dmt->getBase(), *Mod).size() > 1) { appendAnyGenericType(assocTy->getProtocol()); } } void ASTMangler::appendClosureEntity( const SerializedAbstractClosureExpr *closure) { appendClosureComponents(closure->getType(), closure->getDiscriminator(), closure->isImplicit(), closure->getParent(), closure->getLocalContext()); } void ASTMangler::appendClosureEntity(const AbstractClosureExpr *closure) { appendClosureComponents(closure->getType(), closure->getDiscriminator(), isa(closure), closure->getParent(), closure->getLocalContext()); } void ASTMangler::appendClosureComponents(Type Ty, unsigned discriminator, bool isImplicit, const DeclContext *parentContext, const DeclContext *localContext) { if (!DeclCtx) DeclCtx = localContext; assert(discriminator != AbstractClosureExpr::InvalidDiscriminator && "closure must be marked correctly with discriminator"); appendContext(parentContext); if (!Ty) Ty = ErrorType::get(localContext->getASTContext()); Ty = parentContext->mapTypeOutOfContext(Ty); appendType(Ty->getCanonicalType()); appendOperator(isImplicit ? "fu" : "fU", Index(discriminator)); } void ASTMangler::appendDefaultArgumentEntity(const DeclContext *func, unsigned index) { appendContext(func); appendOperator("fA", Index(index)); } void ASTMangler::appendInitializerEntity(const VarDecl *var) { appendEntity(var, "v", var->isStatic()); appendOperator("fi"); } /// Is this declaration a method for mangling purposes? If so, we'll leave the /// Self type out of its mangling. static bool isMethodDecl(const Decl *decl) { return isa(decl) && decl->getDeclContext()->isTypeContext(); } static bool genericParamIsBelowDepth(Type type, unsigned methodDepth) { if (!type->hasTypeParameter()) return true; return !type.findIf([methodDepth](Type t) -> bool { if (auto *gp = t->getAs()) return gp->getDepth() >= methodDepth; return false; }); } CanType ASTMangler::getDeclTypeForMangling( const ValueDecl *decl, ArrayRef &genericParams, unsigned &initialParamDepth, ArrayRef &requirements, SmallVectorImpl &requirementsBuf) { auto &C = decl->getASTContext(); if (!decl->hasInterfaceType() || decl->getInterfaceType()->is()) { if (isa(decl)) return CanFunctionType::get(C.TheErrorType, C.TheErrorType); return C.TheErrorType; } auto type = decl->getInterfaceType()->getCanonicalType(); initialParamDepth = 0; CanGenericSignature sig; if (auto gft = dyn_cast(type)) { sig = gft.getGenericSignature(); CurGenericSignature = sig; genericParams = sig->getGenericParams(); requirements = sig->getRequirements(); type = CanFunctionType::get(gft.getInput(), gft.getResult(), gft->getExtInfo()); } else { genericParams = {}; requirements = {}; } if (!type->hasError()) { // Shed the 'self' type and generic requirements from method manglings. if (isMethodDecl(decl)) { // Drop the Self argument clause from the type. type = cast(type).getResult(); } if (isMethodDecl(decl) || isa(decl)) { // Drop generic parameters and requirements from the method's context. auto parentGenericSig = decl->getDeclContext()->getGenericSignatureOfContext(); if (parentGenericSig && sig) { // The method's depth starts above the depth of the context. if (!parentGenericSig->getGenericParams().empty()) initialParamDepth = parentGenericSig->getGenericParams().back()->getDepth() + 1; while (!genericParams.empty()) { if (genericParams.front()->getDepth() >= initialParamDepth) break; genericParams = genericParams.slice(1); } requirementsBuf.clear(); for (auto &reqt : sig->getRequirements()) { switch (reqt.getKind()) { case RequirementKind::Conformance: case RequirementKind::Layout: case RequirementKind::Superclass: // We don't need the requirement if the constrained type is below the // method depth. if (genericParamIsBelowDepth(reqt.getFirstType(), initialParamDepth)) continue; break; case RequirementKind::SameType: // We don't need the requirement if both types are below the method // depth, or non-dependent. if (genericParamIsBelowDepth(reqt.getFirstType(), initialParamDepth) && genericParamIsBelowDepth(reqt.getSecondType(), initialParamDepth)) continue; break; } // If we fell through the switch, mangle the requirement. requirementsBuf.push_back(reqt); } requirements = requirementsBuf; } } } return type->getCanonicalType(); } void ASTMangler::appendDeclType(const ValueDecl *decl, bool isFunctionMangling) { ArrayRef genericParams; unsigned initialParamDepth; ArrayRef requirements; SmallVector requirementsBuf; Mod = decl->getModuleContext(); auto type = getDeclTypeForMangling(decl, genericParams, initialParamDepth, requirements, requirementsBuf); if (AnyFunctionType *FuncTy = type->getAs()) { bool forceSingleParam = false; if (const auto *FDecl = dyn_cast(decl)) { unsigned PListIdx = isMethodDecl(decl) ? 1 : 0; if (PListIdx < FDecl->getNumParameterLists()) { const ParameterList *Params = FDecl->getParameterList(PListIdx); forceSingleParam = (Params->size() == 1); } } if (isFunctionMangling) { appendFunctionSignature(FuncTy, forceSingleParam); } else { appendFunctionType(FuncTy, forceSingleParam); } } else { appendType(type); } // Mangle the generic signature, if any. if (!genericParams.empty() || !requirements.empty()) { appendGenericSignatureParts(genericParams, initialParamDepth, requirements); // The 'F' function mangling doesn't need a 'u' for its generic signature. if (!isFunctionMangling) appendOperator("u"); } } bool ASTMangler::tryAppendStandardSubstitution(const GenericTypeDecl *decl) { // Bail out if our parent isn't the swift standard library. if (!isStdlibType(decl)) return false; if (char Subst = getStandardTypeSubst(decl->getName().str())) { if (!SubstMerging.tryMergeSubst(*this, Subst, /*isStandardSubst*/ true)) { appendOperator("S", StringRef(&Subst, 1)); } return true; } return false; } void ASTMangler::appendConstructorEntity(const ConstructorDecl *ctor, bool isAllocating) { appendContextOf(ctor); appendDeclType(ctor); appendOperator(isAllocating ? "fC" : "fc"); } void ASTMangler::appendDestructorEntity(const DestructorDecl *dtor, bool isDeallocating) { appendContextOf(dtor); appendOperator(isDeallocating ? "fD" : "fd"); } static StringRef getCodeForAccessorKind(AccessorKind kind, AddressorKind addressorKind) { switch (kind) { case AccessorKind::NotAccessor: llvm_unreachable("bad accessor kind!"); case AccessorKind::IsGetter: return "g"; case AccessorKind::IsSetter: return "s"; case AccessorKind::IsWillSet: return "w"; case AccessorKind::IsDidSet: return "W"; case AccessorKind::IsAddressor: // 'l' is for location. 'A' was taken. switch (addressorKind) { case AddressorKind::NotAddressor: llvm_unreachable("bad combo"); case AddressorKind::Unsafe: return "lu"; case AddressorKind::Owning: return "lO"; case AddressorKind::NativeOwning: return "lo"; case AddressorKind::NativePinning: return "lp"; } llvm_unreachable("bad addressor kind"); case AccessorKind::IsMutableAddressor: switch (addressorKind) { case AddressorKind::NotAddressor: llvm_unreachable("bad combo"); case AddressorKind::Unsafe: return "au"; case AddressorKind::Owning: return "aO"; case AddressorKind::NativeOwning: return "ao"; case AddressorKind::NativePinning: return "aP"; } llvm_unreachable("bad addressor kind"); case AccessorKind::IsMaterializeForSet: return "m"; } llvm_unreachable("bad accessor kind"); } void ASTMangler::appendAccessorEntity(AccessorKind kind, AddressorKind addressorKind, const ValueDecl *decl, bool isStatic) { assert(kind != AccessorKind::NotAccessor); appendContextOf(decl); bindGenericParameters(decl->getDeclContext()); appendDeclName(decl); appendDeclType(decl); appendOperator("f", getCodeForAccessorKind(kind, addressorKind)); if (isStatic) appendOperator("Z"); } void ASTMangler::appendEntity(const ValueDecl *decl, StringRef EntityOp, bool isStatic) { if (!DeclCtx) DeclCtx = decl->getInnermostDeclContext(); appendContextOf(decl); appendDeclName(decl); appendDeclType(decl); appendOperator(EntityOp); if (isStatic) appendOperator("Z"); } void ASTMangler::appendEntity(const ValueDecl *decl) { if (!DeclCtx) DeclCtx = decl->getInnermostDeclContext(); assert(!isa(decl)); assert(!isa(decl)); // Handle accessors specially, they are mangled as modifiers on the accessed // declaration. if (auto func = dyn_cast(decl)) { auto accessorKind = func->getAccessorKind(); if (accessorKind != AccessorKind::NotAccessor) return appendAccessorEntity(accessorKind, func->getAddressorKind(), func->getAccessorStorageDecl(), decl->isStatic()); } if (isa(decl)) return appendEntity(decl, "v", decl->isStatic()); if (isa(decl)) return appendEntity(decl, "i", decl->isStatic()); if (isa(decl)) return appendEntity(decl, "fp", decl->isStatic()); assert(isa(decl) || isa(decl)); appendContextOf(decl); appendDeclName(decl); appendDeclType(decl, /*isFunctionMangling*/ true); appendOperator("F"); if (decl->isStatic()) appendOperator("Z"); } void ASTMangler::appendProtocolConformance(const ProtocolConformance *conformance){ Mod = conformance->getDeclContext()->getParentModule(); if (auto behaviorStorage = conformance->getBehaviorDecl()) { auto topLevelContext = conformance->getDeclContext()->getModuleScopeContext(); appendContextOf(behaviorStorage); FileUnit *fileUnit = cast(topLevelContext); appendIdentifier( fileUnit->getDiscriminatorForPrivateValue(behaviorStorage).str()); appendProtocolName(conformance->getProtocol()); appendIdentifier(behaviorStorage->getName().str()); } else { auto conformanceDC = conformance->getDeclContext(); auto conformingType = conformanceDC->mapTypeOutOfContext(conformance->getType()); appendType(conformingType->getCanonicalType()); appendProtocolName(conformance->getProtocol()); appendModule(conformance->getDeclContext()->getParentModule()); } if (GenericSignature *Sig = conformance->getGenericSignature()) { appendGenericSignature(Sig); } } void ASTMangler::appendOpParamForLayoutConstraint(LayoutConstraint layout) { assert(layout); switch (layout->getKind()) { case LayoutConstraintKind::UnknownLayout: appendOperatorParam("U"); break; case LayoutConstraintKind::RefCountedObject: appendOperatorParam("R"); break; case LayoutConstraintKind::NativeRefCountedObject: appendOperatorParam("N"); break; case LayoutConstraintKind::Class: appendOperatorParam("C"); break; case LayoutConstraintKind::NativeClass: appendOperatorParam("D"); break; case LayoutConstraintKind::Trivial: appendOperatorParam("T"); break; case LayoutConstraintKind::TrivialOfExactSize: if (!layout->getAlignment()) appendOperatorParam("e", Index(layout->getTrivialSizeInBits())); else appendOperatorParam("E", Index(layout->getTrivialSizeInBits()), Index(layout->getAlignment())); break; case LayoutConstraintKind::TrivialOfAtMostSize: if (!layout->getAlignment()) appendOperatorParam("m", Index(layout->getTrivialSizeInBits())); else appendOperatorParam("M", Index(layout->getTrivialSizeInBits()), Index(layout->getAlignment())); break; } }