Skip to content

Commit 1dd76d8

Browse files
committed
[CSClosure] Avoid function conversion when closure result type is optional Void
In cases like: ``` func test<T>(_: () -> T?) -> [T] { ... } test { if ... { return } ... } ``` Contextual return type would be first attempted as optional and then unwrapped if the first attempt did not succeed. To avoid having to solve the closure twice (which results in an implicit function conversion), let's add an implicit empty tuple (`()`) to the `return` statement and allow it be to injected into optional as many times as context requires.
1 parent 9087613 commit 1dd76d8

File tree

1 file changed

+29
-2
lines changed

1 file changed

+29
-2
lines changed

lib/Sema/CSClosure.cpp

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,8 +1204,35 @@ class ClosureConstraintApplication
12041204
}
12051205

12061206
ASTNode visitReturnStmt(ReturnStmt *returnStmt) {
1207-
if (!returnStmt->hasResult())
1208-
return returnStmt;
1207+
if (!returnStmt->hasResult()) {
1208+
// It's possible to infer e.g. `Void?` for cases where
1209+
// `return` doesn't have an expression. If contextual
1210+
// type is `Void` wrapped into N optional types, let's
1211+
// add an implicit `()` expression and let it be injected
1212+
// into optional required number of times.
1213+
auto &ctx = closure->getASTContext();
1214+
1215+
// If contextual is not optional, there is nothing to do here.
1216+
if (resultType->isVoid())
1217+
return returnStmt;
1218+
1219+
assert(resultType->getOptionalObjectType() &&
1220+
resultType->lookThroughAllOptionalTypes()->isVoid());
1221+
1222+
auto &cs = solution.getConstraintSystem();
1223+
1224+
// Build an implicit empty tuple to represent `Void` return
1225+
auto *emptyTuple = TupleExpr::createEmpty(ctx,
1226+
/*LParenLoc=*/SourceLoc(),
1227+
/*RParenLoc=*/SourceLoc(),
1228+
/*Implicit=*/true);
1229+
emptyTuple->setType(ctx.TheEmptyTupleType);
1230+
// Cache the type of this new expression in the constraint system
1231+
// for the future reference.
1232+
cs.cacheExprTypes(emptyTuple);
1233+
1234+
returnStmt->setResult(emptyTuple);
1235+
}
12091236

12101237
auto *resultExpr = returnStmt->getResult();
12111238

0 commit comments

Comments
 (0)