Skip to content

Commit 5aea131

Browse files
committed
Add @_disfavoredOverload attribute to affect overload resolution.
Introduce an attribute @_disfavoredOverload that can be used to state that a particular declaration should be avoided if there is a successful type-check for a non-@_disfavoredOverload. It's a way to nudge overload resolution away from particular solutions.
1 parent 54d3930 commit 5aea131

File tree

9 files changed

+60
-0
lines changed

9 files changed

+60
-0
lines changed

include/swift/AST/Attr.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,9 @@ DECL_ATTR(_custom, Custom,
402402
SIMPLE_DECL_ATTR(_propertyDelegate, PropertyDelegate,
403403
OnStruct | OnClass | OnEnum,
404404
86)
405+
SIMPLE_DECL_ATTR(_disfavoredOverload, DisfavoredOverload,
406+
OnAbstractFunction | OnVar | OnSubscript | UserInaccessible,
407+
87)
405408

406409
#undef TYPE_ATTR
407410
#undef DECL_ATTR_ALIAS

lib/Sema/CSGen.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,7 @@ namespace {
641641
continue;
642642

643643
if (!decl->getAttrs().isUnavailable(CS.getASTContext()) &&
644+
!decl->getAttrs().hasAttribute<DisfavoredOverloadAttr>() &&
644645
isFavored(decl, overloadType)) {
645646
// If we might need to roll back the favored constraints, keep
646647
// track of those we are favoring.

lib/Sema/CSRanking.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ void ConstraintSystem::increaseScore(ScoreKind kind, unsigned value) {
4848
log << "attempting to fix the source";
4949
break;
5050

51+
case SK_DisfavoredOverload:
52+
log << "disfavored overload";
53+
break;
54+
5155
case SK_ForceUnchecked:
5256
log << "force of an implicitly unwrapped optional";
5357
break;

lib/Sema/CSSolver.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2002,6 +2002,9 @@ static Constraint *tryOptimizeGenericDisjunction(
20022002
if (!AFD || !AFD->isGeneric())
20032003
return false;
20042004

2005+
if (AFD->getAttrs().hasAttribute<DisfavoredOverloadAttr>())
2006+
return false;
2007+
20052008
auto funcType = AFD->getInterfaceType();
20062009
auto hasAnyOrOptional = funcType.findIf([](Type type) -> bool {
20072010
if (type->getOptionalObjectType())

lib/Sema/ConstraintSystem.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2169,6 +2169,12 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
21692169
<< boundType->getString() << " := "
21702170
<< refType->getString() << ")\n";
21712171
}
2172+
2173+
// If this overload is disfavored, note that.
2174+
if (choice.isDecl() &&
2175+
choice.getDecl()->getAttrs().hasAttribute<DisfavoredOverloadAttr>()) {
2176+
increaseScore(SK_DisfavoredOverload);
2177+
}
21722178
}
21732179

21742180
template <typename Fn>

lib/Sema/ConstraintSystem.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,8 @@ enum ScoreKind {
470470
SK_Fix,
471471
/// A reference to an @unavailable declaration.
472472
SK_Unavailable,
473+
/// A use of a disfavored overload.
474+
SK_DisfavoredOverload,
473475
/// An implicit force of an implicitly unwrapped optional value.
474476
SK_ForceUnchecked,
475477
/// A user-defined conversion.

lib/Sema/TypeCheckAttr.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ class AttributeEarlyChecker : public AttributeVisitor<AttributeEarlyChecker> {
130130
IGNORED_ATTR(PrivateImport)
131131
IGNORED_ATTR(Custom)
132132
IGNORED_ATTR(PropertyDelegate)
133+
IGNORED_ATTR(DisfavoredOverload)
133134
#undef IGNORED_ATTR
134135

135136
void visitAlignmentAttr(AlignmentAttr *attr) {
@@ -812,6 +813,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
812813
IGNORED_ATTR(Transparent)
813814
IGNORED_ATTR(WarnUnqualifiedAccess)
814815
IGNORED_ATTR(WeakLinked)
816+
IGNORED_ATTR(DisfavoredOverload)
815817
#undef IGNORED_ATTR
816818

817819
void visitAvailableAttr(AvailableAttr *attr);

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,6 +1326,8 @@ namespace {
13261326
UNINTERESTING_ATTR(ImplementationOnly)
13271327
UNINTERESTING_ATTR(Custom)
13281328
UNINTERESTING_ATTR(PropertyDelegate)
1329+
UNINTERESTING_ATTR(DisfavoredOverload)
1330+
13291331
#undef UNINTERESTING_ATTR
13301332

13311333
void visitAvailableAttr(AvailableAttr *attr) {

test/Constraints/disfavored.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
struct A { }
4+
struct B { }
5+
6+
@_disfavoredOverload
7+
func f0<T>(_: T) -> A { return A() }
8+
9+
func f0(_: Int32) -> B { return B() }
10+
11+
12+
func f1(_: StaticString) -> B { return B() }
13+
14+
@_disfavoredOverload
15+
func f1<T>(_: T) -> A { return A() }
16+
17+
func f2(_: Substring) -> B { return B() }
18+
19+
@_disfavoredOverload
20+
func f2<T>(_: T) -> A { return A() }
21+
22+
func test(s: String, answer: Int) {
23+
let r0a = f0(17)
24+
let _: B = r0a
25+
let r0b = f0(answer)
26+
let _: A = r0b
27+
28+
let r1 = f1("hello")
29+
let _: B = r1
30+
31+
let r2a = f2("hello")
32+
let _: B = r2a
33+
let r2b = f2("the answer is \(answer)")
34+
let _: B = r2b
35+
let r2c = f2(s)
36+
let _: A = r2c
37+
}

0 commit comments

Comments
 (0)