bool ide::printAccessorUSR(const AbstractStorageDecl *D, AccessorKind AccKind, llvm::raw_ostream &OS) { // AccKind should always be either IsGetter or IsSetter here, based // on whether a reference is a mutating or non-mutating use. USRs // aren't supposed to reflect implementation differences like stored // vs. addressed vs. observing. // // On the other side, the implementation indexer should be // registering the getter/setter USRs independently of how they're // actually implemented. So a stored variable should still have // getter/setter USRs (pointing to the variable declaration), and an // addressed variable should have its "getter" point at the // addressor. AbstractStorageDecl *SD = const_cast<AbstractStorageDecl*>(D); if (shouldUseObjCUSR(SD)) { return printObjCUSRForAccessor(SD, AccKind, OS); } Mangle::ASTMangler NewMangler; std::string Mangled = NewMangler.mangleAccessorEntityAsUSR(AccKind, AddressorKind::NotAddressor, SD, getUSRSpacePrefix()); OS << Mangled; return false; }
/// Get or create SILGlobalVariable for a given global VarDecl. SILGlobalVariable *SILGenModule::getSILGlobalVariable(VarDecl *gDecl, ForDefinition_t forDef) { // First, get a mangled name for the declaration. std::string mangledName; if (auto SILGenName = gDecl->getAttrs().getAttribute<SILGenNameAttr>()) { mangledName = SILGenName->Name; } else { Mangle::ASTMangler NewMangler; mangledName = NewMangler.mangleGlobalVariableFull(gDecl); } // Check if it is already created, and update linkage if necessary. if (auto gv = M.lookUpGlobalVariable(mangledName)) { // Update the SILLinkage here if this is a definition. if (forDef == ForDefinition) { gv->setLinkage(getSILLinkage(getDeclLinkage(gDecl), ForDefinition)); gv->setDeclaration(false); } return gv; } // Get the linkage for SILGlobalVariable. SILLinkage link = getSILLinkage(getDeclLinkage(gDecl), forDef); SILType silTy = M.Types.getLoweredTypeOfGlobal(gDecl); auto *silGlobal = SILGlobalVariable::create(M, link, IsNotSerialized, mangledName, silTy, None, gDecl); silGlobal->setDeclaration(!forDef); return silGlobal; }
void TBDGenVisitor::visitVarDecl(VarDecl *VD) { // Variables inside non-resilient modules have some additional symbols. if (!VD->isResilient()) { // Non-global variables might have an explicit initializer symbol, in // non-resilient modules. if (VD->getAttrs().hasAttribute<HasInitialValueAttr>() && !isGlobalOrStaticVar(VD)) { auto declRef = SILDeclRef(VD, SILDeclRef::Kind::StoredPropertyInitializer); // Stored property initializers for public properties are currently // public. addSymbol(declRef); } // statically/globally stored variables have some special handling. if (VD->hasStorage() && isGlobalOrStaticVar(VD)) { if (getDeclLinkage(VD) == FormalLinkage::PublicUnique) { // The actual variable has a symbol. Mangle::ASTMangler mangler; addSymbol(mangler.mangleEntity(VD, false)); } if (VD->isLazilyInitializedGlobal()) addSymbol(SILDeclRef(VD, SILDeclRef::Kind::GlobalAccessor)); } } visitAbstractStorageDecl(VD); }
static std::string getMaterializeForSetCallbackName(ProtocolConformance *conformance, FuncDecl *requirement) { DeclContext *dc = requirement; ClosureExpr closure(/*patterns*/ nullptr, /*throws*/ SourceLoc(), /*arrow*/ SourceLoc(), /*in*/ SourceLoc(), /*result*/ TypeLoc(), /*discriminator*/ 0, /*context*/ requirement); closure.setType(TupleType::getEmpty(dc->getASTContext())); closure.getCaptureInfo().setGenericParamCaptures(true); Mangle::ASTMangler Mangler; std::string New; if (conformance) { // Concrete witness thunk for a conformance: // // Mangle this as if it were a conformance thunk for a closure // within the requirement. return Mangler.mangleClosureWitnessThunk(conformance, &closure); } // Default witness thunk or concrete implementation: // // Mangle this as if it were a closure within the requirement. return Mangler.mangleClosureEntity(&closure, Mangle::ASTMangler::SymbolKind::Default); }
SILFunction *SILGenModule:: getOrCreateReabstractionThunk(CanSILFunctionType thunkType, CanSILFunctionType fromType, CanSILFunctionType toType, IsSerialized_t Serialized) { // The reference to the thunk is likely @noescape, but declarations are always // escaping. auto thunkDeclType = thunkType->getWithExtInfo(thunkType->getExtInfo().withNoEscape(false)); // Mangle the reabstraction thunk. // Substitute context parameters out of the "from" and "to" types. auto fromInterfaceType = fromType->mapTypeOutOfContext() ->getCanonicalType(); auto toInterfaceType = toType->mapTypeOutOfContext() ->getCanonicalType(); Mangle::ASTMangler NewMangler; std::string name = NewMangler.mangleReabstractionThunkHelper(thunkType, fromInterfaceType, toInterfaceType, M.getSwiftModule()); auto loc = RegularLocation::getAutoGeneratedLocation(); return M.getOrCreateSharedFunction(loc, name, thunkDeclType, IsBare, IsTransparent, IsSerializable, ProfileCounter(), IsReabstractionThunk); }
/// Emit a global initialization. void SILGenModule::emitGlobalInitialization(PatternBindingDecl *pd, unsigned pbdEntry) { // Generic and dynamic static properties require lazy initialization, which // isn't implemented yet. if (pd->isStatic()) { assert(!pd->getDeclContext()->isGenericContext() || pd->getDeclContext()->getGenericSignatureOfContext() ->areAllParamsConcrete()); } // Emit the lazy initialization token for the initialization expression. auto counter = anonymousSymbolCounter++; // Pick one variable of the pattern. Usually it's only one variable, but it // can also be something like: var (a, b) = ... Pattern *pattern = pd->getPattern(pbdEntry); VarDecl *varDecl = nullptr; pattern->forEachVariable([&](VarDecl *D) { varDecl = D; }); assert(varDecl); Mangle::ASTMangler TokenMangler; std::string onceTokenBuffer = TokenMangler.mangleGlobalInit(varDecl, counter, false); auto onceTy = BuiltinIntegerType::getWordType(M.getASTContext()); auto onceSILTy = SILType::getPrimitiveObjectType(onceTy->getCanonicalType()); // TODO: include the module in the onceToken's name mangling. // Then we can make it fragile. auto onceToken = SILGlobalVariable::create(M, SILLinkage::Private, makeModuleFragile ? IsSerialized : IsNotSerialized, onceTokenBuffer, onceSILTy); onceToken->setDeclaration(false); // Emit the initialization code into a function. Mangle::ASTMangler FuncMangler; std::string onceFuncBuffer = FuncMangler.mangleGlobalInit(varDecl, counter, true); SILFunction *onceFunc = emitLazyGlobalInitializer(onceFuncBuffer, pd, pbdEntry); // Generate accessor functions for all of the declared variables, which // Builtin.once the lazy global initializer we just generated then return // the address of the individual variable. GenGlobalAccessors(*this, onceToken, onceFunc) .visit(pd->getPattern(pbdEntry)); }
static SILValue getBehaviorInitStorageFn(SILGenFunction &SGF, VarDecl *behaviorVar) { Mangle::ASTMangler NewMangler; std::string behaviorInitName = NewMangler.mangleBehaviorInitThunk(behaviorVar); SILFunction *thunkFn; // Skip out early if we already emitted this thunk. if (auto existing = SGF.SGM.M.lookUpFunction(behaviorInitName)) { thunkFn = existing; } else { auto init = behaviorVar->getBehavior()->InitStorageDecl.getDecl(); auto initFn = SGF.SGM.getFunction(SILDeclRef(init), NotForDefinition); // Emit a thunk to inject the `self` metatype and implode tuples. auto storageVar = behaviorVar->getBehavior()->StorageDecl; auto selfTy = behaviorVar->getDeclContext()->getDeclaredInterfaceType(); auto initTy = SGF.getLoweredType(selfTy).getFieldType(behaviorVar, SGF.SGM.M); auto storageTy = SGF.getLoweredType(selfTy).getFieldType(storageVar, SGF.SGM.M); auto initConstantTy = initFn->getLoweredType().castTo<SILFunctionType>(); auto param = SILParameterInfo(initTy.getASTType(), initTy.isAddress() ? ParameterConvention::Indirect_In : ParameterConvention::Direct_Owned); auto result = SILResultInfo(storageTy.getASTType(), storageTy.isAddress() ? ResultConvention::Indirect : ResultConvention::Owned); initConstantTy = SILFunctionType::get(initConstantTy->getGenericSignature(), initConstantTy->getExtInfo(), SILCoroutineKind::None, ParameterConvention::Direct_Unowned, param, /*yields*/ {}, result, // TODO: throwing initializer? None, SGF.getASTContext()); // TODO: Generate the body of the thunk. thunkFn = SGF.SGM.M.getOrCreateFunction(SILLocation(behaviorVar), behaviorInitName, SILLinkage::PrivateExternal, initConstantTy, IsBare, IsTransparent, IsSerialized); } return SGF.B.createFunctionRef(behaviorVar, thunkFn); }
void TBDGenVisitor::addConformances(DeclContext *DC) { for (auto conformance : DC->getLocalConformances()) { auto protocol = conformance->getProtocol(); auto needsWTable = Lowering::TypeConverter::protocolRequiresWitnessTable(protocol); if (!needsWTable) continue; // Only root conformances get symbols; the others get any public symbols // from their parent conformances. auto rootConformance = dyn_cast<RootProtocolConformance>(conformance); if (!rootConformance) { continue; } addSymbol(LinkEntity::forProtocolWitnessTable(rootConformance)); addSymbol(LinkEntity::forProtocolConformanceDescriptor(rootConformance)); // FIXME: the logic around visibility in extensions is confusing, and // sometimes witness thunks need to be manually made public. auto conformanceIsFixed = SILWitnessTable::conformanceIsSerialized( rootConformance); auto addSymbolIfNecessary = [&](ValueDecl *requirementDecl, ValueDecl *witnessDecl) { auto witnessLinkage = SILDeclRef(witnessDecl).getLinkage(ForDefinition); if (conformanceIsFixed && (isa<SelfProtocolConformance>(rootConformance) || fixmeWitnessHasLinkageThatNeedsToBePublic(witnessLinkage))) { Mangle::ASTMangler Mangler; addSymbol( Mangler.mangleWitnessThunk(rootConformance, requirementDecl)); } }; rootConformance->forEachValueWitness( nullptr, [&](ValueDecl *valueReq, Witness witness) { auto witnessDecl = witness.getDecl(); if (isa<AbstractFunctionDecl>(valueReq)) { addSymbolIfNecessary(valueReq, witnessDecl); } else if (auto *storage = dyn_cast<AbstractStorageDecl>(valueReq)) { auto witnessStorage = cast<AbstractStorageDecl>(witnessDecl); storage->visitOpaqueAccessors([&](AccessorDecl *reqtAccessor) { auto witnessAccessor = witnessStorage->getAccessor(reqtAccessor->getAccessorKind()); assert(witnessAccessor && "no corresponding witness accessor?"); addSymbolIfNecessary(reqtAccessor, witnessAccessor); }); } }); } }
void TBDGenVisitor::visitVarDecl(VarDecl *VD) { // statically/globally stored variables have some special handling. if (VD->hasStorage() && isGlobalOrStaticVar(VD)) { // The actual variable has a symbol. Mangle::ASTMangler mangler; addSymbol(mangler.mangleEntity(VD, false)); // Top-level variables (*not* statics) in the main file don't get accessors, // despite otherwise looking like globals. if (!FileHasEntryPoint || VD->isStatic()) addSymbol(SILDeclRef(VD, SILDeclRef::Kind::GlobalAccessor)); } visitAbstractStorageDecl(VD); }
void TBDGenVisitor::visitVarDecl(VarDecl *VD) { if (isPrivateDecl(VD)) return; // statically/globally stored variables have some special handling. if (VD->hasStorage() && isGlobalOrStaticVar(VD)) { // The actual variable has a symbol. Mangle::ASTMangler mangler; addSymbol(mangler.mangleEntity(VD, false)); addSymbol(SILDeclRef(VD, SILDeclRef::Kind::GlobalAccessor)); } visitMembers(VD); }
void TBDGenVisitor::visitVarDecl(VarDecl *VD) { if (isPrivateDecl(VD)) return; // statically/globally stored variables have some special handling. if (VD->hasStorage() && isGlobalOrStaticVar(VD)) { // The actual variable has a symbol. Mangle::ASTMangler mangler; addSymbol(mangler.mangleEntity(VD, false)); // Variables in the main file don't get accessors, despite otherwise looking // like globals. if (!FileHasEntryPoint) addSymbol(SILDeclRef(VD, SILDeclRef::Kind::GlobalAccessor)); } visitMembers(VD); }
SILFunction *SILGenModule::emitProtocolWitness( ProtocolConformanceRef conformance, SILLinkage linkage, IsSerialized_t isSerialized, SILDeclRef requirement, SILDeclRef witnessRef, IsFreeFunctionWitness_t isFree, Witness witness) { auto requirementInfo = Types.getConstantInfo(requirement); // Work out the lowered function type of the SIL witness thunk. auto reqtOrigTy = cast<GenericFunctionType>(requirementInfo.LoweredType); // Mapping from the requirement's generic signature to the witness // thunk's generic signature. auto reqtSubMap = witness.getRequirementToSyntheticSubs(); // The generic environment for the witness thunk. auto *genericEnv = witness.getSyntheticEnvironment(); // The type of the witness thunk. auto input = reqtOrigTy->getInput().subst(reqtSubMap)->getCanonicalType(); auto result = reqtOrigTy->getResult().subst(reqtSubMap)->getCanonicalType(); // If there's something to map to for the witness thunk, the conformance // should be phrased in the same terms. This particularly applies to classes // where a thunk for a method in a conformance like `extension Class: P where // T: Q` will go from its native signature of `<τ_0_0 where τ_0_0: Q>` (with T // canonicalised to τ_0_0), to `<τ_0_0, τ_1_0 where τ_0_0: Class<τ_1_0>, // τ_1_0: Q>` (with T now represented by τ_1_0). Find the right conformance by // looking for the conformance of 'Self'. if (reqtSubMap) { auto requirement = conformance.getRequirement(); auto self = requirement->getProtocolSelfType()->getCanonicalType(); conformance = *reqtSubMap.lookupConformance(self, requirement); } CanAnyFunctionType reqtSubstTy; if (genericEnv) { auto *genericSig = genericEnv->getGenericSignature(); reqtSubstTy = CanGenericFunctionType::get( genericSig->getCanonicalSignature(), input, result, reqtOrigTy->getExtInfo()); } else { reqtSubstTy = CanFunctionType::get( input, result, reqtOrigTy->getExtInfo()); } // FIXME: this needs to pull out the conformances/witness-tables for any // conditional requirements from the witness table and pass them to the // underlying function in the thunk. // Lower the witness thunk type with the requirement's abstraction level. auto witnessSILFnType = getNativeSILFunctionType( M, AbstractionPattern(reqtOrigTy), reqtSubstTy, witnessRef, conformance); // Mangle the name of the witness thunk. Mangle::ASTMangler NewMangler; auto manglingConformance = conformance.isConcrete() ? conformance.getConcrete() : nullptr; std::string nameBuffer = NewMangler.mangleWitnessThunk(manglingConformance, requirement.getDecl()); // If the thunked-to function is set to be always inlined, do the // same with the witness, on the theory that the user wants all // calls removed if possible, e.g. when we're able to devirtualize // the witness method call. Otherwise, use the default inlining // setting on the theory that forcing inlining off should only // effect the user's function, not otherwise invisible thunks. Inline_t InlineStrategy = InlineDefault; if (witnessRef.isAlwaysInline()) InlineStrategy = AlwaysInline; auto *f = M.createFunction( linkage, nameBuffer, witnessSILFnType, genericEnv, SILLocation(witnessRef.getDecl()), IsNotBare, IsTransparent, isSerialized, ProfileCounter(), IsThunk, SubclassScope::NotApplicable, InlineStrategy); f->setDebugScope(new (M) SILDebugScope(RegularLocation(witnessRef.getDecl()), f)); PrettyStackTraceSILFunction trace("generating protocol witness thunk", f); // Create the witness. SILGenFunction SGF(*this, *f); // Substitutions mapping the generic parameters of the witness to // archetypes of the witness thunk generic environment. auto witnessSubs = witness.getSubstitutions(); // Open-code protocol witness thunks for materializeForSet. if (auto witnessFn = dyn_cast<AccessorDecl>(witnessRef.getDecl())) { if (witnessFn->isMaterializeForSet()) { assert(!isFree); auto *proto = cast<ProtocolDecl>(requirement.getDecl()->getDeclContext()); auto selfInterfaceType = proto->getSelfInterfaceType().subst(reqtSubMap); auto selfType = GenericEnvironment::mapTypeIntoContext( genericEnv, selfInterfaceType); auto reqFn = cast<AccessorDecl>(requirement.getDecl()); assert(reqFn->isMaterializeForSet()); if (SGF.maybeEmitMaterializeForSetThunk(conformance, linkage, selfInterfaceType, selfType, genericEnv, reqFn, witnessFn, witnessSubs.toList())) return f; // Proceed down the normal path. } } SGF.emitProtocolWitness(AbstractionPattern(reqtOrigTy), reqtSubstTy, requirement, witnessRef, witnessSubs.toList(), isFree); return f; }
void TBDGenVisitor::addConformances(DeclContext *DC) { for (auto conformance : DC->getLocalConformances()) { auto protocol = conformance->getProtocol(); auto needsWTable = Lowering::TypeConverter::protocolRequiresWitnessTable(protocol); if (!needsWTable) continue; // Only normal conformances get symbols; the others get any public symbols // from their parent normal conformance. auto normalConformance = dyn_cast<NormalProtocolConformance>(conformance); if (!normalConformance) continue; addSymbol(LinkEntity::forDirectProtocolWitnessTable(normalConformance)); addSymbol( LinkEntity::forProtocolWitnessTableAccessFunction(normalConformance)); // FIXME: the logic around visibility in extensions is confusing, and // sometimes witness thunks need to be manually made public. auto conformanceIsFixed = SILWitnessTable::conformanceIsSerialized( normalConformance, SwiftModule->getResilienceStrategy(), SILSerializeWitnessTables); auto addSymbolIfNecessary = [&](ValueDecl *valueReq, SILLinkage witnessLinkage) { if (conformanceIsFixed && fixmeWitnessHasLinkageThatNeedsToBePublic(witnessLinkage)) { Mangle::ASTMangler Mangler; addSymbol(Mangler.mangleWitnessThunk(normalConformance, valueReq)); } }; normalConformance->forEachValueWitness(nullptr, [&](ValueDecl *valueReq, Witness witness) { if (isa<AbstractFunctionDecl>(valueReq)) { auto witnessLinkage = SILDeclRef(witness.getDecl()).getLinkage(ForDefinition); addSymbolIfNecessary(valueReq, witnessLinkage); } else if (auto VD = dyn_cast<AbstractStorageDecl>(valueReq)) { // A var or subscript decl needs extra special handling: the things that // end up in the witness table are the accessors, but the compiler only // talks about the actual storage decl in the conformance, so we have to // manually walk over the members, having pulled out something that will // have the right linkage. auto witnessVD = cast<AbstractStorageDecl>(witness.getDecl()); SmallVector<Decl *, 4> members; VD->getAllAccessorFunctions(members); // Grab one of the accessors, and then use that to pull out which of the // getter or setter will have the appropriate linkage. FuncDecl *witnessWithRelevantLinkage; switch (cast<FuncDecl>(members[0])->getAccessorKind()) { case AccessorKind::NotAccessor: llvm_unreachable("must be an accessor"); case AccessorKind::IsGetter: case AccessorKind::IsAddressor: witnessWithRelevantLinkage = witnessVD->getGetter(); break; case AccessorKind::IsSetter: case AccessorKind::IsWillSet: case AccessorKind::IsDidSet: case AccessorKind::IsMaterializeForSet: case AccessorKind::IsMutableAddressor: witnessWithRelevantLinkage = witnessVD->getSetter(); break; } auto witnessLinkage = SILDeclRef(witnessWithRelevantLinkage).getLinkage(ForDefinition); for (auto member : members) { addSymbolIfNecessary(cast<ValueDecl>(member), witnessLinkage); } } }); } }
bool ide::printDeclTypeUSR(const ValueDecl *D, raw_ostream &OS) { Mangle::ASTMangler Mangler; std::string MangledName = Mangler.mangleDeclType(D); OS << MangledName; return false; }
static std::string mangleTypeAsContext(const NominalTypeDecl *type) { Mangle::ASTMangler Mangler; return Mangler.mangleTypeAsContextUSR(type); }
Optional<SILVTable::Entry> SILGenModule::emitVTableMethod(ClassDecl *theClass, SILDeclRef derived, SILDeclRef base) { assert(base.kind == derived.kind); auto *baseDecl = base.getDecl(); auto *derivedDecl = derived.getDecl(); // Note: We intentionally don't support extension members here. // // Once extensions can override or introduce new vtable entries, this will // all likely change anyway. auto *baseClass = cast<ClassDecl>(baseDecl->getDeclContext()); auto *derivedClass = cast<ClassDecl>(derivedDecl->getDeclContext()); // Figure out if the vtable entry comes from the superclass, in which // case we won't emit it if building a resilient module. SILVTable::Entry::Kind implKind; if (baseClass == theClass) { // This is a vtable entry for a method of the immediate class. implKind = SILVTable::Entry::Kind::Normal; } else if (derivedClass == theClass) { // This is a vtable entry for a method of a base class, but it is being // overridden in the immediate class. implKind = SILVTable::Entry::Kind::Override; } else { // This vtable entry is copied from the superclass. implKind = SILVTable::Entry::Kind::Inherited; // If the override is defined in a class from a different resilience // domain, don't emit the vtable entry. if (derivedClass->isResilient(M.getSwiftModule(), ResilienceExpansion::Maximal)) { return None; } } SILFunction *implFn; SILLinkage implLinkage; // If the member is dynamic, reference its dynamic dispatch thunk so that // it will be redispatched, funneling the method call through the runtime // hook point. if (derivedDecl->isDynamic() && derived.kind != SILDeclRef::Kind::Allocator) { implFn = getDynamicThunk(derived, Types.getConstantInfo(derived).SILFnType); implLinkage = SILLinkage::Public; } else { implFn = getFunction(derived, NotForDefinition); implLinkage = stripExternalFromLinkage(implFn->getLinkage()); } // As a fast path, if there is no override, definitely no thunk is necessary. if (derived == base) return SILVTable::Entry(base, implFn, implKind, implLinkage); // Determine the derived thunk type by lowering the derived type against the // abstraction pattern of the base. auto baseInfo = Types.getConstantInfo(base); auto derivedInfo = Types.getConstantInfo(derived); auto basePattern = AbstractionPattern(baseInfo.LoweredType); auto overrideInfo = M.Types.getConstantOverrideInfo(derived, base); // The override member type is semantically a subtype of the base // member type. If the override is ABI compatible, we do not need // a thunk. if (M.Types.checkFunctionForABIDifferences(derivedInfo.SILFnType, overrideInfo.SILFnType) == TypeConverter::ABIDifference::Trivial) return SILVTable::Entry(base, implFn, implKind, implLinkage); // Generate the thunk name. std::string name; { Mangle::ASTMangler mangler; if (isa<FuncDecl>(baseDecl)) { name = mangler.mangleVTableThunk( cast<FuncDecl>(baseDecl), cast<FuncDecl>(derivedDecl)); } else { name = mangler.mangleConstructorVTableThunk( cast<ConstructorDecl>(baseDecl), cast<ConstructorDecl>(derivedDecl), base.kind == SILDeclRef::Kind::Allocator); } } // If we already emitted this thunk, reuse it. if (auto existingThunk = M.lookUpFunction(name)) return SILVTable::Entry(base, existingThunk, implKind, implLinkage); // Emit the thunk. SILLocation loc(derivedDecl); SILGenFunctionBuilder builder(*this); auto thunk = builder.createFunction( SILLinkage::Private, name, overrideInfo.SILFnType, cast<AbstractFunctionDecl>(derivedDecl)->getGenericEnvironment(), loc, IsBare, IsNotTransparent, IsNotSerialized); thunk->setDebugScope(new (M) SILDebugScope(loc, thunk)); SILGenFunction(*this, *thunk, theClass) .emitVTableThunk(derived, implFn, basePattern, overrideInfo.LoweredType, derivedInfo.LoweredType); return SILVTable::Entry(base, thunk, implKind, implLinkage); }
bool ide::printDeclUSR(const ValueDecl *D, raw_ostream &OS) { if (!D->hasName() && !isa<ParamDecl>(D) && !isa<AccessorDecl>(D)) return true; // Ignore. if (D->getModuleContext()->isBuiltinModule()) return true; // Ignore. if (isa<ModuleDecl>(D)) return true; // Ignore. auto interpretAsClangNode = [](const ValueDecl *D)->ClangNode { ClangNode ClangN = D->getClangNode(); if (auto ClangD = ClangN.getAsDecl()) { // NSErrorDomain causes the clang enum to be imported like this: // // struct MyError { // enum Code : Int32 { // case errFirst // case errSecond // } // static var errFirst: MyError.Code { get } // static var errSecond: MyError.Code { get } // } // // The clang enum constants are associated with both the static vars and // the enum cases. // But we want unique USRs for the above symbols, so use the clang USR // for the enum cases, and the Swift USR for the vars. // if (auto *ClangEnumConst = dyn_cast<clang::EnumConstantDecl>(ClangD)) { if (auto *ClangEnum = dyn_cast<clang::EnumDecl>(ClangEnumConst->getDeclContext())) { if (ClangEnum->hasAttr<clang::NSErrorDomainAttr>() && isa<VarDecl>(D)) return ClangNode(); } } } return ClangN; }; if (ClangNode ClangN = interpretAsClangNode(D)) { llvm::SmallString<128> Buf; if (auto ClangD = ClangN.getAsDecl()) { bool Ignore = clang::index::generateUSRForDecl(ClangD, Buf); if (!Ignore) OS << Buf.str(); return Ignore; } auto &Importer = *D->getASTContext().getClangModuleLoader(); auto ClangMacroInfo = ClangN.getAsMacro(); bool Ignore = clang::index::generateUSRForMacro( D->getBaseName().getIdentifier().str(), ClangMacroInfo->getDefinitionLoc(), Importer.getClangASTContext().getSourceManager(), Buf); if (!Ignore) OS << Buf.str(); return Ignore; } if (shouldUseObjCUSR(D)) { return printObjCUSR(D, OS); } if (!D->hasInterfaceType()) return true; // Invalid code. if (D->getInterfaceType().findIf([](Type t) -> bool { return t->is<ModuleType>(); })) return true; Mangle::ASTMangler NewMangler; std::string Mangled = NewMangler.mangleDeclAsUSR(D, getUSRSpacePrefix()); OS << Mangled; return false; }
static std::string mangleGetter(VarDecl *varDecl) { Mangle::ASTMangler Mangler; return Mangler.mangleGlobalGetterEntity(varDecl); }
std::string SILDefaultWitnessTable::getUniqueName() const { Mangle::ASTMangler Mangler; return Mangler.mangleTypeWithoutPrefix(getProtocol()->getDeclaredType()); }
SILFunction *SILGenModule::emitProtocolWitness( ProtocolConformanceRef conformance, SILLinkage linkage, IsSerialized_t isSerialized, SILDeclRef requirement, SILDeclRef witnessRef, IsFreeFunctionWitness_t isFree, Witness witness) { auto requirementInfo = Types.getConstantInfo(requirement); // Work out the lowered function type of the SIL witness thunk. auto reqtOrigTy = cast<GenericFunctionType>(requirementInfo.LoweredType); // Mapping from the requirement's generic signature to the witness // thunk's generic signature. auto reqtSubMap = witness.getRequirementToSyntheticSubs(); // The generic environment for the witness thunk. auto *genericEnv = witness.getSyntheticEnvironment(); // The type of the witness thunk. auto substReqtTy = cast<AnyFunctionType>(reqtOrigTy.subst(reqtSubMap)->getCanonicalType()); // If there's something to map to for the witness thunk, the conformance // should be phrased in the same terms. This particularly applies to classes // where a thunk for a method in a conformance like `extension Class: P where // T: Q` will go from its native signature of `<τ_0_0 where τ_0_0: Q>` (with T // canonicalised to τ_0_0), to `<τ_0_0, τ_1_0 where τ_0_0: Class<τ_1_0>, // τ_1_0: Q>` (with T now represented by τ_1_0). Find the right conformance by // looking for the conformance of 'Self'. if (reqtSubMap) { auto requirement = conformance.getRequirement(); auto self = requirement->getProtocolSelfType()->getCanonicalType(); conformance = *reqtSubMap.lookupConformance(self, requirement); } CanAnyFunctionType reqtSubstTy; if (genericEnv) { auto *genericSig = genericEnv->getGenericSignature(); reqtSubstTy = CanGenericFunctionType::get( genericSig->getCanonicalSignature(), substReqtTy->getParams(), substReqtTy.getResult(), reqtOrigTy->getExtInfo()); } else { reqtSubstTy = CanFunctionType::get(substReqtTy->getParams(), substReqtTy.getResult(), reqtOrigTy->getExtInfo()); } // Coroutine lowering requires us to provide these substitutions // in order to recreate the appropriate yield types for the accessor // because they aren't reflected in the accessor's AST type. // But this is expensive, so we only do it for coroutine lowering. // When they're part of the AST function type, we can remove this // parameter completely. Optional<SubstitutionMap> witnessSubsForTypeLowering; if (auto accessor = dyn_cast<AccessorDecl>(requirement.getDecl())) { if (accessor->isCoroutine()) { witnessSubsForTypeLowering = witness.getSubstitutions().mapReplacementTypesOutOfContext(); } } // FIXME: this needs to pull out the conformances/witness-tables for any // conditional requirements from the witness table and pass them to the // underlying function in the thunk. // Lower the witness thunk type with the requirement's abstraction level. auto witnessSILFnType = getNativeSILFunctionType( M, AbstractionPattern(reqtOrigTy), reqtSubstTy, requirement, witnessRef, witnessSubsForTypeLowering, conformance); // Mangle the name of the witness thunk. Mangle::ASTMangler NewMangler; auto manglingConformance = conformance.isConcrete() ? conformance.getConcrete() : nullptr; std::string nameBuffer = NewMangler.mangleWitnessThunk(manglingConformance, requirement.getDecl()); // If the thunked-to function is set to be always inlined, do the // same with the witness, on the theory that the user wants all // calls removed if possible, e.g. when we're able to devirtualize // the witness method call. Otherwise, use the default inlining // setting on the theory that forcing inlining off should only // effect the user's function, not otherwise invisible thunks. Inline_t InlineStrategy = InlineDefault; if (witnessRef.isAlwaysInline()) InlineStrategy = AlwaysInline; SILGenFunctionBuilder builder(*this); auto *f = builder.createFunction( linkage, nameBuffer, witnessSILFnType, genericEnv, SILLocation(witnessRef.getDecl()), IsNotBare, IsTransparent, isSerialized, ProfileCounter(), IsThunk, SubclassScope::NotApplicable, InlineStrategy); f->setDebugScope(new (M) SILDebugScope(RegularLocation(witnessRef.getDecl()), f)); PrettyStackTraceSILFunction trace("generating protocol witness thunk", f); // Create the witness. SILGenFunction SGF(*this, *f, SwiftModule); // Substitutions mapping the generic parameters of the witness to // archetypes of the witness thunk generic environment. auto witnessSubs = witness.getSubstitutions(); SGF.emitProtocolWitness(AbstractionPattern(reqtOrigTy), reqtSubstTy, requirement, reqtSubMap, witnessRef, witnessSubs, isFree); return f; }
bool ide::printTypeUSR(Type Ty, raw_ostream &OS) { assert(!Ty->hasArchetype() && "cannot have contextless archetypes mangled."); Mangle::ASTMangler Mangler; OS << Mangler.mangleTypeForDebugger(Ty->getRValueType(), nullptr, nullptr); return false; }