mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[CSOptimizer] Use matchCallArguments to establish argument-to-parameter relationships
This helps to find defaulted parameter positions as well.
This commit is contained in:
@@ -116,6 +116,13 @@ static void determineBestChoicesInContext(
|
||||
if (!argumentList || cs.containsIDEInspectionTarget(argumentList))
|
||||
return;
|
||||
|
||||
SmallVector<FunctionType::Param, 8> argsWithLabels;
|
||||
{
|
||||
argsWithLabels.append(argFuncType->getParams().begin(),
|
||||
argFuncType->getParams().end());
|
||||
FunctionType::relabelParams(argsWithLabels, argumentList);
|
||||
}
|
||||
|
||||
SmallVector<SmallVector<std::pair<Type, /*fromLiteral=*/bool>, 2>, 2>
|
||||
candidateArgumentTypes;
|
||||
candidateArgumentTypes.resize(argFuncType->getNumParams());
|
||||
@@ -159,6 +166,27 @@ static void determineBestChoicesInContext(
|
||||
resultTypes.push_back(resultType);
|
||||
}
|
||||
|
||||
// Match arguments to the given overload choice.
|
||||
auto matchArguments =
|
||||
[&](OverloadChoice choice,
|
||||
FunctionType *overloadType) -> Optional<MatchCallArgumentResult> {
|
||||
auto *decl = choice.getDeclOrNull();
|
||||
assert(decl);
|
||||
|
||||
auto hasAppliedSelf =
|
||||
decl->hasCurriedSelf() &&
|
||||
doesMemberRefApplyCurriedSelf(choice.getBaseType(), decl);
|
||||
|
||||
ParameterListInfo paramListInfo(overloadType->getParams(), decl,
|
||||
hasAppliedSelf);
|
||||
|
||||
MatchCallArgumentListener listener;
|
||||
return matchCallArguments(argsWithLabels, overloadType->getParams(),
|
||||
paramListInfo,
|
||||
argumentList->getFirstTrailingClosureIndex(),
|
||||
/*allow fixes*/ false, listener, None);
|
||||
};
|
||||
|
||||
// The choice with the best score.
|
||||
double bestScore = 0.0;
|
||||
SmallVector<std::pair<Constraint *, double>, 2> favoredChoices;
|
||||
@@ -182,27 +210,35 @@ static void determineBestChoicesInContext(
|
||||
return;
|
||||
}
|
||||
|
||||
ParameterListInfo paramListInfo(
|
||||
overloadType->getParams(), decl,
|
||||
hasAppliedSelf(cs, choice->getOverloadChoice()));
|
||||
auto matchings =
|
||||
matchArguments(choice->getOverloadChoice(), overloadType);
|
||||
if (!matchings)
|
||||
return;
|
||||
|
||||
double score = 0.0;
|
||||
for (unsigned i = 0, n = overloadType->getNumParams(); i != n; ++i) {
|
||||
const auto ¶m = overloadType->getParams()[i];
|
||||
for (unsigned paramIdx = 0, n = overloadType->getNumParams();
|
||||
paramIdx != n; ++paramIdx) {
|
||||
const auto ¶m = overloadType->getParams()[paramIdx];
|
||||
|
||||
if (i >= candidateArgumentTypes.size()) {
|
||||
// If parameter has a default - continue matching,
|
||||
// all of the subsequence parameters should have defaults
|
||||
// as well, if they don't the overload choice in not viable.
|
||||
if (paramListInfo.hasDefaultArgument(i))
|
||||
continue;
|
||||
auto argIndices = matchings->parameterBindings[paramIdx];
|
||||
switch (argIndices.size()) {
|
||||
case 0:
|
||||
// Current parameter is defaulted.
|
||||
continue;
|
||||
|
||||
// Early return because this overload choice is not viable
|
||||
// without default value for the current parameter.
|
||||
case 1:
|
||||
// One-to-one match between argument and parameter.
|
||||
break;
|
||||
|
||||
default:
|
||||
// Cannot deal with multiple possible matchings at the moment.
|
||||
return;
|
||||
}
|
||||
|
||||
if (candidateArgumentTypes[i].empty())
|
||||
auto argIdx = argIndices.front();
|
||||
|
||||
// Looks like there is nothing know about the argument.
|
||||
if (candidateArgumentTypes[argIdx].empty())
|
||||
continue;
|
||||
|
||||
const auto paramFlags = param.getParameterFlags();
|
||||
@@ -220,9 +256,6 @@ static void determineBestChoicesInContext(
|
||||
if (paramType->is<FunctionType>())
|
||||
continue;
|
||||
|
||||
if (candidateArgumentTypes[i].empty())
|
||||
continue;
|
||||
|
||||
// Check protocol requirement(s) if this parameter is a
|
||||
// generic parameter type.
|
||||
GenericSignature::RequiredProtocols protocolRequirements;
|
||||
@@ -248,11 +281,11 @@ static void determineBestChoicesInContext(
|
||||
// all bound concrete types, we consider this is mismatch
|
||||
// at this parameter position and remove the overload choice
|
||||
// from consideration.
|
||||
|
||||
double bestCandidateScore = 0;
|
||||
llvm::BitVector mismatches(candidateArgumentTypes[i].size());
|
||||
llvm::BitVector mismatches(candidateArgumentTypes[argIdx].size());
|
||||
|
||||
for (unsigned candidateIdx : indices(candidateArgumentTypes[i])) {
|
||||
for (unsigned candidateIdx :
|
||||
indices(candidateArgumentTypes[argIdx])) {
|
||||
// If one of the candidates matched exactly there is no reason
|
||||
// to continue checking.
|
||||
if (bestCandidateScore == 1)
|
||||
@@ -262,7 +295,7 @@ static void determineBestChoicesInContext(
|
||||
bool isLiteralDefault;
|
||||
|
||||
std::tie(candidateType, isLiteralDefault) =
|
||||
candidateArgumentTypes[i][candidateIdx];
|
||||
candidateArgumentTypes[argIdx][candidateIdx];
|
||||
|
||||
// `inout` parameter accepts only l-value argument.
|
||||
if (paramFlags.isInOut() && !candidateType->is<LValueType>()) {
|
||||
|
||||
Reference in New Issue
Block a user