Skip to content

Commit 125c3f6

Browse files
committed
[CSRanking] Disambiguate static vs. instance method that used to be supported by a performance hack
Handle the following situation: ```swift struct S { func test() {} static func test(_: S) {} } ``` Calling `S.test(s)` where `s` has a type `S` without any other context should prefer a complete call to a static member over a partial application of an instance once based on the choice of the base type. The behavior is consistent for double-applies as well i.e. `S.test(s)()` if static method produced a function type it would be preferred. Resolves: rdar://165862285
1 parent 767c569 commit 125c3f6

File tree

2 files changed

+78
-0
lines changed

2 files changed

+78
-0
lines changed

lib/Sema/CSRanking.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,29 @@ bool CompareDeclSpecializationRequest::evaluate(
746746
unsigned numParams1 = params1.size();
747747
unsigned numParams2 = params2.size();
748748

749+
// Handle the following situation:
750+
//
751+
// struct S {
752+
// func test() {}
753+
// static func test(_: S) {}
754+
// }
755+
//
756+
// Calling `S.test(s)` where `s` has a type `S` without any other context
757+
// should prefer a complete call to a static member over a partial
758+
// application of an instance once based on the choice of the base type.
759+
//
760+
// The behavior is consistent for double-applies as well i.e.
761+
// `S.test(s)()` if static method produced a function type it would be
762+
// preferred.
763+
if (decl1->isInstanceMember() != decl2->isInstanceMember() &&
764+
isa<FuncDecl>(decl1) && isa<FuncDecl>(decl2)) {
765+
auto selfTy = decl1->isInstanceMember() ? selfTy2 : selfTy1;
766+
auto params = decl1->isInstanceMember() ? params2 : params1;
767+
if (params.size() == 1 && params[0].getPlainType()->isEqual(selfTy)) {
768+
return completeResult(!decl1->isInstanceMember());
769+
}
770+
}
771+
749772
if (numParams1 > numParams2)
750773
return completeResult(false);
751774

test/Constraints/old_hack_related_ambiguities.swift

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,3 +414,58 @@ do {
414414
}
415415
}
416416
}
417+
418+
do {
419+
struct S {
420+
func test() {}
421+
static func test(_: S...) {}
422+
423+
func doubleApply() {}
424+
static func doubleApply(_: S) -> () -> Int { { 42 } }
425+
}
426+
427+
func test(s: S) {
428+
let res1 = S.test(s)
429+
// expected-warning@-1 {{constant 'res1' inferred to have type '()', which may be unexpected}}
430+
// expected-note@-2 {{add an explicit type annotation to silence this warning}}
431+
_ = res1
432+
433+
let res2 = {
434+
S.test(s)
435+
}
436+
let _: () -> Void = res2
437+
438+
let _ = { () async -> Void in
439+
_ = 42
440+
return S.test(s)
441+
}
442+
443+
let res3 = S.doubleApply(s)
444+
let _: () -> Int = res3
445+
446+
let res4 = S.doubleApply(s)()
447+
let _: Int = res4
448+
449+
let res5 = { S.doubleApply(s)() }
450+
let _: () -> Int = res5
451+
452+
let res6 = {
453+
_ = 42
454+
return S.doubleApply(s)
455+
}
456+
let _: () -> Int = res6()
457+
}
458+
459+
func testAsyncContext(s: S) async {
460+
let res1 = S.test(s)
461+
// expected-warning@-1 {{constant 'res1' inferred to have type '()', which may be unexpected}}
462+
// expected-note@-2 {{add an explicit type annotation to silence this warning}}
463+
_ = res1
464+
465+
let res2 = S.doubleApply(s)
466+
let _: () -> Int = res2
467+
468+
let res3 = S.doubleApply(s)()
469+
let _: Int = res3
470+
}
471+
}

0 commit comments

Comments
 (0)