Skip to content

Commit 116d1af

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 116d1af

File tree

2 files changed

+25
-2
lines changed

2 files changed

+25
-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: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,3 +1283,25 @@ 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+
func compute(_ completion: (Semaphore?) -> Void?) {}
1295+
1296+
func test() {
1297+
compute { $0?.signal() }
1298+
// expected-warning@-1 {{result of call to 'signal()' is unused}}
1299+
1300+
true
1301+
? compute({ $0?.signal() }) // expected-warning {{result of call to 'signal()' is unused}}
1302+
: compute({
1303+
let sem = $0!
1304+
sem.signal() // expected-warning {{result of call to 'signal()' is unused}}
1305+
})
1306+
}
1307+
}

0 commit comments

Comments
 (0)