Skip to content

Commit ce97d22

Browse files
committed
[Function builders] Add support for buildFinalResult().
When present in a function builder, buildFinalResult() will be called on the value of the outermost block to form the final result of the closure. This allows one to collapse the full function builder computation into a single result without having to do it in each buildBlock() call.
1 parent a09b641 commit ce97d22

File tree

3 files changed

+70
-0
lines changed

3 files changed

+70
-0
lines changed

include/swift/AST/KnownIdentifiers.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ IDENTIFIER(buildBlock)
3535
IDENTIFIER(buildDo)
3636
IDENTIFIER(buildEither)
3737
IDENTIFIER(buildExpression)
38+
IDENTIFIER(buildFinalResult)
3839
IDENTIFIER(buildIf)
3940
IDENTIFIER(callAsFunction)
4041
IDENTIFIER(Change)

lib/Sema/BuilderTransform.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,15 @@ class BuilderClosureVisitor
210210
return None;
211211

212212
applied.returnExpr = buildVarRef(bodyVar, stmt->getEndLoc());
213+
214+
// If there is a buildFinalResult(_:), call it.
215+
ASTContext &ctx = cs->getASTContext();
216+
if (builderSupports(ctx.Id_buildFinalResult, { Identifier() })) {
217+
applied.returnExpr = buildCallIfWanted(
218+
applied.returnExpr->getLoc(), ctx.Id_buildFinalResult,
219+
{ applied.returnExpr }, { Identifier() });
220+
}
221+
213222
applied.returnExpr = cs->buildTypeErasedExpr(applied.returnExpr,
214223
dc, applied.bodyResultType,
215224
CTP_ReturnStmt);

test/Constraints/function_builder_diags.swift

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,3 +480,63 @@ func testCaseVarTypes(e: E3) {
480480
}
481481
}
482482
}
483+
484+
// Test for buildFinalResult.
485+
@_functionBuilder
486+
struct WrapperBuilder {
487+
static func buildBlock() -> () { }
488+
489+
static func buildBlock<T1>(_ t1: T1) -> T1 {
490+
return t1
491+
}
492+
493+
static func buildBlock<T1, T2>(_ t1: T1, _ t2: T2) -> (T1, T2) {
494+
return (t1, t2)
495+
}
496+
497+
static func buildBlock<T1, T2, T3>(_ t1: T1, _ t2: T2, _ t3: T3)
498+
-> (T1, T2, T3) {
499+
return (t1, t2, t3)
500+
}
501+
502+
static func buildBlock<T1, T2, T3, T4>(_ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4)
503+
-> (T1, T2, T3, T4) {
504+
return (t1, t2, t3, t4)
505+
}
506+
507+
static func buildBlock<T1, T2, T3, T4, T5>(
508+
_ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4, _ t5: T5
509+
) -> (T1, T2, T3, T4, T5) {
510+
return (t1, t2, t3, t4, t5)
511+
}
512+
513+
static func buildDo<T>(_ value: T) -> T { return value }
514+
static func buildIf<T>(_ value: T?) -> T? { return value }
515+
516+
static func buildEither<T,U>(first value: T) -> Either<T,U> {
517+
return .first(value)
518+
}
519+
static func buildEither<T,U>(second value: U) -> Either<T,U> {
520+
return .second(value)
521+
}
522+
static func buildFinalResult<T>(_ value: T) -> Wrapper<T> {
523+
return Wrapper(value: value)
524+
}
525+
}
526+
527+
struct Wrapper<T> {
528+
var value: T
529+
}
530+
531+
func wrapperify<T>(_ cond: Bool, @WrapperBuilder body: (Bool) -> T) -> T{
532+
return body(cond)
533+
}
534+
535+
func testWrapperBuilder() {
536+
let x = wrapperify(true) { c in
537+
3.14159
538+
"hello"
539+
}
540+
541+
let _: Int = x // expected-error{{cannot convert value of type 'Wrapper<(Double, String)>' to specified type 'Int'}}
542+
}

0 commit comments

Comments
 (0)