Repository: apple/swift
File: lib/Sema/ConstraintSystem.cpp (C++)

Code before:
  // and OptionalInjection for a value-to-optional conversion.
  auto iter = path.rbegin();
  auto applyArgElt = locator->findLast<LocatorPathElt::ApplyArgToParam>(iter);
  if (!applyArgElt)
    return std::nullopt;

#ifndef NDEBUG
  auto nextIter = iter + 1;
  assert(!locator->findLast<LocatorPathElt::ApplyArgToParam>(nextIter) &&
         "Multiple ApplyArgToParam components?");
#endif

  // Form a new locator that ends at the apply-arg-to-param element, and
  // simplify it to get the full argument expression.
  auto argPath = path.drop_back(iter - path.rbegin());
  auto *argLocator = getConstraintLocator(anchor, argPath);

  auto *argExpr = castToExpr(simplifyLocatorToAnchor(argLocator));
  auto *argList = getArgumentList(argLocator);

  if (!argList) {
    if (auto *kp = getAsExpr<KeyPathExpr>(anchor)) {
      if (auto componentElt =
              argLocator->findLast<LocatorPathElt::KeyPathComponent>()) {
        auto &component = kp->getComponents()[componentElt->getIndex()];
        argList = component.getArgs();

        if (argList && !argExpr) {
          argExpr = kp;
        }
      }
    }
  }

  // If we were unable to simplify down to the argument expression or find the
  // argument list, we don't know what this is.
  if (!argExpr || !argList)
    return std::nullopt;

  std::optional<OverloadChoice> choice;
  Type rawFnType;
  auto *calleeLocator = getCalleeLocator(argLocator);
  if (auto overload = getOverloadChoiceIfAvailable(calleeLocator)) {
    // If we have resolved an overload for the callee, then use that to get the
    // function type and callee.
    choice = overload->choice;
    rawFnType = overload->adjustedOpenedType;
  } else {
    // If we didn't resolve an overload for the callee, we should be dealing
    // with a call of an arbitrary function expr.
    if (auto *call = getAsExpr<CallExpr>(anchor)) {

Review comment (suggestion):
This looks like a workaround, the underlying issue here is that key path component that represents an application didn't register the argument list like normal applies do and this needs to happen during constraint generation (check uses of `recordArgumentList` in there).

Code after:
    return std::nullopt;

#ifndef NDEBUG
  auto nextIter = iter + 1;
  assert(!locator->findLast<LocatorPathElt::ApplyArgToParam>(nextIter) &&
         "Multiple ApplyArgToParam components?");
#endif

  // Form a new locator that ends at the apply-arg-to-param element, and
  // simplify it to get the full argument expression.
  auto argPath = path.drop_back(iter - path.rbegin());
  auto *argLocator = getConstraintLocator(anchor, argPath);

  auto *argExpr = castToExpr(simplifyLocatorToAnchor(argLocator));

  // If we were unable to simplify down to the argument expression, we don't
  // know what this is.
  if (!argExpr)
    return std::nullopt;

  auto *argList = getArgumentList(argLocator);
  if (!argList)
    return std::nullopt;

  std::optional<OverloadChoice> choice;
  Type rawFnType;
  auto *calleeLocator = getCalleeLocator(argLocator);
  if (auto overload = getOverloadChoiceIfAvailable(calleeLocator)) {
    // If we have resolved an overload for the callee, then use that to get the
    // function type and callee.
    choice = overload->choice;
    rawFnType = overload->adjustedOpenedType;
  } else {
    // If we didn't resolve an overload for the callee, we should be dealing
    // with a call of an arbitrary function expr.
    auto *call = castToExpr<CallExpr>(anchor);
    rawFnType = getType(call->getFn());

    // If callee couldn't be resolved due to expression
    // issues e.g. it's a reference to an invalid member
    // let's just return here.
    if (simplifyType(rawFnType)->is<ErrorType>())
      return std::nullopt;

    // A tuple construction is spelled in the AST as a function call, but
    // is really more like a tuple conversion.
    if (auto metaTy = simplifyType(rawFnType)->getAs<MetatypeType>()) {
      if (metaTy->getInstanceType()->is<TupleType>())
        return std::nullopt;
    }