Skip to content

Commit bf0e9c7

Browse files
committed
[CS] Resolve callees for implicit callAsFunction
Add a case to getCalleeLocator to return the appropriate locator for a call to an implicit callAsFunction member reference. Resolves SR-11386 & SR-11778.
1 parent 778e130 commit bf0e9c7

File tree

5 files changed

+66
-1
lines changed

5 files changed

+66
-1
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7342,6 +7342,8 @@ ConstraintSystem::simplifyApplicableFnConstraint(
73427342
auto memberTy = createTypeVariable(memberLoc, /*options=*/0);
73437343
// TODO: Revisit this if `static func callAsFunction` is to be supported.
73447344
// Static member constraint requires `FunctionRefKind::DoubleApply`.
7345+
// TODO: Use a custom locator element to identify this member constraint
7346+
// instead of just pointing to the function expr.
73457347
addValueMemberConstraint(origLValueType2, DeclName(ctx.Id_callAsFunction),
73467348
memberTy, DC, FunctionRefKind::SingleApply,
73477349
/*outerAlternatives*/ {}, locator);

lib/Sema/ConstraintSystem.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,17 +478,29 @@ ConstraintSystem::getCalleeLocator(ConstraintLocator *locator,
478478
if (lookThroughApply) {
479479
if (auto *applyExpr = dyn_cast<ApplyExpr>(anchor)) {
480480
auto *fnExpr = applyExpr->getFn();
481+
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+
481490
// For an apply of a metatype, we have a short-form constructor. Unlike
482491
// other locators to callees, these are anchored on the apply expression
483492
// rather than the function expr.
484-
auto fnTy = getFixedTypeRecursive(getType(fnExpr), /*wantRValue*/ true);
485493
if (fnTy->is<AnyMetatypeType>()) {
486494
auto *fnLocator =
487495
getConstraintLocator(applyExpr, ConstraintLocator::ApplyFunction);
488496
return getConstraintLocator(fnLocator,
489497
ConstraintLocator::ConstructorMember);
490498
}
491499

500+
// Handle an apply of a nominal type which supports callAsFunction.
501+
if (fnTy->isCallableNominalType(DC))
502+
return getConstraintLocator(anchor, ConstraintLocator::ApplyFunction);
503+
492504
// Otherwise fall through and look for locators anchored on the function
493505
// expr. For CallExprs, this can look through things like parens and
494506
// optional chaining.

test/SILGen/default_arguments.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,3 +408,26 @@ func genericMagic<T : ExpressibleByStringLiteral>(x: T = #file) -> T {
408408
}
409409

410410
let _: String = genericMagic()
411+
412+
// SR-11778
413+
struct CallableWithDefault {
414+
func callAsFunction(x: Int = 4) {}
415+
func callAsFunction(y: Int, z: String = #function) {}
416+
}
417+
418+
// CHECK-LABEL: sil hidden [ossa] @$s17default_arguments23testCallableWithDefaultyyAA0deF0VF : $@convention(thin) (CallableWithDefault) -> ()
419+
func testCallableWithDefault(_ x: CallableWithDefault) {
420+
// CHECK: [[DEF_FN:%[0-9]+]] = function_ref @$s17default_arguments19CallableWithDefaultV14callAsFunction1xySi_tFfA_ : $@convention(thin) () -> Int
421+
// CHECK: [[DEF:%[0-9]+]] = apply [[DEF_FN]]() : $@convention(thin) () -> Int
422+
// CHECK: [[CALL_AS_FN:%[0-9]+]] = function_ref @$s17default_arguments19CallableWithDefaultV14callAsFunction1xySi_tF : $@convention(method) (Int, CallableWithDefault) -> ()
423+
// CHECK: apply [[CALL_AS_FN]]([[DEF]], {{%[0-9]+}})
424+
x()
425+
426+
// CHECK: [[RAW_I:%[0-9]+]] = integer_literal $Builtin.IntLiteral, 5
427+
// CHECK: [[I:%[0-9]+]] = apply {{%[0-9]+}}([[RAW_I]], {{%[0-9]+}}) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int
428+
// CHECK: [[RAW_STR:%[0-9]+]] = string_literal utf8 "testCallableWithDefault(_:)"
429+
// CHECK: [[STR:%[0-9]+]] = apply {{%[0-9]+}}([[RAW_STR]], {{%[0-9]+}}, {{%[0-9]+}}, {{%[0-9]+}}) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
430+
// CHECK: [[CALL_AS_FN:%[0-9]+]] = function_ref @$s17default_arguments19CallableWithDefaultV14callAsFunction1y1zySi_SStF : $@convention(method) (Int, @guaranteed String, CallableWithDefault) -> ()
431+
// CHECK: apply [[CALL_AS_FN]]([[I]], [[STR]], {{%[0-9]+}})
432+
x(y: 5)
433+
}

test/Sema/call_as_function_generic.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,19 @@ let genericString = GenericType<[String]>(collection: ["Hello", "world", "!"])
4141
_ = genericString("Hello")
4242
let genericInt = GenericType<Set<Int>>(collection: [1, 2, 3])
4343
_ = genericInt(initialValue: 1)
44+
45+
// SR-11386
46+
class C<T> {}
47+
protocol P1 {}
48+
extension C where T : P1 { // expected-note {{where 'T' = 'Int'}}
49+
func callAsFunction(t: T) {}
50+
}
51+
52+
struct S0 : P1 {}
53+
54+
func testCallAsFunctionWithWhereClause(_ c1: C<Int>, _ c2: C<S0>, _ s0: S0) {
55+
c1(42) // expected-error {{referencing instance method 'callAsFunction(t:)' on 'C' requires that 'Int' conform to 'P1'}}
56+
// expected-error@-1 {{missing argument label 't:' in call}}
57+
58+
c2(t: s0) // Okay.
59+
}

test/Sema/call_as_function_simple.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,15 @@ func testIUO(a: SimpleCallable!, b: MultipleArgsCallable!, c: Extended!,
192192
_ = try? h()
193193
_ = try? h { throw DummyError() }
194194
}
195+
196+
// SR-11778
197+
struct DoubleANumber {
198+
func callAsFunction(_ x: Int, completion: (Int) -> Void = { _ in }) {
199+
completion(x + x)
200+
}
201+
}
202+
203+
func testDefaults(_ x: DoubleANumber) {
204+
x(5)
205+
x(5, completion: { _ in })
206+
}

0 commit comments

Comments
 (0)