Skip to content

Commit 0c1330d

Browse files
authored
[CS] Resolve callees for callAsFunction .member exprs (#28604)
[CS] Resolve callees for callAsFunction `.member` exprs
2 parents 9dab211 + 8a83440 commit 0c1330d

File tree

4 files changed

+77
-25
lines changed

4 files changed

+77
-25
lines changed

lib/Sema/CSApply.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2385,8 +2385,12 @@ namespace {
23852385

23862386
// If there was an argument, apply it.
23872387
if (auto arg = expr->getArgument()) {
2388-
auto callee = resolveConcreteDeclRef(selected.choice.getDecl(),
2389-
memberLocator);
2388+
// Find the callee. Note this may be different to the member being
2389+
// referenced for things like callAsFunction.
2390+
auto *calleeLoc = cs.getCalleeLocator(exprLoc);
2391+
auto calleeOverload = solution.getOverloadChoice(calleeLoc);
2392+
auto callee = resolveConcreteDeclRef(calleeOverload.choice.getDecl(),
2393+
calleeLoc);
23902394
ApplyExpr *apply = CallExpr::create(
23912395
ctx, result, arg, expr->getArgumentLabels(),
23922396
expr->getArgumentLabelLocs(), expr->hasTrailingClosure(),

lib/Sema/ConstraintSystem.cpp

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -475,31 +475,38 @@ ConstraintSystem::getCalleeLocator(ConstraintLocator *locator,
475475
if (isa<SubscriptExpr>(anchor))
476476
return getConstraintLocator(anchor, ConstraintLocator::SubscriptMember);
477477

478+
auto getSpecialFnCalleeLoc = [&](Type fnTy) -> ConstraintLocator * {
479+
// FIXME: We should probably assert that we don't get a type variable
480+
// here to make sure we only retrieve callee locators for resolved calls,
481+
// ensuring that callee locators don't change after binding a type.
482+
// Unfortunately CSDiag currently calls into getCalleeLocator, so all bets
483+
// are off. Once we remove that legacy diagnostic logic, we should be able
484+
// to assert here.
485+
fnTy = getFixedTypeRecursive(fnTy, /*wantRValue*/ true);
486+
487+
// For an apply of a metatype, we have a short-form constructor. Unlike
488+
// other locators to callees, these are anchored on the apply expression
489+
// rather than the function expr.
490+
if (fnTy->is<AnyMetatypeType>()) {
491+
return getConstraintLocator(anchor,
492+
{LocatorPathElt::ApplyFunction(),
493+
LocatorPathElt::ConstructorMember()});
494+
}
495+
496+
// Handle an apply of a nominal type which supports callAsFunction.
497+
if (fnTy->isCallableNominalType(DC))
498+
return getConstraintLocator(anchor, ConstraintLocator::ApplyFunction);
499+
500+
return nullptr;
501+
};
502+
478503
if (lookThroughApply) {
479504
if (auto *applyExpr = dyn_cast<ApplyExpr>(anchor)) {
480505
auto *fnExpr = applyExpr->getFn();
481506

482-
// FIXME: We should probably assert that we don't get a type variable
483-
// here to make sure we only retrieve callee locators for resolved calls,
484-
// ensuring that callee locators don't change after binding a type.
485-
// Unfortunately CSDiag currently calls into getCalleeLocator, so all bets
486-
// are off. Once we remove that legacy diagnostic logic, we should be able
487-
// to assert here.
488-
auto fnTy = getFixedTypeRecursive(getType(fnExpr), /*wantRValue*/ true);
489-
490-
// For an apply of a metatype, we have a short-form constructor. Unlike
491-
// other locators to callees, these are anchored on the apply expression
492-
// rather than the function expr.
493-
if (fnTy->is<AnyMetatypeType>()) {
494-
auto *fnLocator =
495-
getConstraintLocator(applyExpr, ConstraintLocator::ApplyFunction);
496-
return getConstraintLocator(fnLocator,
497-
ConstraintLocator::ConstructorMember);
498-
}
499-
500-
// Handle an apply of a nominal type which supports callAsFunction.
501-
if (fnTy->isCallableNominalType(DC))
502-
return getConstraintLocator(anchor, ConstraintLocator::ApplyFunction);
507+
// Handle special cases for applies of non-function types.
508+
if (auto *loc = getSpecialFnCalleeLoc(getType(fnExpr)))
509+
return loc;
503510

504511
// Otherwise fall through and look for locators anchored on the function
505512
// expr. For CallExprs, this can look through things like parens and
@@ -519,8 +526,23 @@ ConstraintSystem::getCalleeLocator(ConstraintLocator *locator,
519526
: ConstraintLocator::Member);
520527
}
521528

522-
if (isa<UnresolvedMemberExpr>(anchor))
523-
return getConstraintLocator(anchor, ConstraintLocator::UnresolvedMember);
529+
if (auto *UME = dyn_cast<UnresolvedMemberExpr>(anchor)) {
530+
auto *calleeLoc =
531+
getConstraintLocator(UME, ConstraintLocator::UnresolvedMember);
532+
533+
// Handle special cases for applies of non-function types.
534+
// FIXME: Consider re-designing the AST such that an unresolved member expr
535+
// with arguments uses a CallExpr, which would make this logic unnecessary
536+
// and clean up a bunch of other special cases. Doing so may require a bit
537+
// of hacking in CSGen though.
538+
if (UME->hasArguments()) {
539+
if (auto overload = findSelectedOverloadFor(calleeLoc)) {
540+
if (auto *loc = getSpecialFnCalleeLoc(overload->boundType))
541+
return loc;
542+
}
543+
}
544+
return calleeLoc;
545+
}
524546

525547
if (isa<MemberRefExpr>(anchor))
526548
return getConstraintLocator(anchor, ConstraintLocator::Member);
@@ -3356,11 +3378,17 @@ ConstraintSystem::getArgumentInfoLocator(ConstraintLocator *locator) {
33563378
if (!anchor)
33573379
return nullptr;
33583380

3381+
// Applies and unresolved member exprs can have callee locators that are
3382+
// dependent on the type of their function, which may not have been resolved
3383+
// yet. Therefore we need to handle them specially.
33593384
if (auto *apply = dyn_cast<ApplyExpr>(anchor)) {
33603385
auto *fnExpr = getArgumentLabelTargetExpr(apply->getFn());
33613386
return getConstraintLocator(fnExpr);
33623387
}
33633388

3389+
if (auto *UME = dyn_cast<UnresolvedMemberExpr>(anchor))
3390+
return getConstraintLocator(UME);
3391+
33643392
return getCalleeLocator(locator);
33653393
}
33663394

test/SILGen/default_arguments.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,3 +431,13 @@ func testCallableWithDefault(_ x: CallableWithDefault) {
431431
// CHECK: apply [[CALL_AS_FN]]([[I]], [[STR]], {{%[0-9]+}})
432432
x(y: 5)
433433
}
434+
435+
// FIXME: Arguably we shouldn't allow calling a constructor like this, as
436+
// we usually require the user write an explicit '.init'.
437+
struct WeirdUMEInitCase {
438+
static let ty = WeirdUMEInitCase.self
439+
init(_ x: Int = 0) {}
440+
}
441+
442+
let _: WeirdUMEInitCase = .ty()
443+
let _: WeirdUMEInitCase = .ty(5)

test/Sema/call_as_function_simple.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,3 +228,13 @@ struct PrivateCallable {
228228
func testAccessControl(_ x: PrivateCallable) {
229229
x(5) // expected-error {{'callAsFunction' is inaccessible due to 'private' protection level}}
230230
}
231+
232+
struct SR_11909 {
233+
static let s = SR_11909()
234+
func callAsFunction(_ x: Int = 0) -> SR_11909 { SR_11909() }
235+
}
236+
237+
func testDefaultsWithUMEs(_ x: SR_11909) {
238+
let _: SR_11909 = .s()
239+
let _: SR_11909 = .s(5)
240+
}

0 commit comments

Comments
 (0)