Skip to content

Commit 64fe398

Browse files
authored
Merge pull request #19282 from rudkx/rdar42337247
[ConstraintSystem] Infer empty closures as returning () more eagerly.
2 parents 925e94f + 352e4a2 commit 64fe398

File tree

7 files changed

+78
-13
lines changed

7 files changed

+78
-13
lines changed

include/swift/AST/Expr.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3653,6 +3653,9 @@ class ClosureExpr : public AbstractClosureExpr {
36533653
/// its body; it can only update that expression.
36543654
void setSingleExpressionBody(Expr *NewBody);
36553655

3656+
/// \brief Is this a completely empty closure?
3657+
bool hasEmptyBody() const;
3658+
36563659
static bool classof(const Expr *E) {
36573660
return E->getKind() == ExprKind::Closure;
36583661
}

lib/AST/Expr.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1855,6 +1855,10 @@ void ClosureExpr::setSingleExpressionBody(Expr *NewBody) {
18551855
getBody()->setElement(0, NewBody);
18561856
}
18571857

1858+
bool ClosureExpr::hasEmptyBody() const {
1859+
return getBody()->getNumElements() == 0;
1860+
}
1861+
18581862
FORWARD_SOURCE_LOCS_TO(AutoClosureExpr, Body)
18591863

18601864
void AutoClosureExpr::setBody(Expr *E) {

lib/Sema/CSGen.cpp

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2400,22 +2400,30 @@ namespace {
24002400
expr->getExplicitResultTypeLoc().getType()) {
24012401
resultTy = expr->getExplicitResultTypeLoc().getType();
24022402
CS.setFavoredType(expr, resultTy.getPointer());
2403-
} else if (!crt.isNull()) {
2404-
resultTy = crt;
2405-
} else{
2403+
} else {
24062404
auto locator =
24072405
CS.getConstraintLocator(expr, ConstraintLocator::ClosureResult);
24082406

2409-
// If no return type was specified, create a fresh type
2410-
// variable for it.
2411-
resultTy = CS.createTypeVariable(locator);
2407+
if (expr->hasEmptyBody()) {
2408+
resultTy = CS.createTypeVariable(locator);
24122409

2413-
// Allow it to default to () if there are no return statements.
2414-
if (closureHasNoResult(expr)) {
2415-
CS.addConstraint(ConstraintKind::Defaultable,
2416-
resultTy,
2417-
TupleType::getEmpty(CS.getASTContext()),
2418-
locator);
2410+
// Closures with empty bodies should be inferred to return
2411+
// ().
2412+
CS.addConstraint(ConstraintKind::Bind, resultTy,
2413+
TupleType::getEmpty(CS.getASTContext()), locator);
2414+
} else if (crt) {
2415+
// Otherwise, use the contextual type if present.
2416+
resultTy = crt;
2417+
} else {
2418+
// If no return type was specified, create a fresh type
2419+
// variable for it.
2420+
resultTy = CS.createTypeVariable(locator);
2421+
2422+
if (closureHasNoResult(expr)) {
2423+
// Allow it to default to () if there are no return statements.
2424+
CS.addConstraint(ConstraintKind::Defaultable, resultTy,
2425+
TupleType::getEmpty(CS.getASTContext()), locator);
2426+
}
24192427
}
24202428
}
24212429

test/Constraints/closures.swift

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,3 +749,51 @@ func f20371273() {
749749
let y: UInt = 4
750750
_ = x.filter { ($0 + y) > 42 } // expected-error {{'+' is unavailable}}
751751
}
752+
753+
// rdar://problem/42337247
754+
755+
func overloaded(_ handler: () -> Int) {} // expected-note {{found this candidate}}
756+
func overloaded(_ handler: () -> Void) {} // expected-note {{found this candidate}}
757+
758+
overloaded { } // empty body => inferred as returning ()
759+
760+
overloaded { print("hi") } // single-expression closure => typechecked with body
761+
762+
overloaded { print("hi"); print("bye") } // multiple expression closure without explicit returns; can default to any return type
763+
// expected-error@-1 {{ambiguous use of 'overloaded'}}
764+
765+
func not_overloaded(_ handler: () -> Int) {}
766+
767+
not_overloaded { } // empty body
768+
// expected-error@-1 {{cannot convert value of type '() -> ()' to expected argument type '() -> Int'}}
769+
770+
not_overloaded { print("hi") } // single-expression closure
771+
// expected-error@-1 {{cannot convert value of type '()' to closure result type 'Int'}}
772+
773+
// no error in -typecheck, but dataflow diagnostics will complain about missing return
774+
not_overloaded { print("hi"); print("bye") } // multiple expression closure
775+
776+
func apply(_ fn: (Int) throws -> Int) rethrows -> Int {
777+
return try fn(0)
778+
}
779+
780+
enum E : Error {
781+
case E
782+
}
783+
784+
func test() -> Int? {
785+
return try? apply({ _ in throw E.E })
786+
}
787+
788+
var fn: () -> [Int] = {}
789+
// expected-error@-1 {{cannot convert value of type '() -> ()' to specified type '() -> [Int]'}}
790+
791+
fn = {}
792+
// expected-error@-1 {{cannot assign value of type '() -> ()' to type '() -> [Int]'}}
793+
794+
func test<Instances : Collection>(
795+
_ instances: Instances,
796+
_ fn: (Instances.Index, Instances.Index) -> Bool
797+
) { fatalError() }
798+
799+
test([1]) { _, _ in fatalError(); () }

test/SILGen/objc_blocks_bridging.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ class Test: NSObject {
154154
// CHECK: return [[RESULT]]
155155

156156
func clearDraggingItemImageComponentsProvider(_ x: NSDraggingItem) {
157-
x.imageComponentsProvider = {}
157+
x.imageComponentsProvider = { [] }
158158
}
159159
// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SSayypGIego_So7NSArrayCSgIeyBa_TR
160160
// CHECK: [[CONVERT:%.*]] = function_ref @$SSa10FoundationE19_bridgeToObjectiveCSo7NSArrayCyF

test/decl/func/default-values-swift4.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,5 @@ public func evilCode(
109109
versionedFunction()
110110
// expected-error@-1 {{global function 'versionedFunction()' is internal and cannot be referenced from a default argument value}}
111111
}
112+
return 0
112113
}()) {}

test/expr/closure/closures.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ func rdar19179412() -> (Int) -> Int {
252252
class A {
253253
let d : Int = 0
254254
}
255+
return 0
255256
}
256257
}
257258

0 commit comments

Comments
 (0)