mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge pull request #23085 from xedin/diag-OoO-arguments
[ConstraintSystem] Diagnose out-of-order arguments via fixes
This commit is contained in:
@@ -44,8 +44,9 @@ bool MatchCallArgumentListener::incorrectLabel(unsigned paramIdx) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void MatchCallArgumentListener::outOfOrderArgument(unsigned argIdx,
|
||||
bool MatchCallArgumentListener::outOfOrderArgument(unsigned argIdx,
|
||||
unsigned prevArgIdx) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MatchCallArgumentListener::relabelArguments(ArrayRef<Identifier> newNames){
|
||||
@@ -573,9 +574,47 @@ matchCallArguments(ArrayRef<AnyFunctionType::Param> args,
|
||||
// If any arguments were provided out-of-order, check whether we have
|
||||
// violated any of the reordering rules.
|
||||
if (potentiallyOutOfOrder) {
|
||||
// If we've seen label failures and now there is an out-of-order
|
||||
// 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)
|
||||
return false;
|
||||
|
||||
auto newLabel = args[argIdx].getLabel();
|
||||
auto oldLabel = args[prevArgIdx].getLabel();
|
||||
|
||||
unsigned actualIndex = prevArgIdx;
|
||||
for (; actualIndex != argIdx; ++actualIndex) {
|
||||
// Looks like new position (excluding defaulted parameters),
|
||||
// has a valid label.
|
||||
if (newLabel == params[actualIndex].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 (!defaultMap.test(actualIndex))
|
||||
return false;
|
||||
}
|
||||
|
||||
for (unsigned i = actualIndex + 1, n = params.size(); i != n; ++i) {
|
||||
if (oldLabel == params[i].getLabel())
|
||||
break;
|
||||
|
||||
if (!defaultMap.test(i))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
unsigned argIdx = 0;
|
||||
// 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) {
|
||||
// We've found the parameter that has an out of order
|
||||
@@ -606,17 +645,20 @@ matchCallArguments(ArrayRef<AnyFunctionType::Param> args,
|
||||
// - 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))
|
||||
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))
|
||||
return true;
|
||||
// - The argument label has a typo at the same position.
|
||||
} else if (fromArgIdx == toArgIdx &&
|
||||
listener.incorrectLabel(toArgIdx)) {
|
||||
return true;
|
||||
} else if (fromArgIdx == toArgIdx) {
|
||||
hadLabelMismatch = true;
|
||||
if (listener.incorrectLabel(toArgIdx))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -626,8 +668,18 @@ matchCallArguments(ArrayRef<AnyFunctionType::Param> args,
|
||||
continue;
|
||||
}
|
||||
|
||||
listener.outOfOrderArgument(fromArgIdx, toArgIdx);
|
||||
return true;
|
||||
// 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))
|
||||
return listener.outOfOrderArgument(fromArgIdx, toArgIdx);
|
||||
|
||||
SmallVector<Identifier, 8> expectedLabels;
|
||||
llvm::transform(params, std::back_inserter(expectedLabels),
|
||||
[](const AnyFunctionType::Param ¶m) {
|
||||
return param.getLabel();
|
||||
});
|
||||
return listener.relabelArguments(expectedLabels);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -798,11 +850,14 @@ getCalleeDeclAndArgs(ConstraintSystem &cs,
|
||||
|
||||
class ArgumentFailureTracker : public MatchCallArgumentListener {
|
||||
ConstraintSystem &CS;
|
||||
SmallVectorImpl<ParamBinding> &Bindings;
|
||||
ConstraintLocatorBuilder Locator;
|
||||
|
||||
public:
|
||||
ArgumentFailureTracker(ConstraintSystem &cs, ConstraintLocatorBuilder locator)
|
||||
: CS(cs), Locator(locator) {}
|
||||
ArgumentFailureTracker(ConstraintSystem &cs,
|
||||
SmallVectorImpl<ParamBinding> &bindings,
|
||||
ConstraintLocatorBuilder locator)
|
||||
: CS(cs), Bindings(bindings), Locator(locator) {}
|
||||
|
||||
bool missingLabel(unsigned paramIndex) override {
|
||||
return !CS.shouldAttemptFixes();
|
||||
@@ -816,6 +871,16 @@ public:
|
||||
return !CS.shouldAttemptFixes();
|
||||
}
|
||||
|
||||
bool outOfOrderArgument(unsigned argIdx, unsigned prevArgIdx) override {
|
||||
if (CS.shouldAttemptFixes()) {
|
||||
auto *fix = MoveOutOfOrderArgument::create(
|
||||
CS, argIdx, prevArgIdx, Bindings, CS.getConstraintLocator(Locator));
|
||||
return CS.recordFix(fix);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool relabelArguments(ArrayRef<Identifier> newLabels) override {
|
||||
if (!CS.shouldAttemptFixes())
|
||||
return true;
|
||||
@@ -883,8 +948,8 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments(
|
||||
}
|
||||
|
||||
// Match up the call arguments to the parameters.
|
||||
ArgumentFailureTracker listener(cs, locator);
|
||||
SmallVector<ParamBinding, 4> parameterBindings;
|
||||
ArgumentFailureTracker listener(cs, parameterBindings, locator);
|
||||
if (constraints::matchCallArguments(argsWithLabels, params,
|
||||
defaultMap,
|
||||
hasTrailingClosure,
|
||||
@@ -5965,6 +6030,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
|
||||
case FixKind::AllowInvalidPartialApplication:
|
||||
case FixKind::AllowInvalidInitRef:
|
||||
case FixKind::AllowClosureParameterDestructuring:
|
||||
case FixKind::MoveOutOfOrderArgument:
|
||||
llvm_unreachable("handled elsewhere");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user