mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[ConstraintSystem] Fix bug of argument reordering in matchCallArguments
This commit is contained in:
@@ -651,58 +651,67 @@ matchCallArguments(SmallVectorImpl<AnyFunctionType::Param> &args,
|
||||
// parameter (or even worse - OoO parameter with label re-naming),
|
||||
// we most likely have no idea what would be the best
|
||||
// diagnostic for this situation, so let's just try to re-label.
|
||||
auto isOutOfOrderArgument = [&](bool hadLabelMismatch, unsigned argIdx,
|
||||
unsigned prevArgIdx) {
|
||||
if (hadLabelMismatch)
|
||||
auto isOutOfOrderArgument = [&](unsigned toParamIdx, unsigned fromArgIdx,
|
||||
unsigned toArgIdx) {
|
||||
if (fromArgIdx <= toArgIdx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto newLabel = args[argIdx].getLabel();
|
||||
auto oldLabel = args[prevArgIdx].getLabel();
|
||||
auto newLabel = args[fromArgIdx].getLabel();
|
||||
auto oldLabel = args[toArgIdx].getLabel();
|
||||
|
||||
unsigned actualIndex = prevArgIdx;
|
||||
for (; actualIndex != argIdx; ++actualIndex) {
|
||||
if (newLabel != params[toParamIdx].getLabel()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto paramIdx = toParamIdx + 1;
|
||||
for (; paramIdx < params.size(); ++paramIdx) {
|
||||
// Looks like new position (excluding defaulted parameters),
|
||||
// has a valid label.
|
||||
if (newLabel == params[actualIndex].getLabel())
|
||||
if (oldLabel == params[paramIdx].getLabel())
|
||||
break;
|
||||
|
||||
// If we are moving the the position with a different label
|
||||
// and there is no default value for it, can't diagnose the
|
||||
// problem as a simple re-ordering.
|
||||
if (!paramInfo.hasDefaultArgument(actualIndex))
|
||||
if (!paramInfo.hasDefaultArgument(paramIdx))
|
||||
return false;
|
||||
}
|
||||
|
||||
for (unsigned i = actualIndex + 1, n = params.size(); i != n; ++i) {
|
||||
if (oldLabel == params[i].getLabel())
|
||||
break;
|
||||
|
||||
if (!paramInfo.hasDefaultArgument(i))
|
||||
return false;
|
||||
// label was not found
|
||||
if (paramIdx == params.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
unsigned argIdx = 0;
|
||||
SmallVector<unsigned, 4> paramToArgMap;
|
||||
paramToArgMap.reserve(params.size());
|
||||
{
|
||||
unsigned argIdx = 0;
|
||||
for (const auto &binding : parameterBindings) {
|
||||
paramToArgMap.push_back(argIdx);
|
||||
argIdx += binding.size();
|
||||
}
|
||||
}
|
||||
|
||||
// Enumerate the parameters and their bindings to see if any arguments are
|
||||
// our of order
|
||||
bool hadLabelMismatch = false;
|
||||
for (auto binding : parameterBindings) {
|
||||
for (auto boundArgIdx : binding) {
|
||||
for (const auto paramIdx : indices(params)) {
|
||||
const auto toArgIdx = paramToArgMap[paramIdx];
|
||||
const auto &binding = parameterBindings[paramIdx];
|
||||
for (const auto paramBindIdx : indices(binding)) {
|
||||
// We've found the parameter that has an out of order
|
||||
// argument, and know the indices of the argument that
|
||||
// needs to move (fromArgIdx) and the argument location
|
||||
// it should move to (toArgIdx).
|
||||
auto fromArgIdx = boundArgIdx;
|
||||
auto toArgIdx = argIdx;
|
||||
const auto fromArgIdx = binding[paramBindIdx];
|
||||
|
||||
// If there is no re-ordering going on, and index is past
|
||||
// the number of parameters, it could only mean that this
|
||||
// is variadic parameter, so let's just move on.
|
||||
if (fromArgIdx == toArgIdx && toArgIdx >= params.size()) {
|
||||
// Does nothing for variadic tail.
|
||||
if (params[paramIdx].isVariadic() && paramBindIdx > 0) {
|
||||
assert(args[fromArgIdx].getLabel().empty());
|
||||
argIdx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -711,40 +720,40 @@ matchCallArguments(SmallVectorImpl<AnyFunctionType::Param> &args,
|
||||
// one argument requires label and another one doesn't, but caller
|
||||
// doesn't provide either, problem is going to be identified as
|
||||
// out-of-order argument instead of label mismatch.
|
||||
auto expectedLabel = params[toArgIdx].getLabel();
|
||||
auto argumentLabel = args[fromArgIdx].getLabel();
|
||||
const auto expectedLabel = params[paramIdx].getLabel();
|
||||
const auto argumentLabel = args[fromArgIdx].getLabel();
|
||||
|
||||
if (argumentLabel != expectedLabel) {
|
||||
// - The parameter is unnamed, in which case we try to fix the
|
||||
// problem by removing the name.
|
||||
if (expectedLabel.empty()) {
|
||||
hadLabelMismatch = true;
|
||||
if (listener.extraneousLabel(toArgIdx))
|
||||
if (listener.extraneousLabel(paramIdx))
|
||||
return true;
|
||||
// - The argument is unnamed, in which case we try to fix the
|
||||
// problem by adding the name.
|
||||
} else if (argumentLabel.empty()) {
|
||||
hadLabelMismatch = true;
|
||||
if (listener.missingLabel(toArgIdx))
|
||||
if (listener.missingLabel(paramIdx))
|
||||
return true;
|
||||
// - The argument label has a typo at the same position.
|
||||
} else if (fromArgIdx == toArgIdx) {
|
||||
hadLabelMismatch = true;
|
||||
if (listener.incorrectLabel(toArgIdx))
|
||||
return true;
|
||||
if (listener.incorrectLabel(paramIdx))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (boundArgIdx == argIdx) {
|
||||
if (fromArgIdx == toArgIdx) {
|
||||
// If the argument is in the right location, just continue
|
||||
argIdx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// This situation looks like out-of-order argument but it's hard
|
||||
// to say exactly without considering other factors, because it
|
||||
// could be invalid labeling too.
|
||||
if (isOutOfOrderArgument(hadLabelMismatch, fromArgIdx, toArgIdx))
|
||||
if (!hadLabelMismatch &&
|
||||
isOutOfOrderArgument(paramIdx, fromArgIdx, toArgIdx))
|
||||
return listener.outOfOrderArgument(fromArgIdx, toArgIdx);
|
||||
|
||||
SmallVector<Identifier, 8> expectedLabels;
|
||||
|
||||
Reference in New Issue
Block a user