mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[QoI] Improve diagnostics for unresolved member with incorrect arguments
`FailureDiagnosis::visitUnresolvedMemberExpr` tries to use the same logic as `diagnoseSingleCandidateFailures` so instead of doing that let's remove some of the special handling and use `diagnoseSingleCandidateFailures` directly instead, which improves label diagnostics and handles more erroneous cases as well. Resolves: rdar://problem/31898542
This commit is contained in:
@@ -7205,7 +7205,8 @@ bool FailureDiagnosis::visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
|
||||
candidateInfo.suggestPotentialOverloads(E->getNameLoc().getBaseNameLoc());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
auto *argExpr = E->getArgument();
|
||||
auto candidateArgTy = candidateInfo[0].getArgumentType();
|
||||
|
||||
// Depending on how we matched, produce tailored diagnostics.
|
||||
@@ -7226,8 +7227,8 @@ bool FailureDiagnosis::visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
|
||||
|
||||
// If we have an exact match, then we must have an argument list, check it.
|
||||
if (candidateArgTy) {
|
||||
assert(E->getArgument() && "Exact match without argument?");
|
||||
if (!typeCheckArgumentChildIndependently(E->getArgument(), candidateArgTy,
|
||||
assert(argExpr && "Exact match without argument?");
|
||||
if (!typeCheckArgumentChildIndependently(argExpr, candidateArgTy,
|
||||
candidateInfo))
|
||||
return true;
|
||||
}
|
||||
@@ -7256,71 +7257,50 @@ bool FailureDiagnosis::visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
|
||||
case CC_Inaccessible:
|
||||
// Diagnose some simple and common errors.
|
||||
return candidateInfo.diagnoseSimpleErrors(E);
|
||||
|
||||
case CC_ArgumentLabelMismatch: { // Argument labels are not correct.
|
||||
auto argExpr = typeCheckArgumentChildIndependently(E->getArgument(),
|
||||
candidateArgTy,
|
||||
candidateInfo);
|
||||
if (!argExpr) return true;
|
||||
|
||||
// Construct the actual expected argument labels that our candidate
|
||||
// expected.
|
||||
assert(candidateArgTy &&
|
||||
"Candidate must expect an argument to have a label mismatch");
|
||||
SmallVector<Identifier, 2> argLabelsScratch;
|
||||
auto arguments = decomposeArgType(candidateArgTy,
|
||||
candidateInfo[0].getArgumentLabels(
|
||||
argLabelsScratch));
|
||||
|
||||
// TODO: This is probably wrong for varargs, e.g. calling "print" with the
|
||||
// wrong label.
|
||||
SmallVector<Identifier, 4> expectedNames;
|
||||
for (auto &arg : arguments)
|
||||
expectedNames.push_back(arg.Label);
|
||||
|
||||
return diagnoseArgumentLabelError(CS->TC, argExpr, expectedNames,
|
||||
/*isSubscript*/false);
|
||||
}
|
||||
|
||||
case CC_GeneralMismatch: // Something else is wrong.
|
||||
case CC_ArgumentCountMismatch: // This candidate has wrong # arguments.
|
||||
case CC_ArgumentLabelMismatch:
|
||||
case CC_ArgumentCountMismatch: {
|
||||
// If we have no argument, the candidates must have expected one.
|
||||
if (!E->getArgument()) {
|
||||
if (!argExpr) {
|
||||
if (!candidateArgTy)
|
||||
return false; // Candidate must be incorrect for some other reason.
|
||||
|
||||
|
||||
// Pick one of the arguments that are expected as an exemplar.
|
||||
if (candidateArgTy->isVoid()) {
|
||||
// If this member is () -> T, suggest adding parentheses.
|
||||
diagnose(E->getNameLoc(), diag::expected_parens_in_contextual_member,
|
||||
E->getName())
|
||||
.fixItInsertAfter(E->getEndLoc(), "()");
|
||||
.fixItInsertAfter(E->getEndLoc(), "()");
|
||||
} else {
|
||||
diagnose(E->getNameLoc(), diag::expected_argument_in_contextual_member,
|
||||
E->getName(), candidateArgTy);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
assert(argExpr && candidateArgTy && "Exact match without an argument?");
|
||||
return diagnoseSingleCandidateFailures(candidateInfo, E, argExpr,
|
||||
E->getArgumentLabels());
|
||||
}
|
||||
|
||||
case CC_GeneralMismatch: { // Something else is wrong.
|
||||
// If an argument value was specified, but this member expects no arguments,
|
||||
// then we fail with a nice error message.
|
||||
if (!candidateArgTy) {
|
||||
if (E->getArgument()->getType()->isVoid()) {
|
||||
if (argExpr->getType()->isVoid()) {
|
||||
diagnose(E->getNameLoc(), diag::unexpected_parens_in_contextual_member,
|
||||
E->getName())
|
||||
.fixItRemove(E->getArgument()->getSourceRange());
|
||||
.fixItRemove(E->getArgument()->getSourceRange());
|
||||
} else {
|
||||
diagnose(E->getNameLoc(), diag::unexpected_argument_in_contextual_member,
|
||||
E->getName())
|
||||
.highlight(E->getArgument()->getSourceRange());
|
||||
diagnose(E->getNameLoc(),
|
||||
diag::unexpected_argument_in_contextual_member, E->getName())
|
||||
.highlight(E->getArgument()->getSourceRange());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
assert(E->getArgument() && candidateArgTy &&
|
||||
"Exact match without an argument?");
|
||||
return !typeCheckArgumentChildIndependently(E->getArgument(), candidateArgTy,
|
||||
candidateInfo);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
llvm_unreachable("all cases should be handled");
|
||||
|
||||
Reference in New Issue
Block a user