示例#1
0
/// Given that we have a source for a witness table that the given type
/// conforms to the given protocol, check to see if it fulfills anything.
bool FulfillmentMap::searchWitnessTable(IRGenModule &IGM,
                                        CanType type, ProtocolDecl *protocol,
                                        unsigned source, MetadataPath &&path,
                                        const InterestingKeysCallback &keys) {
  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.isInterestingType(type) &&
      keys.hasLimitedInterestingConformances(type)) {
    // Bail out immediately if the set is empty.
    // This only makes sense because we're not trying to fulfill
    // associated types this way.
    auto requiredConformances = keys.getInterestingConformances(type);
    if (requiredConformances.empty()) return false;

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

  return searchWitnessTable(IGM, type, protocol, source, std::move(path), keys,
                            interestingConformances);
}
示例#2
0
bool FulfillmentMap::searchNominalTypeMetadata(IRGenModule &IGM,
                                               CanType type,
                                               MetadataState metadataState,
                                               unsigned source,
                                               MetadataPath &&path,
                                         const InterestingKeysCallback &keys) {
  // Objective-C generics don't preserve their generic parameters at runtime,
  // so they aren't able to fulfill type metadata requirements.
  if (type.getAnyNominal()->hasClangNode()) {
    return false;
  }
  
  auto *nominal = type.getAnyNominal();
  if (!nominal->isGenericContext() || isa<ProtocolDecl>(nominal)) {
    return false;
  }

  bool hadFulfillment = false;

  GenericTypeRequirements requirements(IGM, nominal);
  requirements.enumerateFulfillments(
      IGM, type->getContextSubstitutionMap(IGM.getSwiftModule(), nominal),
      [&](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) {
      auto argState = getPresumedMetadataStateForTypeArgument(metadataState);
      MetadataPath argPath = path;
      argPath.addNominalTypeArgumentComponent(reqtIndex);
      hadFulfillment |=
        searchTypeMetadata(IGM, arg, IsExact, argState, 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);

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

  return hadFulfillment;
}
示例#3
0
bool FulfillmentMap::searchTypeArgConformances(ModuleDecl &M, CanType arg,
                                               ArchetypeType *param,
                                               unsigned source,
                                               const MetadataPath &path,
                                               unsigned argIndex,
                                         const InterestingKeysCallback &keys) {
  // Our sources are the protocol conformances that are recorded in
  // the generic metadata.
  auto storedConformances = param->getConformsTo();
  if (storedConformances.empty()) return false;

  bool hadFulfillment = false;

  // If we're not limiting the interesting conformances, just add fulfillments
  // for all of the stored conformances.
  if (!keys.hasLimitedInterestingConformances(arg)) {
    for (size_t confIndex : indices(storedConformances)) {
      MetadataPath confPath = path;
      confPath.addNominalTypeArgumentConformanceComponent(argIndex,
                                                          confIndex);
      hadFulfillment |=
        addFulfillment({arg, storedConformances[confIndex]},
                       source, std::move(confPath));
    }

    return hadFulfillment;
  }

  // Otherwise, our targets are the interesting conformances for the type
  // argument.
  auto requiredConformances = keys.getInterestingConformances(arg);
  if (requiredConformances.empty()) return false;

  for (auto target : requiredConformances) {
    // Ignore trivial protocols.
    if (!Lowering::TypeConverter::protocolRequiresWitnessTable(target))
      continue;

    // Check each of the stored conformances.
    for (size_t confIndex : indices(storedConformances)) {
      // TODO: maybe this should consider indirect conformance.
      // But that should be part of the metadata path.
      if (target == storedConformances[confIndex]) {
        MetadataPath confPath = path;
        confPath.addNominalTypeArgumentConformanceComponent(argIndex,
                                                            confIndex);
        hadFulfillment |=
          addFulfillment({arg, target}, source, std::move(confPath));
      }
    }
  }

  return hadFulfillment;
}
示例#4
0
/// Given that we have a source for metadata of the given type, check
/// to see if it fulfills anything.
///
/// \param isExact - true if the metadata is known to be exactly the
///   metadata for the given type, false if it might be a subtype
bool FulfillmentMap::searchTypeMetadata(IRGenModule &IGM, CanType type,
                                        IsExact_t isExact,
                                        MetadataState metadataState,
                                        unsigned source, MetadataPath &&path,
                                        const InterestingKeysCallback &keys) {

  // If this is an exact source, and it's an interesting type, add this
  // as a fulfillment.
  if (isExact && keys.isInterestingType(type)) {
    // If the type isn't a leaf type, also check it as an inexact match.
    bool hadFulfillment = false;
    if (!isLeafTypeMetadata(type)) {
      hadFulfillment |= searchTypeMetadata(IGM, type, IsInexact, metadataState,
                                           source, MetadataPath(path), keys);
    }

    // Consider its super class bound.
    if (metadataState == MetadataState::Complete) {
      if (auto superclassTy = keys.getSuperclassBound(type)) {
        hadFulfillment |= searchNominalTypeMetadata(
            IGM, superclassTy, metadataState, source, std::move(path), keys);
      }
    }

    // Add the fulfillment.
    hadFulfillment |= addFulfillment({type, nullptr},
                                     source, std::move(path), metadataState);
    return hadFulfillment;
  }

  // Search the superclass fields.  We can only do this if the metadata
  // is complete.
  if (metadataState == MetadataState::Complete &&
      keys.isInterestingType(type)) {
    if (auto superclassTy = keys.getSuperclassBound(type)) {
      return searchNominalTypeMetadata(IGM, superclassTy, metadataState,
                                       source, std::move(path), keys);
    }
  }

  // Inexact metadata will be a problem if we ever try to use this
  // to remember that we already have the metadata for something.
  if (isa<NominalType>(type) || isa<BoundGenericType>(type)) {
    return searchNominalTypeMetadata(IGM, type, metadataState,
                                     source, std::move(path), keys);
  }

  // TODO: tuples
  // TODO: functions
  // TODO: metatypes

  return false;
}
示例#5
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;
}
示例#6
0
/// Given that we have a source for metadata of the given type, check
/// to see if it fulfills anything.
///
/// \param isExact - true if the metadata is known to be exactly the
///   metadata for the given type, false if it might be a subtype
bool FulfillmentMap::searchTypeMetadata(IRGenModule &IGM, CanType type,
                                        IsExact_t isExact,
                                        unsigned source, MetadataPath &&path,
                                        const InterestingKeysCallback &keys) {

  // If this is an exact source, and it's an interesting type, add this
  // as a fulfillment.
  if (isExact && keys.isInterestingType(type)) {
    // If the type isn't a leaf type, also check it as an inexact match.
    bool hadFulfillment = false;
    if (!isLeafTypeMetadata(type)) {
      hadFulfillment |= searchTypeMetadata(IGM, type, IsInexact, source,
                                           MetadataPath(path), keys);
    }

    // Add the fulfillment.
    hadFulfillment |= addFulfillment({type, nullptr}, source, std::move(path));
    return hadFulfillment;
  }

  // Inexact metadata will be a problem if we ever try to use this
  // to remember that we already have the metadata for something.
  if (auto nomTy = dyn_cast<NominalType>(type)) {
    return searchNominalTypeMetadata(IGM, nomTy, source, std::move(path), keys);
  }
  if (auto boundTy = dyn_cast<BoundGenericType>(type)) {
    return searchBoundGenericTypeMetadata(IGM, boundTy, source, std::move(path),
                                          keys);
  }

  // TODO: tuples
  // TODO: functions
  // TODO: metatypes

  return false;
}
示例#7
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;
}