Skip to content

Commit 21a8b3c

Browse files
committed
[Diagnostics] Port tailored diagnostics for missing dynamicallyCall methods
1 parent 328143a commit 21a8b3c

File tree

3 files changed

+58
-1
lines changed

3 files changed

+58
-1
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3211,6 +3211,9 @@ bool MissingMemberFailure::diagnoseAsError() {
32113211
if (!anchor || !baseExpr)
32123212
return false;
32133213

3214+
if (diagnoseForDynamicCallable())
3215+
return true;
3216+
32143217
auto baseType = resolveType(getBaseType())->getWithoutSpecifierType();
32153218

32163219
DeclNameLoc nameLoc(anchor->getStartLoc());
@@ -3382,6 +3385,26 @@ bool MissingMemberFailure::diagnoseAsError() {
33823385
return true;
33833386
}
33843387

3388+
bool MissingMemberFailure::diagnoseForDynamicCallable() const {
3389+
auto *locator = getLocator();
3390+
if (!locator->isLastElement<LocatorPathElt::DynamicCallable>())
3391+
return false;
3392+
3393+
auto memberName = getName();
3394+
auto arguments = memberName.getArgumentNames();
3395+
assert(arguments.size() == 1);
3396+
3397+
auto &ctx = getASTContext();
3398+
if (arguments.front() == ctx.Id_withKeywordArguments) {
3399+
auto anchor = getAnchor();
3400+
emitDiagnostic(anchor->getLoc(),
3401+
diag::missing_dynamic_callable_kwargs_method, getBaseType());
3402+
return true;
3403+
}
3404+
3405+
return false;
3406+
}
3407+
33853408
bool InvalidMemberRefOnExistential::diagnoseAsError() {
33863409
auto *anchor = getRawAnchor();
33873410

lib/Sema/CSDiagnostics.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,12 @@ class MissingMemberFailure final : public InvalidMemberRefFailure {
11481148
bool diagnoseAsError() override;
11491149

11501150
private:
1151+
/// Tailored diagnostics for missing special `@dynamicCallable` methods
1152+
/// e.g. if caller expects `dynamicallyCall(withKeywordArguments:)`
1153+
/// overload to be present, but a class marked as `@dynamicCallable`
1154+
/// defines only `dynamicallyCall(withArguments:)` variant.
1155+
bool diagnoseForDynamicCallable() const;
1156+
11511157
static DeclName findCorrectEnumCaseName(Type Ty,
11521158
TypoCorrectionResults &corrections,
11531159
DeclName memberName);

lib/Sema/CSSimplify.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7814,7 +7814,35 @@ ConstraintSystem::simplifyDynamicCallableApplicableFnConstraint(
78147814
choices.push_back(
78157815
OverloadChoice(type2, candidate, FunctionRefKind::SingleApply));
78167816
}
7817-
if (choices.empty()) return SolutionKind::Error;
7817+
7818+
if (choices.empty()) {
7819+
if (!shouldAttemptFixes())
7820+
return SolutionKind::Error;
7821+
7822+
// TODO(diagnostics): This is not going to be necessary once
7823+
// `@dynamicCallable` uses existing `member` machinery.
7824+
7825+
auto memberName = DeclName(
7826+
ctx, ctx.Id_dynamicallyCall,
7827+
{useKwargsMethod ? ctx.Id_withKeywordArguments : ctx.Id_withArguments});
7828+
7829+
auto *fix = DefineMemberBasedOnUse::create(
7830+
*this, desugar2, memberName,
7831+
getConstraintLocator(loc, ConstraintLocator::DynamicCallable));
7832+
7833+
if (recordFix(fix))
7834+
return SolutionKind::Error;
7835+
7836+
recordPotentialHole(tv);
7837+
7838+
Type(func1).visit([&](Type type) {
7839+
if (auto *typeVar = type->getAs<TypeVariableType>())
7840+
recordPotentialHole(typeVar);
7841+
});
7842+
7843+
return SolutionKind::Solved;
7844+
}
7845+
78187846
addOverloadSet(tv, choices, DC, loc);
78197847

78207848
// Create a type variable for the argument to the `dynamicallyCall` method.

0 commit comments

Comments
 (0)