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); }); } }); } }
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; }
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); } } }); } }