Skip to content

Commit 7daed3c

Browse files
authored
Merge pull request swiftlang#33570 from DougGregor/function-builders-throw
2 parents d3b4094 + d46c4ec commit 7daed3c

File tree

3 files changed

+76
-8
lines changed

3 files changed

+76
-8
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 & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@ enum Either<T,U> {
66
case second(U)
77
}
88

9-
struct Do<T> {
10-
var value: T
11-
}
12-
139
@_functionBuilder
1410
struct TupleBuilder {
1511
static func buildBlock<T1>(_ t1: T1) -> (T1) {
@@ -48,8 +44,8 @@ struct TupleBuilder {
4844
static func buildArray<T>(_ array: [T]) -> [T] { return array }
4945
}
5046

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

5551
// CHECK: (17, 3.14159, "Hello, DSL", (["nested", "do"], 6), Optional((2.71828, ["if", "stmt"])))
@@ -753,3 +749,21 @@ let a = buildArray {
753749
// CHECK: ["1", "2"
754750
print(a)
755751

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
@@ -623,3 +623,15 @@ struct MyView {
623623
""
624624
}
625625
}
626+
627+
// Make sure throwing function builder closures are implied.
628+
enum MyError: Error {
629+
case boom
630+
}
631+
632+
do {
633+
tuplify(true) { c in // expected-error{{invalid conversion from throwing function of type '(Bool) throws -> String' to non-throwing function type '(Bool) -> String'}}
634+
"testThrow"
635+
throw MyError.boom
636+
}
637+
}

0 commit comments

Comments
 (0)