Esempio n. 1
0
bool FulfillmentMap::searchBoundGenericTypeMetadata(ModuleDecl &M,
                                                    CanBoundGenericType type,
                                                    unsigned source,
                                                    MetadataPath &&path,
                                         const InterestingKeysCallback &keys) {
  auto params = type->getDecl()->getGenericParams()->getAllArchetypes();
  auto substitutions = type->getSubstitutions(&M, nullptr);
  assert(params.size() >= substitutions.size() &&
         "generic decl archetypes should parallel generic type subs");

  bool hadFulfillment = false;

  for (unsigned i = 0, e = substitutions.size(); i != e; ++i) {
    auto sub = substitutions[i];
    CanType arg = sub.getReplacement()->getCanonicalType();

    // Skip uninteresting type arguments.
    if (!keys.hasInterestingType(arg))
      continue;

    // If the argument is a type parameter, fulfill conformances for it.
    if (keys.isInterestingType(arg)) {
      hadFulfillment |=
        searchTypeArgConformances(M, arg, params[i], source, path, i, keys);
    }

    // Refine the path.
    MetadataPath argPath = path;
    argPath.addNominalTypeArgumentComponent(i);
    hadFulfillment |=
      searchTypeMetadata(M, arg, IsExact, source, std::move(argPath), keys);
  }

  // Also match against the parent.  The polymorphic type
  // will start with any arguments from the parent.
  hadFulfillment |= searchParentTypeMetadata(M, type.getParent(),
                                             source, std::move(path), keys);
  return hadFulfillment;
}
Esempio n. 2
0
clang::CanQualType
GenClangType::visitBoundGenericType(CanBoundGenericType type) {
    // We only expect *Pointer<T>, ImplicitlyUnwrappedOptional<T>, and Optional<T>.
    // The first two are structs; the last is an enum.
    if (auto underlyingTy =
                SILType::getPrimitiveObjectType(type).getAnyOptionalObjectType()) {
        // The underlying type could be a bridged type, which makes any
        // sort of casual assertion here difficult.
        return Converter.convert(IGM, underlyingTy.getSwiftRValueType());
    }

    auto swiftStructDecl = type->getDecl();

    enum class StructKind {
        Invalid,
        UnsafeMutablePointer,
        UnsafePointer,
        AutoreleasingUnsafeMutablePointer,
        Unmanaged,
        CFunctionPointer,
    } kind = llvm::StringSwitch<StructKind>(swiftStructDecl->getName().str())
    .Case("UnsafeMutablePointer", StructKind::UnsafeMutablePointer)
    .Case("UnsafePointer", StructKind::UnsafePointer)
    .Case(
        "AutoreleasingUnsafeMutablePointer",
        StructKind::AutoreleasingUnsafeMutablePointer)
    .Case("Unmanaged", StructKind::Unmanaged)
    .Case("CFunctionPointer", StructKind::CFunctionPointer)
    .Default(StructKind::Invalid);

    auto args = type.getGenericArgs();

    switch (kind) {
    case StructKind::Invalid:
        llvm_unreachable("Unexpected non-pointer generic struct type in imported"
                         " Clang module!");

    case StructKind::UnsafeMutablePointer:
    case StructKind::Unmanaged:
    case StructKind::AutoreleasingUnsafeMutablePointer: {
        assert(args.size() == 1 &&
               "*Pointer<T> should have a single generic argument!");
        auto clangCanTy = Converter.convert(IGM, args.front());
        if (!clangCanTy) return clang::CanQualType();
        return getClangASTContext().getPointerType(clangCanTy);
    }
    case StructKind::UnsafePointer: {
        assert(args.size() == 1 &&
               "*Pointer<T> should have a single generic argument!");
        clang::QualType clangTy
            = Converter.convert(IGM, args.front()).withConst();
        return getCanonicalType(getClangASTContext().getPointerType(clangTy));
    }

    case StructKind::CFunctionPointer: {
        auto &clangCtx = getClangASTContext();

        assert(args.size() == 1 &&
               "CFunctionPointer should have a single generic argument!");
        clang::QualType functionTy;
        if (auto ft = dyn_cast<FunctionType>(args[0])) {
            functionTy = convertFunctionType(ft);
        } else {
            // Fall back to void().
            functionTy = clangCtx.getFunctionNoProtoType(clangCtx.VoidTy);
        }
        auto fnPtrTy = clangCtx.getPointerType(functionTy);
        return getCanonicalType(fnPtrTy);
    }
    }

    llvm_unreachable("Not a valid StructKind.");
}
Esempio n. 3
0
bool FulfillmentMap::searchBoundGenericTypeMetadata(IRGenModule &IGM,
                                                    CanBoundGenericType type,
                                                    unsigned source,
                                                    MetadataPath &&path,
                                         const InterestingKeysCallback &keys) {
  if (type->getDecl()->hasClangNode())
    return false;

  bool hadFulfillment = false;

  GenericTypeRequirements requirements(IGM, type->getDecl());
  requirements.enumerateFulfillments(IGM,
                  type->getSubstitutions(IGM.getSwiftModule(), nullptr),
                                [&](unsigned reqtIndex, CanType arg,
                                    Optional<ProtocolConformanceRef> conf) {
    // Skip uninteresting type arguments.
    if (!keys.hasInterestingType(arg))
      return;

    // If the fulfilled value is type metadata, refine the path.
    if (!conf) {
      MetadataPath argPath = path;
      argPath.addNominalTypeArgumentComponent(reqtIndex);
      hadFulfillment |=
        searchTypeMetadata(IGM, arg, IsExact, source, std::move(argPath), keys);
      return;
    }

    // Otherwise, it's a conformance.

    // Ignore it unless the type itself is interesting.
    if (!keys.isInterestingType(arg))
      return;

    // Refine the path.
    MetadataPath argPath = path;
    argPath.addNominalTypeArgumentConformanceComponent(reqtIndex);

    llvm::SmallPtrSet<ProtocolDecl*, 4> interestingConformancesBuffer;
    llvm::SmallPtrSetImpl<ProtocolDecl*> *interestingConformances = nullptr;

    // If the interesting-keys set is limiting the set of interesting
    // conformances, collect that filter.
    if (keys.hasLimitedInterestingConformances(arg)) {
      // Bail out immediately if the set is empty.
      auto requiredConformances = keys.getInterestingConformances(arg);
      if (requiredConformances.empty()) return;

      interestingConformancesBuffer.insert(requiredConformances.begin(),
                                           requiredConformances.end());
      interestingConformances = &interestingConformancesBuffer;
    }

    hadFulfillment |=
      searchWitnessTable(IGM, arg, conf->getRequirement(), source,
                         std::move(argPath), keys, interestingConformances);
  });

  // Also match against the parent.  The polymorphic type
  // will start with any arguments from the parent.
  hadFulfillment |= searchParentTypeMetadata(IGM, type->getDecl(),
                                             type.getParent(),
                                             source, std::move(path), keys);
  return hadFulfillment;
}