Skip to content

Commit cb8d672

Browse files
authored
Merge pull request #85873 from xedin/rdar-165862285
[CSRanking] Disambiguate static vs. instance method that used to be s…
2 parents 28d6376 + 7c32c2a commit cb8d672

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
@@ -758,6 +758,29 @@ bool CompareDeclSpecializationRequest::evaluate(
758758
unsigned numParams1 = params1.size();
759759
unsigned numParams2 = params2.size();
760760

761+
// Handle the following situation:
762+
//
763+
// struct S {
764+
// func test() {}
765+
// static func test(_: S) {}
766+
// }
767+
//
768+
// Calling `S.test(s)` where `s` has a type `S` without any other context
769+
// should prefer a complete call to a static member over a partial
770+
// application of an instance once based on the choice of the base type.
771+
//
772+
// The behavior is consistent for double-applies as well i.e.
773+
// `S.test(s)()` if static method produced a function type it would be
774+
// preferred.
775+
if (decl1->isInstanceMember() != decl2->isInstanceMember() &&
776+
isa<FuncDecl>(decl1) && isa<FuncDecl>(decl2)) {
777+
auto selfTy = decl1->isInstanceMember() ? selfTy2 : selfTy1;
778+
auto params = decl1->isInstanceMember() ? params2 : params1;
779+
if (params.size() == 1 && params[0].getPlainType()->isEqual(selfTy)) {
780+
return completeResult(!decl1->isInstanceMember());
781+
}
782+
}
783+
761784
if (numParams1 > numParams2)
762785
return completeResult(false);
763786

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)