Skip to content

Commit 7c32c2a

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 7c32c2a

File tree

2 files changed

+81
-0
lines changed

2 files changed

+81
-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: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,3 +414,61 @@ do {
414414
}
415415
}
416416
}
417+
418+
do {
419+
struct S {
420+
func test() -> Int { 42 }
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 useInstance = S.test(s)()
434+
let _: Int = useInstance
435+
436+
let res2 = {
437+
S.test(s)
438+
}
439+
let _: () -> Void = res2
440+
441+
let _ = { () async -> Void in
442+
_ = 42
443+
return S.test(s)
444+
}
445+
446+
let res3 = S.doubleApply(s)
447+
let _: () -> Int = res3
448+
449+
let res4 = S.doubleApply(s)()
450+
let _: Int = res4
451+
452+
let res5 = { S.doubleApply(s)() }
453+
let _: () -> Int = res5
454+
455+
let res6 = {
456+
_ = 42
457+
return S.doubleApply(s)
458+
}
459+
let _: () -> Int = res6()
460+
}
461+
462+
func testAsyncContext(s: S) async {
463+
let res1 = S.test(s)
464+
// expected-warning@-1 {{constant 'res1' inferred to have type '()', which may be unexpected}}
465+
// expected-note@-2 {{add an explicit type annotation to silence this warning}}
466+
_ = res1
467+
468+
let res2 = S.doubleApply(s)
469+
let _: () -> Int = res2
470+
471+
let res3 = S.doubleApply(s)()
472+
let _: Int = res3
473+
}
474+
}

0 commit comments

Comments
 (0)