Skip to content

Commit f29c352

Browse files
committed
[CSBindings] Allow subtype inference from Void? for closure result types
We don't want to do that in general because injection should happen only in one place but Void is special because it allows conversions in that position.
1 parent 9907afa commit f29c352

File tree

2 files changed

+35
-2
lines changed

2 files changed

+35
-2
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2584,7 +2584,8 @@ bool TypeVarBindingProducer::computeNext() {
25842584
//
25852585
// Let's not perform $T? -> $T for closure result types to avoid having
25862586
// to re-discover solutions that differ only in location of optional
2587-
// injection.
2587+
// injection. `Void` is a special case because in $T_result position
2588+
// it has special semantics and enables T? -> Void conversions.
25882589
//
25892590
// The pattern with such type variables is:
25902591
//
@@ -2595,7 +2596,7 @@ bool TypeVarBindingProducer::computeNext() {
25952596
// expression is non-optional), if we allow both the solver would
25962597
// find two solutions that differ only in location of optional
25972598
// injection.
2598-
if (!TypeVar->getImpl().isClosureResultType()) {
2599+
if (!TypeVar->getImpl().isClosureResultType() || objTy->isVoid()) {
25992600
// If T is a type variable, only attempt this if both the
26002601
// type variable we are trying bindings for, and the type
26012602
// variable we will attempt to bind, both have the same

test/Constraints/closures.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,3 +1283,35 @@ do {
12831283
}
12841284
}
12851285
}
1286+
1287+
// Make sure that closure gets both Void? and Void attempted
1288+
// otherwise it won't be possible to type-check the second closure.
1289+
do {
1290+
struct Semaphore {
1291+
func signal() -> Int {}
1292+
}
1293+
1294+
class State {
1295+
func adjust(_: (Int?) -> Void) {}
1296+
}
1297+
1298+
struct Test {
1299+
var mock: Bool
1300+
var state: State?
1301+
1302+
func reply(completion: ((Semaphore?) -> Void?)) {
1303+
}
1304+
1305+
func test() {
1306+
var num: Int
1307+
let sem: Semaphore
1308+
1309+
_ = mock
1310+
? reply(completion: { $0?.signal() }) // expected-warning {{result of call to 'signal()' is unused}}
1311+
: state?.adjust({ newV in
1312+
num = newV ?? num
1313+
sem.signal() // expected-warning {{result of call to 'signal()' is unused}}
1314+
})
1315+
}
1316+
}
1317+
}

0 commit comments

Comments
 (0)