//===--- RequirementMachineRequests.cpp - Request evaluator requests ------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements the main entry points for computing minimized generic
// signatures using the requirement machine via the request evaluator.
//
// There are three requests:
//
// - RequirementSignatureRequest computes protocol requirement signatures from
//   user-written requirements.
// - AbstractGenericSignatureRequest computes minimal generic signatures from a
//   set of abstract Requirements.
// - InferredGenericSignatureRequest computes minimal generic signatures from a
//   set of user-written requirements on a parsed generic declaration.
//
// Each request begins by constructing some desugared requirements using the
// entry points in RequirementLowering.cpp.
//
// The desugared requirements are fed into a new requirement machine instance,
// which is then asked to produce a minimal set of rewrite rules. These rules
// are converted into minimal canonical Requirements using the entry points in
// RuleBuilder.cpp.
//
// The actual logic for finding a minimal set of rewrite rules is implemented in
// HomotopyReduction.cpp and MinimalConformances.cpp.
//
// Routines for constructing Requirements from Rules are implemented in
// RequirementBuilder.cpp.
//
// This process is actually iterated to implement "concrete equivalence class
// splitting", a compatibility behavior to produce the same results as the
// GenericSignatureBuilder in certain esoteric edge cases:
//
//           ------------------------
//          / Desugared Requirement /
//          ------------------------
//                     |
//                     |  +---------------------+
//                     |  |                     |
//                     v  v                     |
//              +-------------+                 |
//              | RuleBuilder |                 |
//              +-------------+                 |
//                     |                        |
//                     v                        |
//             +--------------+                 |
//             | Minimization |                 |
//             +--------------+                 |
//                     |                        |
//                     v                        |
//          +--------------------+              |
//          | RequirementBuilder |              |
//          +--------------------+              |
//                     |                        |
//                     v                        |
//               --------------                 |
//              / Requirement /                 |
//              --------------                  |
//                     |                        |
//                     v                        |
//  +------------------------------------+      |
//  | Split concrete equivalence classes |  ----+
//  +------------------------------------+
//                     |
//                     v
//               --------------
//              / Requirement /
//              --------------
//
// This transformation is described in splitConcreteEquivalenceClasses() below.
//
//===----------------------------------------------------------------------===//

#include "RequirementMachine.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DiagnosticsSema.h"
#include "swift/AST/GenericSignature.h"
#include "swift/AST/LazyResolver.h"
#include "swift/AST/Requirement.h"
#include "swift/AST/RequirementSignature.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/AST/TypeRepr.h"
#include "swift/Basic/Assertions.h"
#include "swift/Basic/Defer.h"
#include "swift/Basic/Statistic.h"
#include <memory>
#include <vector>
#include "RequirementLowering.h"

using namespace swift;
using namespace rewriting;

/// Hack for GenericSignatureBuilder compatibility. We might end up with a
/// same-type requirement between type parameters where one of them has an
/// implied concrete type requirement. In this case, split it up into two
/// concrete type requirements.
static bool shouldSplitConcreteEquivalenceClass(
    Requirement req,
    const ProtocolDecl *proto,
    const RequirementMachine *machine) {
  return (req.getKind() == RequirementKind::SameType &&
          req.getSecondType()->isTypeParameter() &&
          machine->isConcreteType(req.getSecondType(), proto));
}

/// Returns true if this generic signature contains abstract same-type
/// requirements between concrete type parameters. In this case, we split
/// the abstract same-type requirements into pairs of concrete type
/// requirements, and minimize the signature again.
static bool shouldSplitConcreteEquivalenceClasses(
    ArrayRef<Requirement> requirements,
    const ProtocolDecl *proto,
    const RequirementMachine *machine) {
  for (auto req : requirements) {
    if (shouldSplitConcreteEquivalenceClass(req, proto, machine))
      return true;
  }

  return false;
}

/// Same as the above, but with the requirements of a protocol connected
/// component.
static bool shouldSplitConcreteEquivalenceClasses(
    const llvm::DenseMap<const ProtocolDecl *, RequirementSignature> &protos,
    const RequirementMachine *machine) {
  for (const auto &pair : protos) {
    if (shouldSplitConcreteEquivalenceClasses(pair.second.getRequirements(),
                                              pair.first, machine))
      return true;
  }

  return false;
}

/// Replace each same-type requirement 'T == U' where 'T' (and therefore 'U')
/// is known to equal a concrete type 'C' with a pair of requirements
/// 'T == C' and 'U == C'. We build the signature again in this case, since
/// one of the two requirements will be redundant, but we don't know which
/// ahead of time.
static void splitConcreteEquivalenceClasses(
    ASTContext &ctx,
    ArrayRef<Requirement> requirements,
    const ProtocolDecl *proto,
    const RequirementMachine *machine,
    ArrayRef<GenericTypeParamType *> genericParams,
    SmallVectorImpl<StructuralRequirement> &splitRequirements,
    unsigned &attempt) {
  bool debug = machine->getDebugOptions().contains(
      DebugFlags::SplitConcreteEquivalenceClass);

  unsigned maxAttempts =
      ctx.LangOpts.RequirementMachineMaxSplitConcreteEquivClassAttempts;

  if (attempt >= maxAttempts) {
    llvm::errs() << "Splitting concrete equivalence classes did not "
                 << "reach fixed point after " << attempt << " attempts.\n";
    llvm::errs() << "Last attempt produced these requirements:\n";
    for (auto req : requirements) {
      req.dump(llvm::errs());
      llvm::errs() << "\n";
    }
    machine->dump(llvm::errs());
    abort();
  }

  splitRequirements.clear();

  if (debug) {
    llvm::dbgs() << "\n# Splitting concrete equivalence classes:\n";
  }

  for (auto req : requirements) {
    if (shouldSplitConcreteEquivalenceClass(req, proto, machine)) {
      auto concreteType = machine->getConcreteType(
          req.getSecondType(), genericParams, proto);

      Requirement firstReq(RequirementKind::SameType,
                           req.getFirstType(), concreteType);
      Requirement secondReq(RequirementKind::SameType,
                            req.getSecondType(), concreteType);
      splitRequirements.push_back({firstReq, SourceLoc()});
      splitRequirements.push_back({secondReq, SourceLoc()});

      if (debug) {
        llvm::dbgs() << "- First split: ";
        firstReq.dump(llvm::dbgs());
        llvm::dbgs() << "\n- Second split: ";
        secondReq.dump(llvm::dbgs());
        llvm::dbgs() << "\n";
      }
      continue;
    }

    splitRequirements.push_back({req, SourceLoc()});

    if (debug) {
      llvm::dbgs() << "- Not split: ";
      req.dump(llvm::dbgs());
      llvm::dbgs() << "\n";
    }
  }
}

/// Same as the above, but with the requirements of a protocol connected
/// component.
static void splitConcreteEquivalenceClasses(
    ASTContext &ctx,
    const llvm::DenseMap<const ProtocolDecl *, RequirementSignature> &protos,
    const RequirementMachine *machine,
    llvm::DenseMap<const ProtocolDecl *,
                   SmallVector<StructuralRequirement, 4>> &splitProtos,
    unsigned &attempt) {
  for (const auto &pair : protos) {
    const auto *proto = pair.first;
    auto genericParams = proto->getGenericSignature().getGenericParams();
    splitConcreteEquivalenceClasses(ctx, pair.second.getRequirements(),
                                    proto, machine, genericParams,
                                    splitProtos[proto],
                                    attempt);
  }
}

/// Builds the requirement signatures for each protocol in this strongly
/// connected component.
llvm::DenseMap<const ProtocolDecl *, RequirementSignature>
RequirementMachine::computeMinimalProtocolRequirements() {
  auto protos = System.getProtocols();

  ASSERT(protos.size() > 0 &&
         "Not a protocol connected component rewrite system");

  System.minimizeRewriteSystem(Map);

  if (Dump) {
    llvm::dbgs() << "Minimized rewrite system:\n";
    dump(llvm::dbgs());
  }

  auto rules = System.getMinimizedProtocolRules();

  auto &ctx = Context.getASTContext();

  // Note that we build 'result' by iterating over 'protos' rather than
  // 'rules'; this is intentional, so that even if a protocol has no
  // rules, we still end up creating an entry for it in 'result'.
  llvm::DenseMap<const ProtocolDecl *, RequirementSignature> result;
  for (const auto *proto : protos) {
    auto genericParams = proto->getGenericSignature().getGenericParams();

    const auto &entry = rules[proto];

    std::vector<Requirement> reqs;
    std::vector<ProtocolTypeAlias> aliases;
    buildRequirementsFromRules(entry.Requirements,
                               entry.TypeAliases,
                               genericParams,
                               /*reconstituteSugar=*/true,
                               reqs, aliases);

    result[proto] = RequirementSignature(ctx.AllocateCopy(reqs),
                                         ctx.AllocateCopy(aliases),
                                         getErrors());
  }

  return result;
}

RequirementSignature
RequirementSignatureRequest::evaluate(Evaluator &evaluator,
                                      ProtocolDecl *proto) const {
  ASTContext &ctx = proto->getASTContext();

  // First check if we have a deserializable requirement signature.
  if (proto->hasLazyRequirementSignature()) {
    // FIXME: (transitional) increment the redundant "always-on" counter.
    if (ctx.Stats)
      ++ctx.Stats->getFrontendCounters().NumLazyRequirementSignaturesLoaded;

    auto contextData = static_cast<LazyProtocolData *>(
        ctx.getOrCreateLazyContextData(proto, nullptr));

    SmallVector<Requirement, 2> requirements;
    SmallVector<ProtocolTypeAlias, 2> typeAliases;
    contextData->loader->loadRequirementSignature(
        proto, contextData->requirementSignatureData,
        requirements, typeAliases);
    return RequirementSignature(ctx.AllocateCopy(requirements),
                                ctx.AllocateCopy(typeAliases));
  }

  auto &rewriteCtx = ctx.getRewriteContext();

  // We build requirement signatures for all protocols in a strongly connected
  // component at the same time.
  auto component = rewriteCtx.startComputingRequirementSignatures(proto);

  SWIFT_DEFER {
    rewriteCtx.finishComputingRequirementSignatures(proto);
  };

  SmallVector<RequirementError, 4> errors;

  // Collect user-written requirements from the protocols in this connected
  // component.
  llvm::DenseMap<const ProtocolDecl *,
                 SmallVector<StructuralRequirement, 4>> protos;
  for (const auto *proto : component) {
    auto &requirements = protos[proto];
    for (auto req : proto->getStructuralRequirements())
      requirements.push_back(req);
    for (auto req : proto->getTypeAliasRequirements())
      requirements.push_back({req, SourceLoc()});
  }

  if (rewriteCtx.getDebugOptions().contains(DebugFlags::Timers)) {
    rewriteCtx.beginTimer("RequirementSignatureRequest");
    llvm::dbgs() << "[";
    for (auto *proto : component)
      llvm::dbgs() << " " << proto->getName();
    llvm::dbgs() << " ]\n";
  }

  SWIFT_DEFER {
    if (rewriteCtx.getDebugOptions().contains(DebugFlags::Timers)) {
      rewriteCtx.endTimer("RequirementSignatureRequest");
      llvm::dbgs() << "[";
      for (auto *proto : component)
        llvm::dbgs() << " " << proto->getName();
      llvm::dbgs() << " ]\n";
    }
  };

  unsigned attempt = 0;
  for (;;) {
    for (const auto *otherProto : component) {
      auto &requirements = protos[otherProto];

      // Preprocess requirements to eliminate conformances on type parameters
      // which are made concrete.
      if (ctx.LangOpts.EnableRequirementMachineConcreteContraction) {
        SmallVector<StructuralRequirement, 4> contractedRequirements;

        bool debug = rewriteCtx.getDebugOptions()
                               .contains(DebugFlags::ConcreteContraction);

        if (performConcreteContraction(requirements, contractedRequirements,
                                       errors, debug)) {
          std::swap(contractedRequirements, requirements);
        }
      }
    }

    // Heap-allocate the requirement machine to save stack space.
    std::unique_ptr<RequirementMachine> machine(new RequirementMachine(
        rewriteCtx));

    auto status = machine->initWithProtocolWrittenRequirements(component, protos);

    // If completion failed, diagnose an error and return a dummy signature.
    if (status.first != CompletionResult::Success) {
      // All we can do at this point is diagnose and give each protocol an empty
      // requirement signature.
      for (const auto *otherProto : component) {
        ctx.Diags.diagnose(otherProto->getLoc(),
                           diag::requirement_machine_completion_failed,
                           /*protocol=*/1,
                           unsigned(status.first));

        auto rule = machine->getRuleAsStringForDiagnostics(status.second);
        ctx.Diags.diagnose(otherProto->getLoc(),
                           diag::requirement_machine_completion_rule,
                           rule);

        if (otherProto != proto) {
          ctx.evaluator.cacheOutput(
            RequirementSignatureRequest{const_cast<ProtocolDecl *>(otherProto)},
            RequirementSignature::getPlaceholderRequirementSignature(
                otherProto, GenericSignatureErrorFlags::CompletionFailed));
        }
      }

      return RequirementSignature::getPlaceholderRequirementSignature(
          proto, GenericSignatureErrorFlags::CompletionFailed);
    }

    auto minimalRequirements = machine->computeMinimalProtocolRequirements();

    // Don't bother splitting concrete equivalence classes if there were invalid
    // requirements, because the signature is not going to be ABI anyway.
    if (!machine->getErrors().contains(
          GenericSignatureErrorFlags::HasInvalidRequirements)) {
      if (shouldSplitConcreteEquivalenceClasses(minimalRequirements, machine.get())) {
        ++attempt;
        splitConcreteEquivalenceClasses(ctx, minimalRequirements,
                                        machine.get(), protos, attempt);
        continue;
      }
    }

    bool debug = machine->getDebugOptions().contains(DebugFlags::Minimization);

    // The requirement signature for the actual protocol that the result
    // was kicked off with.
    std::optional<RequirementSignature> result;

    if (debug) {
      llvm::dbgs() << "\nRequirement signatures:\n";
    }

    // Cache the requirement signatures for all other protocols in this
    // connected component.
    for (const auto &pair : minimalRequirements) {
      auto *otherProto = pair.first;
      const auto &reqs = pair.second;

      // Dump the result if requested.
      if (debug) {
        llvm::dbgs() << "- Protocol " << otherProto->getName() << ": ";

        auto sig = GenericSignature::get(
            otherProto->getGenericSignature().getGenericParams(),
            reqs.getRequirements());

        PrintOptions opts;
        opts.ProtocolQualifiedDependentMemberTypes = true;
        sig.print(llvm::dbgs(), opts);
        llvm::dbgs() << "\n";
      }

      // Don't call setRequirementSignature() on the original proto; the
      // request evaluator will do it for us.
      if (otherProto == proto)
        result = reqs;
      else {
        auto temp = reqs;
        ctx.evaluator.cacheOutput(
          RequirementSignatureRequest{const_cast<ProtocolDecl *>(otherProto)},
          std::move(temp));
      }
    }

    // FIXME: We don't have the inverses from desugaring available here!
    SmallVector<InverseRequirement, 2> missingInverses;

    // Diagnose redundant requirements and conflicting requirements.
    machine->computeRequirementDiagnostics(errors, missingInverses,
                                           proto->getLoc());
    diagnoseRequirementErrors(ctx, errors,
                              AllowConcreteTypePolicy::NestedAssocTypes);

    for (auto *protocol : machine->System.getProtocols()) {
      auto selfType = protocol->getSelfInterfaceType();
      auto concrete = machine->getConcreteType(selfType,
                                               machine->getGenericParams(),
                                               protocol);
      if (!concrete || concrete->hasError())
        continue;

      protocol->diagnose(diag::requires_generic_param_made_equal_to_concrete,
                         selfType);
    }

    if (!machine->getErrors()) {
      // If this signature was minimized without errors or non-redundant
      // concrete conformances, we can re-use the requirement machine for
      // subsequent queries, instead of building a new requirement machine
      // from the minimized signature.
      rewriteCtx.installRequirementMachine(proto, std::move(machine));
    }

    // Return the result for the specific protocol this request was kicked off on.
    return *result;
  }
}

/// Builds the top-level generic signature requirements for this rewrite system.
GenericSignature
RequirementMachine::computeMinimalGenericSignature(
    bool reconstituteSugar) {
  ASSERT(!Sig &&
         "Already computed minimal generic signature");
  ASSERT(System.getProtocols().empty() &&
         "Not a top-level generic signature rewrite system");
  ASSERT(!Params.empty() &&
         "Not a from-source top-level generic signature rewrite system");

  System.minimizeRewriteSystem(Map);

  if (Dump) {
    llvm::dbgs() << "Minimized rewrite system:\n";
    dump(llvm::dbgs());
  }

  auto rules = System.getMinimizedGenericSignatureRules();

  std::vector<Requirement> reqs;
  std::vector<ProtocolTypeAlias> aliases;

  buildRequirementsFromRules(rules, ArrayRef<unsigned>(), getGenericParams(),
                             reconstituteSugar, reqs, aliases);
  ASSERT(aliases.empty());

  auto sig = GenericSignature::get(getGenericParams(), reqs);

  // Remember the signature for generic signature queries. In particular,
  // getConformancePath() needs the current requirement machine's
  // generic signature.
  Sig = sig.getCanonicalSignature();

  return sig;
}

/// Check whether the inputs to the \c AbstractGenericSignatureRequest are
/// all canonical.
static bool isCanonicalRequest(GenericSignature baseSignature,
                               ArrayRef<GenericTypeParamType *> genericParams,
                               ArrayRef<Requirement> requirements) {
  if (baseSignature && !baseSignature->isCanonical())
    return false;

  for (auto gp : genericParams) {
    if (!gp->isCanonical())
      return false;
  }

  for (const auto &req : requirements) {
    if (!req.isCanonical())
      return false;
  }

  return true;
}

GenericSignatureWithError
AbstractGenericSignatureRequest::evaluate(
         Evaluator &evaluator,
         const GenericSignatureImpl *baseSignatureImpl,
         SmallVector<GenericTypeParamType *, 2> addedParameters,
         SmallVector<Requirement, 2> addedRequirements,
         bool allowInverses) const {
  GenericSignature baseSignature = GenericSignature{baseSignatureImpl};
  // If nothing is added to the base signature, just return the base
  // signature.
  if (addedParameters.empty() && addedRequirements.empty())
    return GenericSignatureWithError(baseSignature, GenericSignatureErrors());

  ASTContext &ctx = addedParameters.empty()
      ? addedRequirements.front().getFirstType()->getASTContext()
      : addedParameters.front()->getASTContext();

  SmallVector<GenericTypeParamType *, 4> genericParams(
      baseSignature.getGenericParams().begin(),
      baseSignature.getGenericParams().end());
  genericParams.append(
      addedParameters.begin(),
      addedParameters.end());

  // If there are no added requirements, we can form the signature directly
  // with the added parameters.
  if (addedRequirements.empty() && !allowInverses) {
    auto result = GenericSignature::get(genericParams,
                                        baseSignature.getRequirements());
    return GenericSignatureWithError(result, GenericSignatureErrors());
  }

  // If the request is non-canonical, we won't need to build our own
  // generic signature builder.
  if (!isCanonicalRequest(baseSignature, addedParameters, addedRequirements)) {
    // Canonicalize the inputs so we can form the canonical request.
    auto canBaseSignature = baseSignature.getCanonicalSignature();

    SmallVector<GenericTypeParamType *, 2> canAddedParameters;
    canAddedParameters.reserve(addedParameters.size());
    for (auto gp : addedParameters) {
      auto canGP = gp->getCanonicalType()->castTo<GenericTypeParamType>();
      canAddedParameters.push_back(canGP);
    }

    SmallVector<Requirement, 2> canAddedRequirements;
    canAddedRequirements.reserve(addedRequirements.size());
    for (const auto &req : addedRequirements) {
      canAddedRequirements.push_back(req.getCanonical());
    }

    // Build the canonical signature.
    auto canSignatureResult = evaluateOrDefault(
        ctx.evaluator,
        AbstractGenericSignatureRequest{
          canBaseSignature.getPointer(), std::move(canAddedParameters),
          std::move(canAddedRequirements),
          allowInverses},
        GenericSignatureWithError());
    if (!canSignatureResult.getPointer())
      return GenericSignatureWithError();

    // Substitute in the original generic parameters to form the sugared
    // result the original request wanted.
    auto canSignature = canSignatureResult.getPointer();
    SmallVector<GenericTypeParamType *, 2> resugaredParameters;
    resugaredParameters.reserve(canSignature.getGenericParams().size());
    if (baseSignature) {
      resugaredParameters.append(baseSignature.getGenericParams().begin(),
                                 baseSignature.getGenericParams().end());
    }
    resugaredParameters.append(addedParameters.begin(), addedParameters.end());
    ASSERT(resugaredParameters.size() ==
               canSignature.getGenericParams().size());

    SmallVector<Requirement, 2> resugaredRequirements;
    resugaredRequirements.reserve(canSignature.getRequirements().size());
    for (const auto &req : canSignature.getRequirements()) {
      auto resugaredReq = req.subst(
          [&](SubstitutableType *type) {
            if (auto gp = dyn_cast<GenericTypeParamType>(type)) {
              unsigned ordinal = canSignature->getGenericParamOrdinal(gp);
              return Type(resugaredParameters[ordinal]);
            }
            return Type(type);
          },
          MakeAbstractConformanceForGenericType(),
          SubstFlags::PreservePackExpansionLevel);
      resugaredRequirements.push_back(resugaredReq);
    }

    return GenericSignatureWithError(
        GenericSignature::get(resugaredParameters, resugaredRequirements),
        canSignatureResult.getInt());
  }

  // Convert the input Requirements into StructuralRequirements by adding
  // empty source locations.
  SmallVector<StructuralRequirement, 2> requirements;
  for (auto req : baseSignature.getRequirements())
    requirements.push_back({req, SourceLoc()});

  // Add the new requirements.
  for (auto req : addedRequirements)
    requirements.push_back({req, SourceLoc()});

  // The requirements passed to this request may have been substituted,
  // meaning the subject type might be a concrete type and not a type
  // parameter.
  //
  // Also, the right hand side of conformance requirements here might be
  // a protocol composition.
  //
  // Desugaring converts these kinds of requirements into "proper"
  // requirements where the subject type is always a type parameter,
  // which is what the RuleBuilder expects.
  SmallVector<RequirementError, 2> errors;
  SmallVector<InverseRequirement, 2> inverses;
  desugarRequirements(requirements, inverses, errors);

  /// Next, we need to expand default requirements and then apply inverses.
  SmallVector<Type, 2> paramsAsTypes;
  if (allowInverses) {
    for (auto *gtpt : addedParameters)
      paramsAsTypes.push_back(gtpt);
  }

  SmallVector<StructuralRequirement, 2> defaults;
  InverseRequirement::expandDefaults(ctx, paramsAsTypes, defaults);
  applyInverses(ctx, paramsAsTypes, inverses, defaults, errors);
  requirements.append(defaults);

  auto &rewriteCtx = ctx.getRewriteContext();

  if (rewriteCtx.getDebugOptions().contains(DebugFlags::Timers)) {
    rewriteCtx.beginTimer("AbstractGenericSignatureRequest");
    llvm::dbgs() << "\n";
  }

  unsigned attempt = 0;
  for (;;) {
    // Preprocess requirements to eliminate conformances on generic parameters
    // which are made concrete.
    if (ctx.LangOpts.EnableRequirementMachineConcreteContraction) {
      SmallVector<StructuralRequirement, 4> contractedRequirements;
      bool debug = rewriteCtx.getDebugOptions()
                             .contains(DebugFlags::ConcreteContraction);
      if (performConcreteContraction(requirements, contractedRequirements,
                                     errors, debug)) {
        std::swap(contractedRequirements, requirements);
      }
    }

    // Heap-allocate the requirement machine to save stack space.
    std::unique_ptr<RequirementMachine> machine(new RequirementMachine(
        rewriteCtx));

    auto status =
        machine->initWithWrittenRequirements(genericParams, requirements);
    machine->checkCompletionResult(status.first);

    // We pass reconstituteSugar=false to ensure that if the original
    // requirements were canonical, the final signature remains canonical.
    auto result = machine->computeMinimalGenericSignature(
          /*reconstituteSugar=*/false);
    auto errorFlags = machine->getErrors();

    // Don't bother splitting concrete equivalence classes if there were invalid
    // requirements, because the signature is not going to be ABI anyway.
    if (!errorFlags.contains(GenericSignatureErrorFlags::HasInvalidRequirements)) {
      if (shouldSplitConcreteEquivalenceClasses(result.getRequirements(),
                                                /*proto=*/nullptr,
                                                machine.get())) {
        ++attempt;
        splitConcreteEquivalenceClasses(ctx, result.getRequirements(),
                                        /*proto=*/nullptr, machine.get(),
                                        result.getGenericParams(),
                                        requirements, attempt);
        continue;
      }
    }

    if (!errorFlags) {
      // If this signature was minimized without errors or non-redundant
      // concrete conformances, we can re-use the requirement machine for
      // subsequent queries, instead of building a new requirement machine
      // from the minimized signature. Do this before verify(), which
      // performs queries.
      rewriteCtx.installRequirementMachine(result.getCanonicalSignature(),
                                           std::move(machine));
    }

    if (!errorFlags.contains(GenericSignatureErrorFlags::HasInvalidRequirements)) {
      // Check invariants.
      result.verify();
    }

    if (rewriteCtx.getDebugOptions().contains(DebugFlags::Timers)) {
      rewriteCtx.endTimer("AbstractGenericSignatureRequest");
      llvm::dbgs() << result << "\n";
    }

    return GenericSignatureWithError(result, errorFlags);
  }
}

/// If completion fails, build a dummy generic signature where everything is
/// Copyable and Escapable, to avoid spurious downstream diagnostics
/// concerning move-only types.
static GenericSignature getPlaceholderGenericSignature(
    ASTContext &ctx, ArrayRef<GenericTypeParamType *> genericParams) {
  SmallVector<Requirement, 2> requirements;
  for (auto param : genericParams) {
    if (param->isValue())
      continue;

    for (auto ip : InvertibleProtocolSet::allKnown()) {
      auto proto = ctx.getProtocol(getKnownProtocolKind(ip));
      requirements.emplace_back(RequirementKind::Conformance, param,
                                proto->getDeclaredInterfaceType());
    }
  }

  return GenericSignature::get(genericParams, requirements);
}

GenericSignatureWithError
InferredGenericSignatureRequest::evaluate(
        Evaluator &evaluator,
        const GenericSignatureImpl *parentSigImpl,
        GenericParamList *genericParamList,
        WhereClauseOwner whereClause,
        SmallVector<Requirement, 2> addedRequirements,
        SmallVector<TypeBase *, 2> inferenceSources,
        SourceLoc loc, ExtensionDecl *forExtension, bool allowInverses) const {
  GenericSignature parentSig(parentSigImpl);

  SmallVector<GenericTypeParamType *, 4> genericParams(
      parentSig.getGenericParams().begin(),
      parentSig.getGenericParams().end());

  unsigned numOuterParams = genericParams.size();
  if (forExtension) {
    numOuterParams = 0;
  }

  SmallVector<StructuralRequirement, 2> requirements;
  SmallVector<RequirementError, 2> errors;
  SmallVector<InverseRequirement, 2> inverses;

  for (const auto &req : parentSig.getRequirements())
    requirements.push_back({req, loc});

  DeclContext *lookupDC = nullptr;

  const auto visitRequirement = [&](const Requirement &req,
                                    RequirementRepr *reqRepr) {
    realizeRequirement(lookupDC, req, reqRepr, /*inferRequirements=*/true,
                       requirements, errors);
    return false;
  };

  if (genericParamList) {
    // If we have multiple parameter lists, we're in SIL mode, and there's
    // no parent signature from context.
    ASSERT(genericParamList->getOuterParameters() == nullptr || !parentSig);

    // Collect all outer generic parameter lists.
    SmallVector<GenericParamList *, 2> gpLists;
    for (auto *outerParamList = genericParamList;
         outerParamList != nullptr;
         outerParamList = outerParamList->getOuterParameters()) {
      gpLists.push_back(outerParamList);
    }

    // The generic parameter lists must appear from innermost to outermost.
    // We walk them backwards to order outer parameters before inner
    // parameters.
    for (auto *gpList : llvm::reverse(gpLists)) {
      ASSERT(gpList->size() > 0 &&
             "Parsed an empty generic parameter list?");

      for (auto *gpDecl : *gpList) {
        if (gpDecl->isValue() &&
            !gpDecl->getASTContext().LangOpts.hasFeature(Feature::ValueGenerics))
          gpDecl->diagnose(diag::value_generics_missing_feature);

        auto *gpType = gpDecl->getDeclaredInterfaceType()
                             ->castTo<GenericTypeParamType>();
        genericParams.push_back(gpType);

        realizeInheritedRequirements(gpDecl, gpType,
                                     /*inferRequirements=*/true,
                                     requirements, errors);
      }

      lookupDC = (*gpList->begin())->getDeclContext();

      // Add the generic parameter list's 'where' clause to the builder.
      //
      // The only time generic parameter lists have a 'where' clause is
      // in SIL mode; all other generic declarations have a free-standing
      // 'where' clause, which will be visited below.
      WhereClauseOwner(lookupDC, gpList)
        .visitRequirements(TypeResolutionStage::Structural,
                           visitRequirement);
    }
  }

  // Realize all requirements in the free-standing 'where' clause, if there
  // is one.
  if (whereClause) {
    lookupDC = whereClause.dc;

    std::move(whereClause).visitRequirements(
        TypeResolutionStage::Structural,
        visitRequirement);
  }

  auto *moduleForInference = lookupDC->getParentModule();
  auto &ctx = moduleForInference->getASTContext();

  // Perform requirement inference from function parameter and result
  // types and such.
  for (auto source : inferenceSources) {
    inferRequirements(source, moduleForInference, lookupDC, requirements);
  }

  // Finish by adding any remaining requirements. This is used to introduce
  // inferred same-type requirements when building the generic signature of
  // an extension whose extended type is a generic typealias.
  for (const auto &req : addedRequirements)
    requirements.push_back({req, SourceLoc()});

  desugarRequirements(requirements, inverses, errors);

  // After realizing requirements, expand default requirements only for local
  // generic parameters, as the outer parameters have already been expanded.
  SmallVector<Type, 4> paramTypes;
  if (allowInverses) {
    paramTypes.append(genericParams.begin() + numOuterParams,
                      genericParams.end());
  }

  SmallVector<StructuralRequirement, 2> defaults;
  InverseRequirement::expandDefaults(ctx, paramTypes, defaults);
  applyInverses(ctx, paramTypes, inverses, defaults, errors);
  
  // Any remaining implicit defaults in a conditional inverse requirement
  // extension must be made explicit.
  if (forExtension) {
    auto invertibleProtocol = forExtension->isAddingConformanceToInvertible();
    // FIXME: to workaround a reverse condfail, always infer the requirements if
    //  the extension is in a swiftinterface file. This is temporary and should
    //  be removed soon. (rdar://130424971)
    if (auto *sf = forExtension->getOutermostParentSourceFile()) {
      if (sf->Kind == SourceFileKind::Interface
          && !ctx.LangOpts.hasFeature(Feature::SE427NoInferenceOnExtension)) {
        invertibleProtocol = std::nullopt;
      }
    }
    if (invertibleProtocol) {
      for (auto &def : defaults) {
        // Check whether a corresponding explicit requirement was provided.
        for (auto &req : requirements) {
          // An explicit requirement can match the default exactly.
          if (req.req.getCanonical() == def.req.getCanonical()) {
            goto next;
          }
          
          // Disregard requirements on other parameters.
          if (!req.req.getFirstType()->isEqual(def.req.getFirstType())) {
            continue;
          }
          
          // Or it can be implied by a requirement on something that's inherently
          // copyable.
          if (req.req.getKind() == RequirementKind::Superclass) {
            // classes are currently always escapable and copyable
            goto next;
          }
          if (req.req.getKind() == RequirementKind::Layout) {
            // layout constraints currently always imply escapable and copyable
            goto next;
          }
          if (req.req.getKind() == RequirementKind::Conformance
              && req.req.getProtocolDecl()
                        ->inheritsFrom(def.req.getProtocolDecl())) {
            goto next;
          }

          // A same-type constraint removes the ability for the copyability
          // to vary independently at all.
          if (req.req.getKind() == RequirementKind::SameType) {
            goto next;
          }
        }
        ctx.Diags.diagnose(loc,diag::inverse_conditional_must_be_fully_explicit,
           ctx.getProtocol(getKnownProtocolKind(*invertibleProtocol)),
                           def.req.getFirstType(),
                           def.req.getProtocolDecl());
      next:;
      }
      // Don't actually apply the inferred requirements since they should be
      // stated explicitly.
      defaults.clear();
    }
  }
  
  requirements.append(defaults);

  auto &rewriteCtx = ctx.getRewriteContext();

  if (rewriteCtx.getDebugOptions().contains(DebugFlags::Timers)) {
    rewriteCtx.beginTimer("InferredGenericSignatureRequest");

    llvm::dbgs() << "@ ";
    auto &sourceMgr = ctx.SourceMgr;
    loc.print(llvm::dbgs(), sourceMgr);
    llvm::dbgs() << "\n";
  }

  unsigned attempt = 0;
  for (;;) {
    // Preprocess requirements to eliminate conformances on generic parameters
    // which are made concrete.
    if (ctx.LangOpts.EnableRequirementMachineConcreteContraction) {
      SmallVector<StructuralRequirement, 4> contractedRequirements;
      bool debug = rewriteCtx.getDebugOptions()
                             .contains(DebugFlags::ConcreteContraction);
      if (performConcreteContraction(requirements, contractedRequirements,
                                     errors, debug)) {
        std::swap(contractedRequirements, requirements);
      }
    }

    // Heap-allocate the requirement machine to save stack space.
    std::unique_ptr<RequirementMachine> machine(new RequirementMachine(
        rewriteCtx));

    auto status =
        machine->initWithWrittenRequirements(genericParams, requirements);

    // If completion failed, diagnose an error and return a dummy signature.
    if (status.first != CompletionResult::Success) {
      ctx.Diags.diagnose(loc,
                         diag::requirement_machine_completion_failed,
                         /*protocol=*/0,
                         unsigned(status.first));

      auto rule = machine->getRuleAsStringForDiagnostics(status.second);
      ctx.Diags.diagnose(loc,
                         diag::requirement_machine_completion_rule,
                         rule);

      auto result = getPlaceholderGenericSignature(ctx, genericParams);

      if (rewriteCtx.getDebugOptions().contains(DebugFlags::Timers)) {
        rewriteCtx.endTimer("InferredGenericSignatureRequest");
        llvm::dbgs() << result << "\n";
      }

      return GenericSignatureWithError(
          result, GenericSignatureErrorFlags::CompletionFailed);
    }

    auto result = machine->computeMinimalGenericSignature(
          /*reconstituteSugar=*/true);
    auto errorFlags = machine->getErrors();

    // Diagnose redundant requirements and conflicting requirements.
    if (attempt == 0) {
      machine->computeRequirementDiagnostics(errors, inverses, loc);
      diagnoseRequirementErrors(ctx, errors,
                                (forExtension || !genericParamList)
                                ? AllowConcreteTypePolicy::All
                                : AllowConcreteTypePolicy::AssocTypes);
    }

    // Don't bother splitting concrete equivalence classes if there were invalid
    // requirements, because the signature is not going to be ABI anyway.
    if (!errorFlags.contains(GenericSignatureErrorFlags::HasInvalidRequirements)) {
      // Check if we need to rebuild the signature.
      if (shouldSplitConcreteEquivalenceClasses(result.getRequirements(),
                                                /*proto=*/nullptr,
                                                machine.get())) {
        ++attempt;
        splitConcreteEquivalenceClasses(ctx, result.getRequirements(),
                                        /*proto=*/nullptr, machine.get(),
                                        result.getGenericParams(),
                                        requirements, attempt);
        continue;
      }
    }

    if (!errorFlags) {
      // If this signature was minimized without errors or non-redundant
      // concrete conformances, we can re-use the requirement machine for
      // subsequent queries, instead of building a new requirement machine
      // from the minimized signature. Do this before verify(), which
      // performs queries.
      rewriteCtx.installRequirementMachine(result.getCanonicalSignature(),
                                           std::move(machine));
    }

    if (genericParamList && !forExtension) {
      for (auto genericParam : result.getInnermostGenericParams()) {
        auto reduced = result.getReducedType(genericParam);

        if (reduced->hasError() || reduced->isEqual(genericParam))
          continue;

        // If one side is a parameter pack and the other is not, this is a
        // same-element requirement that cannot be expressed with only one
        // type parameter.
        if (genericParam->isParameterPack() != reduced->isParameterPack())
          continue;

        if (reduced->isTypeParameter()) {
          ctx.Diags.diagnose(loc, diag::requires_generic_params_made_equal,
                             genericParam, result->getSugaredType(reduced))
            .warnUntilSwiftVersion(6);
        } else {
          ctx.Diags.diagnose(loc,
                             diag::requires_generic_param_made_equal_to_concrete,
                             genericParam)
            .warnUntilSwiftVersion(6);
        }
      }
    }

    if (!errorFlags.contains(GenericSignatureErrorFlags::HasInvalidRequirements)) {
      // Check invariants.
      result.verify();
    }

    if (rewriteCtx.getDebugOptions().contains(DebugFlags::Timers)) {
      rewriteCtx.endTimer("InferredGenericSignatureRequest");
      llvm::dbgs() << result << "\n";
    }

    return GenericSignatureWithError(result, errorFlags);
  }
}
