Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions lib/Sema/CSRanking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,29 @@ bool CompareDeclSpecializationRequest::evaluate(
unsigned numParams1 = params1.size();
unsigned numParams2 = params2.size();

// Handle the following situation:
//
// 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.
if (decl1->isInstanceMember() != decl2->isInstanceMember() &&
isa<FuncDecl>(decl1) && isa<FuncDecl>(decl2)) {
auto selfTy = decl1->isInstanceMember() ? selfTy2 : selfTy1;
auto params = decl1->isInstanceMember() ? params2 : params1;
if (params.size() == 1 && params[0].getPlainType()->isEqual(selfTy)) {
return completeResult(!decl1->isInstanceMember());
}
}

if (numParams1 > numParams2)
return completeResult(false);

Expand Down
58 changes: 58 additions & 0 deletions test/Constraints/old_hack_related_ambiguities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -414,3 +414,61 @@ do {
}
}
}

do {
struct S {
func test() -> Int { 42 }
static func test(_: S...) {}

func doubleApply() {}
static func doubleApply(_: S) -> () -> Int { { 42 } }
}

func test(s: S) {
let res1 = S.test(s)
// expected-warning@-1 {{constant 'res1' inferred to have type '()', which may be unexpected}}
// expected-note@-2 {{add an explicit type annotation to silence this warning}}
_ = res1

let useInstance = S.test(s)()
let _: Int = useInstance

let res2 = {
S.test(s)
}
let _: () -> Void = res2

let _ = { () async -> Void in
_ = 42
return S.test(s)
}

let res3 = S.doubleApply(s)
let _: () -> Int = res3

let res4 = S.doubleApply(s)()
let _: Int = res4

let res5 = { S.doubleApply(s)() }
let _: () -> Int = res5

let res6 = {
_ = 42
return S.doubleApply(s)
}
let _: () -> Int = res6()
}

func testAsyncContext(s: S) async {
let res1 = S.test(s)
// expected-warning@-1 {{constant 'res1' inferred to have type '()', which may be unexpected}}
// expected-note@-2 {{add an explicit type annotation to silence this warning}}
_ = res1

let res2 = S.doubleApply(s)
let _: () -> Int = res2

let res3 = S.doubleApply(s)()
let _: Int = res3
}
}