Beispiel #1
0
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);
            });
          }
        });
  }
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
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);
        }
      }
    });
  }
}