Skip to content

Commit e4920a6

Browse files
committed
[CSOptimizer] Consider choices marked as @_disfavoredOverload
These choices could be better than some other non-disfavored ones in certain situations i.e. when `async` overload is disfavored but appears in async context it's preferrable to a non-async overload choice. Note that the code that mimic old hacks still needs to filter on `@_disfavoredOverload` in few places to maintain source compatibility.
1 parent 704304e commit e4920a6

File tree

2 files changed

+36
-5
lines changed

2 files changed

+36
-5
lines changed

lib/Sema/CSOptimizer.cpp

+13-5
Original file line numberDiff line numberDiff line change
@@ -371,10 +371,9 @@ static ValueDecl *isViableOverloadChoice(ConstraintSystem &cs,
371371
}
372372
}
373373

374-
// If disjunction choice is unavailable or disfavored we cannot
374+
// If disjunction choice is unavailable we cannot
375375
// do anything with it.
376-
if (decl->getAttrs().hasAttribute<DisfavoredOverloadAttr>() ||
377-
cs.isDeclUnavailable(decl, locator))
376+
if (cs.isDeclUnavailable(decl, locator))
378377
return nullptr;
379378

380379
return decl;
@@ -621,8 +620,13 @@ static void findFavoredChoicesBasedOnArity(
621620
forEachDisjunctionChoice(
622621
cs, disjunction,
623622
[&](Constraint *choice, ValueDecl *decl, FunctionType *overloadType) {
624-
if (isVariadicGenericOverload(decl))
623+
if (decl->getAttrs().hasAttribute<DisfavoredOverloadAttr>())
624+
return;
625+
626+
if (isVariadicGenericOverload(decl)) {
625627
hasVariadicGenerics = true;
628+
return;
629+
}
626630

627631
if (overloadType->getNumParams() == argumentList->size() ||
628632
llvm::count_if(*getParameterList(decl), [](auto *param) {
@@ -661,7 +665,8 @@ static std::optional<DisjunctionInfo> preserveFavoringOfUnlabeledUnaryArgument(
661665
return false;
662666

663667
return isa<ProtocolDecl>(decl->getDeclContext()) ||
664-
isVariadicGenericOverload(decl);
668+
(!decl->getAttrs().hasAttribute<DisfavoredOverloadAttr>() &&
669+
isVariadicGenericOverload(decl));
665670
}))
666671
return std::nullopt;
667672

@@ -721,6 +726,9 @@ static std::optional<DisjunctionInfo> preserveFavoringOfUnlabeledUnaryArgument(
721726
cs, disjunction,
722727
[&argumentType, &favoredChoices, &argument](
723728
Constraint *choice, ValueDecl *decl, FunctionType *overloadType) {
729+
if (decl->getAttrs().hasAttribute<DisfavoredOverloadAttr>())
730+
return;
731+
724732
if (overloadType->getNumParams() != 1)
725733
return;
726734

test/Constraints/old_hack_related_ambiguities.swift

+23
Original file line numberDiff line numberDiff line change
@@ -360,3 +360,26 @@ class TestFailableOnly {
360360
}
361361
}
362362
}
363+
364+
do {
365+
@_disfavoredOverload
366+
func test(over: Int, that: String = "", block: @escaping (Int) throws -> Void) async throws {}
367+
func test(over: Int, that: String = "", block: @escaping (Int) throws -> Void) throws {} // expected-note {{found this candidate}}
368+
func test(over: Int, other: String = "", block: @escaping (Int) throws -> Void) throws {} // expected-note {{found this candidate}}
369+
370+
func performLocal(v: Int, block: @escaping (Int) throws -> Void) async throws {
371+
try await test(over: v, block: block) // expected-error {{ambiguous use of 'test'}}
372+
}
373+
374+
// The hack applied only to `OverloadedDeclRefExpr`s.
375+
struct MemberTest {
376+
@_disfavoredOverload
377+
func test(over: Int, that: String = "", block: @escaping (Int) throws -> Void) async throws {}
378+
func test(over: Int, that: String = "", block: @escaping (Int) throws -> Void) throws {}
379+
func test(over: Int, other: String = "", block: @escaping (Int) throws -> Void) throws {}
380+
381+
func performMember(v: Int, block: @escaping (Int) throws -> Void) async throws {
382+
try await test(over: v, block: block) // Ok
383+
}
384+
}
385+
}

0 commit comments

Comments
 (0)