| //===--- Mangle.cpp - Swift Name Mangling ---------------------------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See http://swift.org/LICENSE.txt for license information |
| // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements declaration name mangling in Swift. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "swift/AST/Mangle.h" |
| #include "swift/AST/ASTContext.h" |
| #include "swift/AST/ASTVisitor.h" |
| #include "swift/AST/Initializer.h" |
| #include "swift/AST/Module.h" |
| #include "swift/AST/ProtocolConformance.h" |
| #include "swift/Basic/Demangle.h" |
| #include "swift/Basic/Punycode.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" |
| |
| using namespace swift; |
| using namespace Mangle; |
| |
| static bool isNonAscii(StringRef str) { |
| for (unsigned char c : str) { |
| if (c >= 0x80) |
| return true; |
| } |
| return false; |
| } |
| |
| namespace { |
| /// A helpful little wrapper for a value that should be mangled |
| /// in a particular, compressed value. |
| class Index { |
| unsigned N; |
| public: |
| explicit Index(unsigned n) : N(n) {} |
| friend raw_ostream &operator<<(raw_ostream &out, Index n) { |
| if (n.N != 0) out << (n.N - 1); |
| return (out << '_'); |
| } |
| }; |
| } |
| |
| // Translates operator fixity to demangler operators. |
| static Demangle::OperatorKind TranslateOperator(OperatorFixity fixity) { |
| switch (fixity) { |
| case OperatorFixity::NotOperator:return Demangle::OperatorKind::NotOperator; |
| case OperatorFixity::Prefix: return Demangle::OperatorKind::Prefix; |
| case OperatorFixity::Postfix: return Demangle::OperatorKind::Postfix; |
| case OperatorFixity::Infix: return Demangle::OperatorKind::Infix; |
| } |
| llvm_unreachable("invalid operator fixity"); |
| } |
| |
| /// Finish the mangling of the symbol and return the mangled name. |
| std::string Mangler::finalize() { |
| assert(Storage.size() && "Mangling an empty name"); |
| std::string result = std::string(Storage.data(), Storage.size()); |
| Storage.clear(); |
| return result; |
| } |
| |
| /// Finish the mangling of the symbol and write the mangled name into |
| /// \p stream. |
| void Mangler::finalize(llvm::raw_ostream &stream) { |
| std::string result = finalize(); |
| stream.write(result.data(), result.size()); |
| } |
| |
| /// Mangle a StringRef as an identifier into a buffer. |
| void Mangler::mangleIdentifier(StringRef str, OperatorFixity fixity, |
| bool isOperator) { |
| auto operatorKind = isOperator ? TranslateOperator(fixity) : |
| Demangle::OperatorKind::NotOperator; |
| |
| std::string buf; |
| Demangle::mangleIdentifier(str.data(), str.size(), operatorKind, buf, |
| UsePunycode); |
| Buffer << buf; |
| } |
| |
| /// Mangle an identifier into the buffer. |
| void Mangler::mangleIdentifier(Identifier ident, OperatorFixity fixity) { |
| StringRef str = ident.str(); |
| assert(!str.empty() && "mangling an empty identifier!"); |
| return mangleIdentifier(str, fixity, ident.isOperator()); |
| } |
| |
| bool Mangler::tryMangleSubstitution(const void *ptr) { |
| auto ir = Substitutions.find(ptr); |
| if (ir == Substitutions.end()) return false; |
| |
| // substitution ::= 'S' integer? '_' |
| |
| unsigned index = ir->second; |
| Buffer << 'S'; |
| if (index) Buffer << (index - 1); |
| Buffer << '_'; |
| return true; |
| } |
| |
| void Mangler::addSubstitution(const void *ptr) { |
| Substitutions.insert(std::make_pair(ptr, Substitutions.size())); |
| } |
| |
| /// Mangle the context of the given declaration as a <context. |
| /// This is the top-level entrypoint for mangling <context>. |
| void Mangler::mangleContextOf(const ValueDecl *decl) { |
| auto clangDecl = decl->getClangDecl(); |
| |
| // Classes and protocols implemented in Objective-C have a special context |
| // mangling. |
| // known-context ::= 'So' |
| if (isa<ClassDecl>(decl) && clangDecl) { |
| assert(isa<clang::ObjCInterfaceDecl>(clangDecl) || |
| isa<clang::TypedefDecl>(clangDecl)); |
| Buffer << "So"; |
| return; |
| } |
| |
| if (isa<ProtocolDecl>(decl) && clangDecl) { |
| assert(isa<clang::ObjCProtocolDecl>(clangDecl)); |
| Buffer << "So"; |
| return; |
| } |
| |
| // Declarations provided by a C module have a special context mangling. |
| // known-context ::= 'SC' |
| // Do a dance to avoid a layering dependency. |
| if (auto file = dyn_cast<FileUnit>(decl->getDeclContext())) { |
| if (file->getKind() == FileUnitKind::ClangModule) { |
| Buffer << "SC"; |
| return; |
| } |
| } |
| |
| // Just mangle the decl's DC. |
| mangleContext(decl->getDeclContext()); |
| } |
| |
| namespace { |
| class FindFirstVariable : |
| public PatternVisitor<FindFirstVariable, VarDecl *> { |
| 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" |
| }; |
| } |
| |
| /// 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 VarDecl *findFirstVariable(PatternBindingDecl *binding) { |
| for (auto entry : binding->getPatternList()) { |
| auto var = FindFirstVariable().visit(entry.getPattern()); |
| if (var) return var; |
| } |
| llvm_unreachable("pattern-binding bound no variables?"); |
| } |
| |
| void Mangler::mangleContext(const DeclContext *ctx) { |
| switch (ctx->getContextKind()) { |
| case DeclContextKind::Module: |
| return mangleModule(cast<Module>(ctx)); |
| |
| case DeclContextKind::FileUnit: |
| assert(!isa<BuiltinUnit>(ctx) && "mangling member of builtin module!"); |
| mangleContext(ctx->getParent()); |
| return; |
| |
| case DeclContextKind::SerializedLocal: { |
| auto local = cast<SerializedLocalDeclContext>(ctx); |
| switch (local->getLocalDeclContextKind()) { |
| case LocalDeclContextKind::AbstractClosure: |
| mangleClosureEntity(cast<SerializedAbstractClosureExpr>(local), |
| /*uncurry*/ 0); |
| return; |
| case LocalDeclContextKind::DefaultArgumentInitializer: { |
| auto argInit = cast<SerializedDefaultArgumentInitializer>(local); |
| mangleDefaultArgumentEntity(ctx->getParent(), argInit->getIndex()); |
| return; |
| } |
| case LocalDeclContextKind::PatternBindingInitializer: { |
| auto patternInit = cast<SerializedPatternBindingInitializer>(local); |
| auto var = findFirstVariable(patternInit->getBinding()); |
| mangleInitializerEntity(var); |
| return; |
| } |
| case LocalDeclContextKind::TopLevelCodeDecl: |
| return mangleContext(local->getParent()); |
| } |
| } |
| |
| case DeclContextKind::GenericTypeDecl: |
| if (auto nomctx = dyn_cast<NominalTypeDecl>(ctx)) |
| mangleNominalType(nomctx); |
| else |
| mangleContext(ctx->getParent()); |
| return; |
| |
| case DeclContextKind::ExtensionDecl: { |
| auto ExtD = cast<ExtensionDecl>(ctx); |
| auto ExtTy = ExtD->getExtendedType(); |
| // Recover from erroneous extension. |
| if (ExtTy.isNull() || ExtTy->is<ErrorType>()) |
| return mangleContext(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. |
| bool mangleSignature = sig && ExtD->isConstrainedExtension(); |
| Buffer << (mangleSignature ? 'e' : 'E'); |
| mangleModule(ExtD->getParentModule()); |
| if (mangleSignature) { |
| Mod = ExtD->getModuleContext(); |
| mangleGenericSignature(sig); |
| } |
| } |
| mangleNominalType(decl); |
| return; |
| } |
| |
| case DeclContextKind::AbstractClosureExpr: |
| return mangleClosureEntity(cast<AbstractClosureExpr>(ctx), |
| /*uncurry*/ 0); |
| |
| case DeclContextKind::AbstractFunctionDecl: { |
| auto fn = cast<AbstractFunctionDecl>(ctx); |
| |
| // Constructors and destructors as contexts are always mangled |
| // using the non-(de)allocating variants. |
| if (auto ctor = dyn_cast<ConstructorDecl>(fn)) { |
| return mangleConstructorEntity(ctor, /*allocating*/ false, |
| /*uncurry*/ 0); |
| } |
| |
| if (auto dtor = dyn_cast<DestructorDecl>(fn)) |
| return mangleDestructorEntity(dtor, /*deallocating*/ false); |
| |
| return mangleEntity(fn, /*uncurry*/ 0); |
| } |
| |
| case DeclContextKind::SubscriptDecl: |
| // FIXME: We may need to do something here if subscripts contain any symbols |
| // exposed with linkage names. |
| return mangleContext(ctx->getParent()); |
| |
| case DeclContextKind::Initializer: |
| switch (cast<Initializer>(ctx)->getInitializerKind()) { |
| case InitializerKind::DefaultArgument: { |
| auto argInit = cast<DefaultArgumentInitializer>(ctx); |
| mangleDefaultArgumentEntity(ctx->getParent(), |
| argInit->getIndex()); |
| return; |
| } |
| |
| case InitializerKind::PatternBinding: { |
| auto patternInit = cast<PatternBindingInitializer>(ctx); |
| auto var = findFirstVariable(patternInit->getBinding()); |
| mangleInitializerEntity(var); |
| return; |
| } |
| } |
| llvm_unreachable("bad initializer kind"); |
| |
| case DeclContextKind::TopLevelCodeDecl: |
| // Mangle the containing module context. |
| return mangleContext(ctx->getParent()); |
| } |
| |
| llvm_unreachable("bad decl context"); |
| } |
| |
| void Mangler::mangleModule(const Module *module) { |
| assert(!module->getParent() && "cannot mangle nested modules!"); |
| |
| // Try the special 'swift' substitution. |
| // context ::= known-module |
| // known-module ::= 's' |
| if (module->isStdlibModule()) { |
| Buffer << "s"; |
| return; |
| } |
| |
| // context ::= substitution |
| if (tryMangleSubstitution(module)) return; |
| |
| // context ::= identifier |
| mangleIdentifier(module->getName()); |
| |
| addSubstitution(module); |
| } |
| |
| /// Bind the generic parameters from the given signature. |
| void Mangler::bindGenericParameters(CanGenericSignature sig) { |
| if (sig) |
| CurGenericSignature = sig; |
| } |
| |
| /// Bind the generic parameters from the given context and its parents. |
| void Mangler::bindGenericParameters(const DeclContext *DC) { |
| if (auto sig = DC->getGenericSignatureOfContext()) { |
| Mod = DC->getParentModule(); |
| bindGenericParameters(sig->getCanonicalManglingSignature(*Mod)); |
| } |
| } |
| |
| static OperatorFixity getDeclFixity(const ValueDecl *decl) { |
| if (!decl->getName().isOperator()) |
| return OperatorFixity::NotOperator; |
| |
| switch (decl->getAttrs().getUnaryOperatorKind()) { |
| case UnaryOperatorKind::Prefix: return OperatorFixity::Prefix; |
| case UnaryOperatorKind::Postfix: return OperatorFixity::Postfix; |
| case UnaryOperatorKind::None: return OperatorFixity::Infix; |
| } |
| llvm_unreachable("bad UnaryOperatorKind"); |
| } |
| |
| /// 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->is<ErrorType>()) |
| return false; |
| |
| auto *nominal = declaredType->getAnyNominal(); |
| if (nominal->getFormalAccess() <= Accessibility::FilePrivate) |
| return true; |
| return isInPrivateOrLocalContext(nominal); |
| } |
| |
| void Mangler::mangleDeclName(const ValueDecl *decl) { |
| if (decl->getDeclContext()->isLocalContext()) { |
| // Mangle local declarations with a numeric discriminator. |
| // decl-name ::= 'L' index identifier |
| Buffer << 'L' << Index(decl->getLocalDiscriminator()); |
| // Fall through to mangle the <identifier>. |
| |
| } else if (decl->hasAccessibility() && |
| decl->getFormalAccess() <= Accessibility::FilePrivate && |
| !isInPrivateOrLocalContext(decl)) { |
| // Mangle non-local private declarations with a textual discriminator |
| // based on their enclosing file. |
| // decl-name ::= 'P' identifier identifier |
| |
| // The first <identifier> is a discriminator string unique to the decl's |
| // original source file. |
| auto topLevelContext = decl->getDeclContext()->getModuleScopeContext(); |
| auto fileUnit = cast<FileUnit>(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"); |
| |
| Buffer << 'P'; |
| mangleIdentifier(discriminator); |
| // Fall through to mangle the name. |
| } |
| |
| // decl-name ::= identifier |
| mangleIdentifier(decl->getName(), getDeclFixity(decl)); |
| } |
| |
| void Mangler::mangleTypeForDebugger(Type Ty, const DeclContext *DC) { |
| assert(DWARFMangling && "DWARFMangling expected when mangling for debugger"); |
| |
| Buffer << "_Tt"; |
| |
| if (DC) |
| bindGenericParameters(DC); |
| DeclCtx = DC; |
| |
| mangleType(Ty, /*uncurry*/ 0); |
| } |
| |
| void Mangler::mangleDeclTypeForDebugger(const ValueDecl *decl) { |
| assert(DWARFMangling && "DWARFMangling expected"); |
| Buffer << "_Tt"; |
| |
| if (isa<TypeDecl>(decl)) return; |
| |
| DeclCtx = decl->getInnermostDeclContext(); |
| |
| // Bind the generic parameters from that. |
| bindGenericParameters(DeclCtx); |
| |
| mangleDeclType(decl, /*uncurry*/ 0); |
| } |
| |
| /// 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<AbstractFunctionDecl>(decl) |
| && (isa<NominalTypeDecl>(decl->getDeclContext()) |
| || isa<ExtensionDecl>(decl->getDeclContext())); |
| } |
| |
| static bool genericParamIsBelowDepth(Type type, unsigned methodDepth) { |
| if (auto gp = type->getAs<GenericTypeParamType>()) { |
| return gp->getDepth() >= methodDepth; |
| } |
| if (auto dm = type->getAs<DependentMemberType>()) { |
| return genericParamIsBelowDepth(dm->getBase(), methodDepth); |
| } |
| // Non-dependent types in a same-type requirement don't affect whether we |
| // mangle the requirement. |
| return false; |
| } |
| |
| Type Mangler::getDeclTypeForMangling(const ValueDecl *decl, |
| ArrayRef<GenericTypeParamType *> &genericParams, |
| unsigned &initialParamDepth, |
| ArrayRef<Requirement> &requirements, |
| SmallVectorImpl<Requirement> &requirementsBuf) { |
| auto &C = decl->getASTContext(); |
| if (!decl->hasType()) |
| return ErrorType::get(C); |
| |
| Type type = decl->getInterfaceType(); |
| |
| initialParamDepth = 0; |
| CanGenericSignature sig; |
| if (auto gft = type->getAs<GenericFunctionType>()) { |
| assert(Mod); |
| sig = gft->getGenericSignature()->getCanonicalManglingSignature(*Mod); |
| CurGenericSignature = sig; |
| genericParams = sig->getGenericParams(); |
| requirements = sig->getRequirements(); |
| |
| type = FunctionType::get(gft->getInput(), gft->getResult(), |
| gft->getExtInfo()); |
| } else { |
| genericParams = {}; |
| requirements = {}; |
| } |
| |
| // Shed the 'self' type and generic requirements from method manglings. |
| if (isMethodDecl(decl) && type && !type->is<ErrorType>()) { |
| // Drop the Self argument clause from the type. |
| type = type->castTo<AnyFunctionType>()->getResult(); |
| |
| // Drop generic parameters and requirements from the method's context. |
| if (auto parentGenericSig = |
| decl->getDeclContext()->getGenericSignatureOfContext()) { |
| // The method's depth starts below 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::WitnessMarker: |
| // Not needed for mangling. |
| continue; |
| |
| case RequirementKind::Conformance: |
| case RequirementKind::Superclass: |
| // We don't need the requirement if the constrained type is above the |
| // method depth. |
| if (!genericParamIsBelowDepth(reqt.getFirstType(), initialParamDepth)) |
| continue; |
| break; |
| case RequirementKind::SameType: |
| // We don't need the requirement if both types are above 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; |
| } |
| |
| void Mangler::mangleDeclType(const ValueDecl *decl, |
| unsigned uncurryLevel) { |
| ArrayRef<GenericTypeParamType *> genericParams; |
| unsigned initialParamDepth; |
| ArrayRef<Requirement> requirements; |
| SmallVector<Requirement, 4> requirementsBuf; |
| Mod = decl->getModuleContext(); |
| Type type = getDeclTypeForMangling(decl, |
| genericParams, initialParamDepth, |
| requirements, requirementsBuf); |
| |
| // Mangle the generic signature, if any. |
| if (!genericParams.empty() || !requirements.empty()) { |
| Buffer << 'u'; |
| mangleGenericSignatureParts(genericParams, initialParamDepth, |
| requirements); |
| } |
| |
| mangleType(type->getCanonicalType(), uncurryLevel); |
| } |
| |
| void Mangler::mangleConstrainedType(CanType type) { |
| // The type constrained by a generic requirement should always be a |
| // generic parameter or associated type thereof. Assuming this lets us save |
| // an introducer character in the common case when a generic parameter is |
| // constrained. |
| assert(isa<DependentMemberType>(type) || isa<GenericTypeParamType>(type)); |
| |
| if (auto gp = dyn_cast<GenericTypeParamType>(type)) { |
| mangleGenericParamIndex(gp); |
| return; |
| } |
| mangleType(type, 0); |
| } |
| |
| void Mangler::mangleGenericSignatureParts( |
| ArrayRef<GenericTypeParamType*> params, |
| unsigned initialParamDepth, |
| ArrayRef<Requirement> requirements) { |
| // 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) |
| Buffer << 'z'; |
| else |
| Buffer << Index(count - 1); |
| }; |
| |
| // As a special case, mangle nothing if there's a single generic parameter |
| // at the initial depth. |
| if (params.size() == 1 && params[0]->getDepth() == initialParamDepth) |
| goto mangle_requirements; |
| |
| 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); |
| |
| mangle_requirements: |
| bool didMangleRequirement = false; |
| // Mangle the requirements. |
| for (auto &reqt : requirements) { |
| switch (reqt.getKind()) { |
| case RequirementKind::WitnessMarker: |
| break; |
| |
| case RequirementKind::Conformance: |
| if (!didMangleRequirement) { |
| Buffer << 'R'; |
| didMangleRequirement = true; |
| } |
| // Protocol constraints are the common case, so mangle them more |
| // efficiently. |
| // TODO: We could golf this a little more by assuming the first type |
| // is a dependent type. |
| mangleConstrainedType(reqt.getFirstType()->getCanonicalType()); |
| mangleProtocolName( |
| reqt.getSecondType()->castTo<ProtocolType>()->getDecl()); |
| break; |
| |
| case RequirementKind::Superclass: |
| if (!didMangleRequirement) { |
| Buffer << 'R'; |
| didMangleRequirement = true; |
| } |
| mangleConstrainedType(reqt.getFirstType()->getCanonicalType()); |
| mangleType(reqt.getSecondType()->getCanonicalType(), 0); |
| break; |
| |
| case RequirementKind::SameType: |
| if (!didMangleRequirement) { |
| Buffer << 'R'; |
| didMangleRequirement = true; |
| } |
| mangleConstrainedType(reqt.getFirstType()->getCanonicalType()); |
| Buffer << 'z'; |
| mangleType(reqt.getSecondType()->getCanonicalType(), 0); |
| break; |
| } |
| } |
| // Mark end of requirements. |
| Buffer << 'r'; |
| } |
| |
| void Mangler::mangleGenericSignature(const GenericSignature *sig) { |
| assert(Mod); |
| auto canSig = sig->getCanonicalManglingSignature(*Mod); |
| CurGenericSignature = canSig; |
| mangleGenericSignatureParts(canSig->getGenericParams(), 0, |
| canSig->getRequirements()); |
| } |
| |
| static void mangleMetatypeRepresentation(raw_ostream &Buffer, |
| MetatypeRepresentation Rep) { |
| switch (Rep) { |
| case MetatypeRepresentation::Thin: |
| Buffer << 't'; |
| break; |
| case MetatypeRepresentation::Thick: |
| Buffer << 'T'; |
| break; |
| case MetatypeRepresentation::ObjC: |
| Buffer << 'o'; |
| } |
| } |
| |
| void Mangler::mangleGenericParamIndex(GenericTypeParamType *paramTy) { |
| if (paramTy->getDepth() > 0) { |
| Buffer << 'd'; |
| Buffer << Index(paramTy->getDepth() - 1); |
| Buffer << Index(paramTy->getIndex()); |
| return; |
| } |
| if (paramTy->getIndex() == 0) { |
| Buffer << 'x'; |
| return; |
| } |
| Buffer << Index(paramTy->getIndex() - 1); |
| } |
| |
| void Mangler::mangleAssociatedTypeName(DependentMemberType *dmt, |
| bool canAbbreviate) { |
| auto assocTy = dmt->getAssocType(); |
| |
| if (tryMangleSubstitution(assocTy)) |
| return; |
| |
| // 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. |
| // 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. |
| if (!canAbbreviate || !CurGenericSignature || !Mod |
| || CurGenericSignature->getConformsTo(dmt->getBase(), *Mod).size() > 1) { |
| Buffer << 'P'; |
| mangleProtocolName(assocTy->getProtocol()); |
| } |
| mangleIdentifier(assocTy->getName()); |
| |
| addSubstitution(assocTy); |
| } |
| |
| /// Mangle a type into the buffer. |
| /// |
| /// Type manglings should never start with [0-9dz_] or end with [0-9]. |
| /// |
| /// <type> ::= A <natural> <type> # fixed-sized arrays |
| /// <type> ::= Bb # Builtin.UnsafeValueBuffer |
| /// <type> ::= Bf <natural> _ # Builtin.Float |
| /// <type> ::= Bi <natural> _ # Builtin.Integer |
| /// <type> ::= BO # Builtin.UnknownObject |
| /// <type> ::= Bo # Builtin.NativeObject |
| /// <type> ::= Bb # Builtin.BridgeObject |
| /// <type> ::= Bp # Builtin.RawPointer |
| /// <type> ::= Bv <natural> <type> # Builtin.Vector |
| /// <type> ::= C <decl> # class (substitutable) |
| /// <type> ::= D <type> # dynamic Self return |
| /// <type> ::= ERR # Error type |
| /// <type> ::= 'a' <context> <identifier> # Type alias (DWARF only) |
| /// <type> ::= F <type> <type> # function type |
| /// <type> ::= f <type> <type> # uncurried function type |
| /// <type> ::= G <type> <type>+ _ # bound generic type |
| /// <type> ::= O <decl> # enum (substitutable) |
| /// <type> ::= M <type> # metatype |
| /// <type> ::= P <protocol-list> _ # protocol composition |
| /// <type> ::= PM <type> # existential metatype |
| /// <type> ::= Q <index> # archetype with depth=0, index=N |
| /// <type> ::= Qd <index> <index> # archetype with depth=M+1, index=N |
| /// <type> ::= 'Qq' index context # archetype+context (DWARF only) |
| /// |
| /// <type> ::= R <type> # inout |
| /// <type> ::= T <tuple-element>* _ # tuple |
| /// <type> ::= U <generic-parameter>+ _ <type> |
| /// <type> ::= V <decl> # struct (substitutable) |
| /// <type> ::= Xo <type> # unowned reference type |
| /// <type> ::= Xw <type> # weak reference type |
| /// <type> ::= XF <impl-function-type> # SIL function type |
| /// <type> ::= Xb <type> # SIL @box type |
| /// |
| /// <index> ::= _ # 0 |
| /// <index> ::= <natural> _ # N+1 |
| /// |
| /// <tuple-element> ::= <identifier>? <type> |
| void Mangler::mangleType(Type type, unsigned uncurryLevel) { |
| 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: |
| Buffer << "ERR"; |
| 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<BuiltinFloatType>(tybase)->getFPKind()) { |
| case BuiltinFloatType::IEEE16: Buffer << "Bf16_"; return; |
| case BuiltinFloatType::IEEE32: Buffer << "Bf32_"; return; |
| case BuiltinFloatType::IEEE64: Buffer << "Bf64_"; return; |
| case BuiltinFloatType::IEEE80: Buffer << "Bf80_"; return; |
| case BuiltinFloatType::IEEE128: Buffer << "Bf128_"; return; |
| case BuiltinFloatType::PPC128: llvm_unreachable("ppc128 not supported"); |
| } |
| llvm_unreachable("bad floating-point kind"); |
| case TypeKind::BuiltinInteger: { |
| auto width = cast<BuiltinIntegerType>(tybase)->getWidth(); |
| if (width.isFixedWidth()) |
| Buffer << "Bi" << width.getFixedWidth() << '_'; |
| else if (width.isPointerWidth()) |
| Buffer << "Bw"; |
| else |
| llvm_unreachable("impossible width value"); |
| return; |
| } |
| case TypeKind::BuiltinRawPointer: |
| Buffer << "Bp"; |
| return; |
| case TypeKind::BuiltinNativeObject: |
| Buffer << "Bo"; |
| return; |
| case TypeKind::BuiltinBridgeObject: |
| Buffer << "Bb"; |
| return; |
| case TypeKind::BuiltinUnknownObject: |
| Buffer << "BO"; |
| return; |
| case TypeKind::BuiltinUnsafeValueBuffer: |
| Buffer << "BB"; |
| return; |
| case TypeKind::BuiltinVector: |
| Buffer << "Bv" << cast<BuiltinVectorType>(tybase)->getNumElements(); |
| mangleType(cast<BuiltinVectorType>(tybase)->getElementType(), uncurryLevel); |
| return; |
| |
| case TypeKind::NameAlias: { |
| assert(DWARFMangling && "sugared types are only legal for the debugger"); |
| auto NameAliasTy = cast<NameAliasType>(tybase); |
| TypeAliasDecl *decl = NameAliasTy->getDecl(); |
| if (decl->getModuleContext() == decl->getASTContext().TheBuiltinModule) { |
| // It's not possible to mangle the context of the builtin module. |
| return mangleType(decl->getUnderlyingType(), uncurryLevel); |
| } |
| |
| Buffer << "a"; |
| // For the DWARF output we want to mangle the type alias + context, |
| // unless the type alias references a builtin type. |
| mangleContextOf(decl); |
| mangleDeclName(decl); |
| return; |
| } |
| |
| case TypeKind::Paren: |
| return mangleSugaredType<ParenType>(type); |
| case TypeKind::AssociatedType: |
| return mangleSugaredType<AssociatedTypeType>(type); |
| case TypeKind::Substituted: |
| return mangleSugaredType<SubstitutedType>(type); |
| case TypeKind::ArraySlice: /* fallthrough */ |
| case TypeKind::Optional: |
| return mangleSugaredType<SyntaxSugarType>(type); |
| case TypeKind::Dictionary: |
| return mangleSugaredType<DictionaryType>(type); |
| |
| case TypeKind::ImplicitlyUnwrappedOptional: { |
| assert(DWARFMangling && "sugared types are only legal for the debugger"); |
| auto *IUO = cast<ImplicitlyUnwrappedOptionalType>(tybase); |
| auto implDecl = tybase->getASTContext().getImplicitlyUnwrappedOptionalDecl(); |
| auto GenTy = BoundGenericType::get(implDecl, Type(), IUO->getBaseType()); |
| return mangleType(GenTy, 0); |
| } |
| |
| case TypeKind::ExistentialMetatype: { |
| ExistentialMetatypeType *EMT = cast<ExistentialMetatypeType>(tybase); |
| if (EMT->hasRepresentation()) { |
| Buffer << 'X' << 'P' << 'M'; |
| mangleMetatypeRepresentation(Buffer, EMT->getRepresentation()); |
| } else { |
| Buffer << 'P' << 'M'; |
| } |
| return mangleType(EMT->getInstanceType(), 0); |
| } |
| case TypeKind::Metatype: { |
| MetatypeType *MT = cast<MetatypeType>(tybase); |
| if (MT->hasRepresentation()) { |
| Buffer << 'X' << 'M'; |
| mangleMetatypeRepresentation(Buffer, MT->getRepresentation()); |
| } else { |
| Buffer << 'M'; |
| } |
| return mangleType(MT->getInstanceType(), 0); |
| } |
| case TypeKind::LValue: |
| llvm_unreachable("@lvalue types should not occur in function interfaces"); |
| case TypeKind::InOut: |
| Buffer << 'R'; |
| return mangleType(cast<InOutType>(tybase)->getObjectType(), 0); |
| |
| case TypeKind::UnmanagedStorage: |
| Buffer << "Xu"; |
| return mangleType(cast<UnmanagedStorageType>(tybase)->getReferentType(), 0); |
| |
| case TypeKind::UnownedStorage: |
| Buffer << "Xo"; |
| return mangleType(cast<UnownedStorageType>(tybase)->getReferentType(), 0); |
| |
| case TypeKind::WeakStorage: |
| Buffer << "Xw"; |
| return mangleType(cast<WeakStorageType>(tybase)->getReferentType(), 0); |
| |
| case TypeKind::Tuple: { |
| auto tuple = cast<TupleType>(tybase); |
| // type ::= 'T' tuple-field+ '_' // tuple |
| // type ::= 't' tuple-field+ '_' // variadic tuple |
| // tuple-field ::= identifier? type |
| if (tuple->getNumElements() > 0 |
| && tuple->getElements().back().isVararg()) |
| Buffer << 't'; |
| else |
| Buffer << 'T'; |
| for (auto &field : tuple->getElements()) { |
| if (field.hasName()) |
| mangleIdentifier(field.getName()); |
| mangleType(field.getType(), 0); |
| } |
| Buffer << '_'; |
| return; |
| } |
| |
| case TypeKind::Protocol: |
| // Protocol type manglings have a variable number of protocol names |
| // follow the 'P' sigil, so a trailing underscore is needed after the |
| // type name, unlike protocols as contexts. |
| Buffer << 'P'; |
| mangleProtocolList(type); |
| Buffer << '_'; |
| return; |
| |
| case TypeKind::UnboundGeneric: |
| case TypeKind::Class: |
| case TypeKind::Enum: |
| case TypeKind::Struct: |
| case TypeKind::BoundGenericClass: |
| case TypeKind::BoundGenericEnum: |
| case TypeKind::BoundGenericStruct: { |
| if (type->isSpecialized()) |
| mangleBoundGenericType(type); |
| else |
| mangleNominalType(tybase->getAnyNominal()); |
| return; |
| } |
| |
| case TypeKind::PolymorphicFunction: |
| llvm_unreachable("should not be mangled"); |
| |
| case TypeKind::SILFunction: { |
| // <type> ::= 'XF' <impl-function-type> |
| // <impl-function-type> ::= <impl-callee-convention> |
| // <impl-function-attribute>* <generics>? '_' |
| // <impl-parameter>* '_' <impl-result>* '_' |
| // <impl-callee-convention> ::= 't' // thin |
| // <impl-callee-convention> ::= <impl-convention> // thick |
| // <impl-convention> ::= 'a' // direct, autoreleased |
| // <impl-convention> ::= 'd' // direct, no ownership transfer |
| // <impl-convention> ::= 'g' // direct, guaranteed |
| // <impl-convention> ::= 'e' // direct, deallocating |
| // <impl-convention> ::= 'i' // indirect, ownership transfer |
| // <impl-convention> ::= 'l' // indirect, inout |
| // <impl-convention> ::= 'L' // indirect, inout, aliasable |
| // <impl-convention> ::= 'g' // direct, guaranteed |
| // <impl-convention> ::= 'G' // indirect, guaranteed |
| // <impl-convention> ::= 'z' <impl-convention> // error result |
| // <impl-function-attribute> ::= 'Cb' // block invocation function |
| // <impl-function-attribute> ::= 'Cc' // C global function |
| // <impl-function-attribute> ::= 'Cm' // Swift method |
| // <impl-function-attribute> ::= 'CO' // ObjC method |
| // <impl-function-attribute> ::= 'g' // pseudogeneric |
| // <impl-function-attribute> ::= 'G' // generic |
| // <impl-parameter> ::= <impl-convention> <type> |
| // <impl-result> ::= <impl-convention> <type> |
| auto fn = cast<SILFunctionType>(tybase); |
| Buffer << "XF"; |
| |
| auto mangleParameterConvention = [](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 'L'; |
| case ParameterConvention::Indirect_In_Guaranteed: return 'G'; |
| case ParameterConvention::Direct_Owned: return 'o'; |
| case ParameterConvention::Direct_Unowned: return 'd'; |
| case ParameterConvention::Direct_Guaranteed: return 'g'; |
| case ParameterConvention::Direct_Deallocating: return 'e'; |
| } |
| llvm_unreachable("bad parameter convention"); |
| }; |
| auto mangleResultConvention = [](ResultConvention conv) { |
| switch (conv) { |
| case ResultConvention::Indirect: return 'i'; |
| case ResultConvention::Owned: return 'o'; |
| case ResultConvention::Unowned: return 'd'; |
| case ResultConvention::UnownedInnerPointer: return 'D'; |
| case ResultConvention::Autoreleased: return 'a'; |
| } |
| llvm_unreachable("bad result convention"); |
| }; |
| |
| // <impl-callee-convention> |
| if (!fn->getExtInfo().hasContext()) { |
| Buffer << 't'; |
| } else { |
| Buffer << mangleParameterConvention(fn->getCalleeConvention()); |
| } |
| |
| // <impl-function-attribute>* |
| switch (fn->getRepresentation()) { |
| case SILFunctionTypeRepresentation::Block: |
| Buffer << "Cb"; |
| break; |
| case SILFunctionTypeRepresentation::Thick: |
| case SILFunctionTypeRepresentation::Thin: |
| break; |
| case SILFunctionTypeRepresentation::CFunctionPointer: |
| Buffer << "Cc"; |
| break; |
| case SILFunctionTypeRepresentation::ObjCMethod: |
| Buffer << "CO"; |
| break; |
| case SILFunctionTypeRepresentation::Method: |
| Buffer << "Cm"; |
| break; |
| case SILFunctionTypeRepresentation::WitnessMethod: |
| Buffer << "Cw"; |
| break; |
| } |
| |
| if (fn->isPolymorphic()) { |
| Buffer << (fn->isPseudogeneric() ? 'g' : 'G'); |
| mangleGenericSignature(fn->getGenericSignature()); |
| } |
| Buffer << '_'; |
| |
| // Mangle the parameters. |
| for (auto param : fn->getParameters()) { |
| Buffer << mangleParameterConvention(param.getConvention()); |
| mangleType(param.getType(), 0); |
| } |
| Buffer << '_'; |
| |
| // Mangle the results. |
| for (auto result : fn->getAllResults()) { |
| Buffer << mangleResultConvention(result.getConvention()); |
| mangleType(result.getType(), 0); |
| } |
| |
| // Mangle the error result if present. |
| if (fn->hasErrorResult()) { |
| auto error = fn->getErrorResult(); |
| Buffer << 'z' << mangleResultConvention(error.getConvention()); |
| mangleType(error.getType(), 0); |
| } |
| |
| Buffer << '_'; |
| return; |
| } |
| |
| // type ::= archetype |
| case TypeKind::Archetype: { |
| auto *archetype = cast<ArchetypeType>(tybase); |
| |
| // archetype ::= associated-type |
| |
| // associated-type ::= substitution |
| if (tryMangleSubstitution(archetype)) |
| return; |
| |
| Buffer << 'Q'; |
| |
| // associated-type ::= 'Q' archetype identifier |
| // Mangle the associated type of a parent archetype. |
| if (auto parent = archetype->getParent()) { |
| assert(archetype->getAssocType() |
| && "child archetype has no associated type?!"); |
| |
| mangleType(parent, 0); |
| mangleIdentifier(archetype->getName()); |
| addSubstitution(archetype); |
| return; |
| } |
| |
| // associated-type ::= 'Q' protocol-context |
| // Mangle the Self archetype of a protocol. |
| if (auto proto = archetype->getSelfProtocol()) { |
| Buffer << 'P'; |
| mangleProtocolName(proto); |
| addSubstitution(archetype); |
| return; |
| } |
| |
| // archetype ::= 'Q' <index> # archetype with depth=0, index=N |
| // archetype ::= 'Qd' <index> <index> # archetype with depth=M+1, index=N |
| // Mangle generic parameter archetypes. |
| |
| // Find the archetype information. |
| const DeclContext *DC = DeclCtx; |
| auto GTPT = ArchetypeBuilder::mapTypeOutOfContext(DC, archetype) |
| ->castTo<GenericTypeParamType>(); |
| |
| if (DWARFMangling) { |
| Buffer << 'q' << Index(GTPT->getIndex()); |
| |
| { |
| // 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 (_Tt). |
| // Clone a new, non-DWARF Mangler for the DeclContext. |
| Mangler ContextMangler(/*DWARFMangling=*/false); |
| SmallVector<const void *, 4> SortedSubsts(Substitutions.size()); |
| for (auto S : Substitutions) SortedSubsts[S.second] = S.first; |
| for (auto S : SortedSubsts) ContextMangler.addSubstitution(S); |
| while (DC && DC->getGenericParamsOfContext()) { |
| if (DC->isInnermostContextGeneric() && |
| DC->getGenericParamsOfContext()->getDepth() == GTPT->getDepth()) |
| break; |
| DC = DC->getParent(); |
| } |
| assert(DC && "no decl context for archetype found"); |
| if (!DC) return; |
| ContextMangler.mangleContext(DC); |
| ContextMangler.finalize(Buffer); |
| } |
| |
| } else { |
| if (GTPT->getDepth() != 0) { |
| Buffer << 'd' << Index(GTPT->getDepth() - 1); |
| } |
| Buffer << Index(GTPT->getIndex()); |
| } |
| return; |
| } |
| |
| case TypeKind::DynamicSelf: { |
| auto dynamicSelf = cast<DynamicSelfType>(tybase); |
| if (dynamicSelf->getSelfType()->getAnyNominal()) { |
| Buffer << 'D'; |
| mangleType(dynamicSelf->getSelfType(), uncurryLevel); |
| } else { |
| // Mangle DynamicSelf as Self within a protocol. |
| mangleType(dynamicSelf->getSelfType(), uncurryLevel); |
| } |
| return; |
| } |
| |
| case TypeKind::GenericFunction: { |
| auto genFunc = cast<GenericFunctionType>(tybase); |
| Buffer << 'u'; |
| mangleGenericSignature(genFunc->getGenericSignature()); |
| mangleFunctionType(genFunc, uncurryLevel); |
| return; |
| } |
| |
| case TypeKind::GenericTypeParam: { |
| auto paramTy = cast<GenericTypeParamType>(tybase); |
| // FIXME: Notion of depth is reversed from that for archetypes. |
| |
| // 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) { |
| Buffer << 'x'; |
| return; |
| } |
| |
| Buffer << 'q'; |
| mangleGenericParamIndex(paramTy); |
| return; |
| } |
| |
| case TypeKind::DependentMember: { |
| auto memTy = cast<DependentMemberType>(tybase); |
| auto base = memTy->getBase()->getCanonicalType(); |
| |
| // type ::= 'w' generic-param-index associated-type-name |
| // 't_0_0.Member' |
| if (auto gpBase = dyn_cast<GenericTypeParamType>(base)) { |
| Buffer << 'w'; |
| mangleGenericParamIndex(gpBase); |
| mangleAssociatedTypeName(memTy, OptimizeProtocolNames); |
| return; |
| } |
| |
| // type ::= 'W' generic-param-index associated-type-name+ '_' |
| // 't_0_0.Member.Member...' |
| SmallVector<DependentMemberType*, 2> path; |
| path.push_back(memTy); |
| while (auto dmBase = dyn_cast<DependentMemberType>(base)) { |
| path.push_back(dmBase); |
| base = dmBase.getBase(); |
| } |
| if (auto gpRoot = dyn_cast<GenericTypeParamType>(base)) { |
| Buffer << 'W'; |
| mangleGenericParamIndex(gpRoot); |
| for (auto *member : reversed(path)) { |
| mangleAssociatedTypeName(member, OptimizeProtocolNames); |
| } |
| Buffer << '_'; |
| return; |
| } |
| |
| // type ::= 'q' type associated-type-name |
| // Dependent members of non-generic-param types are not canonical, but |
| // we may still want to mangle them for debugging or indexing purposes. |
| Buffer << 'q'; |
| mangleType(memTy->getBase(), 0); |
| mangleAssociatedTypeName(memTy, OptimizeProtocolNames); |
| return; |
| } |
| |
| case TypeKind::Function: |
| mangleFunctionType(cast<FunctionType>(tybase), uncurryLevel); |
| return; |
| |
| case TypeKind::ProtocolComposition: { |
| // We mangle ProtocolType and ProtocolCompositionType using the |
| // same production: |
| // <type> ::= P <protocol-list> _ |
| |
| auto protocols = cast<ProtocolCompositionType>(tybase)->getProtocols(); |
| Buffer << 'P'; |
| mangleProtocolList(protocols); |
| Buffer << '_'; |
| return; |
| } |
| |
| case TypeKind::SILBox: |
| Buffer << 'X' << 'b'; |
| mangleType(cast<SILBoxType>(tybase)->getBoxedType(), |
| uncurryLevel); |
| return; |
| |
| case TypeKind::SILBlockStorage: |
| llvm_unreachable("should never be mangled"); |
| } |
| llvm_unreachable("bad type kind"); |
| } |
| |
| /// Mangle a list of protocols. Each protocol is a substitution |
| /// candidate. |
| /// <protocol-list> ::= <protocol-name>+ |
| void Mangler::mangleProtocolList(ArrayRef<Type> protocols) { |
| for (auto protoTy : protocols) |
| if (auto composition = protoTy->getAs<ProtocolCompositionType>()) |
| mangleProtocolList(composition->getProtocols()); |
| else |
| mangleProtocolName(protoTy->castTo<ProtocolType>()->getDecl()); |
| } |
| void Mangler::mangleProtocolList(ArrayRef<ProtocolDecl*> protocols) { |
| for (auto protocol : protocols) |
| mangleProtocolName(protocol); |
| } |
| |
| /// Mangle the name of a protocol as a substitution candidate. |
| void Mangler::mangleProtocolName(const ProtocolDecl *protocol) { |
| // <protocol-name> ::= <decl> # substitutable |
| // The <decl> in a protocol-name is the same substitution |
| // candidate as a protocol <type>, but it is mangled without |
| // the surrounding 'P'...'_'. |
| ProtocolType *type = cast<ProtocolType>(protocol->getDeclaredType()); |
| if (tryMangleSubstitution(type)) |
| return; |
| mangleContextOf(protocol); |
| mangleDeclName(protocol); |
| addSubstitution(type); |
| } |
| |
| static char getSpecifierForNominalType(const NominalTypeDecl *decl) { |
| switch (decl->getKind()) { |
| #define NOMINAL_TYPE_DECL(id, parent) |
| #define DECL(id, parent) \ |
| case DeclKind::id: |
| #include "swift/AST/DeclNodes.def" |
| llvm_unreachable("not a nominal type"); |
| |
| case DeclKind::Protocol: return 'P'; |
| case DeclKind::Class: return 'C'; |
| case DeclKind::Enum: return 'O'; |
| case DeclKind::Struct: return 'V'; |
| } |
| llvm_unreachable("bad decl kind"); |
| } |
| |
| void Mangler::mangleNominalType(const NominalTypeDecl *decl) { |
| // Check for certain standard types. |
| if (tryMangleStandardSubstitution(decl)) |
| return; |
| |
| // For generic types, this uses the unbound type. |
| TypeBase *key = decl->getDeclaredType().getPointer(); |
| |
| // Try to mangle the entire name as a substitution. |
| // type ::= substitution |
| if (tryMangleSubstitution(key)) |
| return; |
| |
| Buffer << getSpecifierForNominalType(decl); |
| mangleContextOf(decl); |
| mangleDeclName(decl); |
| |
| addSubstitution(key); |
| } |
| |
| static void |
| collectBoundGenericArgs(Type type, |
| SmallVectorImpl<SmallVector<Type, 2>> &genericArgs) { |
| if (auto *unboundType = type->getAs<UnboundGenericType>()) { |
| if (auto parent = unboundType->getParent()) |
| collectBoundGenericArgs(parent, genericArgs); |
| genericArgs.push_back({}); |
| } else if (auto *nominalType = type->getAs<NominalType>()) { |
| if (auto parent = nominalType->getParent()) |
| collectBoundGenericArgs(parent, genericArgs); |
| genericArgs.push_back({}); |
| } else { |
| auto *boundType = type->castTo<BoundGenericType>(); |
| if (auto parent = boundType->getParent()) |
| collectBoundGenericArgs(parent, genericArgs); |
| |
| SmallVector<Type, 2> args; |
| for (auto arg : boundType->getGenericArgs()) |
| args.push_back(arg); |
| genericArgs.push_back(args); |
| } |
| } |
| |
| void Mangler::mangleBoundGenericType(Type type) { |
| // type ::= 'G' <type> (<type>+ '_')+ |
| Buffer << 'G'; |
| auto *nominal = type->getAnyNominal(); |
| mangleNominalType(nominal); |
| |
| SmallVector<SmallVector<Type, 2>, 2> genericArgs; |
| collectBoundGenericArgs(type, genericArgs); |
| assert(!genericArgs.empty()); |
| |
| for (auto args : genericArgs) { |
| for (auto arg : args) |
| mangleType(arg, /*uncurry*/ 0); |
| Buffer << '_'; |
| } |
| } |
| |
| void Mangler::mangleProtocolDecl(const ProtocolDecl *protocol) { |
| Buffer << 'P'; |
| mangleContextOf(protocol); |
| mangleDeclName(protocol); |
| Buffer << '_'; |
| } |
| |
| bool Mangler::tryMangleStandardSubstitution(const NominalTypeDecl *decl) { |
| // Bail out if our parent isn't the swift standard library. |
| DeclContext *dc = decl->getDeclContext(); |
| if (!dc->isModuleScopeContext() || !dc->getParentModule()->isStdlibModule()) |
| return false; |
| |
| // Standard substitutions shouldn't start with 's' (because that's |
| // reserved for the swift module itself) or a digit or '_'. |
| |
| StringRef name = decl->getName().str(); |
| if (name == "Int") { |
| Buffer << "Si"; |
| return true; |
| } else if (name == "UInt") { |
| Buffer << "Su"; |
| return true; |
| } else if (name == "Bool") { |
| Buffer << "Sb"; |
| return true; |
| } else if (name == "UnicodeScalar") { |
| Buffer << "Sc"; |
| return true; |
| } else if (name == "Double") { |
| Buffer << "Sd"; |
| return true; |
| } else if (name == "Float") { |
| Buffer << "Sf"; |
| return true; |
| } else if (name == "UnsafeRawPointer") { |
| Buffer << "SV"; |
| return true; |
| } else if (name == "UnsafeMutableRawPointer") { |
| Buffer << "Sv"; |
| return true; |
| } else if (name == "UnsafePointer") { |
| Buffer << "SP"; |
| return true; |
| } else if (name == "UnsafeMutablePointer") { |
| Buffer << "Sp"; |
| return true; |
| } else if (name == "Optional") { |
| Buffer << "Sq"; |
| return true; |
| } else if (name == "ImplicitlyUnwrappedOptional") { |
| Buffer << "SQ"; |
| return true; |
| } else if (name == "UnsafeBufferPointer") { |
| Buffer << "SR"; |
| return true; |
| } else if (name == "UnsafeMutableBufferPointer") { |
| Buffer << "Sr"; |
| return true; |
| } else if (name == "Array") { |
| Buffer << "Sa"; |
| return true; |
| } else if (name == "String") { |
| Buffer << "SS"; |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| void Mangler::mangleFunctionType(AnyFunctionType *fn, |
| unsigned uncurryLevel) { |
| assert((DWARFMangling || fn->isCanonical()) && |
| "expecting canonical types when not mangling for the debugger"); |
| |
| // type ::= 'F' type type (curried) |
| // type ::= 'f' type type (uncurried) |
| // type ::= 'b' type type (objc block) |
| // type ::= 'c' type type (c function pointer) |
| // type ::= 'Xf' type type (thin) |
| // type ::= 'K' type type (auto closure) |
| // |
| // 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: |
| Buffer << 'b'; |
| break; |
| case AnyFunctionType::Representation::Thin: |
| Buffer << "Xf"; |
| break; |
| case AnyFunctionType::Representation::Swift: |
| if (fn->isAutoClosure()) |
| Buffer << 'K'; |
| else |
| Buffer << (uncurryLevel > 0 ? 'f' : 'F'); |
| break; |
| case AnyFunctionType::Representation::CFunctionPointer: |
| Buffer << 'c'; |
| break; |
| } |
| |
| if (fn->throws()) |
| Buffer << 'z'; |
| |
| mangleType(fn->getInput(), 0); |
| mangleType(fn->getResult(), (uncurryLevel > 0 ? uncurryLevel - 1 : 0)); |
| } |
| |
| void Mangler::mangleClosureComponents(Type Ty, unsigned discriminator, |
| bool isImplicit, |
| const DeclContext *parentContext, |
| const DeclContext *localContext) { |
| // entity-name ::= 'U' index type // explicit anonymous closure |
| // entity-name ::= 'u' index type // implicit anonymous closure |
| |
| if (!DeclCtx) DeclCtx = localContext; |
| |
| assert(discriminator != AbstractClosureExpr::InvalidDiscriminator |
| && "closure must be marked correctly with discriminator"); |
| |
| Buffer << 'F'; |
| mangleContext(parentContext); |
| Buffer << (isImplicit ? 'u' : 'U') << Index(discriminator); |
| |
| if (!Ty) |
| Ty = ErrorType::get(localContext->getASTContext()); |
| |
| mangleType(Ty->getCanonicalType(), /*uncurry*/ 0); |
| } |
| |
| void Mangler::mangleClosureEntity(const SerializedAbstractClosureExpr *closure, |
| unsigned uncurryingLevel) { |
| mangleClosureComponents(closure->getType(), closure->getDiscriminator(), |
| closure->isImplicit(), closure->getParent(), |
| closure->getLocalContext()); |
| } |
| |
| void Mangler::mangleClosureEntity(const AbstractClosureExpr *closure, |
| unsigned uncurryLevel) { |
| mangleClosureComponents(closure->getType(), closure->getDiscriminator(), |
| isa<AutoClosureExpr>(closure), closure->getParent(), |
| closure->getLocalContext()); |
| } |
| |
| void Mangler::mangleConstructorEntity(const ConstructorDecl *ctor, |
| bool isAllocating, |
| unsigned uncurryLevel) { |
| Buffer << 'F'; |
| mangleContextOf(ctor); |
| Buffer << (isAllocating ? 'C' : 'c'); |
| mangleDeclType(ctor, uncurryLevel); |
| } |
| |
| void Mangler::mangleDestructorEntity(const DestructorDecl *dtor, |
| bool isDeallocating) { |
| Buffer << 'F'; |
| mangleContextOf(dtor); |
| Buffer << (isDeallocating ? 'D' : 'd'); |
| } |
| |
| void Mangler::mangleIVarInitDestroyEntity(const ClassDecl *decl, |
| bool isDestroyer) { |
| Buffer << 'F'; |
| mangleContext(decl); |
| Buffer << (isDestroyer ? 'E' : 'e'); |
| } |
| |
| 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 Mangler::mangleAccessorEntity(AccessorKind kind, |
| AddressorKind addressorKind, |
| const AbstractStorageDecl *decl) { |
| assert(kind != AccessorKind::NotAccessor); |
| Buffer << 'F'; |
| mangleContextOf(decl); |
| Buffer << getCodeForAccessorKind(kind, addressorKind); |
| |
| bindGenericParameters(decl->getDeclContext()); |
| mangleDeclName(decl); |
| mangleDeclType(decl, 0); |
| } |
| |
| void Mangler::mangleAddressorEntity(const ValueDecl *decl) { |
| Buffer << 'F'; |
| mangleContextOf(decl); |
| Buffer << "au"; |
| mangleDeclName(decl); |
| mangleDeclType(decl, 0); |
| } |
| |
| void Mangler::mangleGlobalGetterEntity(ValueDecl *decl) { |
| Buffer << 'F'; |
| mangleContextOf(decl); |
| Buffer << 'G'; |
| mangleDeclName(decl); |
| mangleDeclType(decl, 0); |
| } |
| |
| void Mangler::mangleDefaultArgumentEntity(const DeclContext *func, |
| unsigned index) { |
| Buffer << 'I'; |
| mangleContext(func); |
| Buffer << 'A' << Index(index); |
| } |
| |
| void Mangler::mangleInitializerEntity(const VarDecl *var) { |
| // The initializer is its own entity whose context is the variable. |
| Buffer << 'I'; |
| mangleEntity(var, /*uncurry*/ 0); |
| Buffer << 'i'; |
| } |
| |
| void Mangler::mangleEntity(const ValueDecl *decl, |
| unsigned uncurryLevel) { |
| assert(!isa<ConstructorDecl>(decl)); |
| assert(!isa<DestructorDecl>(decl)); |
| |
| // entity ::= static? entity-kind context entity-name |
| if (decl->isStatic()) |
| Buffer << 'Z'; |
| |
| // Handle accessors specially, they are mangled as modifiers on the accessed |
| // declaration. |
| if (auto func = dyn_cast<FuncDecl>(decl)) { |
| auto accessorKind = func->getAccessorKind(); |
| if (accessorKind != AccessorKind::NotAccessor) |
| return mangleAccessorEntity(accessorKind, func->getAddressorKind(), |
| func->getAccessorStorageDecl()); |
| } |
| |
| if (isa<VarDecl>(decl)) { |
| Buffer << 'v'; |
| } else if (isa<SubscriptDecl>(decl)) { |
| Buffer << 'i'; |
| } else if (isa<GenericTypeParamDecl>(decl)) { |
| Buffer << 't'; |
| } else { |
| assert(isa<AbstractFunctionDecl>(decl) || |
| isa<EnumElementDecl>(decl)); |
| Buffer << 'F'; |
| } |
| |
| if (!DeclCtx) DeclCtx = decl->getInnermostDeclContext(); |
| mangleContextOf(decl); |
| mangleDeclName(decl); |
| mangleDeclType(decl, uncurryLevel); |
| } |
| |
| void Mangler::mangleDirectness(bool isIndirect) { |
| Buffer << (isIndirect ? 'i': 'd'); |
| } |
| |
| void Mangler::mangleProtocolConformance(const ProtocolConformance *conformance){ |
| // protocol-conformance ::= ('u' generic-parameters '_')? |
| // type protocol module |
| // FIXME: explosion level? |
| |
| // If the conformance is generic, mangle its generic parameters. |
| Mod = conformance->getDeclContext()->getParentModule(); |
| if (auto sig = conformance->getGenericSignature()) { |
| Buffer << 'u'; |
| mangleGenericSignature(sig); |
| } |
| |
| if (auto behaviorStorage = conformance->getBehaviorDecl()) { |
| Buffer << 'b'; |
| auto topLevelContext = |
| conformance->getDeclContext()->getModuleScopeContext(); |
| auto fileUnit = cast<FileUnit>(topLevelContext); |
| mangleIdentifier( |
| fileUnit->getDiscriminatorForPrivateValue(behaviorStorage)); |
| mangleContextOf(behaviorStorage); |
| mangleIdentifier(behaviorStorage->getName()); |
| mangleProtocolName(conformance->getProtocol()); |
| return; |
| } |
| |
| mangleType(conformance->getInterfaceType()->getCanonicalType(), 0); |
| mangleProtocolName(conformance->getProtocol()); |
| mangleModule(conformance->getDeclContext()->getParentModule()); |
| } |
| |
| void Mangler::mangleFieldOffsetFull(const ValueDecl *decl, bool isIndirect) { |
| Buffer << "_TWv"; |
| mangleDirectness(isIndirect); |
| mangleEntity(decl, 0); |
| } |
| |
| void Mangler::mangleTypeFullMetadataFull(CanType ty) { |
| Buffer << "_TMf"; |
| mangleType(ty, 0); |
| } |
| |
| void Mangler::mangleTypeMetadataFull(CanType ty, bool isPattern) { |
| Buffer << "_TM"; |
| if (isPattern) |
| Buffer << 'P'; |
| mangleType(ty, 0); |
| } |
| |
| void Mangler::append(StringRef S) { |
| Buffer << S; |
| } |
| |
| void Mangler::append(char C) { |
| Buffer << C; |
| } |
| |
| void Mangler::mangleNatural(const APInt &Nat) { |
| Buffer << Nat; |
| } |
| |
| void Mangler::mangleIdentifierSymbol(StringRef Name) { |
| // Mangle normal identifiers as: |
| // count identifier-char+ |
| // where the count is the number of characters in the identifier, |
| // and where individual identifier characters represent themselves. |
| Buffer << Name.size() << Name; |
| } |
| |
| void Mangler::appendSymbol(StringRef Name) { |
| Buffer << Name; |
| } |
| |
| void Mangler::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<clang::DeclaratorDecl>(decl->getClangDecl())) { |
| if (auto asmLabel = clangDecl->getAttr<clang::AsmLabelAttr>()) { |
| Buffer << '\01' << asmLabel->getLabel(); |
| } else { |
| Buffer << clangDecl->getName(); |
| } |
| return; |
| } |
| |
| Buffer << "_T"; |
| mangleEntity(decl, 0); |
| } |
| |
| void Mangler::mangleGlobalInit(const VarDecl *decl, int counter, |
| bool isInitFunc) { |
| auto topLevelContext = decl->getDeclContext()->getModuleScopeContext(); |
| auto fileUnit = cast<FileUnit>(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_"; |
| mangleIdentifier(discriminator); |
| Buffer << (isInitFunc ? "_func" : "_token"); |
| Buffer << counter; |
| } |
| |
| void Mangler::mangleBehaviorInitThunk(const VarDecl *decl) { |
| auto topLevelContext = decl->getDeclContext()->getModuleScopeContext(); |
| auto fileUnit = cast<FileUnit>(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 << "_TTB"; |
| mangleIdentifier(discriminator); |
| mangleContextOf(decl); |
| mangleIdentifier(decl->getName()); |
| } |