Skip to content

Commit d46c4ec

Browse files
committed
[Function builders] Add support for 'throw' statement.
1 parent 1a90ecc commit d46c4ec

File tree

3 files changed

+76
-4
lines changed

3 files changed

+76
-4
lines changed

lib/Sema/BuilderTransform.cpp

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,26 @@ class BuilderClosureVisitor
896896
return finalForEachVar;
897897
}
898898

899+
/// Visit a throw statement, which never produces a result.
900+
VarDecl *visitThrowStmt(ThrowStmt *throwStmt) {
901+
Type exnType = ctx.getErrorDecl()->getDeclaredInterfaceType();
902+
if (!exnType) {
903+
hadError = true;
904+
}
905+
906+
if (cs) {
907+
SolutionApplicationTarget target(
908+
throwStmt->getSubExpr(), dc, CTP_ThrowStmt, exnType,
909+
/*isDiscarded=*/false);
910+
if (cs->generateConstraints(target, FreeTypeVariableBinding::Disallow))
911+
hadError = true;
912+
913+
cs->setSolutionApplicationTarget(throwStmt, target);
914+
}
915+
916+
return nullptr;
917+
}
918+
899919
CONTROL_FLOW_STMT(Guard)
900920
CONTROL_FLOW_STMT(While)
901921
CONTROL_FLOW_STMT(DoCatch)
@@ -905,7 +925,6 @@ class BuilderClosureVisitor
905925
CONTROL_FLOW_STMT(Continue)
906926
CONTROL_FLOW_STMT(Fallthrough)
907927
CONTROL_FLOW_STMT(Fail)
908-
CONTROL_FLOW_STMT(Throw)
909928
CONTROL_FLOW_STMT(PoundAssert)
910929

911930
#undef CONTROL_FLOW_STMT
@@ -1141,6 +1160,14 @@ class BuilderClosureRewriter
11411160
}
11421161

11431162
if (auto stmt = node.dyn_cast<Stmt *>()) {
1163+
// "throw" statements produce no value. Transform them directly.
1164+
if (auto throwStmt = dyn_cast<ThrowStmt>(stmt)) {
1165+
if (auto newStmt = visitThrowStmt(throwStmt)) {
1166+
newElements.push_back(stmt);
1167+
}
1168+
continue;
1169+
}
1170+
11441171
// Each statement turns into a (potential) temporary variable
11451172
// binding followed by the statement itself.
11461173
auto captured = takeCapturedStmt(stmt);
@@ -1429,6 +1456,22 @@ class BuilderClosureRewriter
14291456
ctx, forEachStmt->getStartLoc(), outerBodySteps, newBody->getEndLoc());
14301457
}
14311458

1459+
Stmt *visitThrowStmt(ThrowStmt *throwStmt) {
1460+
// Rewrite the error.
1461+
auto target = *solution.getConstraintSystem()
1462+
.getSolutionApplicationTarget(throwStmt);
1463+
if (auto result = rewriteTarget(target))
1464+
throwStmt->setSubExpr(result->getAsExpr());
1465+
else
1466+
return nullptr;
1467+
1468+
return throwStmt;
1469+
}
1470+
1471+
Stmt *visitThrowStmt(ThrowStmt *throwStmt, FunctionBuilderTarget target) {
1472+
llvm_unreachable("Throw statements produce no value");
1473+
}
1474+
14321475
#define UNHANDLED_FUNCTION_BUILDER_STMT(STMT) \
14331476
Stmt *visit##STMT##Stmt(STMT##Stmt *stmt, FunctionBuilderTarget target) { \
14341477
llvm_unreachable("Function builders do not allow statement of kind " \
@@ -1446,7 +1489,6 @@ class BuilderClosureRewriter
14461489
UNHANDLED_FUNCTION_BUILDER_STMT(Continue)
14471490
UNHANDLED_FUNCTION_BUILDER_STMT(Fallthrough)
14481491
UNHANDLED_FUNCTION_BUILDER_STMT(Fail)
1449-
UNHANDLED_FUNCTION_BUILDER_STMT(Throw)
14501492
UNHANDLED_FUNCTION_BUILDER_STMT(PoundAssert)
14511493
#undef UNHANDLED_FUNCTION_BUILDER_STMT
14521494
};

test/Constraints/function_builder.swift

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ struct TupleBuilder {
4444
static func buildArray<T>(_ array: [T]) -> [T] { return array }
4545
}
4646

47-
func tuplify<T>(_ cond: Bool, @TupleBuilder body: (Bool) -> T) {
48-
print(body(cond))
47+
func tuplify<T>(_ cond: Bool, @TupleBuilder body: (Bool) throws -> T) rethrows {
48+
print(try body(cond))
4949
}
5050

5151
// CHECK: (17, 3.14159, "Hello, DSL", (["nested", "do"], 6), Optional((2.71828, ["if", "stmt"])))
@@ -749,3 +749,21 @@ let a = buildArray {
749749
// CHECK: ["1", "2"
750750
print(a)
751751

752+
// Throwing in function builders.
753+
enum MyError: Error {
754+
case boom
755+
}
756+
757+
// CHECK: testThrow
758+
do {
759+
print("testThrow")
760+
try tuplify(true) { c in
761+
"ready to throw"
762+
throw MyError.boom
763+
}
764+
} catch MyError.boom {
765+
// CHECK: caught it!
766+
print("caught it!")
767+
} catch {
768+
fatalError("Threw something else?")
769+
}

test/Constraints/function_builder_diags.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,3 +620,15 @@ struct MyView {
620620
""
621621
}
622622
}
623+
624+
// Make sure throwing function builder closures are implied.
625+
enum MyError: Error {
626+
case boom
627+
}
628+
629+
do {
630+
tuplify(true) { c in // expected-error{{invalid conversion from throwing function of type '(Bool) throws -> String' to non-throwing function type '(Bool) -> String'}}
631+
"testThrow"
632+
throw MyError.boom
633+
}
634+
}

0 commit comments

Comments
 (0)