Skip to content

Commit d271f4b

Browse files
committed
[ConstraintSystem] Ensure we prefer f(_: Any) to f(_: Any?) when both work.
...unless the argument is an `Any?`, in which case we prefer `f(_: Any?)`. This change also results in our selecting f<T>(_: T) over f(_: Any). Coercing with 'as Any' makes it possible to explicitly select the Any overload. Previously there was no way to select the generic overload.
1 parent 186c2f2 commit d271f4b

File tree

5 files changed

+50
-3
lines changed

5 files changed

+50
-3
lines changed

lib/Sema/CSRanking.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,8 @@ static bool isDeclAsSpecializedAs(TypeChecker &tc, DeclContext *dc,
656656
Type objType2 = paramType2->lookThroughAllOptionalTypes(optionals2);
657657
auto numOptionals2 = optionals2.size();
658658

659-
if (numOptionals1 > numOptionals2 && objType2->is<TypeVariableType>())
659+
if (numOptionals1 > numOptionals2 &&
660+
(objType2->is<TypeVariableType>() || objType2->isAny()))
660661
return false;
661662

662663
// Check whether the first parameter is a subtype of the second.

lib/Sema/CSSimplify.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,9 @@ matchCallArguments(ConstraintSystem &cs, ConstraintKind kind,
683683
}
684684
}
685685

686+
if (!argType->isAny())
687+
cs.increaseScore(ScoreKind::SK_EmptyExistentialConversion);
688+
686689
return cs.getTypeMatchSuccess();
687690
}
688691

test/Constraints/overload.swift

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,38 @@ func coalesce() {
251251

252252
// Ensure that we do not select the (T?, T) -> T version of ??, which
253253
// would result in a warning about RHS never being selected.
254-
func rdar19748710(_ value: Int?) -> Int? {
254+
func rdar19748710_0(_ value: Int?) -> Int? {
255255
return value ?? value
256256
}
257+
258+
// Again, ensure we do not select (T?, T) -> T, despite forcing the result.
259+
func rdar19748710_1(_ value: Int?) -> Int? {
260+
return (value ?? value)!
261+
}
262+
263+
// FIXME: We choose to inject the LHS, which really doesn't seem like
264+
// the reasonable choice here. It seems more predictable and safe to
265+
// either inject the result of ??, or treat this as an error since the
266+
// current behavior will result in .some(nil) being force-unwrapped
267+
// rather than the RHS value. The diagnostic is problematic, too,
268+
// since it claims 'Int?' is a non-optional type.
269+
func rdar19748710_2(_ value: Int?) -> Int? {
270+
return (value ?? value)!! // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'Int?', so the right side is never used}}
271+
}
272+
273+
// Ensure that we select the more closely matching function between
274+
// the two _g overloads.
275+
func giveAny() -> Any { fatalError() }
276+
func giveAnyOptional() -> Any? { fatalError() }
277+
func takeAny(_ a: Any?) -> Any? { fatalError() }
278+
func takeAny(_ a: Any) -> Any { fatalError() }
279+
280+
func testAnyOptional() {
281+
let r = takeAny(giveAnyOptional())
282+
let _ = r!
283+
}
284+
285+
func testAny() {
286+
let r = takeAny(giveAny())
287+
let _ = r! // expected-error {{cannot force unwrap value of non-optional type 'Any'}}
288+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %target-swift-emit-silgen %s | %FileCheck %s
2+
3+
// CHECK: sil hidden @$S15overload_silgen8anyToIntySiypF
4+
// CHECK: end sil function '$S15overload_silgen8anyToIntySiypF'
5+
func anyToInt(_: Any) -> Int { fatalError() }
6+
7+
// CHECK: sil hidden @$S15overload_silgen8anyToIntySiSgypSgF
8+
// CHECK: function_ref @$S15overload_silgen8anyToIntySiypF
9+
// CHECK: end sil function '$S15overload_silgen8anyToIntySiSgypSgF'
10+
func anyToInt(_ value: Any?) -> Int? { return anyToInt(value!) }

validation-test/Sema/OverridesAndOverloads.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,8 @@ Overloads.test("generic methods are worse than non-generic") {
328328
}
329329

330330
Base().foo(C1()); expectEqual("foo(C1)", which)
331-
Base().foo(Token1()); expectEqual("foo(Any)", which)
331+
Base().foo(Token1()); expectEqual("foo(T)", which)
332+
Base().foo(Token1() as Any); expectEqual("foo(Any)", which)
332333

333334
Base().bar(C1()); expectEqual("bar(C1)", which)
334335
Base().bar(Token1()); expectEqual("bar(T)", which)

0 commit comments

Comments
 (0)