Пример #1
0
Substitution Substitution::subst(Module *module,
                                 ArrayRef<Substitution> subs,
                                 TypeSubstitutionMap &subMap,
                                 ArchetypeConformanceMap &conformanceMap) const {
  // Substitute the replacement.
  Type substReplacement = Replacement.subst(module, subMap, None);
  assert(substReplacement && "substitution replacement failed");

  if (substReplacement->isEqual(Replacement))
    return *this;

  if (Conformance.empty()) {
    return {substReplacement, Conformance};
  }

  bool conformancesChanged = false;
  SmallVector<ProtocolConformanceRef, 4> substConformances;
  substConformances.reserve(Conformance.size());

  for (auto c : Conformance) {
    // If we have a concrete conformance, we need to substitute the
    // conformance to apply to the new type.
    if (c.isConcrete()) {
      auto substC = c.getConcrete()->subst(module, substReplacement, subs,
                                           subMap, conformanceMap);
      substConformances.push_back(ProtocolConformanceRef(substC));
      if (c != substConformances.back())
        conformancesChanged = true;
      continue;
    }

    // Otherwise, we may need to fill in the conformance.
    ProtocolDecl *proto = c.getAbstract();
    Optional<ProtocolConformanceRef> conformance;

    // If the original type was an archetype, check the conformance map.
    if (auto replacementArch = Replacement->getAs<ArchetypeType>()) {
      // Check for conformances for the type that apply to the original
      // substituted archetype.
      auto it = conformanceMap.find(replacementArch);
      assert(it != conformanceMap.end());
      for (ProtocolConformanceRef found : it->second) {
        auto foundProto = found.getRequirement();
        if (foundProto == proto) {
          conformance = found;
          break;
        } else if (foundProto->inheritsFrom(proto)) {
          if (found.isConcrete()) {
            conformance = ProtocolConformanceRef(
              found.getConcrete()->getInheritedConformance(proto));
          } else {
            conformance = found;
          }
          break;
        }
      }
    }

    // If that didn't find anything, we can still synthesize AnyObject
    // conformances from thin air.  FIXME: gross.
    if (!conformance &&
        proto->isSpecificProtocol(KnownProtocolKind::AnyObject)) {
      auto classDecl
        = substReplacement->getClassOrBoundGenericClass();
      SmallVector<ProtocolConformance *, 1> lookupResults;
      classDecl->lookupConformance(classDecl->getParentModule(),
                                   proto, lookupResults);
      conformance = ProtocolConformanceRef(lookupResults.front());
    }

    if (conformance) {
      if (conformance->isConcrete())
        conformancesChanged = true;
      substConformances.push_back(*conformance);
    } else {
      assert(substReplacement->hasDependentProtocolConformances() &&
             "couldn't find concrete conformance for concrete type?");
      substConformances.push_back(ProtocolConformanceRef(proto));
    }
  }
  assert(substConformances.size() == Conformance.size());

  ArrayRef<ProtocolConformanceRef> substConfs;
  if (conformancesChanged)
    substConfs = module->getASTContext().AllocateCopy(substConformances);
  else
    substConfs = Conformance;

  return Substitution{substReplacement, substConfs};
}
Пример #2
0
Substitution Substitution::subst(Module *module,
                                 ArrayRef<Substitution> subs,
                                 TypeSubstitutionMap &subMap,
                                 ArchetypeConformanceMap &conformanceMap) const {
  // Substitute the replacement.
  Type substReplacement = Replacement.subst(module, subMap, None);
  assert(substReplacement && "substitution replacement failed");

  if (substReplacement->isEqual(Replacement))
    return *this;

  bool conformancesChanged = false;
  SmallVector<ProtocolConformance *, 4> substConformance;
  substConformance.reserve(Conformance.size());

  // When substituting a concrete type for an archetype, we need to fill in the
  // conformances.
  if (auto replacementArch = Replacement->getAs<ArchetypeType>()) {
    if (!substReplacement->hasDependentProtocolConformances()) {
      // Find the conformances mapped to the archetype.
      auto found = conformanceMap.find(replacementArch);
      assert(found != conformanceMap.end()
             && "no conformances for replaced archetype?!");

      auto &foundConformances = found->second;

      // If the substituted replacement archetype has no conformances,
      // then there are no conformances to substitute.
      if (foundConformances.empty())
        return Substitution{Archetype, substReplacement, Conformance};

      conformancesChanged = true;

      // Get the conformances for the type that apply to the original
      // substituted archetype.
      for (auto proto : Archetype->getConformsTo()) {
        for (auto c : foundConformances) {
          if (c->getProtocol() == proto) {
            substConformance.push_back(c);
            goto found_conformance;
          }
          if (c->getProtocol()->inheritsFrom(proto)) {
            substConformance.push_back(c->getInheritedConformance(proto));
            goto found_conformance;
          }
        }

        // FIXME: AnyObject conformances can be synthesized from
        // thin air. Gross.
        if (proto->isSpecificProtocol(KnownProtocolKind::AnyObject)) {
          auto classDecl
            = substReplacement->getClassOrBoundGenericClass();
          SmallVector<ProtocolConformance *, 1> conformances;
          classDecl->lookupConformance(classDecl->getParentModule(),
                                       proto, conformances);
          substConformance.push_back(conformances.front());
          goto found_conformance;
        }

        assert(false && "did not find conformance for archetype requirement?!");
found_conformance:;
      }
    }
  } else {
    // If we substituted a concrete type for another, we need to substitute the
    // conformance to apply to the new type.
    for (auto c : Conformance) {
      auto substC = c->subst(module, substReplacement, subs,
                             subMap, conformanceMap);
      if (c != substC)
        conformancesChanged = true;
      substConformance.push_back(substC);
    }
  }

  ArrayRef<ProtocolConformance *> substConformanceRef;
  if (conformancesChanged)
    substConformanceRef = module->getASTContext().AllocateCopy(substConformance);
  else
    substConformanceRef = Conformance;

  assert(substReplacement->hasDependentProtocolConformances()
         || substConformanceRef.size() == Archetype->getConformsTo().size());

  return Substitution{Archetype, substReplacement, substConformanceRef};
}