Skip to content

Commit 94dbbd7

Browse files
authored
Merge pull request #15134 from xedin/rdar-37790062-v3
[CSBindings] Try `Void` as a binding for `closure result` type variable
2 parents ae2cdfc + 18d2c1d commit 94dbbd7

File tree

3 files changed

+102
-1
lines changed

3 files changed

+102
-1
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,8 +376,28 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) {
376376
break;
377377

378378
auto type = binding->BindingType;
379-
if (exactTypes.insert(type->getCanonicalType()).second)
379+
if (exactTypes.insert(type->getCanonicalType()).second) {
380380
result.addPotentialBinding(*binding);
381+
382+
if (auto *locator = typeVar->getImpl().getLocator()) {
383+
auto path = locator->getPath();
384+
auto voidType = TupleType::getEmpty(getASTContext());
385+
386+
// If this is a type variable representing closure result,
387+
// which is on the right-side of some relational constraint
388+
// let's have it try `Void` as well because there is an
389+
// implicit conversion `() -> T` to `() -> Void` and this
390+
// helps to avoid creating a thunk to support it.
391+
if (!path.empty() &&
392+
path.back().getKind() == ConstraintLocator::ClosureResult &&
393+
binding->Kind == AllowedBindingKind::Supertypes &&
394+
exactTypes.insert(voidType->getCanonicalType()).second) {
395+
result.addPotentialBinding(
396+
{voidType, binding->Kind, constraint->getKind()},
397+
/*allowJoinMeet=*/false);
398+
}
399+
}
400+
}
381401
break;
382402
}
383403

test/Constraints/closures.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,3 +652,38 @@ func rdar36054961() {
652652
str.replaceSubrange(range, with: str[range].reversed())
653653
}])
654654
}
655+
656+
protocol P_37790062 {
657+
associatedtype T
658+
var elt: T { get }
659+
}
660+
661+
func rdar37790062() {
662+
struct S<T> {
663+
init(_ a: () -> T, _ b: () -> T) {}
664+
}
665+
666+
class C1 : P_37790062 {
667+
typealias T = Int
668+
var elt: T { return 42 }
669+
}
670+
671+
class C2 : P_37790062 {
672+
typealias T = (String, Int, Void)
673+
var elt: T { return ("question", 42, ()) }
674+
}
675+
676+
func foo() -> Int { return 42 }
677+
func bar() -> Void {}
678+
func baz() -> (String, Int) { return ("question", 42) }
679+
func bzz<T>(_ a: T) -> T { return a }
680+
func faz<T: P_37790062>(_ a: T) -> T.T { return a.elt }
681+
682+
_ = S({ foo() }, { bar() }) // expected-warning {{result of call to 'foo()' is unused}}
683+
_ = S({ baz() }, { bar() }) // expected-warning {{result of call to 'baz()' is unused}}
684+
_ = S({ bzz(("question", 42)) }, { bar() }) // expected-warning {{result of call to 'bzz' is unused}}
685+
_ = S({ bzz(String.self) }, { bar() }) // expected-warning {{result of call to 'bzz' is unused}}
686+
_ = S({ bzz(((), (()))) }, { bar() }) // expected-warning {{result of call to 'bzz' is unused}}
687+
_ = S({ bzz(C1()) }, { bar() }) // expected-warning {{result of call to 'bzz' is unused}}
688+
_ = S({ faz(C2()) }, { bar() }) // expected-warning {{result of call to 'faz' is unused}}
689+
}

test/Constraints/rdar37790062.swift

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
protocol A {
4+
associatedtype V
5+
associatedtype E: Error
6+
7+
init(value: V)
8+
init(error: E)
9+
10+
func foo<U>(value: (V) -> U, error: (E) -> U) -> U
11+
}
12+
13+
enum R<T, E: Error> : A {
14+
case foo(T)
15+
case bar(E)
16+
17+
init(value: T) { self = .foo(value) }
18+
init(error: E) { self = .bar(error) }
19+
20+
func foo<R>(value: (T) -> R, error: (E) -> R) -> R {
21+
fatalError()
22+
}
23+
}
24+
25+
protocol P {
26+
associatedtype V
27+
28+
@discardableResult
29+
func baz(callback: @escaping (V) -> Void) -> Self
30+
}
31+
32+
class C<V> : P {
33+
func baz(callback: @escaping (V) -> Void) -> Self { return self }
34+
}
35+
class D<T, E: Error> : C<R<T, E>> {
36+
init(fn: (_ ret: @escaping (V) -> Void) -> Void) {}
37+
}
38+
39+
extension A where V: P, V.V: A, E == V.V.E {
40+
func bar() -> D<V.V.V, V.V.E> {
41+
return D { complete in
42+
foo(value: { promise in promise.baz { result in } },
43+
error: { complete(R(error: $0)) })
44+
}
45+
}
46+
}

0 commit comments

Comments
 (0)