Skip to content

Commit 97e34d1

Browse files
authored
Merge pull request #33516 from DougGregor/function-builders-qualified-lookup
[Function builders] Allow `build` functions to be declared elsewhere.
2 parents e76ee54 + 9ef0fce commit 97e34d1

File tree

2 files changed

+69
-1
lines changed

2 files changed

+69
-1
lines changed

lib/Sema/BuilderTransform.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,11 @@ class BuilderClosureVisitor
146146
}
147147

148148
bool found = false;
149-
for (auto decl : builder->lookupDirect(fnName)) {
149+
SmallVector<ValueDecl *, 4> foundDecls;
150+
dc->lookupQualified(
151+
builderType, DeclNameRef(fnName),
152+
NL_QualifiedDefault | NL_ProtocolMembers, foundDecls);
153+
for (auto decl : foundDecls) {
150154
if (auto func = dyn_cast<FuncDecl>(decl)) {
151155
// Function must be static.
152156
if (!func->isStatic())

test/Constraints/function_builder.swift

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,5 +703,69 @@ tuplify(true) { c in
703703
}
704704
}
705705

706+
// Test the use of function builders partly implemented through a protocol.
707+
indirect enum FunctionBuilder<Expression> {
708+
case expression(Expression)
709+
case block([FunctionBuilder])
710+
case either(Either<FunctionBuilder, FunctionBuilder>)
711+
case optional(FunctionBuilder?)
712+
}
713+
714+
protocol FunctionBuilderProtocol {
715+
associatedtype Expression
716+
typealias Component = FunctionBuilder<Expression>
717+
associatedtype Return
718+
719+
static func buildExpression(_ expression: Expression) -> Component
720+
static func buildBlock(_ components: Component...) -> Component
721+
static func buildDo(_ components: Component...) -> Component
722+
static func buildOptional(_ optional: Component?) -> Component
723+
static func buildArray(_ components: [Component]) -> Component
724+
static func buildLimitedAvailability(_ component: Component) -> Component
725+
726+
static func buildFinalResult(_ components: Component) -> Return
727+
}
728+
729+
extension FunctionBuilderProtocol {
730+
static func buildExpression(_ expression: Expression) -> Component { .expression(expression) }
731+
static func buildBlock(_ components: Component...) -> Component { .block(components) }
732+
static func buildDo(_ components: Component...) -> Component { .block(components) }
733+
static func buildOptional(_ optional: Component?) -> Component { .optional(optional) }
734+
static func buildArray(_ components: [Component]) -> Component { .block(components) }
735+
static func buildLimitedAvailability(_ component: Component) -> Component { component }
736+
}
737+
738+
@_functionBuilder
739+
enum ArrayBuilder<E>: FunctionBuilderProtocol {
740+
typealias Expression = E
741+
typealias Component = FunctionBuilder<E>
742+
typealias Return = [E]
743+
744+
static func buildFinalResult(_ components: Component) -> Return {
745+
switch components {
746+
case .expression(let e): return [e]
747+
case .block(let children): return children.flatMap(buildFinalResult)
748+
case .either(.first(let child)): return buildFinalResult(child)
749+
case .either(.second(let child)): return buildFinalResult(child)
750+
case .optional(let child?): return buildFinalResult(child)
751+
case .optional(nil): return []
752+
}
753+
}
754+
}
755+
756+
757+
func buildArray(@ArrayBuilder<String> build: () -> [String]) -> [String] {
758+
return build()
759+
}
706760

707761

762+
let a = buildArray {
763+
"1"
764+
"2"
765+
if Bool.random() {
766+
"maybe 3"
767+
}
768+
}
769+
// CHECK: ["1", "2"
770+
print(a)
771+

0 commit comments

Comments
 (0)