Skip to content

Commit b148ea0

Browse files
authored
Merge pull request #26444 from xedin/diag-missing-call-with-defaults
[CSDiagnostics] Teach `missing explicit call` fix to account for defa…
2 parents 22d7c28 + 5c82b57 commit b148ea0

File tree

3 files changed

+58
-12
lines changed

3 files changed

+58
-12
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2014,7 +2014,6 @@ bool MissingCallFailure::diagnoseAsError() {
20142014
case ConstraintLocator::ContextualType:
20152015
case ConstraintLocator::ApplyArgToParam: {
20162016
auto fnType = getType(baseExpr)->castTo<FunctionType>();
2017-
assert(fnType->getNumParams() == 0);
20182017
emitDiagnostic(baseExpr->getLoc(), diag::missing_nullary_call,
20192018
fnType->getResult())
20202019
.fixItInsertAfter(baseExpr->getEndLoc(), "()");

lib/Sema/CSSimplify.cpp

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,21 @@ matchCallArguments(ArrayRef<AnyFunctionType::Param> args,
714714
return listener.relabelArguments(actualArgNames);
715715
}
716716

717+
static bool hasAppliedSelf(ConstraintSystem &cs, const OverloadChoice &choice) {
718+
auto *decl = choice.getDeclOrNull();
719+
if (!decl)
720+
return false;
721+
722+
auto baseType = choice.getBaseType();
723+
if (baseType)
724+
baseType = cs.getFixedTypeRecursive(baseType, /*wantRValue=*/true);
725+
726+
// In most cases where we reference a declaration with a curried self
727+
// parameter, it gets dropped from the type of the reference.
728+
return decl->hasCurriedSelf() &&
729+
doesMemberRefApplyCurriedSelf(baseType, decl);
730+
}
731+
717732
/// Find the callee declaration and uncurry level for a given call
718733
/// locator.
719734
static std::tuple<ValueDecl *, bool, ArrayRef<Identifier>, bool,
@@ -828,16 +843,8 @@ getCalleeDeclAndArgs(ConstraintSystem &cs,
828843

829844
// If there's a declaration, return it.
830845
if (auto *decl = choice->getDeclOrNull()) {
831-
auto baseType = choice->getBaseType();
832-
if (baseType)
833-
baseType = cs.getFixedTypeRecursive(baseType, /*wantRValue=*/true);
834-
835-
// In most cases where we reference a declaration with a curried self
836-
// parameter, it gets dropped from the type of the reference.
837-
bool hasAppliedSelf =
838-
decl->hasCurriedSelf() && doesMemberRefApplyCurriedSelf(baseType, decl);
839-
return std::make_tuple(decl, hasAppliedSelf, argLabels, hasTrailingClosure,
840-
calleeLocator);
846+
return std::make_tuple(decl, hasAppliedSelf(cs, *choice), argLabels,
847+
hasTrailingClosure, calleeLocator);
841848
}
842849

843850
return std::make_tuple(nullptr, /*hasAppliedSelf=*/false, argLabels,
@@ -2197,9 +2204,34 @@ bool ConstraintSystem::repairFailures(
21972204
// of the function value e.g. `foo = bar` or `foo = .bar`
21982205
auto repairByInsertingExplicitCall = [&](Type srcType, Type dstType) -> bool {
21992206
auto fnType = srcType->getAs<FunctionType>();
2200-
if (!fnType || fnType->getNumParams() > 0)
2207+
if (!fnType)
22012208
return false;
22022209

2210+
// If argument is a function type and all of its parameters have
2211+
// default values, let's see whether error is related to missing
2212+
// explicit call.
2213+
if (fnType->getNumParams() > 0) {
2214+
auto *anchor =
2215+
simplifyLocatorToAnchor(*this, getConstraintLocator(locator));
2216+
2217+
if (!anchor)
2218+
return false;
2219+
2220+
auto *overload = findSelectedOverloadFor(anchor);
2221+
if (!(overload && overload->Choice.isDecl()))
2222+
return false;
2223+
2224+
const auto &choice = overload->Choice;
2225+
ParameterListInfo info(fnType->getParams(), choice.getDecl(),
2226+
hasAppliedSelf(*this, choice));
2227+
2228+
if (llvm::any_of(indices(fnType->getParams()),
2229+
[&info](const unsigned idx) {
2230+
return !info.hasDefaultArgument(idx);
2231+
}))
2232+
return false;
2233+
}
2234+
22032235
auto resultType = fnType->getResult();
22042236
// If this is situation like `x = { ... }` where closure results in
22052237
// `Void`, let's not suggest to call the closure, because it's most

test/Constraints/fixes.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ func forgotCall() {
3535
// As a call
3636
f5(f4) // expected-error{{function produces expected type 'B'; did you mean to call it with '()'?}}{{8-8=()}}
3737
f6(f4, f2) // expected-error{{function produces expected type 'B'; did you mean to call it with '()'?}}{{8-8=()}}
38+
// expected-error@-1 {{function produces expected type 'Int'; did you mean to call it with '()'?}} {{12-12=()}}
3839

3940
// With overloading: only one succeeds.
4041
a = createB // expected-error{{function produces expected type 'B'; did you mean to call it with '()'?}}
@@ -303,3 +304,17 @@ func coalesceWithParensRootExprFix() {
303304
// expected-note@-1{{coalesce using '??' to provide a default when the optional value contains 'nil'}}{{7-7=(}}{{19-19= ?? <#default value#>)}}
304305
// expected-note@-2{{force-unwrap using '!' to abort execution if the optional value contains 'nil'}}
305306
}
307+
308+
func test_explicit_call_with_overloads() {
309+
func foo(_: Int) {}
310+
311+
struct S {
312+
func foo(_: Int) -> Int { return 0 }
313+
func foo(_: Int = 32, _: String = "hello") -> Int {
314+
return 42
315+
}
316+
}
317+
318+
foo(S().foo)
319+
// expected-error@-1 {{function produces expected type 'Int'; did you mean to call it with '()'?}} {{14-14=()}}
320+
}

0 commit comments

Comments
 (0)