mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[ConstraintSystem] Move FailureDiagnostic::getFunctionArgApplyInfo
into `ConstraintSystem`.
This commit is contained in:
@@ -3377,6 +3377,164 @@ ConstraintSystem::getArgumentInfo(ConstraintLocator *locator) {
|
||||
return None;
|
||||
}
|
||||
|
||||
/// Given an apply expr, returns true if it is expected to have a direct callee
|
||||
/// overload, resolvable using `getChoiceFor`. Otherwise, returns false.
|
||||
static bool shouldHaveDirectCalleeOverload(const CallExpr *callExpr) {
|
||||
auto *fnExpr = callExpr->getDirectCallee();
|
||||
|
||||
// An apply of an apply/subscript doesn't have a direct callee.
|
||||
if (isa<ApplyExpr>(fnExpr) || isa<SubscriptExpr>(fnExpr))
|
||||
return false;
|
||||
|
||||
// Applies of closures don't have callee overloads.
|
||||
if (isa<ClosureExpr>(fnExpr))
|
||||
return false;
|
||||
|
||||
// No direct callee for a try!/try?.
|
||||
if (isa<ForceTryExpr>(fnExpr) || isa<OptionalTryExpr>(fnExpr))
|
||||
return false;
|
||||
|
||||
// If we have an intermediate cast, there's no direct callee.
|
||||
if (isa<ExplicitCastExpr>(fnExpr))
|
||||
return false;
|
||||
|
||||
// No direct callee for an if expr.
|
||||
if (isa<IfExpr>(fnExpr))
|
||||
return false;
|
||||
|
||||
// Assume that anything else would have a direct callee.
|
||||
return true;
|
||||
}
|
||||
|
||||
Type ConstraintSystem::resolveInterfaceType(Type type) const {
|
||||
auto resolvedType = type.transform([&](Type type) -> Type {
|
||||
if (auto *tvt = type->getAs<TypeVariableType>()) {
|
||||
// If this type variable is for a generic parameter, return that.
|
||||
if (auto *gp = tvt->getImpl().getGenericParameter())
|
||||
return gp;
|
||||
|
||||
// Otherwise resolve its fixed type, mapped out of context.
|
||||
if (auto fixed = getFixedType(tvt))
|
||||
return resolveInterfaceType(fixed->mapTypeOutOfContext());
|
||||
|
||||
return getRepresentative(tvt);
|
||||
}
|
||||
if (auto *dmt = type->getAs<DependentMemberType>()) {
|
||||
// For a dependent member, first resolve the base.
|
||||
auto newBase = resolveInterfaceType(dmt->getBase());
|
||||
|
||||
// Then reconstruct using its associated type.
|
||||
assert(dmt->getAssocType());
|
||||
return DependentMemberType::get(newBase, dmt->getAssocType());
|
||||
}
|
||||
return type;
|
||||
});
|
||||
|
||||
assert(!resolvedType->hasArchetype());
|
||||
return resolvedType;
|
||||
}
|
||||
|
||||
Optional<FunctionArgApplyInfo>
|
||||
ConstraintSystem::getFunctionArgApplyInfo(ConstraintLocator *locator) {
|
||||
auto *anchor = locator->getAnchor();
|
||||
auto path = locator->getPath();
|
||||
|
||||
// Look for the apply-arg-to-param element in the locator's path. We may
|
||||
// have to look through other elements that are generated from an argument
|
||||
// conversion such as GenericArgument for an optional-to-optional conversion,
|
||||
// and OptionalPayload for a value-to-optional conversion.
|
||||
auto iter = path.rbegin();
|
||||
auto applyArgElt = locator->findLast<LocatorPathElt::ApplyArgToParam>(iter);
|
||||
if (!applyArgElt)
|
||||
return None;
|
||||
|
||||
auto nextIter = iter + 1;
|
||||
assert(!locator->findLast<LocatorPathElt::ApplyArgToParam>(nextIter) &&
|
||||
"Multiple ApplyArgToParam components?");
|
||||
|
||||
// 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, ConstraintLocator::getSummaryFlagsForPath(argPath));
|
||||
|
||||
auto *argExpr = simplifyLocatorToAnchor(argLocator);
|
||||
|
||||
// If we were unable to simplify down to the argument expression, we don't
|
||||
// know what this is.
|
||||
if (!argExpr)
|
||||
return None;
|
||||
|
||||
Optional<OverloadChoice> choice;
|
||||
Type rawFnType;
|
||||
auto *calleeLocator = getCalleeLocator(argLocator);
|
||||
if (auto overload = findSelectedOverloadFor(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->openedType;
|
||||
} 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 = dyn_cast<CallExpr>(anchor)) {
|
||||
assert(!shouldHaveDirectCalleeOverload(call) &&
|
||||
"Should we have resolved a callee for this?");
|
||||
rawFnType = getType(call->getFn());
|
||||
} else {
|
||||
// FIXME: ArgumentMismatchFailure is currently used from CSDiag, meaning
|
||||
// we can end up a BinaryExpr here with an unresolved callee. It should be
|
||||
// possible to remove this once we've gotten rid of the old CSDiag logic
|
||||
// and just assert that we have a CallExpr.
|
||||
auto *apply = cast<ApplyExpr>(anchor);
|
||||
rawFnType = getType(apply->getFn());
|
||||
}
|
||||
}
|
||||
|
||||
// Try to resolve the function type by loading lvalues and looking through
|
||||
// optional types, which can occur for expressions like `fn?(5)`.
|
||||
auto *fnType = simplifyType(rawFnType)
|
||||
->getRValueType()
|
||||
->lookThroughAllOptionalTypes()
|
||||
->getAs<FunctionType>();
|
||||
if (!fnType)
|
||||
return None;
|
||||
|
||||
// Resolve the interface type for the function. Note that this may not be a
|
||||
// function type, for example it could be a generic parameter.
|
||||
Type fnInterfaceType;
|
||||
auto *callee = choice ? choice->getDeclOrNull() : nullptr;
|
||||
if (callee && callee->hasInterfaceType()) {
|
||||
// If we have a callee with an interface type, we can use it. This is
|
||||
// preferable to resolveInterfaceType, as this will allow us to get a
|
||||
// GenericFunctionType for generic decls.
|
||||
//
|
||||
// Note that it's possible to find a callee without an interface type. This
|
||||
// can happen for example with closure parameters, where the interface type
|
||||
// isn't set until the solution is applied. In that case, use
|
||||
// resolveInterfaceType.
|
||||
fnInterfaceType = callee->getInterfaceType();
|
||||
|
||||
// Strip off the curried self parameter if necessary.
|
||||
if (hasAppliedSelf(*this, *choice))
|
||||
fnInterfaceType = fnInterfaceType->castTo<AnyFunctionType>()->getResult();
|
||||
|
||||
if (auto *fn = fnInterfaceType->getAs<AnyFunctionType>()) {
|
||||
assert(fn->getNumParams() == fnType->getNumParams() &&
|
||||
"Parameter mismatch?");
|
||||
(void)fn;
|
||||
}
|
||||
} else {
|
||||
fnInterfaceType = resolveInterfaceType(rawFnType);
|
||||
}
|
||||
|
||||
auto argIdx = applyArgElt->getArgIdx();
|
||||
auto paramIdx = applyArgElt->getParamIdx();
|
||||
|
||||
return FunctionArgApplyInfo(getParentExpr(argExpr), argExpr, argIdx,
|
||||
simplifyType(getType(argExpr)),
|
||||
paramIdx, fnInterfaceType, fnType, callee);
|
||||
}
|
||||
|
||||
bool constraints::isKnownKeyPathType(Type type) {
|
||||
if (auto *BGT = type->getAs<BoundGenericType>())
|
||||
return isKnownKeyPathDecl(type->getASTContext(), BGT->getDecl());
|
||||
|
||||
Reference in New Issue
Block a user