Skip to content

Commit cb1cb20

Browse files
committed
[CSOptimizer] Use matchCallArguments to establish argument-to-parameter relationships
This helps to find defaulted parameter positions as well.
1 parent 14e2a16 commit cb1cb20

File tree

1 file changed

+55
-22
lines changed

1 file changed

+55
-22
lines changed

lib/Sema/CSOptimizer.cpp

+55-22
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,13 @@ static void determineBestChoicesInContext(
116116
if (!argumentList || cs.containsIDEInspectionTarget(argumentList))
117117
return;
118118

119+
SmallVector<FunctionType::Param, 8> argsWithLabels;
120+
{
121+
argsWithLabels.append(argFuncType->getParams().begin(),
122+
argFuncType->getParams().end());
123+
FunctionType::relabelParams(argsWithLabels, argumentList);
124+
}
125+
119126
SmallVector<SmallVector<std::pair<Type, /*fromLiteral=*/bool>, 2>, 2>
120127
candidateArgumentTypes;
121128
candidateArgumentTypes.resize(argFuncType->getNumParams());
@@ -159,6 +166,27 @@ static void determineBestChoicesInContext(
159166
resultTypes.push_back(resultType);
160167
}
161168

169+
// Match arguments to the given overload choice.
170+
auto matchArguments =
171+
[&](OverloadChoice choice,
172+
FunctionType *overloadType) -> Optional<MatchCallArgumentResult> {
173+
auto *decl = choice.getDeclOrNull();
174+
assert(decl);
175+
176+
auto hasAppliedSelf =
177+
decl->hasCurriedSelf() &&
178+
doesMemberRefApplyCurriedSelf(choice.getBaseType(), decl);
179+
180+
ParameterListInfo paramListInfo(overloadType->getParams(), decl,
181+
hasAppliedSelf);
182+
183+
MatchCallArgumentListener listener;
184+
return matchCallArguments(argsWithLabels, overloadType->getParams(),
185+
paramListInfo,
186+
argumentList->getFirstTrailingClosureIndex(),
187+
/*allow fixes*/ false, listener, None);
188+
};
189+
162190
// The choice with the best score.
163191
double bestScore = 0.0;
164192
SmallVector<std::pair<Constraint *, double>, 2> favoredChoices;
@@ -182,27 +210,35 @@ static void determineBestChoicesInContext(
182210
return;
183211
}
184212

185-
ParameterListInfo paramListInfo(
186-
overloadType->getParams(), decl,
187-
hasAppliedSelf(cs, choice->getOverloadChoice()));
213+
auto matchings =
214+
matchArguments(choice->getOverloadChoice(), overloadType);
215+
if (!matchings)
216+
return;
188217

189218
double score = 0.0;
190-
for (unsigned i = 0, n = overloadType->getNumParams(); i != n; ++i) {
191-
const auto &param = overloadType->getParams()[i];
192-
193-
if (i >= candidateArgumentTypes.size()) {
194-
// If parameter has a default - continue matching,
195-
// all of the subsequence parameters should have defaults
196-
// as well, if they don't the overload choice in not viable.
197-
if (paramListInfo.hasDefaultArgument(i))
198-
continue;
219+
for (unsigned paramIdx = 0, n = overloadType->getNumParams();
220+
paramIdx != n; ++paramIdx) {
221+
const auto &param = overloadType->getParams()[paramIdx];
222+
223+
auto argIndices = matchings->parameterBindings[paramIdx];
224+
switch (argIndices.size()) {
225+
case 0:
226+
// Current parameter is defaulted.
227+
continue;
228+
229+
case 1:
230+
// One-to-one match between argument and parameter.
231+
break;
199232

200-
// Early return because this overload choice is not viable
201-
// without default value for the current parameter.
233+
default:
234+
// Cannot deal with multiple possible matchings at the moment.
202235
return;
203236
}
204237

205-
if (candidateArgumentTypes[i].empty())
238+
auto argIdx = argIndices.front();
239+
240+
// Looks like there is nothing know about the argument.
241+
if (candidateArgumentTypes[argIdx].empty())
206242
continue;
207243

208244
const auto paramFlags = param.getParameterFlags();
@@ -220,9 +256,6 @@ static void determineBestChoicesInContext(
220256
if (paramType->is<FunctionType>())
221257
continue;
222258

223-
if (candidateArgumentTypes[i].empty())
224-
continue;
225-
226259
// Check protocol requirement(s) if this parameter is a
227260
// generic parameter type.
228261
GenericSignature::RequiredProtocols protocolRequirements;
@@ -248,11 +281,11 @@ static void determineBestChoicesInContext(
248281
// all bound concrete types, we consider this is mismatch
249282
// at this parameter position and remove the overload choice
250283
// from consideration.
251-
252284
double bestCandidateScore = 0;
253-
llvm::BitVector mismatches(candidateArgumentTypes[i].size());
285+
llvm::BitVector mismatches(candidateArgumentTypes[argIdx].size());
254286

255-
for (unsigned candidateIdx : indices(candidateArgumentTypes[i])) {
287+
for (unsigned candidateIdx :
288+
indices(candidateArgumentTypes[argIdx])) {
256289
// If one of the candidates matched exactly there is no reason
257290
// to continue checking.
258291
if (bestCandidateScore == 1)
@@ -262,7 +295,7 @@ static void determineBestChoicesInContext(
262295
bool isLiteralDefault;
263296

264297
std::tie(candidateType, isLiteralDefault) =
265-
candidateArgumentTypes[i][candidateIdx];
298+
candidateArgumentTypes[argIdx][candidateIdx];
266299

267300
// `inout` parameter accepts only l-value argument.
268301
if (paramFlags.isInOut() && !candidateType->is<LValueType>()) {

0 commit comments

Comments
 (0)