Skip to content

Commit 8b0b89e

Browse files
Merge pull request #36076 from LucianoPAlmeida/SR-2705-ranking-autoclosure
[SR-2705][Sema] Always favor non-autoclosure parameter function overload
2 parents 751cd38 + 419baee commit 8b0b89e

File tree

4 files changed

+80
-1
lines changed

4 files changed

+80
-1
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -802,8 +802,10 @@ enum ScoreKind {
802802
SK_KeyPathSubscript,
803803
/// A conversion from a string, array, or inout to a pointer.
804804
SK_ValueToPointerConversion,
805+
/// A closure/function conversion to an autoclosure parameter.
806+
SK_FunctionToAutoClosureConversion,
805807

806-
SK_LastScoreKind = SK_ValueToPointerConversion,
808+
SK_LastScoreKind = SK_FunctionToAutoClosureConversion,
807809
};
808810

809811
/// The number of score kinds.

lib/Sema/CSRanking.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ static StringRef getScoreKindName(ScoreKind kind) {
8181

8282
case SK_ValueToPointerConversion:
8383
return "value-to-pointer conversion";
84+
85+
case SK_FunctionToAutoClosureConversion:
86+
return "function to autoclosure parameter";
8487
}
8588
}
8689

lib/Sema/CSSimplify.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,6 +1378,17 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments(
13781378
auto *fnType = paramTy->castTo<FunctionType>();
13791379
auto *argExpr = getArgumentExpr(locator.getAnchor(), argIdx);
13801380

1381+
// If this is a call to a function with a closure argument and the
1382+
// parameter is an autoclosure, let's just increment the score here
1383+
// so situations like bellow are not ambiguous.
1384+
// func f<T>(_: () -> T) {}
1385+
// func f<T>(_: @autoclosure () -> T) {}
1386+
//
1387+
// f { } // OK
1388+
if (isExpr<ClosureExpr>(argExpr)) {
1389+
cs.increaseScore(SK_FunctionToAutoClosureConversion);
1390+
}
1391+
13811392
// If the argument is not marked as @autoclosure or
13821393
// this is Swift version >= 5 where forwarding is not allowed,
13831394
// argument would always be wrapped into an implicit closure
@@ -2242,6 +2253,26 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
22422253
auto func1Param = func1Params[i];
22432254
auto func2Param = func2Params[i];
22442255

2256+
// Increase the score if matching an autoclosure parameter to an function
2257+
// type, so we enforce that non-autoclosure overloads are preferred.
2258+
//
2259+
// func autoclosure(f: () -> Int) { }
2260+
// func autoclosure(f: @autoclosure () -> Int) { }
2261+
//
2262+
// let _ = autoclosure as (() -> (Int)) -> () // non-autoclosure preferred
2263+
//
2264+
auto isAutoClosureFunctionMatch = [](AnyFunctionType::Param &param1,
2265+
AnyFunctionType::Param &param2) {
2266+
return param1.isAutoClosure() &&
2267+
(!param2.isAutoClosure() &&
2268+
param2.getPlainType()->is<FunctionType>());
2269+
};
2270+
2271+
if (isAutoClosureFunctionMatch(func1Param, func2Param) ||
2272+
isAutoClosureFunctionMatch(func2Param, func1Param)) {
2273+
increaseScore(SK_FunctionToAutoClosureConversion);
2274+
}
2275+
22452276
// Variadic bit must match.
22462277
if (func1Param.isVariadic() != func2Param.isVariadic()) {
22472278
if (!(shouldAttemptFixes() && func2Param.isVariadic()))

test/Constraints/sr2705.swift

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// RUN: %target-swift-emit-silgen %s -verify | %FileCheck %s
2+
3+
func f<T>(_: () -> T) {}
4+
func f<T>(_: @autoclosure () -> T) {}
5+
6+
// CHECK: function_ref @$s6sr27051fyyxyXElF
7+
f { } // OK
8+
9+
func f1<T>(_: () -> T, _: () -> T) {}
10+
func f1<T>(_: @autoclosure () -> T, _: @autoclosure () -> T) {}
11+
12+
// CHECK: function_ref @$s6sr27052f1yyxyXE_xyXEtlF
13+
f1({}, {}) // OK
14+
15+
func f2<T>(_: () -> T, _: () -> T) { }
16+
func f2<T>(_: () -> T, _: @autoclosure () -> T) { }
17+
18+
// CHECK: function_ref @$s6sr27052f2yyxyXE_xyXEtlF
19+
f2({}, {}) // OK
20+
21+
func f3(_: () -> Int) {}
22+
func f3(_: @autoclosure () -> Int) {}
23+
24+
// CHECK: function_ref @$s6sr27052f3yySiyXEF
25+
f3 { 0 } // OK
26+
27+
func autoclosure(f: () -> Int) { }
28+
func autoclosure(f: @autoclosure () -> Int) { }
29+
func autoclosure(f: Int) { }
30+
31+
// CHECK: function_ref @$s6sr270511autoclosure1fySiyXE_tF
32+
autoclosure(f: { 0 }) // OK
33+
34+
// CHECK: function_ref @$s6sr27052fnyySiyXEF
35+
let _ = autoclosure as (() -> (Int)) -> () // OK
36+
37+
func test(_: (@autoclosure () -> Int) -> Void) {}
38+
func test(_: (() -> Int) -> Void) {}
39+
40+
func fn(_: () -> Int) {}
41+
42+
// CHECK: function_ref @$s6sr27054testyyySiyXEXEF
43+
test(fn) // OK

0 commit comments

Comments
 (0)