When they say
static func buildBlock(_ components: Component...) -> Component
They don't strictly mean that there exists one type, Component
, that buildBlock
must take in and return. They just mean that buildBlock
should take in a number of parameters, whose types are the types of "partial results", and return a type that is a type of a "partial result". Calling them both Component
might be a bit confusing.
I think the Swift evolution proposal explains a little better (emphasis mine):
The typing here is subtle, as it often is in macro-like features. In the following descriptions, Expression
stands for any type that is acceptable for an expression-statement to have (that is, a raw partial result), Component
stands for any type that is acceptable for a partial or combined result to have, and FinalResult
stands for any type that is acceptable to be ultimately returned by the transformed function.
So Component
, Expression
and FinalResult
etc don't have to be fixed to a single type. You can even overload the buildXXX
methods, as demonstrated later in the evolution proposal.
Ultimately, result builders undergo a transformation to calls to buildXXX
, when you actually use them. That is when type errors, if you have them, will be reported.
For example,
@resultBuilder
struct MyBuilder {
static func buildBlock(_ p1: String, _ p2: String) -> Int {
1
}
}
func foo(@MyBuilder _ block: () -> Double) -> Double {
block()
}
foo { // Cannot convert value of type 'Int' to closure result type 'Double'
10 // Cannot convert value of type 'Int' to expected argument type 'String'
20 // Cannot convert value of type 'Int' to expected argument type 'String'
}
The first error is because the result builder's result type is Int
, but foo
's closure parameter expects a return value of type Double
. The last two is because the transformation of the result builder attempts to call MyBuilder.buildBlock(10, 20)
.
It all makes sense if you look at the transformed closure:
foo {
let v1 = 10
let v2 = 20
return MyBuilder.buildBlock(v1, v2)
}
Essentially, as long as the transformed code compiles, there is no problem.
See more details about the transformation here.